From 1dd26042cc11e15eb7406e750c9454a2e2289a0f Mon Sep 17 00:00:00 2001 From: Manlio Perillo Date: Sat, 25 Feb 2023 10:41:37 +0100 Subject: [PATCH 001/725] docgen: remove line support in printShell Line support in printShell breaks the support to terminal colors, when a color is active over multiple lines. An example is when printing reference traces. Remove line support in printShell, since they are not really necessary like in printSourceBlock. In genHtml, remove an empty line when printing the execution of the executable generated by `zig build-exe`. Update the "shell parsed" tests. Remove the call to log.emerg, since it is no longer supported. Add an extra space after "--build-option1 \", as documented. Fixes #13280 --- doc/docgen.zig | 75 ++++++++++++++++++++++++-------------------------- 1 file changed, 36 insertions(+), 39 deletions(-) diff --git a/doc/docgen.zig b/doc/docgen.zig index 277316dd37..e7663cdfe2 100644 --- a/doc/docgen.zig +++ b/doc/docgen.zig @@ -1224,41 +1224,39 @@ fn printShell(out: anytype, shell_content: []const u8, escape: bool) !void { while (iter.next()) |orig_line| { const line = mem.trimRight(u8, orig_line, " "); if (!cmd_cont and line.len > 1 and mem.eql(u8, line[0..2], "$ ") and line[line.len - 1] != '\\') { - try out.writeAll(start_line ++ "$ "); + try out.writeAll("$ "); const s = std.mem.trimLeft(u8, line[1..], " "); if (escape) { try writeEscaped(out, s); } else { try out.writeAll(s); } - try out.writeAll("" ++ end_line ++ "\n"); + try out.writeAll("" ++ "\n"); } else if (!cmd_cont and line.len > 1 and mem.eql(u8, line[0..2], "$ ") and line[line.len - 1] == '\\') { - try out.writeAll(start_line ++ "$ "); + try out.writeAll("$ "); const s = std.mem.trimLeft(u8, line[1..], " "); if (escape) { try writeEscaped(out, s); } else { try out.writeAll(s); } - try out.writeAll(end_line ++ "\n"); + try out.writeAll("\n"); cmd_cont = true; } else if (line.len > 0 and line[line.len - 1] != '\\' and cmd_cont) { - try out.writeAll(start_line); if (escape) { try writeEscaped(out, line); } else { try out.writeAll(line); } - try out.writeAll("" ++ end_line ++ "\n"); + try out.writeAll("" ++ "\n"); cmd_cont = false; } else { - try out.writeAll(start_line); if (escape) { try writeEscaped(out, line); } else { try out.writeAll(line); } - try out.writeAll(end_line ++ "\n"); + try out.writeAll("\n"); } } @@ -1511,7 +1509,7 @@ fn genHtml( const colored_stderr = try termColor(allocator, escaped_stderr); const colored_stdout = try termColor(allocator, escaped_stdout); - try shell_out.print("\n$ ./{s}\n{s}{s}", .{ code.name, colored_stdout, colored_stderr }); + try shell_out.print("$ ./{s}\n{s}{s}", .{ code.name, colored_stdout, colored_stderr }); if (exited_with_signal) { try shell_out.print("(process terminated by signal)", .{}); } @@ -1884,7 +1882,7 @@ test "shell parsed" { \\$ zig build test.zig ; const expected = - \\
Shell
$ zig build test.zig
+            \\
Shell
$ zig build test.zig
             \\
; @@ -1892,7 +1890,6 @@ test "shell parsed" { defer buffer.deinit(); try printShell(buffer.writer(), shell_out, false); - std.log.emerg("{s}", .{buffer.items}); try testing.expectEqualSlices(u8, expected, buffer.items); } { @@ -1901,8 +1898,8 @@ test "shell parsed" { \\build output ; const expected = - \\
Shell
$ zig build test.zig
-            \\build output
+            \\
Shell
$ zig build test.zig
+            \\build output
             \\
; @@ -1919,9 +1916,9 @@ test "shell parsed" { \\$ ./test ; const expected = - \\
Shell
$ zig build test.zig
-            \\build output
-            \\$ ./test
+            \\
Shell
$ zig build test.zig
+            \\build output
+            \\$ ./test
             \\
; @@ -1939,10 +1936,10 @@ test "shell parsed" { \\output ; const expected = - \\
Shell
$ zig build test.zig
-            \\
-            \\$ ./test
-            \\output
+            \\
Shell
$ zig build test.zig
+            \\
+            \\$ ./test
+            \\output
             \\
; @@ -1959,9 +1956,9 @@ test "shell parsed" { \\output ; const expected = - \\
Shell
$ zig build test.zig
-            \\$ ./test
-            \\output
+            \\
Shell
$ zig build test.zig
+            \\$ ./test
+            \\output
             \\
; @@ -1980,11 +1977,11 @@ test "shell parsed" { \\output ; const expected = - \\
Shell
$ zig build test.zig \
-            \\ --build-option
-            \\build output
-            \\$ ./test
-            \\output
+            \\
Shell
$ zig build test.zig \
+            \\ --build-option
+            \\build output
+            \\$ ./test
+            \\output
             \\
; @@ -1998,15 +1995,15 @@ test "shell parsed" { // intentional space after "--build-option1 \" const shell_out = \\$ zig build test.zig \ - \\ --build-option1 \ + \\ --build-option1 \ \\ --build-option2 \\$ ./test ; const expected = - \\
Shell
$ zig build test.zig \
-            \\ --build-option1 \
-            \\ --build-option2
-            \\$ ./test
+            \\
Shell
$ zig build test.zig \
+            \\ --build-option1 \
+            \\ --build-option2
+            \\$ ./test
             \\
; @@ -2022,8 +2019,8 @@ test "shell parsed" { \\$ ./test ; const expected = - \\
Shell
$ zig build test.zig \
-            \\$ ./test
+            \\
Shell
$ zig build test.zig \
+            \\$ ./test
             \\
; @@ -2040,9 +2037,9 @@ test "shell parsed" { \\$1 ; const expected = - \\
Shell
$ zig build test.zig
-            \\$ ./test
-            \\$1
+            \\
Shell
$ zig build test.zig
+            \\$ ./test
+            \\$1
             \\
; @@ -2057,7 +2054,7 @@ test "shell parsed" { \\$zig build test.zig ; const expected = - \\
Shell
$zig build test.zig
+            \\
Shell
$zig build test.zig
             \\
; From 7ca052a6fb017882de1ebcf86226f3b2927a11c7 Mon Sep 17 00:00:00 2001 From: Manlio Perillo Date: Sat, 25 Feb 2023 11:14:43 +0100 Subject: [PATCH 002/725] docgen: improve the termColor function Make the termColor function more robust, ensuring that the generated HTML classes are more consistent and that they are supported in the CSS. Add documentation about the ANSI codes generated by Zig, and remove the previous comment with the supported colors. Improve test coverage for the termColor function, and move the tests at the end of the file before the printShell tests. Rename the "term color" test to "term supported colors" and add an additional "term output from zig" test, using test data generated from the Zig compiler. Update the langref.html.in CSS to use the new names and remove incorrect or obsolete colors like .t0_1, .t37 and .t37_1. Fix support for the 1m color. Change font-weight to normal for the kbd element, to avoid both the command (like `zig build-exe`) and the first line of the error message having a bold font. Rename the "shell parsed" test to "printShell". --- doc/docgen.zig | 258 +++++++++++++++++++++++++++++++++++++++----- doc/langref.html.in | 20 ++-- 2 files changed, 243 insertions(+), 35 deletions(-) diff --git a/doc/docgen.zig b/doc/docgen.zig index e7663cdfe2..6f2438c857 100644 --- a/doc/docgen.zig +++ b/doc/docgen.zig @@ -793,28 +793,37 @@ fn writeEscaped(out: anytype, input: []const u8) !void { } } -//#define VT_RED "\x1b[31;1m" -//#define VT_GREEN "\x1b[32;1m" -//#define VT_CYAN "\x1b[36;1m" -//#define VT_WHITE "\x1b[37;1m" -//#define VT_BOLD "\x1b[0;1m" -//#define VT_RESET "\x1b[0m" - -test "term color" { - const input_bytes = "A\x1b[32;1mgreen\x1b[0mB"; - const result = try termColor(std.testing.allocator, input_bytes); - defer std.testing.allocator.free(result); - try testing.expectEqualSlices(u8, "AgreenB", result); +// Returns true if number is in slice. +fn in(slice: []const u8, number: u8) bool { + for (slice) |n| { + if (number == n) return true; + } + return false; } fn termColor(allocator: Allocator, input: []const u8) ![]u8 { + // The SRG sequences generates by the Zig compiler are in the format: + // ESC [ ; m + // or + // ESC [ m + // + // where + // foreground-color is 31 (red), 32 (green), 36 (cyan) + // n is 0 (reset), 1 (bold), 2 (dim) + // + // Note that 37 (white) is currently not used by the compiler. + // + // See std.debug.TTY.Color. + const supported_sgr_colors = [_]u8{ 31, 32, 36 }; + const supported_sgr_numbers = [_]u8{ 0, 1, 2 }; + var buf = std.ArrayList(u8).init(allocator); defer buf.deinit(); var out = buf.writer(); - var number_start_index: usize = undefined; - var first_number: usize = undefined; - var second_number: usize = undefined; + var sgr_param_start_index: usize = undefined; + var sgr_num: u8 = undefined; + var sgr_color: u8 = undefined; var i: usize = 0; var state: enum { start, @@ -845,7 +854,7 @@ fn termColor(allocator: Allocator, input: []const u8) ![]u8 { }, .lbracket => switch (c) { '0'...'9' => { - number_start_index = i; + sgr_param_start_index = i; state = .number; }, else => return error.UnsupportedEscape, @@ -853,13 +862,12 @@ fn termColor(allocator: Allocator, input: []const u8) ![]u8 { .number => switch (c) { '0'...'9' => {}, else => { - first_number = std.fmt.parseInt(usize, input[number_start_index..i], 10) catch unreachable; - second_number = 0; + sgr_num = try std.fmt.parseInt(u8, input[sgr_param_start_index..i], 10); + sgr_color = 0; state = .after_number; i -= 1; }, }, - .after_number => switch (c) { ';' => state = .arg, 'D' => state = .start, @@ -874,7 +882,7 @@ fn termColor(allocator: Allocator, input: []const u8) ![]u8 { }, .arg => switch (c) { '0'...'9' => { - number_start_index = i; + sgr_param_start_index = i; state = .arg_number; }, else => return error.UnsupportedEscape, @@ -882,7 +890,15 @@ fn termColor(allocator: Allocator, input: []const u8) ![]u8 { .arg_number => switch (c) { '0'...'9' => {}, else => { - second_number = std.fmt.parseInt(usize, input[number_start_index..i], 10) catch unreachable; + // Keep the sequence consistent, foreground color first. + // 32;1m is equivalent to 1;32m, but the latter will + // generate an incorrect HTML class without notice. + sgr_color = sgr_num; + if (!in(&supported_sgr_colors, sgr_color)) return error.UnsupportedForegroundColor; + + sgr_num = try std.fmt.parseInt(u8, input[sgr_param_start_index..i], 10); + if (!in(&supported_sgr_numbers, sgr_num)) return error.UnsupportedNumber; + state = .expect_end; i -= 1; }, @@ -893,10 +909,16 @@ fn termColor(allocator: Allocator, input: []const u8) ![]u8 { while (open_span_count != 0) : (open_span_count -= 1) { try out.writeAll(""); } - if (first_number != 0 or second_number != 0) { - try out.print("", .{ first_number, second_number }); - open_span_count += 1; + if (sgr_num == 0) { + if (sgr_color != 0) return error.UnsupportedColor; + continue; } + if (sgr_color != 0) { + try out.print("", .{ sgr_color, sgr_num }); + } else { + try out.print("", .{sgr_num}); + } + open_span_count += 1; }, else => return error.UnsupportedEscape, }, @@ -1874,7 +1896,193 @@ fn dumpArgs(args: []const []const u8) void { print("\n", .{}); } -test "shell parsed" { +test "term supported colors" { + const test_allocator = testing.allocator; + + { + const input = "A\x1b[31;1mred\x1b[0mB"; + const expect = "AredB"; + + const result = try termColor(test_allocator, input); + defer test_allocator.free(result); + try testing.expectEqualSlices(u8, expect, result); + } + + { + const input = "A\x1b[32;1mgreen\x1b[0mB"; + const expect = "AgreenB"; + + const result = try termColor(test_allocator, input); + defer test_allocator.free(result); + try testing.expectEqualSlices(u8, expect, result); + } + + { + const input = "A\x1b[36;1mcyan\x1b[0mB"; + const expect = "AcyanB"; + + const result = try termColor(test_allocator, input); + defer test_allocator.free(result); + try testing.expectEqualSlices(u8, expect, result); + } + + { + const input = "A\x1b[1mbold\x1b[0mB"; + const expect = "AboldB"; + + const result = try termColor(test_allocator, input); + defer test_allocator.free(result); + try testing.expectEqualSlices(u8, expect, result); + } + + { + const input = "A\x1b[2mdim\x1b[0mB"; + const expect = "AdimB"; + + const result = try termColor(test_allocator, input); + defer test_allocator.free(result); + try testing.expectEqualSlices(u8, expect, result); + } +} + +test "term output from zig" { + // Use data generated by https://github.com/perillo/zig-tty-test-data, + // with zig version 0.11.0-dev.1898+36d47dd19. + const test_allocator = testing.allocator; + + { + // 1.1-with-build-progress.out + const input = "Semantic Analysis [1324] \x1b[25D\x1b[0KLLVM Emit Object... \x1b[20D\x1b[0KLLVM Emit Object... \x1b[20D\x1b[0KLLD Link... \x1b[12D\x1b[0K"; + const expect = ""; + + const result = try termColor(test_allocator, input); + defer test_allocator.free(result); + try testing.expectEqualSlices(u8, expect, result); + } + + { + // 2.1-with-reference-traces.out + const input = "\x1b[1msrc/2.1-with-reference-traces.zig:3:7: \x1b[31;1merror: \x1b[0m\x1b[1mcannot assign to constant\n\x1b[0m x += 1;\n \x1b[32;1m~~^~~~\n\x1b[0m\x1b[0m\x1b[2mreferenced by:\n main: src/2.1-with-reference-traces.zig:7:5\n callMain: /usr/local/lib/zig/lib/std/start.zig:607:17\n remaining reference traces hidden; use '-freference-trace' to see all reference traces\n\n\x1b[0m"; + const expect = + \\src/2.1-with-reference-traces.zig:3:7: error: cannot assign to constant + \\ x += 1; + \\ ~~^~~~ + \\referenced by: + \\ main: src/2.1-with-reference-traces.zig:7:5 + \\ callMain: /usr/local/lib/zig/lib/std/start.zig:607:17 + \\ remaining reference traces hidden; use '-freference-trace' to see all reference traces + \\ + \\ + ; + + const result = try termColor(test_allocator, input); + defer test_allocator.free(result); + try testing.expectEqualSlices(u8, expect, result); + } + + { + // 2.2-without-reference-traces.out + const input = "\x1b[1m/usr/local/lib/zig/lib/std/io/fixed_buffer_stream.zig:128:29: \x1b[31;1merror: \x1b[0m\x1b[1minvalid type given to fixedBufferStream\n\x1b[0m else => @compileError(\"invalid type given to fixedBufferStream\"),\n \x1b[32;1m^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\x1b[0m\x1b[1m/usr/local/lib/zig/lib/std/io/fixed_buffer_stream.zig:116:66: \x1b[36;1mnote: \x1b[0m\x1b[1mcalled from here\n\x1b[0mpub fn fixedBufferStream(buffer: anytype) FixedBufferStream(Slice(@TypeOf(buffer))) {\n; \x1b[32;1m~~~~~^~~~~~~~~~~~~~~~~\n\x1b[0m"; + const expect = + \\/usr/local/lib/zig/lib/std/io/fixed_buffer_stream.zig:128:29: error: invalid type given to fixedBufferStream + \\ else => @compileError("invalid type given to fixedBufferStream"), + \\ ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + \\/usr/local/lib/zig/lib/std/io/fixed_buffer_stream.zig:116:66: note: called from here + \\pub fn fixedBufferStream(buffer: anytype) FixedBufferStream(Slice(@TypeOf(buffer))) { + \\; ~~~~~^~~~~~~~~~~~~~~~~ + \\ + ; + + const result = try termColor(test_allocator, input); + defer test_allocator.free(result); + try testing.expectEqualSlices(u8, expect, result); + } + + { + // 2.3-with-notes.out + const input = "\x1b[1msrc/2.3-with-notes.zig:6:9: \x1b[31;1merror: \x1b[0m\x1b[1mexpected type '*2.3-with-notes.Derp', found '*2.3-with-notes.Wat'\n\x1b[0m bar(w);\n \x1b[32;1m^\n\x1b[0m\x1b[1msrc/2.3-with-notes.zig:6:9: \x1b[36;1mnote: \x1b[0m\x1b[1mpointer type child '2.3-with-notes.Wat' cannot cast into pointer type child '2.3-with-notes.Derp'\n\x1b[0m\x1b[1msrc/2.3-with-notes.zig:2:13: \x1b[36;1mnote: \x1b[0m\x1b[1mopaque declared here\n\x1b[0mconst Wat = opaque {};\n \x1b[32;1m^~~~~~~~~\n\x1b[0m\x1b[1msrc/2.3-with-notes.zig:1:14: \x1b[36;1mnote: \x1b[0m\x1b[1mopaque declared here\n\x1b[0mconst Derp = opaque {};\n \x1b[32;1m^~~~~~~~~\n\x1b[0m\x1b[1msrc/2.3-with-notes.zig:4:18: \x1b[36;1mnote: \x1b[0m\x1b[1mparameter type declared here\n\x1b[0mextern fn bar(d: *Derp) void;\n \x1b[32;1m^~~~~\n\x1b[0m\x1b[0m\x1b[2mreferenced by:\n main: src/2.3-with-notes.zig:10:5\n callMain: /usr/local/lib/zig/lib/std/start.zig:607:17\n remaining reference traces hidden; use '-freference-trace' to see all reference traces\n\n\x1b[0m"; + const expect = + \\src/2.3-with-notes.zig:6:9: error: expected type '*2.3-with-notes.Derp', found '*2.3-with-notes.Wat' + \\ bar(w); + \\ ^ + \\src/2.3-with-notes.zig:6:9: note: pointer type child '2.3-with-notes.Wat' cannot cast into pointer type child '2.3-with-notes.Derp' + \\src/2.3-with-notes.zig:2:13: note: opaque declared here + \\const Wat = opaque {}; + \\ ^~~~~~~~~ + \\src/2.3-with-notes.zig:1:14: note: opaque declared here + \\const Derp = opaque {}; + \\ ^~~~~~~~~ + \\src/2.3-with-notes.zig:4:18: note: parameter type declared here + \\extern fn bar(d: *Derp) void; + \\ ^~~~~ + \\referenced by: + \\ main: src/2.3-with-notes.zig:10:5 + \\ callMain: /usr/local/lib/zig/lib/std/start.zig:607:17 + \\ remaining reference traces hidden; use '-freference-trace' to see all reference traces + \\ + \\ + ; + + const result = try termColor(test_allocator, input); + defer test_allocator.free(result); + try testing.expectEqualSlices(u8, expect, result); + } + + { + // 3.1-with-error-return-traces.out + + const input = "error: Error\n\x1b[1m/home/zig/src/3.1-with-error-return-traces.zig:5:5\x1b[0m: \x1b[2m0x20b008 in callee (3.1-with-error-return-traces)\x1b[0m\n return error.Error;\n \x1b[32;1m^\x1b[0m\n\x1b[1m/home/zig/src/3.1-with-error-return-traces.zig:9:5\x1b[0m: \x1b[2m0x20b113 in caller (3.1-with-error-return-traces)\x1b[0m\n try callee();\n \x1b[32;1m^\x1b[0m\n\x1b[1m/home/zig/src/3.1-with-error-return-traces.zig:13:5\x1b[0m: \x1b[2m0x20b153 in main (3.1-with-error-return-traces)\x1b[0m\n try caller();\n \x1b[32;1m^\x1b[0m\n"; + const expect = + \\error: Error + \\/home/zig/src/3.1-with-error-return-traces.zig:5:5: 0x20b008 in callee (3.1-with-error-return-traces) + \\ return error.Error; + \\ ^ + \\/home/zig/src/3.1-with-error-return-traces.zig:9:5: 0x20b113 in caller (3.1-with-error-return-traces) + \\ try callee(); + \\ ^ + \\/home/zig/src/3.1-with-error-return-traces.zig:13:5: 0x20b153 in main (3.1-with-error-return-traces) + \\ try caller(); + \\ ^ + \\ + ; + + const result = try termColor(test_allocator, input); + defer test_allocator.free(result); + try testing.expectEqualSlices(u8, expect, result); + } + + { + // 3.2-with-stack-trace.out + const input = "\x1b[1m/usr/local/lib/zig/lib/std/debug.zig:561:19\x1b[0m: \x1b[2m0x22a107 in writeCurrentStackTrace__anon_5898 (3.2-with-stack-trace)\x1b[0m\n while (it.next()) |return_address| {\n \x1b[32;1m^\x1b[0m\n\x1b[1m/usr/local/lib/zig/lib/std/debug.zig:157:80\x1b[0m: \x1b[2m0x20bb23 in dumpCurrentStackTrace (3.2-with-stack-trace)\x1b[0m\n writeCurrentStackTrace(stderr, debug_info, detectTTYConfig(io.getStdErr()), start_addr) catch |err| {\n \x1b[32;1m^\x1b[0m\n\x1b[1m/home/zig/src/3.2-with-stack-trace.zig:5:36\x1b[0m: \x1b[2m0x20d3b2 in foo (3.2-with-stack-trace)\x1b[0m\n std.debug.dumpCurrentStackTrace(null);\n \x1b[32;1m^\x1b[0m\n\x1b[1m/home/zig/src/3.2-with-stack-trace.zig:9:8\x1b[0m: \x1b[2m0x20b458 in main (3.2-with-stack-trace)\x1b[0m\n foo();\n \x1b[32;1m^\x1b[0m\n\x1b[1m/usr/local/lib/zig/lib/std/start.zig:607:22\x1b[0m: \x1b[2m0x20a965 in posixCallMainAndExit (3.2-with-stack-trace)\x1b[0m\n root.main();\n \x1b[32;1m^\x1b[0m\n\x1b[1m/usr/local/lib/zig/lib/std/start.zig:376:5\x1b[0m: \x1b[2m0x20a411 in _start (3.2-with-stack-trace)\x1b[0m\n @call(.never_inline, posixCallMainAndExit, .{});\n \x1b[32;1m^\x1b[0m\n"; + const expect = + \\/usr/local/lib/zig/lib/std/debug.zig:561:19: 0x22a107 in writeCurrentStackTrace__anon_5898 (3.2-with-stack-trace) + \\ while (it.next()) |return_address| { + \\ ^ + \\/usr/local/lib/zig/lib/std/debug.zig:157:80: 0x20bb23 in dumpCurrentStackTrace (3.2-with-stack-trace) + \\ writeCurrentStackTrace(stderr, debug_info, detectTTYConfig(io.getStdErr()), start_addr) catch |err| { + \\ ^ + \\/home/zig/src/3.2-with-stack-trace.zig:5:36: 0x20d3b2 in foo (3.2-with-stack-trace) + \\ std.debug.dumpCurrentStackTrace(null); + \\ ^ + \\/home/zig/src/3.2-with-stack-trace.zig:9:8: 0x20b458 in main (3.2-with-stack-trace) + \\ foo(); + \\ ^ + \\/usr/local/lib/zig/lib/std/start.zig:607:22: 0x20a965 in posixCallMainAndExit (3.2-with-stack-trace) + \\ root.main(); + \\ ^ + \\/usr/local/lib/zig/lib/std/start.zig:376:5: 0x20a411 in _start (3.2-with-stack-trace) + \\ @call(.never_inline, posixCallMainAndExit, .{}); + \\ ^ + \\ + ; + + const result = try termColor(test_allocator, input); + defer test_allocator.free(result); + try testing.expectEqualSlices(u8, expect, result); + } +} + +test "printShell" { const test_allocator = std.testing.allocator; { diff --git a/doc/langref.html.in b/doc/langref.html.in index 907464867e..c88c91560c 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -71,19 +71,19 @@ text-align: left; font-weight: normal; } - .t0_1, .t37, .t37_1 { + .sgr-1m { font-weight: bold; } - .t2_0 { + .sgr-2m { color: #575757; } - .t31_1 { + .sgr-31_1m { color: #b40000; } - .t32_1 { + .sgr-32_1m { color: green; } - .t36_1 { + .sgr-36_1m { color: #005C7A; } .file { @@ -114,7 +114,7 @@ line-height: normal; } kbd { - font-weight: bold; + font-weight: normal; } .table-wrapper { width: 100%; @@ -232,16 +232,16 @@ table, th, td { border-color: grey; } - .t2_0 { + .sgr-2m { color: grey; } - .t31_1 { + .sgr-31_1m { color: red; } - .t32_1 { + .sgr-32_1m { color: #00B800; } - .t36_1 { + .sgr-36_1m { color: #0086b3; } code { From c579a23c5d997964a67883db5677c290bdbd7da6 Mon Sep 17 00:00:00 2001 From: David CARLIER Date: Sun, 16 Apr 2023 13:27:38 +0100 Subject: [PATCH 003/725] std: add CCRandomGenerateBytes macOs native api. --- lib/std/c/darwin.zig | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/lib/std/c/darwin.zig b/lib/std/c/darwin.zig index a46337b721..4ede0b3891 100644 --- a/lib/std/c/darwin.zig +++ b/lib/std/c/darwin.zig @@ -897,7 +897,35 @@ pub extern "c" fn pthread_attr_get_qos_class_np(attr: *pthread_attr_t, qos_class pub extern "c" fn pthread_set_qos_class_self_np(qos_class: qos_class_t, relative_priority: c_int) c_int; pub extern "c" fn pthread_get_qos_class_np(pthread: std.c.pthread_t, qos_class: *qos_class_t, relative_priority: *c_int) c_int; +pub const CCryptorStatus = enum(i32) { + /// Operation completed + kCCSuccess = 0, + /// Illegal parameter + kCCParamError = -4300, + /// Provided buffer too small + kCCBufferTooSmall = -4301, + /// Failed memory allocation + kCCMemoryFailure = -4302, + /// Size alignment issue + kCCAlignmentError = -4303, + /// Decoding issue + kCCDecodeError = -4304, + /// Call not implemented + kCCUnimplemented = -4305, + kCCOverflow = -4306, + kCCRNGFailure = -4307, + /// Unspecified error + kCCUnspecifiedError = -4308, + kCCCallSequenceError = -4309, + kCCKeySizeError = -4310, + /// Invalid key + kCCInvalidKey = -4311, +}; + +pub const CCRNGStatus = CCryptorStatus; + pub extern "c" fn arc4random_buf(buf: [*]u8, len: usize) void; +pub extern "c" fn CCRandomGenerateBytes(bytes: ?*anyopaque, count: usize) CCRNGStatus; // Grand Central Dispatch is exposed by libSystem. pub extern "c" fn dispatch_release(object: *anyopaque) void; From 6248ac535b9bfc7113101c1ff0f0bb1e41c394d4 Mon Sep 17 00:00:00 2001 From: David CARLIER Date: Sun, 16 Apr 2023 15:49:42 +0100 Subject: [PATCH 004/725] os: getrandom wrapper favoring it for macOs/iOs only --- lib/std/os.zig | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/lib/std/os.zig b/lib/std/os.zig index 13b0c62455..c2591ac355 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -512,7 +512,18 @@ pub fn getrandom(buffer: []u8) GetRandomError!void { return; } switch (builtin.os.tag) { - .netbsd, .openbsd, .macos, .ios, .tvos, .watchos => { + .macos, .ios => { + const rc = darwin.CCRandomGenerateBytes(buffer.ptr, buffer.len); + if (rc != darwin.CCRNGStatus.kCCSuccess) { + if (rc == darwin.CCRNGStatus.kCCParamError or rc == darwin.CCRNGStatus.kCCBufferTooSmall) { + return error.InvalidHandle; + } else { + return error.SystemResources; + } + } + return; + }, + .netbsd, .openbsd, .tvos, .watchos => { system.arc4random_buf(buffer.ptr, buffer.len); return; }, @@ -991,7 +1002,7 @@ pub fn preadv(fd: fd_t, iov: []const iovec, offset: u64) PReadError!usize { if (have_pread_but_not_preadv) { // We could loop here; but proper usage of `preadv` must handle partial reads anyway. // So we simply read into the first vector only. - if (iov.len == 0) return @as(usize, 0); + if (iov.len == 0) return @intCast(usize, 0); const first = iov[0]; return pread(fd, first.iov_base[0..first.iov_len], offset); } From d339e86fb1308f8df37fc351ee01007492e72f25 Mon Sep 17 00:00:00 2001 From: Koakuma Date: Wed, 4 Jan 2023 10:46:05 +0700 Subject: [PATCH 005/725] stage2: sparc64: Skip unimplemented tests --- test/behavior/array.zig | 4 ++++ test/behavior/bugs/12051.zig | 1 + test/behavior/bugs/12450.zig | 1 + test/behavior/comptime_memory.zig | 3 +++ test/behavior/packed-struct.zig | 4 +++- test/behavior/ptrcast.zig | 10 ++++++++++ test/behavior/tuple.zig | 5 +++++ test/behavior/union.zig | 1 + test/behavior/var_args.zig | 2 ++ test/behavior/vector.zig | 1 + 10 files changed, 31 insertions(+), 1 deletion(-) diff --git a/test/behavior/array.zig b/test/behavior/array.zig index ec31d4a3fb..6cf0ab9e1d 100644 --- a/test/behavior/array.zig +++ b/test/behavior/array.zig @@ -47,6 +47,7 @@ fn getArrayLen(a: []const u32) usize { test "array concat with undefined" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO const S = struct { fn doTheTest() !void { @@ -70,6 +71,7 @@ test "array concat with undefined" { test "array concat with tuple" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO const array: [2]u8 = .{ 1, 2 }; { @@ -103,6 +105,7 @@ test "array init with mult" { test "array literal with explicit type" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO const hex_mult: [4]u16 = .{ 4096, 256, 16, 1 }; @@ -203,6 +206,7 @@ test "nested arrays of strings" { test "nested arrays of integers" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO const array_of_numbers = [_][2]u8{ [2]u8{ 1, 2 }, diff --git a/test/behavior/bugs/12051.zig b/test/behavior/bugs/12051.zig index 5e2087d422..2b2765358b 100644 --- a/test/behavior/bugs/12051.zig +++ b/test/behavior/bugs/12051.zig @@ -6,6 +6,7 @@ test { if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO const x = X{}; try std.testing.expectEqual(@as(u16, 0), x.y.a); try std.testing.expectEqual(false, x.y.b); diff --git a/test/behavior/bugs/12450.zig b/test/behavior/bugs/12450.zig index 89e5c774e0..4d0c7cd9a1 100644 --- a/test/behavior/bugs/12450.zig +++ b/test/behavior/bugs/12450.zig @@ -13,6 +13,7 @@ test { if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO var f1: *align(16) Foo = @alignCast(16, @ptrCast(*align(1) Foo, &buffer[0])); try expect(@typeInfo(@TypeOf(f1)).Pointer.alignment == 16); try expect(@ptrToInt(f1) == @ptrToInt(&f1.a)); diff --git a/test/behavior/comptime_memory.zig b/test/behavior/comptime_memory.zig index 98e6e65725..5c3012d1dc 100644 --- a/test/behavior/comptime_memory.zig +++ b/test/behavior/comptime_memory.zig @@ -76,6 +76,7 @@ fn bigToNativeEndian(comptime T: type, v: T) T { } test "type pun endianness" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO comptime { const StructOfBytes = extern struct { x: [4]u8 }; @@ -376,6 +377,8 @@ test "offset field ptr by enclosing array element size" { test "accessing reinterpreted memory of parent object" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + const S = extern struct { a: f32, b: [4]u8, diff --git a/test/behavior/packed-struct.zig b/test/behavior/packed-struct.zig index ac4b62b0b8..8a0ef72382 100644 --- a/test/behavior/packed-struct.zig +++ b/test/behavior/packed-struct.zig @@ -563,7 +563,7 @@ test "packed struct passed to callconv(.C) function" { test "overaligned pointer to packed struct" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; - + if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO const S = packed struct { a: u32, b: u32 }; var foo: S align(4) = .{ .a = 123, .b = 456 }; const ptr: *align(4) S = &foo; @@ -583,6 +583,7 @@ test "overaligned pointer to packed struct" { test "packed struct initialized in bitcast" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO const T = packed struct { val: u8 }; var val: u8 = 123; @@ -595,6 +596,7 @@ test "pointer to container level packed struct field" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO const S = packed struct(u32) { test_bit: bool, diff --git a/test/behavior/ptrcast.zig b/test/behavior/ptrcast.zig index becdee6b05..6a5ae726ae 100644 --- a/test/behavior/ptrcast.zig +++ b/test/behavior/ptrcast.zig @@ -4,6 +4,8 @@ const expect = std.testing.expect; const native_endian = builtin.target.cpu.arch.endian(); test "reinterpret bytes as integer with nonzero offset" { + if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + try testReinterpretBytesAsInteger(); comptime try testReinterpretBytesAsInteger(); } @@ -74,6 +76,8 @@ fn testReinterpretBytesAsExternStruct() !void { } test "reinterpret bytes of an extern struct (with under-aligned fields) into another" { + if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + try testReinterpretExternStructAsExternStruct(); comptime try testReinterpretExternStructAsExternStruct(); } @@ -96,6 +100,8 @@ fn testReinterpretExternStructAsExternStruct() !void { } test "reinterpret bytes of an extern struct into another" { + if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + try testReinterpretOverAlignedExternStructAsExternStruct(); comptime try testReinterpretOverAlignedExternStructAsExternStruct(); } @@ -191,6 +197,8 @@ const Bytes = struct { }; test "comptime ptrcast keeps larger alignment" { + if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + comptime { const a: u32 = 1234; const p = @ptrCast([*]const u8, &a); @@ -199,6 +207,8 @@ test "comptime ptrcast keeps larger alignment" { } test "ptrcast of const integer has the correct object size" { + if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + const is_value = ~@intCast(isize, std.math.minInt(isize)); const is_bytes = @ptrCast([*]const u8, &is_value)[0..@sizeOf(isize)]; if (@sizeOf(isize) == 8) { diff --git a/test/behavior/tuple.zig b/test/behavior/tuple.zig index 1cf68a0769..11cc8b2dce 100644 --- a/test/behavior/tuple.zig +++ b/test/behavior/tuple.zig @@ -296,6 +296,7 @@ test "coerce tuple to tuple" { test "tuple type with void field" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO const T = std.meta.Tuple(&[_]type{void}); const x = T{{}}; @@ -341,6 +342,7 @@ test "tuple type with void field and a runtime field" { test "branching inside tuple literal" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO const S = struct { fn foo(a: anytype) !void { @@ -355,6 +357,7 @@ test "tuple initialized with a runtime known value" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO const E = union(enum) { e: []const u8 }; const W = union(enum) { w: E }; @@ -368,6 +371,7 @@ test "tuple of struct concatenation and coercion to array" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO const StructWithDefault = struct { value: f32 = 42 }; const SomeStruct = struct { array: [4]StructWithDefault }; @@ -381,6 +385,7 @@ test "tuple of struct concatenation and coercion to array" { test "nested runtime conditionals in tuple initializer" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO var data: u8 = 0; const x = .{ diff --git a/test/behavior/union.zig b/test/behavior/union.zig index 37b1f0cb49..025eb4f6bd 100644 --- a/test/behavior/union.zig +++ b/test/behavior/union.zig @@ -1495,6 +1495,7 @@ test "packed union with zero-bit field" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO const S = packed struct { nested: packed union { diff --git a/test/behavior/var_args.zig b/test/behavior/var_args.zig index cdceea96c6..968b15b218 100644 --- a/test/behavior/var_args.zig +++ b/test/behavior/var_args.zig @@ -95,6 +95,7 @@ fn doNothingWithFirstArg(args: anytype) void { test "simple variadic function" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO @@ -143,6 +144,7 @@ test "simple variadic function" { test "variadic functions" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO diff --git a/test/behavior/vector.zig b/test/behavior/vector.zig index d549588dee..f6521f04c3 100644 --- a/test/behavior/vector.zig +++ b/test/behavior/vector.zig @@ -1282,6 +1282,7 @@ test "store to vector in slice" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO var v = [_]@Vector(3, f32){ .{ 1, 1, 1 }, From 1794a45572a30a493a5c10fcdc45ba0fa3ac4218 Mon Sep 17 00:00:00 2001 From: Koakuma Date: Wed, 4 Jan 2023 10:46:27 +0700 Subject: [PATCH 006/725] stage2: sparc64: Add stub for c_va_* --- src/arch/sparc64/CodeGen.zig | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/arch/sparc64/CodeGen.zig b/src/arch/sparc64/CodeGen.zig index cc5c9e9832..58b384c832 100644 --- a/src/arch/sparc64/CodeGen.zig +++ b/src/arch/sparc64/CodeGen.zig @@ -720,10 +720,10 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .error_set_has_value => @panic("TODO implement error_set_has_value"), .vector_store_elem => @panic("TODO implement vector_store_elem"), - .c_va_arg => @panic("TODO implement c_va_arg"), - .c_va_copy => @panic("TODO implement c_va_copy"), - .c_va_end => @panic("TODO implement c_va_end"), - .c_va_start => @panic("TODO implement c_va_start"), + .c_va_arg => return self.fail("TODO implement c_va_arg", .{}), + .c_va_copy => return self.fail("TODO implement c_va_copy", .{}), + .c_va_end => return self.fail("TODO implement c_va_end", .{}), + .c_va_start => return self.fail("TODO implement c_va_start", .{}), .wasm_memory_size => unreachable, .wasm_memory_grow => unreachable, From cc2a5185d631b8b33eb5d466cc52ceb092435fd4 Mon Sep 17 00:00:00 2001 From: Koakuma Date: Wed, 4 Jan 2023 10:58:40 +0700 Subject: [PATCH 007/725] stage2: sparc64: Implement airStructFieldPtr --- src/arch/sparc64/CodeGen.zig | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/arch/sparc64/CodeGen.zig b/src/arch/sparc64/CodeGen.zig index 58b384c832..d682ce8c2b 100644 --- a/src/arch/sparc64/CodeGen.zig +++ b/src/arch/sparc64/CodeGen.zig @@ -595,7 +595,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .ret_load => try self.airRetLoad(inst), .store => try self.airStore(inst, false), .store_safe => try self.airStore(inst, true), - .struct_field_ptr=> @panic("TODO try self.airStructFieldPtr(inst)"), + .struct_field_ptr=> try self.airStructFieldPtr(inst), .struct_field_val=> try self.airStructFieldVal(inst), .array_to_slice => try self.airArrayToSlice(inst), .int_to_float => try self.airIntToFloat(inst), @@ -2425,6 +2425,13 @@ fn airStore(self: *Self, inst: Air.Inst.Index, safety: bool) !void { return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); } +fn airStructFieldPtr(self: *Self, inst: Air.Inst.Index) !void { + const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; + const extra = self.air.extraData(Air.StructField, ty_pl.payload).data; + const result = try self.structFieldPtr(inst, extra.struct_operand, extra.field_index); + return self.finishAir(inst, result, .{ extra.struct_operand, .none, .none }); +} + fn airStructFieldPtrIndex(self: *Self, inst: Air.Inst.Index, index: u8) !void { const ty_op = self.air.instructions.items(.data)[inst].ty_op; const result = try self.structFieldPtr(inst, ty_op.operand, index); From 486ab3852e22f8d5ba474691a5b068f1f1729f2e Mon Sep 17 00:00:00 2001 From: Koakuma Date: Wed, 4 Jan 2023 12:53:11 +0700 Subject: [PATCH 008/725] stage2: sparc64: Factor machine offset calculation --- src/arch/sparc64/CodeGen.zig | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/arch/sparc64/CodeGen.zig b/src/arch/sparc64/CodeGen.zig index d682ce8c2b..3d82cad4ec 100644 --- a/src/arch/sparc64/CodeGen.zig +++ b/src/arch/sparc64/CodeGen.zig @@ -141,6 +141,8 @@ const MCValue = union(enum) { /// The value is one of the stack variables. /// If the type is a pointer, it means the pointer address is in the stack at this offset. /// Note that this stores the plain value (i.e without the effects of the stack bias). + /// Always convert this value into machine offsets with realStackOffset() before + /// lowering into asm! stack_offset: u32, /// The value is a pointer to one of the stack variables (payload is stack offset). ptr_stack_offset: u32, @@ -3651,7 +3653,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void return self.genSetReg(ty, reg, .{ .immediate = 0xaaaaaaaaaaaaaaaa }); }, .ptr_stack_offset => |off| { - const real_offset = off + abi.stack_bias + abi.stack_reserved_area; + const real_offset = realStackOffset(off); const simm13 = math.cast(i13, real_offset) orelse return self.fail("TODO larger stack offsets: {}", .{real_offset}); @@ -3783,7 +3785,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void try self.genLoad(reg, reg, i13, 0, ty.abiSize(self.target.*)); }, .stack_offset => |off| { - const real_offset = off + abi.stack_bias + abi.stack_reserved_area; + const real_offset = realStackOffset(off); const simm13 = math.cast(i13, real_offset) orelse return self.fail("TODO larger stack offsets: {}", .{real_offset}); try self.genLoad(reg, .sp, i13, simm13, ty.abiSize(self.target.*)); @@ -3817,7 +3819,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }); }, .register => |reg| { - const real_offset = stack_offset + abi.stack_bias + abi.stack_reserved_area; + const real_offset = realStackOffset(stack_offset); const simm13 = math.cast(i13, real_offset) orelse return self.fail("TODO larger stack offsets: {}", .{real_offset}); return self.genStore(reg, .sp, i13, simm13, abi_size); @@ -4252,6 +4254,17 @@ fn processDeath(self: *Self, inst: Air.Inst.Index) void { } } +/// Turns stack_offset MCV into a real SPARCv9 stack offset usable for asm. +fn realStackOffset(off: u32) u32 { + return off + // SPARCv9 %sp points away from the stack by some amount. + + abi.stack_bias + // The first couple bytes of each stack frame is reserved + // for ABI and hardware purposes. + + abi.stack_reserved_area; + // Only after that we have the usable stack frame portion. +} + /// Caller must call `CallMCValues.deinit`. fn resolveCallingConventionValues(self: *Self, fn_ty: Type, role: RegisterView) !CallMCValues { const cc = fn_ty.fnCallingConvention(); From 83e6223192acd635275e67614e55b7a4c579a969 Mon Sep 17 00:00:00 2001 From: Koakuma Date: Wed, 4 Jan 2023 16:38:15 +0700 Subject: [PATCH 009/725] stage2: sparc64: Implement airByteSwap --- src/arch/sparc64/CodeGen.zig | 156 +++++++++++++++++++++++++++++++++-- src/arch/sparc64/Emit.zig | 10 +++ src/arch/sparc64/Mir.zig | 30 +++++++ 3 files changed, 189 insertions(+), 7 deletions(-) diff --git a/src/arch/sparc64/CodeGen.zig b/src/arch/sparc64/CodeGen.zig index 3d82cad4ec..a4fa7e179c 100644 --- a/src/arch/sparc64/CodeGen.zig +++ b/src/arch/sparc64/CodeGen.zig @@ -22,6 +22,7 @@ const Type = @import("../../type.zig").Type; const CodeGenError = codegen.CodeGenError; const Result = @import("../../codegen.zig").Result; const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput; +const Endian = std.builtin.Endian; const build_options = @import("build_options"); @@ -30,6 +31,7 @@ const abi = @import("abi.zig"); const errUnionPayloadOffset = codegen.errUnionPayloadOffset; const errUnionErrorOffset = codegen.errUnionErrorOffset; const Instruction = bits.Instruction; +const ASI = Instruction.ASI; const ShiftWidth = Instruction.ShiftWidth; const RegisterManager = abi.RegisterManager; const RegisterLock = RegisterManager.RegisterLock; @@ -615,7 +617,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .clz => try self.airClz(inst), .ctz => try self.airCtz(inst), .popcount => try self.airPopcount(inst), - .byte_swap => @panic("TODO try self.airByteSwap(inst)"), + .byte_swap => try self.airByteSwap(inst), .bit_reverse => try self.airBitReverse(inst), .tag_name => try self.airTagName(inst), .error_name => try self.airErrorName(inst), @@ -1200,6 +1202,90 @@ fn airBreakpoint(self: *Self) !void { return self.finishAirBookkeeping(); } +fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void { + const ty_op = self.air.instructions.items(.data)[inst].ty_op; + + // We have hardware byteswapper in SPARCv9, don't let mainstream compilers mislead you. + // That being said, the strategy to lower this is: + // - If src is an immediate, comptime-swap it. + // - If src is in memory then issue an LD*A with #ASI_P_[oppposite-endian] + // - If src is a register then issue an ST*A with #ASI_P_[oppposite-endian] + // to a stack slot, then follow with a normal load from said stack slot. + // This is because on some implementations, ASI-tagged memory operations are non-piplelinable + // and loads tend to have longer latency than stores, so the sequence will minimize stall. + // The result will always be either another immediate or stored in a register. + // TODO: Fold byteswap+store into a single ST*A and load+byteswap into a single LD*A. + const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { + const operand = try self.resolveInst(ty_op.operand); + const operand_ty = self.air.typeOf(ty_op.operand); + switch (operand_ty.zigTypeTag()) { + .Vector => return self.fail("TODO byteswap for vectors", .{}), + .Int => { + const int_info = operand_ty.intInfo(self.target.*); + if (int_info.bits == 8) break :result operand; + + const abi_size = int_info.bits >> 3; + const abi_align = operand_ty.abiAlignment(self.target.*); + const opposite_endian_asi = switch (self.target.cpu.arch.endian()) { + Endian.Big => ASI.asi_primary_little, + Endian.Little => ASI.asi_primary, + }; + + switch (operand) { + .immediate => |imm| { + const swapped = switch (int_info.bits) { + 16 => @byteSwap(@intCast(u16, imm)), + 24 => @byteSwap(@intCast(u24, imm)), + 32 => @byteSwap(@intCast(u32, imm)), + 40 => @byteSwap(@intCast(u40, imm)), + 48 => @byteSwap(@intCast(u48, imm)), + 56 => @byteSwap(@intCast(u56, imm)), + 64 => @byteSwap(@intCast(u64, imm)), + else => return self.fail("TODO synthesize SPARCv9 byteswap for other integer sizes", .{}), + }; + break :result .{ .immediate = swapped }; + }, + .register => |reg| { + if (int_info.bits > 64 or @popCount(int_info.bits) != 1) + return self.fail("TODO synthesize SPARCv9 byteswap for other integer sizes", .{}); + + const off = try self.allocMem(inst, abi_size, abi_align); + const off_reg = try self.copyToTmpRegister(operand_ty, .{ .immediate = realStackOffset(off) }); + + try self.genStoreASI(reg, .sp, off_reg, abi_size, opposite_endian_asi); + try self.genLoad(reg, .sp, Register, off_reg, abi_size); + break :result reg; + }, + .memory => { + if (int_info.bits > 64 or @popCount(int_info.bits) != 1) + return self.fail("TODO synthesize SPARCv9 byteswap for other integer sizes", .{}); + + const addr_reg = try self.copyToTmpRegister(operand_ty, operand); + const dst_reg = try self.register_manager.allocReg(null, gp); + + try self.genLoadASI(dst_reg, addr_reg, .g0, abi_size, opposite_endian_asi); + break :result dst_reg; + }, + .stack_offset => |off| { + if (int_info.bits > 64 or @popCount(int_info.bits) != 1) + return self.fail("TODO synthesize SPARCv9 byteswap for other integer sizes", .{}); + + const off_reg = try self.copyToTmpRegister(operand_ty, .{ .immediate = realStackOffset(off) }); + const dst_reg = try self.register_manager.allocReg(null, gp); + + try self.genLoadASI(dst_reg, .sp, off_reg, abi_size, opposite_endian_asi); + break :result dst_reg; + }, + else => unreachable, + } + }, + else => unreachable, + } + }; + + return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); +} + fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void { if (modifier == .always_tail) return self.fail("TODO implement tail calls for {}", .{self.target.cpu.arch}); @@ -3583,6 +3669,34 @@ fn genLoad(self: *Self, value_reg: Register, addr_reg: Register, comptime off_ty } } +fn genLoadASI(self: *Self, value_reg: Register, addr_reg: Register, off_reg: Register, abi_size: u64, asi: ASI) !void { + switch (abi_size) { + 1, 2, 4, 8 => { + const tag: Mir.Inst.Tag = switch (abi_size) { + 1 => .lduba, + 2 => .lduha, + 4 => .lduwa, + 8 => .ldxa, + else => unreachable, // unexpected abi size + }; + + _ = try self.addInst(.{ + .tag = tag, + .data = .{ + .mem_asi = .{ + .rd = value_reg, + .rs1 = addr_reg, + .rs2 = off_reg, + .asi = asi, + }, + }, + }); + }, + 3, 5, 6, 7 => return self.fail("TODO: genLoad for more abi_sizes", .{}), + else => unreachable, + } +} + fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void { switch (mcv) { .dead => unreachable, @@ -3942,6 +4056,34 @@ fn genStore(self: *Self, value_reg: Register, addr_reg: Register, comptime off_t } } +fn genStoreASI(self: *Self, value_reg: Register, addr_reg: Register, off_reg: Register, abi_size: u64, asi: ASI) !void { + switch (abi_size) { + 1, 2, 4, 8 => { + const tag: Mir.Inst.Tag = switch (abi_size) { + 1 => .stba, + 2 => .stha, + 4 => .stwa, + 8 => .stxa, + else => unreachable, // unexpected abi size + }; + + _ = try self.addInst(.{ + .tag = tag, + .data = .{ + .mem_asi = .{ + .rd = value_reg, + .rs1 = addr_reg, + .rs2 = off_reg, + .asi = asi, + }, + }, + }); + }, + 3, 5, 6, 7 => return self.fail("TODO: genLoad for more abi_sizes", .{}), + else => unreachable, + } +} + fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { const mcv: MCValue = switch (try codegen.genTypedValue( self.bin_file, @@ -4257,12 +4399,12 @@ fn processDeath(self: *Self, inst: Air.Inst.Index) void { /// Turns stack_offset MCV into a real SPARCv9 stack offset usable for asm. fn realStackOffset(off: u32) u32 { return off - // SPARCv9 %sp points away from the stack by some amount. - + abi.stack_bias - // The first couple bytes of each stack frame is reserved - // for ABI and hardware purposes. - + abi.stack_reserved_area; - // Only after that we have the usable stack frame portion. + // SPARCv9 %sp points away from the stack by some amount. + + abi.stack_bias + // The first couple bytes of each stack frame is reserved + // for ABI and hardware purposes. + + abi.stack_reserved_area; + // Only after that we have the usable stack frame portion. } /// Caller must call `CallMCValues.deinit`. diff --git a/src/arch/sparc64/Emit.zig b/src/arch/sparc64/Emit.zig index 7e71492af7..c0dbab5a14 100644 --- a/src/arch/sparc64/Emit.zig +++ b/src/arch/sparc64/Emit.zig @@ -91,6 +91,11 @@ pub fn emitMir( .lduw => try emit.mirArithmetic3Op(inst), .ldx => try emit.mirArithmetic3Op(inst), + .lduba => unreachable, + .lduha => unreachable, + .lduwa => unreachable, + .ldxa => unreachable, + .@"and" => try emit.mirArithmetic3Op(inst), .@"or" => try emit.mirArithmetic3Op(inst), .xor => try emit.mirArithmetic3Op(inst), @@ -127,6 +132,11 @@ pub fn emitMir( .stw => try emit.mirArithmetic3Op(inst), .stx => try emit.mirArithmetic3Op(inst), + .stba => unreachable, + .stha => unreachable, + .stwa => unreachable, + .stxa => unreachable, + .sub => try emit.mirArithmetic3Op(inst), .subcc => try emit.mirArithmetic3Op(inst), diff --git a/src/arch/sparc64/Mir.zig b/src/arch/sparc64/Mir.zig index f854152a2f..f9a4056705 100644 --- a/src/arch/sparc64/Mir.zig +++ b/src/arch/sparc64/Mir.zig @@ -15,6 +15,7 @@ const bits = @import("bits.zig"); const Air = @import("../../Air.zig"); const Instruction = bits.Instruction; +const ASI = bits.Instruction.ASI; const Register = bits.Register; instructions: std.MultiArrayList(Inst).Slice, @@ -70,6 +71,16 @@ pub const Inst = struct { lduw, ldx, + /// A.28 Load Integer from Alternate Space + /// This uses the mem_asi field. + /// Note that the ldda variant of this instruction is deprecated, so do not emit + /// it unless specifically requested (e.g. by inline assembly). + // TODO add other operations. + lduba, + lduha, + lduwa, + ldxa, + /// A.31 Logical Operations /// This uses the arithmetic_3op field. // TODO add other operations. @@ -132,6 +143,16 @@ pub const Inst = struct { stw, stx, + /// A.55 Store Integer into Alternate Space + /// This uses the mem_asi field. + /// Note that the stda variant of this instruction is deprecated, so do not emit + /// it unless specifically requested (e.g. by inline assembly). + // TODO add other operations. + stba, + stha, + stwa, + stxa, + /// A.56 Subtract /// This uses the arithmetic_3op field. // TODO add other operations. @@ -241,6 +262,15 @@ pub const Inst = struct { inst: Index, }, + /// ASI-tagged memory operations. + /// Used by e.g. ldxa, stxa + mem_asi: struct { + rd: Register, + rs1: Register, + rs2: Register = .g0, + asi: ASI, + }, + /// Membar mask, controls the barrier behavior /// Used by e.g. membar membar_mask: struct { From 75a1360cdd1745ac267c9a25b84ec7ee765d9262 Mon Sep 17 00:00:00 2001 From: Koakuma Date: Mon, 20 Feb 2023 22:40:08 +0700 Subject: [PATCH 010/725] stage2: sparc64: Implement ASI load/store ops --- src/arch/sparc64/CodeGen.zig | 6 +++--- src/arch/sparc64/Emit.zig | 39 ++++++++++++++++++++++++++++-------- src/arch/sparc64/bits.zig | 32 +++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+), 11 deletions(-) diff --git a/src/arch/sparc64/CodeGen.zig b/src/arch/sparc64/CodeGen.zig index a4fa7e179c..7c9476161c 100644 --- a/src/arch/sparc64/CodeGen.zig +++ b/src/arch/sparc64/CodeGen.zig @@ -1254,7 +1254,7 @@ fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void { try self.genStoreASI(reg, .sp, off_reg, abi_size, opposite_endian_asi); try self.genLoad(reg, .sp, Register, off_reg, abi_size); - break :result reg; + break :result .{ .register = reg }; }, .memory => { if (int_info.bits > 64 or @popCount(int_info.bits) != 1) @@ -1264,7 +1264,7 @@ fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void { const dst_reg = try self.register_manager.allocReg(null, gp); try self.genLoadASI(dst_reg, addr_reg, .g0, abi_size, opposite_endian_asi); - break :result dst_reg; + break :result .{ .register = dst_reg }; }, .stack_offset => |off| { if (int_info.bits > 64 or @popCount(int_info.bits) != 1) @@ -1274,7 +1274,7 @@ fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void { const dst_reg = try self.register_manager.allocReg(null, gp); try self.genLoadASI(dst_reg, .sp, off_reg, abi_size, opposite_endian_asi); - break :result dst_reg; + break :result .{ .register = dst_reg }; }, else => unreachable, } diff --git a/src/arch/sparc64/Emit.zig b/src/arch/sparc64/Emit.zig index c0dbab5a14..7d16105348 100644 --- a/src/arch/sparc64/Emit.zig +++ b/src/arch/sparc64/Emit.zig @@ -91,10 +91,10 @@ pub fn emitMir( .lduw => try emit.mirArithmetic3Op(inst), .ldx => try emit.mirArithmetic3Op(inst), - .lduba => unreachable, - .lduha => unreachable, - .lduwa => unreachable, - .ldxa => unreachable, + .lduba => try emit.mirMemASI(inst), + .lduha => try emit.mirMemASI(inst), + .lduwa => try emit.mirMemASI(inst), + .ldxa => try emit.mirMemASI(inst), .@"and" => try emit.mirArithmetic3Op(inst), .@"or" => try emit.mirArithmetic3Op(inst), @@ -132,10 +132,10 @@ pub fn emitMir( .stw => try emit.mirArithmetic3Op(inst), .stx => try emit.mirArithmetic3Op(inst), - .stba => unreachable, - .stha => unreachable, - .stwa => unreachable, - .stxa => unreachable, + .stba => try emit.mirMemASI(inst), + .stha => try emit.mirMemASI(inst), + .stwa => try emit.mirMemASI(inst), + .stxa => try emit.mirMemASI(inst), .sub => try emit.mirArithmetic3Op(inst), .subcc => try emit.mirArithmetic3Op(inst), @@ -378,6 +378,29 @@ fn mirConditionalMove(emit: *Emit, inst: Mir.Inst.Index) !void { } } +fn mirMemASI(emit: *Emit, inst: Mir.Inst.Index) !void { + const tag = emit.mir.instructions.items(.tag)[inst]; + const data = emit.mir.instructions.items(.data)[inst].mem_asi; + + const rd = data.rd; + const rs1 = data.rs1; + const rs2 = data.rs2; + const asi = data.asi; + + switch (tag) { + .lduba => try emit.writeInstruction(Instruction.lduba(rs1, rs2, asi, rd)), + .lduha => try emit.writeInstruction(Instruction.lduha(rs1, rs2, asi, rd)), + .lduwa => try emit.writeInstruction(Instruction.lduwa(rs1, rs2, asi, rd)), + .ldxa => try emit.writeInstruction(Instruction.ldxa(rs1, rs2, asi, rd)), + + .stba => try emit.writeInstruction(Instruction.stba(rs1, rs2, asi, rd)), + .stha => try emit.writeInstruction(Instruction.stha(rs1, rs2, asi, rd)), + .stwa => try emit.writeInstruction(Instruction.stwa(rs1, rs2, asi, rd)), + .stxa => try emit.writeInstruction(Instruction.stxa(rs1, rs2, asi, rd)), + else => unreachable, + } +} + fn mirMembar(emit: *Emit, inst: Mir.Inst.Index) !void { const tag = emit.mir.instructions.items(.tag)[inst]; const mask = emit.mir.instructions.items(.data)[inst].membar_mask; diff --git a/src/arch/sparc64/bits.zig b/src/arch/sparc64/bits.zig index 0446a84d6d..7c943626f9 100644 --- a/src/arch/sparc64/bits.zig +++ b/src/arch/sparc64/bits.zig @@ -1229,6 +1229,22 @@ pub const Instruction = union(enum) { }; } + pub fn lduba(rs1: Register, rs2: Register, asi: ASI, rd: Register) Instruction { + return format3i(0b11, 0b01_0001, rs1, rs2, rd, asi); + } + + pub fn lduha(rs1: Register, rs2: Register, asi: ASI, rd: Register) Instruction { + return format3i(0b11, 0b01_0010, rs1, rs2, rd, asi); + } + + pub fn lduwa(rs1: Register, rs2: Register, asi: ASI, rd: Register) Instruction { + return format3i(0b11, 0b01_0000, rs1, rs2, rd, asi); + } + + pub fn ldxa(rs1: Register, rs2: Register, asi: ASI, rd: Register) Instruction { + return format3i(0b11, 0b01_1011, rs1, rs2, rd, asi); + } + pub fn @"and"(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction { return switch (s2) { Register => format3a(0b10, 0b00_0001, rs1, rs2, rd), @@ -1417,6 +1433,22 @@ pub const Instruction = union(enum) { }; } + pub fn stba(rs1: Register, rs2: Register, asi: ASI, rd: Register) Instruction { + return format3i(0b11, 0b01_0101, rs1, rs2, rd, asi); + } + + pub fn stha(rs1: Register, rs2: Register, asi: ASI, rd: Register) Instruction { + return format3i(0b11, 0b01_0110, rs1, rs2, rd, asi); + } + + pub fn stwa(rs1: Register, rs2: Register, asi: ASI, rd: Register) Instruction { + return format3i(0b11, 0b01_0100, rs1, rs2, rd, asi); + } + + pub fn stxa(rs1: Register, rs2: Register, asi: ASI, rd: Register) Instruction { + return format3i(0b11, 0b01_1110, rs1, rs2, rd, asi); + } + pub fn sub(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction { return switch (s2) { Register => format3a(0b10, 0b00_0100, rs1, rs2, rd), From ccc9b8caf632bf97f7765c1b1d7821118cf34008 Mon Sep 17 00:00:00 2001 From: Koakuma Date: Mon, 24 Apr 2023 13:23:17 +0700 Subject: [PATCH 011/725] stage2: sparc64: Implement airPtrSliceLenPtr/airPtrSlicePtrPtr stubs --- src/arch/sparc64/CodeGen.zig | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/src/arch/sparc64/CodeGen.zig b/src/arch/sparc64/CodeGen.zig index 7c9476161c..226a0c6fc9 100644 --- a/src/arch/sparc64/CodeGen.zig +++ b/src/arch/sparc64/CodeGen.zig @@ -667,8 +667,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .slice_ptr => try self.airSlicePtr(inst), .slice_len => try self.airSliceLen(inst), - .ptr_slice_len_ptr => @panic("TODO try self.airPtrSliceLenPtr(inst)"), - .ptr_slice_ptr_ptr => @panic("TODO try self.airPtrSlicePtrPtr(inst)"), + .ptr_slice_len_ptr => try self.airPtrSliceLenPtr(inst), + .ptr_slice_ptr_ptr => try self.airPtrSlicePtrPtr(inst), .array_elem_val => try self.airArrayElemVal(inst), .slice_elem_val => try self.airSliceElemVal(inst), @@ -2238,6 +2238,38 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void { return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none }); } +fn airPtrSliceLenPtr(self: *Self, inst: Air.Inst.Index) !void { + const ty_op = self.air.instructions.items(.data)[inst].ty_op; + const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { + const ptr_bits = self.target.cpu.arch.ptrBitWidth(); + const ptr_bytes = @divExact(ptr_bits, 8); + const mcv = try self.resolveInst(ty_op.operand); + switch (mcv) { + .dead, .unreach, .none => unreachable, + .ptr_stack_offset => |off| { + break :result MCValue{ .ptr_stack_offset = off - ptr_bytes }; + }, + else => return self.fail("TODO implement ptr_slice_len_ptr for {}", .{mcv}), + } + }; + return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); +} + +fn airPtrSlicePtrPtr(self: *Self, inst: Air.Inst.Index) !void { + const ty_op = self.air.instructions.items(.data)[inst].ty_op; + const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { + const mcv = try self.resolveInst(ty_op.operand); + switch (mcv) { + .dead, .unreach, .none => unreachable, + .ptr_stack_offset => |off| { + break :result MCValue{ .ptr_stack_offset = off }; + }, + else => return self.fail("TODO implement ptr_slice_len_ptr for {}", .{mcv}), + } + }; + return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); +} + fn airPtrToInt(self: *Self, inst: Air.Inst.Index) !void { const un_op = self.air.instructions.items(.data)[inst].un_op; const result = try self.resolveInst(un_op); From 0c9c9117bacfcff2b11ab658b89f192e27fc7c3d Mon Sep 17 00:00:00 2001 From: r00ster91 Date: Sat, 29 Apr 2023 03:35:16 +0200 Subject: [PATCH 012/725] std.builtin.CallModifier: add missing word --- lib/std/builtin.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig index 3523c5ac12..4a5e8a28d6 100644 --- a/lib/std/builtin.zig +++ b/lib/std/builtin.zig @@ -646,7 +646,7 @@ pub const CallModifier = enum { /// If this is not possible, a compile error is emitted instead. always_tail, - /// Guarantees that the call will inlined at the callsite. + /// Guarantees that the call will be inlined at the callsite. /// If this is not possible, a compile error is emitted instead. always_inline, From bd8b5c25ece2fa158196381004db6e655226576c Mon Sep 17 00:00:00 2001 From: r00ster91 Date: Sat, 29 Apr 2023 04:19:58 +0200 Subject: [PATCH 013/725] Sema: emit error for always_inline call of noinline function Fixes #15489 This also lays the groundwork for exposing the whether or not a function is noinline in std.builtin.Fn as an `is_noinline: bool` field if we ever want to do that. --- src/Sema.zig | 10 ++++++++-- src/type.zig | 13 ++++++++++++ .../compile_errors/bad_usage_of_call.zig | 20 +++++++++++++++---- 3 files changed, 37 insertions(+), 6 deletions(-) diff --git a/src/Sema.zig b/src/Sema.zig index 8b47f1877b..207ccb41a9 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -6565,7 +6565,10 @@ fn analyzeCall( }; if (modifier == .never_inline and func_ty_info.cc == .Inline) { - return sema.fail(block, call_src, "no-inline call of inline function", .{}); + return sema.fail(block, call_src, "'never_inline' call of inline function", .{}); + } + if (modifier == .always_inline and func_ty_info.is_noinline) { + return sema.fail(block, call_src, "'always_inline' call of noinline function", .{}); } const gpa = sema.gpa; @@ -8784,7 +8787,8 @@ fn funcCommon( if (!is_generic and block.params.items.len == 0 and !var_args and !inferred_error_set and alignment.? == 0 and address_space.? == target_util.defaultAddressSpace(target, .function) and - section == .default) + section == .default and + !is_noinline) { if (bare_return_type.zigTypeTag() == .NoReturn and cc.? == .Unspecified) { break :fn_ty Type.initTag(.fn_noreturn_no_args); @@ -9002,6 +9006,7 @@ fn funcCommon( .addrspace_is_generic = address_space == null, .is_var_args = var_args, .is_generic = is_generic, + .is_noinline = is_noinline, .noalias_bits = noalias_bits, }); }; @@ -19217,6 +19222,7 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in .cc = cc, .is_var_args = is_var_args, .is_generic = false, + .is_noinline = false, .align_is_generic = false, .cc_is_generic = false, .section_is_generic = false, diff --git a/src/type.zig b/src/type.zig index c7b2844970..82896800ed 100644 --- a/src/type.zig +++ b/src/type.zig @@ -666,6 +666,9 @@ pub const Type = extern union { if (a_info.is_generic != b_info.is_generic) return false; + if (a_info.is_noinline != b_info.is_noinline) + return false; + if (a_info.noalias_bits != b_info.noalias_bits) return false; @@ -1074,6 +1077,7 @@ pub const Type = extern union { } std.hash.autoHash(hasher, fn_info.is_var_args); std.hash.autoHash(hasher, fn_info.is_generic); + std.hash.autoHash(hasher, fn_info.is_noinline); std.hash.autoHash(hasher, fn_info.noalias_bits); std.hash.autoHash(hasher, fn_info.param_types.len); @@ -1454,6 +1458,7 @@ pub const Type = extern union { .alignment = payload.alignment, .is_var_args = payload.is_var_args, .is_generic = payload.is_generic, + .is_noinline = payload.is_noinline, .comptime_params = comptime_params.ptr, .align_is_generic = payload.align_is_generic, .cc_is_generic = payload.cc_is_generic, @@ -2069,6 +2074,9 @@ pub const Type = extern union { .function => { const fn_info = ty.fnInfo(); + if (fn_info.is_noinline) { + try writer.writeAll("noinline "); + } try writer.writeAll("fn("); for (fn_info.param_types, 0..) |param_ty, i| { if (i != 0) try writer.writeAll(", "); @@ -4863,6 +4871,7 @@ pub const Type = extern union { .alignment = 0, .is_var_args = false, .is_generic = false, + .is_noinline = false, .align_is_generic = false, .cc_is_generic = false, .section_is_generic = false, @@ -4877,6 +4886,7 @@ pub const Type = extern union { .alignment = 0, .is_var_args = false, .is_generic = false, + .is_noinline = false, .align_is_generic = false, .cc_is_generic = false, .section_is_generic = false, @@ -4891,6 +4901,7 @@ pub const Type = extern union { .alignment = 0, .is_var_args = false, .is_generic = false, + .is_noinline = false, .align_is_generic = false, .cc_is_generic = false, .section_is_generic = false, @@ -4905,6 +4916,7 @@ pub const Type = extern union { .alignment = 0, .is_var_args = false, .is_generic = false, + .is_noinline = false, .align_is_generic = false, .cc_is_generic = false, .section_is_generic = false, @@ -6367,6 +6379,7 @@ pub const Type = extern union { cc: std.builtin.CallingConvention, is_var_args: bool, is_generic: bool, + is_noinline: bool, align_is_generic: bool, cc_is_generic: bool, section_is_generic: bool, diff --git a/test/cases/compile_errors/bad_usage_of_call.zig b/test/cases/compile_errors/bad_usage_of_call.zig index c0b632bef6..3669cda3bf 100644 --- a/test/cases/compile_errors/bad_usage_of_call.zig +++ b/test/cases/compile_errors/bad_usage_of_call.zig @@ -14,14 +14,25 @@ export fn entry5(c: bool) void { var baz = if (c) &baz1 else &baz2; @call(.compile_time, baz, .{}); } +export fn entry6() void { + _ = @call(.always_inline, dummy, .{}); +} +export fn entry7() void { + _ = @call(.always_inline, dummy2, .{}); +} pub export fn entry() void { var call_me: *const fn () void = undefined; @call(.always_inline, call_me, .{}); } + fn foo() void {} -fn bar() callconv(.Inline) void {} +inline fn bar() void {} fn baz1() void {} fn baz2() void {} +noinline fn dummy() u32 { + return 0; +} +noinline fn dummy2() void {} // error // backend=stage2 @@ -30,7 +41,8 @@ fn baz2() void {} // :2:23: error: expected a tuple, found 'void' // :5:21: error: unable to perform 'never_inline' call at compile-time // :8:21: error: unable to perform 'never_tail' call at compile-time -// :11:5: error: no-inline call of inline function +// :11:5: error: 'never_inline' call of inline function // :15:26: error: modifier 'compile_time' requires a comptime-known function -// :19:27: error: modifier 'always_inline' requires a comptime-known function - +// :18:9: error: 'always_inline' call of noinline function +// :21:9: error: 'always_inline' call of noinline function +// :25:27: error: modifier 'always_inline' requires a comptime-known function From 440b3df702f1c8bfddabc1c594a3f49cf0011a63 Mon Sep 17 00:00:00 2001 From: kcbanner Date: Sat, 29 Apr 2023 11:54:21 -0400 Subject: [PATCH 014/725] main: parse --dynamicbase linker arg --- src/main.zig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main.zig b/src/main.zig index 66b207aa43..45b0cf30b8 100644 --- a/src/main.zig +++ b/src/main.zig @@ -2072,6 +2072,8 @@ fn buildOutputType( linker_tsaware = true; } else if (mem.eql(u8, arg, "--nxcompat")) { linker_nxcompat = true; + } else if (mem.eql(u8, arg, "--dynamicbase")) { + linker_dynamicbase = true; } else if (mem.eql(u8, arg, "--no-dynamicbase")) { linker_dynamicbase = false; } else if (mem.eql(u8, arg, "--high-entropy-va")) { From 4f248e1b519b001cee67e461068245c142d38e73 Mon Sep 17 00:00:00 2001 From: David CARLIER Date: Sat, 29 Apr 2023 22:44:32 +0100 Subject: [PATCH 015/725] std.c:complete further more netbsd's mmap flags --- lib/std/c/netbsd.zig | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/lib/std/c/netbsd.zig b/lib/std/c/netbsd.zig index f70549775c..11126e7115 100644 --- a/lib/std/c/netbsd.zig +++ b/lib/std/c/netbsd.zig @@ -603,6 +603,17 @@ pub const MAP = struct { pub const ANON = 0x1000; pub const ANONYMOUS = ANON; pub const STACK = 0x2000; + + pub const ALIGNMENT_SHIFT = 24; + pub fn ALIGNED(n: u32) u32 { + return n << ALIGNMENT_SHIFT; + } + pub const ALIGNMENT_64KB = MAP.ALIGNED(0xff); + pub const ALIGNMENT_16MB = MAP.ALIGNED(16); + pub const ALIGNMENT_4GB = MAP.ALIGNED(32); + pub const ALIGNMENT_1TB = MAP.ALIGNED(40); + pub const ALIGNMENT_256TB = MAP.ALIGNED(48); + pub const ALIGNMENT_64PB = MAP.ALIGNED(56); }; pub const MSF = struct { From 3fb93fc8f2d3e755492a495fa69f65ae6615cab6 Mon Sep 17 00:00:00 2001 From: David CARLIER Date: Wed, 26 Apr 2023 22:04:55 +0100 Subject: [PATCH 016/725] std.c: freebsd add procctl exclusive x86_64 flags --- lib/std/c/freebsd.zig | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/lib/std/c/freebsd.zig b/lib/std/c/freebsd.zig index d3fa8f51c7..e5cdc0e715 100644 --- a/lib/std/c/freebsd.zig +++ b/lib/std/c/freebsd.zig @@ -2172,6 +2172,30 @@ pub const PROC = struct { pub const WX_MAPPINGS_PERMIT = 0x0001; pub const WX_MAPPINGS_DISALLOW_EXEC = 0x0002; pub const WX_MAPPINGS_ENFORCE = 0x80000000; + pub const PROCCTL_MD_MIN = 0x10000000; + // x86_64-only constants + pub const KPTI = switch (builtin.cpu.arch) { + .x86_64 => struct { + pub const CTL = PROC.PROCCTL_MD_MIND; + pub const STATUS = PROC.PROCCTL_MD_MIND + 1; + pub const CTL_ENABLE_ON_EXEC = 1; + pub const CTL_DISABLE_ON_EXEC = 2; + pub const STATUS_ACTIVE = 0x80000000; + }, + else => void, + }; + pub const LA = switch (builtin.cpu.arch) { + .x86_64 => struct { + pub const CTL = PROC.PROCCTL_MD_MIND + 2; + pub const STATUS = PROC.PROCCTL_MD_MIND + 3; + pub const CTL_LA48_ON_EXEC = 1; + pub const CTL_LA57_ON_EXEC = 2; + pub const CTL_DEFAULT_ON_EXEC = 3; + pub const STATUS_LA48 = 0x01000000; + pub const STATUS_LA57 = 0x02000000; + }, + else => void, + }; }; pub const PPROT = struct { From ab086b62cf585aa7fa73f2df3332e87f60226f86 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 30 Apr 2023 00:09:51 -0700 Subject: [PATCH 017/725] update zig1.wasm Looks like I might have messed up the wasm kernel in my recent branch causing some sporadic failures on the CI. This file was built the following way: 1. check out d0311e28b397d173f0d60c403985047ec952a172 2. do the cmake bootstrap 3. check out 57ea6207d3cb2db706bdc06c14605e4b901736dd 4. `zig build update-zig1` and stash those modified files 5. check out 440b3df702f1c8bfddabc1c594a3f49cf0011a63 (master) 6. do the cmake bootstrap 7. `zig build update-zig1` to produce this commit --- stage1/zig1.wasm | Bin 2454149 -> 2455067 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/stage1/zig1.wasm b/stage1/zig1.wasm index b00227e45d31187e03274df3b2c07a91832b35c7..600e273ec172ff7a813830f128187f5c04ecd69a 100644 GIT binary patch delta 222707 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 ?qw2>+eek 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 ZO`t{N$B4|rmlE3sit5eRFD2gme*h(3-l+fp From 91b4729962ddec96d1ee60d742326da828dae94a Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 30 Apr 2023 12:14:02 -0700 Subject: [PATCH 018/725] fix compilation error on 32-bit LLVM-enabled compiler builds Fixes a regression introduced in 9295355985202c267b4326b5a6e2ad5158b48e5d that caused 32-bit builds with `-Denable-llvm` to fail to build from source due to that common u64/usize casting issue. --- src/value.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/value.zig b/src/value.zig index 16ccc0c642..503797abba 100644 --- a/src/value.zig +++ b/src/value.zig @@ -5390,7 +5390,7 @@ pub const Value = extern union { /// have the same value, return that byte value, otherwise null. pub fn hasRepeatedByteRepr(val: Value, ty: Type, mod: *Module, value_buffer: *Payload.U64) !?Value { const target = mod.getTarget(); - const abi_size = ty.abiSize(target); + const abi_size = std.math.cast(usize, ty.abiSize(target)) orelse return null; assert(abi_size >= 1); const byte_buffer = try mod.gpa.alloc(u8, abi_size); defer mod.gpa.free(byte_buffer); From 339cae7fd0af5730673fcba7d97568af24b5aa4f Mon Sep 17 00:00:00 2001 From: Eric Joldasov Date: Tue, 10 Jan 2023 13:20:40 +0600 Subject: [PATCH 019/725] cmake: install zig to 'build_dir/stage3' during building This commit installs Zig to "build_dir/stage3" during building so that distros' can easily find binary and use it for testing/etc. This commit also splits "add_custom_target(stage3 ALL" and command that it invokes, so that it won't retry it during installation, as target will be considered not out-of-date. See also https://www.github.com/ziglang/zig/issues/14240#issuecomment-1374642063 --- CMakeLists.txt | 8 ++++++-- build.zig | 3 --- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7c63bff6e0..23222d73c7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -860,8 +860,12 @@ set(ZIG_BUILD_ARGS ) add_custom_target(stage3 ALL - COMMAND zig2 build compile ${ZIG_BUILD_ARGS} - DEPENDS zig2 + DEPENDS "${CMAKE_BINARY_DIR}/stage3/bin/zig" +) + +add_custom_command( + OUTPUT "${CMAKE_BINARY_DIR}/stage3/bin/zig" + COMMAND zig2 build --prefix "${CMAKE_BINARY_DIR}/stage3" ${ZIG_BUILD_ARGS} COMMENT STATUS "Building stage3" WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" ) diff --git a/build.zig b/build.zig index 6cb3e35488..78345ac9e4 100644 --- a/build.zig +++ b/build.zig @@ -179,9 +179,6 @@ pub fn build(b: *std.Build) !void { exe.entitlements = entitlements; b.installArtifact(exe); - const compile_step = b.step("compile", "Build the self-hosted compiler"); - compile_step.dependOn(&exe.step); - test_step.dependOn(&exe.step); exe.single_threaded = single_threaded; From 1b432072b5ae6a70a00464b48b7ebf8610293fc3 Mon Sep 17 00:00:00 2001 From: dweiller <4678790+dweiller@users.noreplay.github.com> Date: Fri, 10 Mar 2023 13:03:40 +1100 Subject: [PATCH 020/725] std.Build: detect and disallow top-level step name clashes --- lib/std/Build.zig | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/std/Build.zig b/lib/std/Build.zig index f23b3ba5aa..a2c8a22e32 100644 --- a/lib/std/Build.zig +++ b/lib/std/Build.zig @@ -926,7 +926,12 @@ pub fn step(self: *Build, name: []const u8, description: []const u8) *Step { }), .description = self.dupe(description), }; - self.top_level_steps.put(self.allocator, step_info.step.name, step_info) catch @panic("OOM"); + const gop = self.top_level_steps.getOrPut(self.allocator, name) catch @panic("OOM"); + if (gop.found_existing) std.debug.panic("A top-level step with name \"{s}\" already exists", .{name}); + + gop.key_ptr.* = step_info.step.name; + gop.value_ptr.* = step_info; + return &step_info.step; } From ec6ffaa1e47388a59035277dafbe3d9999a80fca Mon Sep 17 00:00:00 2001 From: kcbanner Date: Thu, 27 Apr 2023 21:42:32 -0400 Subject: [PATCH 021/725] sema: improve the error message when coercing to []anyopaque --- src/Sema.zig | 3 ++- .../double_pointer_to_anyopaque_pointer.zig | 7 +++++++ .../compile_errors/pointer_to_anyopaque_slice.zig | 11 +++++++++++ 3 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 test/cases/compile_errors/pointer_to_anyopaque_slice.zig diff --git a/src/Sema.zig b/src/Sema.zig index 8593edf6cc..71a1215dcd 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -25335,7 +25335,7 @@ fn coerceExtra( // cast from *T and [*]T to *anyopaque // but don't do it if the source type is a double pointer - if (dest_info.pointee_type.tag() == .anyopaque and inst_ty.zigTypeTag() == .Pointer) { + if (dest_info.pointee_type.tag() == .anyopaque and inst_ty.zigTypeTag() == .Pointer) to_anyopaque: { if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :pointer; const elem_ty = inst_ty.elemType2(); if (elem_ty.zigTypeTag() == .Pointer or elem_ty.isPtrLikeOptional()) { @@ -25345,6 +25345,7 @@ fn coerceExtra( } }; break :pointer; } + if (dest_ty.isSlice()) break :to_anyopaque; if (inst_ty.isSlice()) { in_memory_result = .{ .slice_to_anyopaque = .{ .actual = inst_ty, diff --git a/test/cases/compile_errors/double_pointer_to_anyopaque_pointer.zig b/test/cases/compile_errors/double_pointer_to_anyopaque_pointer.zig index c7e54738d1..c695b7393d 100644 --- a/test/cases/compile_errors/double_pointer_to_anyopaque_pointer.zig +++ b/test/cases/compile_errors/double_pointer_to_anyopaque_pointer.zig @@ -15,6 +15,11 @@ pub export fn entry3() void { const ptr: *const anyopaque = x; _ = ptr; } +export fn entry4() void { + var a: []*u32 = undefined; + var b: []anyopaque = undefined; + b = a; +} // error // backend=stage2 @@ -27,3 +32,5 @@ pub export fn entry3() void { // :11:12: note: parameter type declared here // :15:35: error: expected type '*const anyopaque', found '*?*usize' // :15:35: note: cannot implicitly cast double pointer '*?*usize' to anyopaque pointer '*const anyopaque' +// :21:9: error: expected type '[]anyopaque', found '[]*u32' +// :21:9: note: cannot implicitly cast double pointer '[]*u32' to anyopaque pointer '[]anyopaque' diff --git a/test/cases/compile_errors/pointer_to_anyopaque_slice.zig b/test/cases/compile_errors/pointer_to_anyopaque_slice.zig new file mode 100644 index 0000000000..2c7334bedb --- /dev/null +++ b/test/cases/compile_errors/pointer_to_anyopaque_slice.zig @@ -0,0 +1,11 @@ +export fn x() void { + var a: *u32 = undefined; + var b: []anyopaque = undefined; + b = a; +} + +// error +// backend=stage2 +// target=native +// +// :4:9: error: expected type '[]anyopaque', found '*u32' From 94e30a756edc4c2182168dabd97d481b8aec0ff2 Mon Sep 17 00:00:00 2001 From: Linus Groh Date: Sun, 30 Apr 2023 18:02:08 +0100 Subject: [PATCH 022/725] std: fix a bunch of typos The majority of these are in comments, some in doc comments which might affect the generated documentation, and a few in parameter names - nothing that should be breaking, however. --- lib/std/Build/Cache/DepTokenizer.zig | 2 +- lib/std/Build/CheckObjectStep.zig | 2 +- lib/std/Build/RunStep.zig | 2 +- lib/std/Build/Step.zig | 2 +- lib/std/Thread.zig | 4 ++-- lib/std/Thread/Condition.zig | 2 +- lib/std/Thread/Futex.zig | 2 +- lib/std/atomic/Atomic.zig | 2 +- lib/std/builtin.zig | 2 +- lib/std/c/darwin.zig | 8 ++++---- lib/std/c/solaris.zig | 2 +- lib/std/child_process.zig | 2 +- lib/std/compress/deflate/huffman_code.zig | 2 +- lib/std/crypto/25519/edwards25519.zig | 4 ++-- lib/std/crypto/25519/field.zig | 2 +- lib/std/crypto/Certificate.zig | 4 ++-- lib/std/crypto/errors.zig | 2 +- lib/std/crypto/kyber_d00.zig | 4 ++-- lib/std/event/lock.zig | 4 ++-- lib/std/event/loop.zig | 6 +++--- lib/std/fmt/parse_float/convert_fast.zig | 2 +- lib/std/fs/file.zig | 4 ++-- lib/std/fs/path.zig | 4 ++-- lib/std/hash_map.zig | 2 +- lib/std/heap.zig | 2 +- lib/std/heap/arena_allocator.zig | 2 +- lib/std/heap/general_purpose_allocator.zig | 4 ++-- lib/std/heap/memory_pool.zig | 2 +- lib/std/http.zig | 2 +- lib/std/json.zig | 2 +- lib/std/linked_list.zig | 2 +- lib/std/macho.zig | 12 ++++++------ lib/std/math/big/int.zig | 20 ++++++++++---------- lib/std/math/complex/tan.zig | 2 +- lib/std/math/log10.zig | 2 +- lib/std/math/sqrt.zig | 2 +- lib/std/mem.zig | 10 +++++----- lib/std/os.zig | 6 +++--- lib/std/os/linux.zig | 6 +++--- lib/std/os/linux/bpf/btf.zig | 6 +++--- lib/std/os/linux/seccomp.zig | 2 +- lib/std/os/windows.zig | 2 +- lib/std/packed_int_array.zig | 4 ++-- lib/std/pdb.zig | 2 +- lib/std/simd.zig | 2 +- lib/std/target/csky.zig | 14 +++++++------- lib/std/time.zig | 2 +- lib/std/valgrind/memcheck.zig | 4 ++-- lib/std/zig/parser_test.zig | 6 +++--- lib/std/zig/render.zig | 2 +- 50 files changed, 97 insertions(+), 97 deletions(-) diff --git a/lib/std/Build/Cache/DepTokenizer.zig b/lib/std/Build/Cache/DepTokenizer.zig index 8f9f2f81cd..c640fa4adc 100644 --- a/lib/std/Build/Cache/DepTokenizer.zig +++ b/lib/std/Build/Cache/DepTokenizer.zig @@ -829,7 +829,7 @@ test "error illegal char at position - bad target escape" { ); } -test "error illegal char at position - execting dollar_sign" { +test "error illegal char at position - expecting dollar_sign" { try depTokenizer("$\t", \\ERROR: illegal char \x09 at position 1: expecting '$' ); diff --git a/lib/std/Build/CheckObjectStep.zig b/lib/std/Build/CheckObjectStep.zig index fbeb87baee..e79ce9d3df 100644 --- a/lib/std/Build/CheckObjectStep.zig +++ b/lib/std/Build/CheckObjectStep.zig @@ -68,7 +68,7 @@ const SearchPhrase = struct { } }; -/// There two types of actions currently suported: +/// There two types of actions currently supported: /// * `.match` - is the main building block of standard matchers with optional eat-all token `{*}` /// and extractors by name such as `{n_value}`. Please note this action is very simplistic in nature /// i.e., it won't really handle edge cases/nontrivial examples. But given that we do want to use diff --git a/lib/std/Build/RunStep.zig b/lib/std/Build/RunStep.zig index ce2dd0234a..5d530c7a25 100644 --- a/lib/std/Build/RunStep.zig +++ b/lib/std/Build/RunStep.zig @@ -90,7 +90,7 @@ pub const StdIo = union(enum) { /// certain conditions, and the step will succeed or fail based on these /// conditions. /// Note that an explicit check for exit code 0 needs to be added to this - /// list if such a check is desireable. + /// list if such a check is desirable. check: std.ArrayList(Check), /// This RunStep is running a zig unit test binary and will communicate /// extra metadata over the IPC protocol. diff --git a/lib/std/Build/Step.zig b/lib/std/Build/Step.zig index 0c05a64b1c..bdb500d99c 100644 --- a/lib/std/Build/Step.zig +++ b/lib/std/Build/Step.zig @@ -37,7 +37,7 @@ result_duration_ns: ?u64, result_peak_rss: usize, test_results: TestResults, -/// The return addresss associated with creation of this step that can be useful +/// The return address associated with creation of this step that can be useful /// to print along with debugging messages. debug_stack_trace: [n_debug_stack_frames]usize, diff --git a/lib/std/Thread.zig b/lib/std/Thread.zig index 119328b2a8..d213b167dd 100644 --- a/lib/std/Thread.zig +++ b/lib/std/Thread.zig @@ -469,8 +469,8 @@ const UnsupportedImpl = struct { return unsupported(self); } - fn unsupported(unusued: anytype) noreturn { - _ = unusued; + fn unsupported(unused: anytype) noreturn { + _ = unused; @compileError("Unsupported operating system " ++ @tagName(target.os.tag)); } }; diff --git a/lib/std/Thread/Condition.zig b/lib/std/Thread/Condition.zig index bc579878da..2f8ab02d5e 100644 --- a/lib/std/Thread/Condition.zig +++ b/lib/std/Thread/Condition.zig @@ -261,7 +261,7 @@ const FutexImpl = struct { const signals = (state & signal_mask) / one_signal; // Reserves which waiters to wake up by incrementing the signals count. - // Therefor, the signals count is always less than or equal to the waiters count. + // Therefore, the signals count is always less than or equal to the waiters count. // We don't need to Futex.wake if there's nothing to wake up or if other wake() threads have reserved to wake up the current waiters. const wakeable = waiters - signals; if (wakeable == 0) { diff --git a/lib/std/Thread/Futex.zig b/lib/std/Thread/Futex.zig index 7efdc69d3b..7fbe49fea2 100644 --- a/lib/std/Thread/Futex.zig +++ b/lib/std/Thread/Futex.zig @@ -772,7 +772,7 @@ const PosixImpl = struct { waiter.event.wait(timeout) catch { // If we fail to cancel after a timeout, it means a wake() thread dequeued us and will wake us up. - // We must wait until the event is set as that's a signal that the wake() thread wont access the waiter memory anymore. + // We must wait until the event is set as that's a signal that the wake() thread won't access the waiter memory anymore. // If we return early without waiting, the waiter on the stack would be invalidated and the wake() thread risks a UAF. defer if (!cancelled) waiter.event.wait(null) catch unreachable; diff --git a/lib/std/atomic/Atomic.zig b/lib/std/atomic/Atomic.zig index 51e61ca628..5bb25e9bde 100644 --- a/lib/std/atomic/Atomic.zig +++ b/lib/std/atomic/Atomic.zig @@ -31,7 +31,7 @@ pub fn Atomic(comptime T: type) type { /// // Release ensures code before unref() happens-before the count is decremented as dropFn could be called by then. /// if (self.count.fetchSub(1, .Release)) { /// // Acquire ensures count decrement and code before previous unrefs()s happens-before we call dropFn below. - /// // NOTE: another alterative is to use .AcqRel on the fetchSub count decrement but it's extra barrier in possibly hot path. + /// // NOTE: another alternative is to use .AcqRel on the fetchSub count decrement but it's extra barrier in possibly hot path. /// self.count.fence(.Acquire); /// (self.dropFn)(self); /// } diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig index 4a5e8a28d6..ea513ae87e 100644 --- a/lib/std/builtin.zig +++ b/lib/std/builtin.zig @@ -749,7 +749,7 @@ pub const PrefetchOptions = struct { /// 3 means high temporal locality. That is, the data should be kept in /// the cache as it is likely to be accessed again soon. locality: u2 = 3, - /// The cache that the prefetch should be preformed on. + /// The cache that the prefetch should be performed on. cache: Cache = .data, pub const Rw = enum(u1) { diff --git a/lib/std/c/darwin.zig b/lib/std/c/darwin.zig index cd1fbb9d9b..6e4ef59d38 100644 --- a/lib/std/c/darwin.zig +++ b/lib/std/c/darwin.zig @@ -178,13 +178,13 @@ pub extern "c" fn __getdirentries64(fd: c_int, buf_ptr: [*]u8, buf_len: usize, b const private = struct { extern "c" fn fstat(fd: fd_t, buf: *Stat) c_int; - /// On x86_64 Darwin, fstat has to be manully linked with $INODE64 suffix to + /// On x86_64 Darwin, fstat has to be manually linked with $INODE64 suffix to /// force 64bit version. /// Note that this is fixed on aarch64 and no longer necessary. extern "c" fn @"fstat$INODE64"(fd: fd_t, buf: *Stat) c_int; extern "c" fn fstatat(dirfd: fd_t, path: [*:0]const u8, stat_buf: *Stat, flags: u32) c_int; - /// On x86_64 Darwin, fstatat has to be manully linked with $INODE64 suffix to + /// On x86_64 Darwin, fstatat has to be manually linked with $INODE64 suffix to /// force 64bit version. /// Note that this is fixed on aarch64 and no longer necessary. extern "c" fn @"fstatat$INODE64"(dirfd: fd_t, path_name: [*:0]const u8, buf: *Stat, flags: u32) c_int; @@ -2643,7 +2643,7 @@ pub const F = struct { pub const ADDSIGS = 59; /// add signature from same file (used by dyld for shared libs) pub const ADDFILESIGS = 61; - /// used in conjunction with F.NOCACHE to indicate that DIRECT, synchonous writes + /// used in conjunction with F.NOCACHE to indicate that DIRECT, synchronous writes /// should not be used (i.e. its ok to temporaily create cached pages) pub const NODIRECT = 62; ///Get the protection class of a file from the EA, returns int @@ -3866,4 +3866,4 @@ pub const MIN = struct { pub const ANONYMOUS = 0x80; }; -pub extern "c" fn mincore(addr: *align(std.mem.page_size) const anyopaque, lengh: usize, vec: [*]u8) c_int; +pub extern "c" fn mincore(addr: *align(std.mem.page_size) const anyopaque, length: usize, vec: [*]u8) c_int; diff --git a/lib/std/c/solaris.zig b/lib/std/c/solaris.zig index c2c38f46ce..b2225c6d00 100644 --- a/lib/std/c/solaris.zig +++ b/lib/std/c/solaris.zig @@ -1822,7 +1822,7 @@ pub const file_obj = extern struct { name: [*:0]u8, }; -// struct ifreq is marked obsolete, with struct lifreq prefered for interface requests. +// struct ifreq is marked obsolete, with struct lifreq preferred for interface requests. // Here we alias lifreq to ifreq to avoid chainging existing code in os and x.os.IPv6. pub const SIOCGLIFINDEX = IOWR('i', 133, lifreq); pub const SIOCGIFINDEX = SIOCGLIFINDEX; diff --git a/lib/std/child_process.zig b/lib/std/child_process.zig index f5ca72ed39..daaa1689bc 100644 --- a/lib/std/child_process.zig +++ b/lib/std/child_process.zig @@ -1174,7 +1174,7 @@ fn windowsCreateProcess(app_name: [*:0]u16, cmd_line: [*:0]u16, envp_ptr: ?[*]u1 ); } -/// Case-insenstive UTF-16 lookup +/// Case-insensitive UTF-16 lookup fn windowsCreateProcessSupportsExtension(ext: []const u16) bool { if (ext.len != 4) return false; const State = enum { diff --git a/lib/std/compress/deflate/huffman_code.zig b/lib/std/compress/deflate/huffman_code.zig index cf1dd71c75..4827feb245 100644 --- a/lib/std/compress/deflate/huffman_code.zig +++ b/lib/std/compress/deflate/huffman_code.zig @@ -421,7 +421,7 @@ test "generate a Huffman code from an array of frequencies" { try testing.expectEqual(@as(u16, 0x3f), enc.codes[16].code); } -test "generate a Huffman code for the fixed litteral table specific to Deflate" { +test "generate a Huffman code for the fixed literal table specific to Deflate" { var enc = try generateFixedLiteralEncoding(testing.allocator); defer enc.deinit(); } diff --git a/lib/std/crypto/25519/edwards25519.zig b/lib/std/crypto/25519/edwards25519.zig index a8ca8e2fb6..b9ce14bc92 100644 --- a/lib/std/crypto/25519/edwards25519.zig +++ b/lib/std/crypto/25519/edwards25519.zig @@ -137,7 +137,7 @@ pub const Edwards25519 = struct { }; } - /// Substract two Edwards25519 points. + /// Subtract two Edwards25519 points. pub fn sub(p: Edwards25519, q: Edwards25519) Edwards25519 { return p.add(q.neg()); } @@ -529,7 +529,7 @@ test "edwards25519 packing/unpacking" { } } -test "edwards25519 point addition/substraction" { +test "edwards25519 point addition/subtraction" { var s1: [32]u8 = undefined; var s2: [32]u8 = undefined; crypto.random.bytes(&s1); diff --git a/lib/std/crypto/25519/field.zig b/lib/std/crypto/25519/field.zig index 1885f9286e..f6265cba48 100644 --- a/lib/std/crypto/25519/field.zig +++ b/lib/std/crypto/25519/field.zig @@ -179,7 +179,7 @@ pub const Fe = struct { return fe; } - /// Substract a field element + /// Subtract a field element pub inline fn sub(a: Fe, b: Fe) Fe { var fe = b; comptime var i = 0; diff --git a/lib/std/crypto/Certificate.zig b/lib/std/crypto/Certificate.zig index ec4766322c..113d169cbc 100644 --- a/lib/std/crypto/Certificate.zig +++ b/lib/std/crypto/Certificate.zig @@ -1134,9 +1134,9 @@ pub const rsa = struct { return res; } - fn setBytes(r: *BigInt, bytes: []const u8, allcator: std.mem.Allocator) !void { + fn setBytes(r: *BigInt, bytes: []const u8, allocator: std.mem.Allocator) !void { try r.set(0); - var tmp = try BigInt.init(allcator); + var tmp = try BigInt.init(allocator); defer tmp.deinit(); for (bytes) |b| { try r.shiftLeft(r, 8); diff --git a/lib/std/crypto/errors.zig b/lib/std/crypto/errors.zig index 4d79055919..bf37faaf29 100644 --- a/lib/std/crypto/errors.zig +++ b/lib/std/crypto/errors.zig @@ -10,7 +10,7 @@ pub const IdentityElementError = error{IdentityElement}; /// Encoded input cannot be decoded pub const EncodingError = error{InvalidEncoding}; -/// The signature does't verify for the given message and public key +/// The signature doesn't verify for the given message and public key pub const SignatureVerificationError = error{SignatureVerificationFailed}; /// Both a public and secret key have been provided, but they are incompatible diff --git a/lib/std/crypto/kyber_d00.zig b/lib/std/crypto/kyber_d00.zig index b52f9f475d..dca4ab7ea7 100644 --- a/lib/std/crypto/kyber_d00.zig +++ b/lib/std/crypto/kyber_d00.zig @@ -80,7 +80,7 @@ //! m = Compress(Decompress(c_2, d_v) - s^T Decompress(c_1, d_u), 1). //! //! It it not straight-forward to see that this formula is correct. In -//! fact, there is negligable but non-zero probability that a ciphertext +//! fact, there is negligible but non-zero probability that a ciphertext //! does not decrypt correctly given by the DFP column in Table 4. This //! failure probability can be computed by a careful automated analysis //! of the probabilities involved, see kyber_failure.py of [SecEst]. @@ -640,7 +640,7 @@ fn montReduce(x: i32) i16 { // we have int32(int64(a)*int64(b)) = int32(a*b) and so the result is ok. const m = @truncate(i16, @truncate(i32, x *% qInv)); - // Note that x - m q is divisable by R; indeed modulo R we have + // Note that x - m q is divisible by R; indeed modulo R we have // // x - m q ≡ x - x q' q ≡ x - x q⁻¹ q ≡ x - x = 0. // diff --git a/lib/std/event/lock.zig b/lib/std/event/lock.zig index 6e095b1890..9cda7f2aba 100644 --- a/lib/std/event/lock.zig +++ b/lib/std/event/lock.zig @@ -36,7 +36,7 @@ pub const Lock = struct { // self.head transitions from multiple stages depending on the value: // UNLOCKED -> LOCKED: - // acquire Lock ownership when theres no waiters + // acquire Lock ownership when there are no waiters // LOCKED -> : // Lock is already owned, enqueue first Waiter // -> : @@ -87,7 +87,7 @@ pub const Lock = struct { // self.head goes through the reverse transition from acquire(): // -> : - // pop a waiter from the queue to give Lock ownership when theres still others pending + // pop a waiter from the queue to give Lock ownership when there are still others pending // -> LOCKED: // pop the laster waiter from the queue, while also giving it lock ownership when awaken // LOCKED -> UNLOCKED: diff --git a/lib/std/event/loop.zig b/lib/std/event/loop.zig index 34f74e10d2..eea1ec75be 100644 --- a/lib/std/event/loop.zig +++ b/lib/std/event/loop.zig @@ -903,7 +903,7 @@ pub const Loop = struct { } } - // TODO: use a tickless heirarchical timer wheel: + // TODO: use a tickless hierarchical timer wheel: // https://github.com/wahern/timeout/ const Waiters = struct { entries: std.atomic.Queue(anyframe), @@ -947,7 +947,7 @@ pub const Loop = struct { // starting from the head var head = self.entries.head orelse return null; - // traverse the list of waiting entires to + // traverse the list of waiting entries to // find the Node with the smallest `expires` field var min = head; while (head.next) |node| { @@ -1756,7 +1756,7 @@ test "std.event.Loop - runDetached" { try loop.runDetached(std.testing.allocator, testRunDetached, .{}); // Now we can start the event loop. The function will return only - // after all tasks have been completed, allowing us to synchonize + // after all tasks have been completed, allowing us to synchronize // with the previous runDetached. loop.run(); diff --git a/lib/std/fmt/parse_float/convert_fast.zig b/lib/std/fmt/parse_float/convert_fast.zig index 75875156fd..74beb745de 100644 --- a/lib/std/fmt/parse_float/convert_fast.zig +++ b/lib/std/fmt/parse_float/convert_fast.zig @@ -1,4 +1,4 @@ -//! Representation of a float as the signficant digits and exponent. +//! Representation of a float as the significant digits and exponent. //! The fast path algorithm using machine-sized integers and floats. //! //! This only works if both the mantissa and the exponent can be exactly diff --git a/lib/std/fs/file.zig b/lib/std/fs/file.zig index 3f8e7185d0..23021a26f5 100644 --- a/lib/std/fs/file.zig +++ b/lib/std/fs/file.zig @@ -92,7 +92,7 @@ pub const File = struct { /// processes from acquiring a exclusive lock, but does not prevent /// other process from getting their own shared locks. /// - /// The lock is advisory, except on Linux in very specific cirsumstances[1]. + /// The lock is advisory, except on Linux in very specific circumstances[1]. /// This means that a process that does not respect the locking API can still get access /// to the file, despite the lock. /// @@ -156,7 +156,7 @@ pub const File = struct { /// processes from acquiring a exclusive lock, but does not prevent /// other process from getting their own shared locks. /// - /// The lock is advisory, except on Linux in very specific cirsumstances[1]. + /// The lock is advisory, except on Linux in very specific circumstances[1]. /// This means that a process that does not respect the locking API can still get access /// to the file, despite the lock. /// diff --git a/lib/std/fs/path.zig b/lib/std/fs/path.zig index 4f3e05cd59..4c320ae5cf 100644 --- a/lib/std/fs/path.zig +++ b/lib/std/fs/path.zig @@ -105,13 +105,13 @@ fn joinSepMaybeZ(allocator: Allocator, separator: u8, comptime sepPredicate: fn return buf; } -/// Naively combines a series of paths with the native path seperator. +/// Naively combines a series of paths with the native path separator. /// Allocates memory for the result, which must be freed by the caller. pub fn join(allocator: Allocator, paths: []const []const u8) ![]u8 { return joinSepMaybeZ(allocator, sep, isSep, paths, false); } -/// Naively combines a series of paths with the native path seperator and null terminator. +/// Naively combines a series of paths with the native path separator and null terminator. /// Allocates memory for the result, which must be freed by the caller. pub fn joinZ(allocator: Allocator, paths: []const []const u8) ![:0]u8 { const out = try joinSepMaybeZ(allocator, sep, isSep, paths, true); diff --git a/lib/std/hash_map.zig b/lib/std/hash_map.zig index 65b07b8e77..df3446a2c0 100644 --- a/lib/std/hash_map.zig +++ b/lib/std/hash_map.zig @@ -690,7 +690,7 @@ pub fn HashMap( /// It achieves good performance with quite high load factors (by default, /// grow is triggered at 80% full) and only one byte of overhead per element. /// The struct itself is only 16 bytes for a small footprint. This comes at -/// the price of handling size with u32, which should be reasonnable enough +/// the price of handling size with u32, which should be reasonable enough /// for almost all uses. /// Deletions are achieved with tombstones. pub fn HashMapUnmanaged( diff --git a/lib/std/heap.zig b/lib/std/heap.zig index 111314a1d9..7d2a66df1e 100644 --- a/lib/std/heap.zig +++ b/lib/std/heap.zig @@ -79,7 +79,7 @@ const CAllocator = struct { } // Thin wrapper around regular malloc, overallocate to account for - // alignment padding and store the orignal malloc()'ed pointer before + // alignment padding and store the original malloc()'ed pointer before // the aligned address. var unaligned_ptr = @ptrCast([*]u8, c.malloc(len + alignment - 1 + @sizeOf(usize)) orelse return null); const unaligned_addr = @ptrToInt(unaligned_ptr); diff --git a/lib/std/heap/arena_allocator.zig b/lib/std/heap/arena_allocator.zig index d07c45cb70..9489bbb449 100644 --- a/lib/std/heap/arena_allocator.zig +++ b/lib/std/heap/arena_allocator.zig @@ -136,7 +136,7 @@ pub const ArenaAllocator = struct { it = next_it; } else null; std.debug.assert(maybe_first_node == null or maybe_first_node.?.next == null); - // reset the state before we try resizing the buffers, so we definitly have reset the arena to 0. + // reset the state before we try resizing the buffers, so we definitely have reset the arena to 0. self.state.end_index = 0; if (maybe_first_node) |first_node| { // perfect, no need to invoke the child_allocator diff --git a/lib/std/heap/general_purpose_allocator.zig b/lib/std/heap/general_purpose_allocator.zig index de7bc7c423..ef88787fc6 100644 --- a/lib/std/heap/general_purpose_allocator.zig +++ b/lib/std/heap/general_purpose_allocator.zig @@ -130,7 +130,7 @@ pub const Config = struct { thread_safe: bool = !builtin.single_threaded, /// What type of mutex you'd like to use, for thread safety. - /// when specfied, the mutex type must have the same shape as `std.Thread.Mutex` and + /// when specified, the mutex type must have the same shape as `std.Thread.Mutex` and /// `DummyMutex`, and have no required fields. Specifying this field causes /// the `thread_safe` field to be ignored. /// @@ -1241,7 +1241,7 @@ test "realloc large object to small object" { try std.testing.expect(slice[16] == 0x34); } -test "overrideable mutexes" { +test "overridable mutexes" { var gpa = GeneralPurposeAllocator(.{ .MutexType = std.Thread.Mutex }){ .backing_allocator = std.testing.allocator, .mutex = std.Thread.Mutex{}, diff --git a/lib/std/heap/memory_pool.zig b/lib/std/heap/memory_pool.zig index 6ae90a3894..ca6eb7f518 100644 --- a/lib/std/heap/memory_pool.zig +++ b/lib/std/heap/memory_pool.zig @@ -150,7 +150,7 @@ test "memory pool: basic" { pool.destroy(p2); const p4 = try pool.create(); - // Assert memory resuse + // Assert memory reuse try std.testing.expect(p2 == p4); } diff --git a/lib/std/http.zig b/lib/std/http.zig index bb06bb1c19..744615d7d7 100644 --- a/lib/std/http.zig +++ b/lib/std/http.zig @@ -12,7 +12,7 @@ pub const Version = enum { }; /// https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods -/// https://datatracker.ietf.org/doc/html/rfc7231#section-4 Initial definiton +/// https://datatracker.ietf.org/doc/html/rfc7231#section-4 Initial definition /// https://datatracker.ietf.org/doc/html/rfc5789#section-2 PATCH pub const Method = enum { GET, diff --git a/lib/std/json.zig b/lib/std/json.zig index 432f4e6911..af928bc564 100644 --- a/lib/std/json.zig +++ b/lib/std/json.zig @@ -1603,7 +1603,7 @@ fn parseInternal( if (fields_seen[i]) { switch (options.duplicate_field_behavior) { .UseFirst => { - // unconditonally ignore value. for comptime fields, this skips check against default_value + // unconditionally ignore value. for comptime fields, this skips check against default_value parseFree(field.type, try parse(field.type, tokens, child_options), child_options); found = true; break; diff --git a/lib/std/linked_list.zig b/lib/std/linked_list.zig index 577bae3d38..f9084a55c4 100644 --- a/lib/std/linked_list.zig +++ b/lib/std/linked_list.zig @@ -406,7 +406,7 @@ test "TailQueue concatenation" { } } - // Swap them back, this verifies that concating to an empty list works. + // Swap them back, this verifies that concatenating to an empty list works. list2.concatByMoving(&list1); // Traverse forwards. diff --git a/lib/std/macho.zig b/lib/std/macho.zig index a25ffca4fa..8bddd67023 100644 --- a/lib/std/macho.zig +++ b/lib/std/macho.zig @@ -356,7 +356,7 @@ pub const dysymtab_command = extern struct { // All the local relocation entries are grouped together (they are not // grouped by their module since they are only used if the object is moved - // from it staticly link edited address). + // from its statically link edited address). /// offset to local relocation entries locreloff: u32 = 0, @@ -418,7 +418,7 @@ pub const dyld_info_command = extern struct { // // The opcodes are a compressed way to encode the table by only // encoding when a column changes. In addition simple patterns - // like for runs of pointers initialzed to the same value can be + // like for runs of pointers initialized to the same value can be // encoded in a few bytes. /// file offset to binding info @@ -1141,7 +1141,7 @@ pub const MH_NOUNDEFS = 0x1; /// the object file is the output of an incremental link against a base file and can't be link edited again pub const MH_INCRLINK = 0x2; -/// the object file is input for the dynamic linker and can't be staticly link edited again +/// the object file is input for the dynamic linker and can't be statically link edited again pub const MH_DYLDLINK = 0x4; /// the object file's undefined references are bound by the dynamic linker when loaded. @@ -1162,7 +1162,7 @@ pub const MH_TWOLEVEL = 0x80; /// the executable is forcing all images to use flat name space bindings pub const MH_FORCE_FLAT = 0x100; -/// this umbrella guarantees no multiple defintions of symbols in its sub-images so the two-level namespace hints can always be used. +/// this umbrella guarantees no multiple definitions of symbols in its sub-images so the two-level namespace hints can always be used. pub const MH_NOMULTIDEFS = 0x200; /// do not have dyld notify the prebinding agent about this executable @@ -1658,7 +1658,7 @@ pub const EXPORT_SYMBOL_FLAGS_REEXPORT: u8 = 0x08; pub const EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER: u8 = 0x10; // An indirect symbol table entry is simply a 32bit index into the symbol table -// to the symbol that the pointer or stub is refering to. Unless it is for a +// to the symbol that the pointer or stub is referring to. Unless it is for a // non-lazy symbol pointer section for a defined symbol which strip(1) as // removed. In which case it has the value INDIRECT_SYMBOL_LOCAL. If the // symbol was also absolute INDIRECT_SYMBOL_ABS is or'ed with that. @@ -1741,7 +1741,7 @@ pub const CS_LINKER_SIGNED: u32 = 0x20000; pub const CS_EXECSEG_MAIN_BINARY: u32 = 0x1; -/// This CodeDirectory is tailored specfically at version 0x20400. +/// This CodeDirectory is tailored specifically at version 0x20400. pub const CodeDirectory = extern struct { /// Magic number (CSMAGIC_CODEDIRECTORY) magic: u32, diff --git a/lib/std/math/big/int.zig b/lib/std/math/big/int.zig index 2406d669ec..b01d9b04ff 100644 --- a/lib/std/math/big/int.zig +++ b/lib/std/math/big/int.zig @@ -408,7 +408,7 @@ pub const Mutable = struct { } /// Base implementation for addition. Adds `max(a.limbs.len, b.limbs.len)` elements from a and b, - /// and returns whether any overflow occured. + /// and returns whether any overflow occurred. /// r, a and b may be aliases. /// /// Asserts r has enough elements to hold the result. The upper bound is `max(a.limbs.len, b.limbs.len)`. @@ -467,7 +467,7 @@ pub const Mutable = struct { const req_limbs = calcTwosCompLimbCount(bit_count); // Slice of the upper bits if they exist, these will be ignored and allows us to use addCarry to determine - // if an overflow occured. + // if an overflow occurred. const x = Const{ .positive = a.positive, .limbs = a.limbs[0..math.min(req_limbs, a.limbs.len)], @@ -512,7 +512,7 @@ pub const Mutable = struct { const req_limbs = calcTwosCompLimbCount(bit_count); // Slice of the upper bits if they exist, these will be ignored and allows us to use addCarry to determine - // if an overflow occured. + // if an overflow occurred. const x = Const{ .positive = a.positive, .limbs = a.limbs[0..math.min(req_limbs, a.limbs.len)], @@ -544,7 +544,7 @@ pub const Mutable = struct { } /// Base implementation for subtraction. Subtracts `max(a.limbs.len, b.limbs.len)` elements from a and b, - /// and returns whether any overflow occured. + /// and returns whether any overflow occurred. /// r, a and b may be aliases. /// /// Asserts r has enough elements to hold the result. The upper bound is `max(a.limbs.len, b.limbs.len)`. @@ -605,7 +605,7 @@ pub const Mutable = struct { r.add(a, b.negate()); } - /// r = a - b with 2s-complement wrapping semantics. Returns whether any overflow occured. + /// r = a - b with 2s-complement wrapping semantics. Returns whether any overflow occurred. /// /// r, a and b may be aliases /// Asserts the result fits in `r`. An upper bound on the number of limbs needed by @@ -1141,7 +1141,7 @@ pub const Mutable = struct { return; } - // Generate a mask with the bits to check in the most signficant limb. We'll need to check + // Generate a mask with the bits to check in the most significant limb. We'll need to check // all bits with equal or more significance than checkbit. // const msb = @truncate(Log2Limb, checkbit); // const checkmask = (@as(Limb, 1) << msb) -% 1; @@ -2037,7 +2037,7 @@ pub const Const = struct { add_res = ov[0]; carry = ov[1]; sum += @popCount(add_res); - remaining_bits -= limb_bits; // Asserted not to undeflow by fitsInTwosComp + remaining_bits -= limb_bits; // Asserted not to underflow by fitsInTwosComp } // The most significant limb may have fewer than @bitSizeOf(Limb) meaningful bits, @@ -2813,7 +2813,7 @@ pub const Managed = struct { r.setMetadata(m.positive, m.len); } - /// r = a + b with 2s-complement wrapping semantics. Returns whether any overflow occured. + /// r = a + b with 2s-complement wrapping semantics. Returns whether any overflow occurred. /// /// r, a and b may be aliases. /// @@ -2856,7 +2856,7 @@ pub const Managed = struct { r.setMetadata(m.positive, m.len); } - /// r = a - b with 2s-complement wrapping semantics. Returns whether any overflow occured. + /// r = a - b with 2s-complement wrapping semantics. Returns whether any overflow occurred. /// /// r, a and b may be aliases. /// @@ -4010,7 +4010,7 @@ fn llsquareBasecase(r: []Limb, x: []const Limb) void { assert(r.len >= 2 * x_norm.len + 1); // Compute the square of a N-limb bigint with only (N^2 + N)/2 - // multiplications by exploting the symmetry of the coefficients around the + // multiplications by exploiting the symmetry of the coefficients around the // diagonal: // // a b c * diff --git a/lib/std/math/complex/tan.zig b/lib/std/math/complex/tan.zig index 9e1025f74f..a0ce5d18e0 100644 --- a/lib/std/math/complex/tan.zig +++ b/lib/std/math/complex/tan.zig @@ -4,7 +4,7 @@ const math = std.math; const cmath = math.complex; const Complex = cmath.Complex; -/// Returns the tanget of z. +/// Returns the tangent of z. pub fn tan(z: anytype) Complex(@TypeOf(z.re)) { const T = @TypeOf(z.re); const q = Complex(T).init(-z.im, z.re); diff --git a/lib/std/math/log10.zig b/lib/std/math/log10.zig index b1ecb9ad2b..6b5758763c 100644 --- a/lib/std/math/log10.zig +++ b/lib/std/math/log10.zig @@ -58,7 +58,7 @@ pub fn log10_int(x: anytype) Log2Int(@TypeOf(x)) { var log: u32 = 0; inline for (0..11) |i| { - // Unnecesary branches should be removed by the compiler + // Unnecessary branches should be removed by the compiler if (bit_size > (1 << (11 - i)) * 5 * @log2(10.0) and val >= pow10((1 << (11 - i)) * 5)) { const num_digits = (1 << (11 - i)) * 5; val /= pow10(num_digits); diff --git a/lib/std/math/sqrt.zig b/lib/std/math/sqrt.zig index e642f8a309..926582034e 100644 --- a/lib/std/math/sqrt.zig +++ b/lib/std/math/sqrt.zig @@ -11,7 +11,7 @@ const maxInt = std.math.maxInt; /// - sqrt(+-0) = +-0 /// - sqrt(x) = nan if x < 0 /// - sqrt(nan) = nan -/// TODO Decide if all this logic should be implemented directly in the @sqrt bultin function. +/// TODO Decide if all this logic should be implemented directly in the @sqrt builtin function. pub fn sqrt(x: anytype) Sqrt(@TypeOf(x)) { const T = @TypeOf(x); switch (@typeInfo(T)) { diff --git a/lib/std/mem.zig b/lib/std/mem.zig index 557e39cdfc..6cc60ddad2 100644 --- a/lib/std/mem.zig +++ b/lib/std/mem.zig @@ -114,7 +114,7 @@ pub fn validationWrap(allocator: anytype) ValidationAllocator(@TypeOf(allocator) /// An allocator helper function. Adjusts an allocation length satisfy `len_align`. /// `full_len` should be the full capacity of the allocation which may be greater -/// than the `len` that was requsted. This function should only be used by allocators +/// than the `len` that was requested. This function should only be used by allocators /// that are unaffected by `len_align`. pub fn alignAllocLen(full_len: usize, alloc_len: usize, len_align: u29) usize { assert(alloc_len > 0); @@ -427,7 +427,7 @@ pub fn zeroInit(comptime T: type, init: anytype) T { .Struct => |init_info| { if (init_info.is_tuple) { if (init_info.fields.len > struct_info.fields.len) { - @compileError("Tuple initializer has more elments than there are fields in `" ++ @typeName(T) ++ "`"); + @compileError("Tuple initializer has more elements than there are fields in `" ++ @typeName(T) ++ "`"); } } else { inline for (init_info.fields) |field| { @@ -668,7 +668,7 @@ test "Span" { /// Takes a sentinel-terminated pointer and returns a slice, iterating over the /// memory to find the sentinel and determine the length. -/// Ponter attributes such as const are preserved. +/// Pointer attributes such as const are preserved. /// `[*c]` pointers are assumed to be non-null and 0-terminated. pub fn span(ptr: anytype) Span(@TypeOf(ptr)) { if (@typeInfo(@TypeOf(ptr)) == .Optional) { @@ -1835,7 +1835,7 @@ test "writeIntBig and writeIntLittle" { } /// Swap the byte order of all the members of the fields of a struct -/// (Changing their endianess) +/// (Changing their endianness) pub fn byteSwapAllFields(comptime S: type, ptr: *S) void { if (@typeInfo(S) != .Struct) @compileError("byteSwapAllFields expects a struct as the first argument"); inline for (std.meta.fields(S)) |f| { @@ -3168,7 +3168,7 @@ test "replace" { try testing.expectEqualStrings(expected, output[0..expected.len]); } -/// Replace all occurences of `needle` with `replacement`. +/// Replace all occurrences of `needle` with `replacement`. pub fn replaceScalar(comptime T: type, slice: []T, needle: T, replacement: T) void { for (slice, 0..) |e, i| { if (e == needle) { diff --git a/lib/std/os.zig b/lib/std/os.zig index 32c73916d4..7759f1403f 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -659,7 +659,7 @@ pub fn exit(status: u8) noreturn { linux.exit_group(status); } if (builtin.os.tag == .uefi) { - // exit() is only avaliable if exitBootServices() has not been called yet. + // exit() is only available if exitBootServices() has not been called yet. // This call to exit should not fail, so we don't care about its return value. if (uefi.system_table.boot_services) |bs| { _ = bs.exit(uefi.handle, @intToEnum(uefi.Status, status), 0, null); @@ -2978,7 +2978,7 @@ pub fn chdirZ(dir_path: [*:0]const u8) ChangeCurDirError!void { } } -/// Windows-only. Same as `chdir` except the paramter is WTF16 encoded. +/// Windows-only. Same as `chdir` except the parameter is WTF16 encoded. pub fn chdirW(dir_path: []const u16) ChangeCurDirError!void { windows.SetCurrentDirectory(dir_path) catch |err| switch (err) { error.NoDevice => return error.FileSystem, @@ -6925,7 +6925,7 @@ pub const PrctlError = error{ /// Can only occur with PR_SET_SPECULATION_CTRL, PR_MPX_ENABLE_MANAGEMENT, /// or PR_MPX_DISABLE_MANAGEMENT UnsupportedFeature, - /// Can only occur wih PR_SET_FP_MODE + /// Can only occur with PR_SET_FP_MODE OperationNotSupported, PermissionDenied, } || UnexpectedError; diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig index 901bb8dbb3..4ffaeb54a4 100644 --- a/lib/std/os/linux.zig +++ b/lib/std/os/linux.zig @@ -472,7 +472,7 @@ pub fn preadv(fd: i32, iov: [*]const iovec, count: usize, offset: i64) usize { @bitCast(usize, @as(isize, fd)), @ptrToInt(iov), count, - // Kernel expects the offset is splitted into largest natural word-size. + // Kernel expects the offset is split into largest natural word-size. // See following link for detail: // https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=601cc11d054ae4b5e9b5babec3d8e4667a2cb9b5 @truncate(usize, offset_u), @@ -3912,7 +3912,7 @@ pub const io_uring_cqe = extern struct { /// If set, the upper 16 bits are the buffer ID pub const IORING_CQE_F_BUFFER = 1 << 0; /// If set, parent SQE will generate more CQE entries. -/// Avaiable since Linux 5.13. +/// Available since Linux 5.13. pub const IORING_CQE_F_MORE = 1 << 1; /// If set, more data to read after socket recv pub const IORING_CQE_F_SOCK_NONEMPTY = 1 << 2; @@ -4234,7 +4234,7 @@ pub const tcp_fastopen_client_fail = enum { pub const TCPI_OPT_TIMESTAMPS = 1; pub const TCPI_OPT_SACK = 2; pub const TCPI_OPT_WSCALE = 4; -/// ECN was negociated at TCP session init +/// ECN was negotiated at TCP session init pub const TCPI_OPT_ECN = 8; /// we received at least one packet with ECT pub const TCPI_OPT_ECN_SEEN = 16; diff --git a/lib/std/os/linux/bpf/btf.zig b/lib/std/os/linux/bpf/btf.zig index 7b85a618b3..39d25014da 100644 --- a/lib/std/os/linux/bpf/btf.zig +++ b/lib/std/os/linux/bpf/btf.zig @@ -109,7 +109,7 @@ pub const Enum64 = extern struct { val_hi32: i32, }; -/// array kind is followd by this struct +/// array kind is followed by this struct pub const Array = extern struct { typ: u32, index_type: u32, @@ -149,13 +149,13 @@ pub const FuncLinkage = enum { external, }; -/// var kind is followd by a single Var struct to describe additional +/// var kind is followed by a single Var struct to describe additional /// information related to the variable such as its linkage pub const Var = extern struct { linkage: u32, }; -/// datasec kind is followed by multible VarSecInfo to describe all Var kind +/// datasec kind is followed by multiple VarSecInfo to describe all Var kind /// types it contains along with it's in-section offset as well as size. pub const VarSecInfo = extern struct { typ: u32, diff --git a/lib/std/os/linux/seccomp.zig b/lib/std/os/linux/seccomp.zig index 23dbb6ee38..f10cb84aa0 100644 --- a/lib/std/os/linux/seccomp.zig +++ b/lib/std/os/linux/seccomp.zig @@ -65,7 +65,7 @@ //! //! Unfortunately, there is no easy solution for issue 5. The most reliable //! strategy is to keep testing; test newer Zig versions, different libcs, -//! different distros, and design your filter to accomidate all of them. +//! different distros, and design your filter to accommodate all of them. //! Alternatively, you could inject a filter at runtime. Since filters are //! preserved across execve(2), a filter could be setup before executing your //! program, without your program having any knowledge of this happening. This diff --git a/lib/std/os/windows.zig b/lib/std/os/windows.zig index 6d654f1c20..22ffc850e6 100644 --- a/lib/std/os/windows.zig +++ b/lib/std/os/windows.zig @@ -2114,7 +2114,7 @@ pub fn loadWinsockExtensionFunction(comptime T: type, sock: ws2_32.SOCKET, guid: /// and you get an unexpected error. pub fn unexpectedError(err: Win32Error) std.os.UnexpectedError { if (std.os.unexpected_error_tracing) { - // 614 is the length of the longest windows error desciption + // 614 is the length of the longest windows error description var buf_wstr: [614]WCHAR = undefined; var buf_utf8: [614]u8 = undefined; const len = kernel32.FormatMessageW( diff --git a/lib/std/packed_int_array.zig b/lib/std/packed_int_array.zig index 8004d223f7..10d8af0575 100644 --- a/lib/std/packed_int_array.zig +++ b/lib/std/packed_int_array.zig @@ -33,7 +33,7 @@ pub fn PackedIntIo(comptime Int: type, comptime endian: Endian) type { // In the worst case, this is the number of bytes we need to touch // to read or write a value, as bits. To calculate for int_bits > 1, // set aside 2 bits to touch the first and last bytes, then divide - // by 8 to see how many bytes can be filled up inbetween. + // by 8 to see how many bytes can be filled up in between. const max_io_bits = switch (int_bits) { 0 => 0, 1 => 8, @@ -298,7 +298,7 @@ pub fn PackedIntSliceEndian(comptime Int: type, comptime endian: Endian) type { } /// Initialize a packed slice using the memory at `bytes`, with `int_count` - /// elements. `bytes` must be large enough to accomodate the requested + /// elements. `bytes` must be large enough to accommodate the requested /// count. pub fn init(bytes: []u8, int_count: usize) Self { debug.assert(bytes.len >= bytesRequired(int_count)); diff --git a/lib/std/pdb.zig b/lib/std/pdb.zig index fdd162a34f..5bc836b08e 100644 --- a/lib/std/pdb.zig +++ b/lib/std/pdb.zig @@ -912,7 +912,7 @@ const Msf = struct { const stream_sizes = try allocator.alloc(u32, stream_count); defer allocator.free(stream_sizes); - // Microsoft's implementation uses @as(u32, -1) for inexistant streams. + // Microsoft's implementation uses @as(u32, -1) for inexistent streams. // These streams are not used, but still participate in the file // and must be taken into account when resolving stream indices. const Nil = 0xFFFFFFFF; diff --git a/lib/std/simd.zig b/lib/std/simd.zig index c2e0d9f972..905925fb78 100644 --- a/lib/std/simd.zig +++ b/lib/std/simd.zig @@ -159,7 +159,7 @@ pub fn interlace(vecs: anytype) @Vector(vectorLength(@TypeOf(vecs[0])) * vecs.le } /// The contents of `interlaced` is evenly split between vec_count vectors that are returned as an array. They "take turns", -/// recieving one element from `interlaced` at a time. +/// receiving one element from `interlaced` at a time. pub fn deinterlace( comptime vec_count: usize, interlaced: anytype, diff --git a/lib/std/target/csky.zig b/lib/std/target/csky.zig index 10386b31b8..0a2812c6d9 100644 --- a/lib/std/target/csky.zig +++ b/lib/std/target/csky.zig @@ -214,7 +214,7 @@ pub const all_features = blk: { }; result[@enumToInt(Feature.dsp_silan)] = .{ .llvm_name = "dsp_silan", - .description = "Enable DSP Silan instrutions", + .description = "Enable DSP Silan instructions", .dependencies = featureSet(&[_]Feature{}), }; result[@enumToInt(Feature.dspe60)] = .{ @@ -224,7 +224,7 @@ pub const all_features = blk: { }; result[@enumToInt(Feature.dspv2)] = .{ .llvm_name = "dspv2", - .description = "Enable DSP V2.0 instrutions", + .description = "Enable DSP V2.0 instructions", .dependencies = featureSet(&[_]Feature{}), }; result[@enumToInt(Feature.e1)] = .{ @@ -243,7 +243,7 @@ pub const all_features = blk: { }; result[@enumToInt(Feature.edsp)] = .{ .llvm_name = "edsp", - .description = "Enable DSP instrutions", + .description = "Enable DSP instructions", .dependencies = featureSet(&[_]Feature{}), }; result[@enumToInt(Feature.elrw)] = .{ @@ -333,12 +333,12 @@ pub const all_features = blk: { }; result[@enumToInt(Feature.hwdiv)] = .{ .llvm_name = "hwdiv", - .description = "Enable divide instrutions", + .description = "Enable divide instructions", .dependencies = featureSet(&[_]Feature{}), }; result[@enumToInt(Feature.istack)] = .{ .llvm_name = "istack", - .description = "Enable interrput attribute", + .description = "Enable interrupt attribute", .dependencies = featureSet(&[_]Feature{}), }; result[@enumToInt(Feature.java)] = .{ @@ -362,7 +362,7 @@ pub const all_features = blk: { }; result[@enumToInt(Feature.multiple_stld)] = .{ .llvm_name = "multiple_stld", - .description = "Enable multiple load/store instrutions", + .description = "Enable multiple load/store instructions", .dependencies = featureSet(&[_]Feature{}), }; result[@enumToInt(Feature.nvic)] = .{ @@ -372,7 +372,7 @@ pub const all_features = blk: { }; result[@enumToInt(Feature.pushpop)] = .{ .llvm_name = "pushpop", - .description = "Enable push/pop instrutions", + .description = "Enable push/pop instructions", .dependencies = featureSet(&[_]Feature{}), }; result[@enumToInt(Feature.smart)] = .{ diff --git a/lib/std/time.zig b/lib/std/time.zig index 5f86c25b8d..3eb342fa85 100644 --- a/lib/std/time.zig +++ b/lib/std/time.zig @@ -258,7 +258,7 @@ pub const Instant = struct { /// A monotonic, high performance timer. /// -/// Timer.start() is used to initalize the timer +/// Timer.start() is used to initialize the timer /// and gives the caller an opportunity to check for the existence of a supported clock. /// Once a supported clock is discovered, /// it is assumed that it will be available for the duration of the Timer's use. diff --git a/lib/std/valgrind/memcheck.zig b/lib/std/valgrind/memcheck.zig index 489abac2f6..25081510cd 100644 --- a/lib/std/valgrind/memcheck.zig +++ b/lib/std/valgrind/memcheck.zig @@ -77,7 +77,7 @@ pub fn discard(blkindex: usize) bool { } /// Check that memory at qzz.ptr is addressable for qzz.len bytes. -/// If suitable addressibility is not established, Valgrind prints an +/// If suitable addressability is not established, Valgrind prints an /// error message and returns the address of the first offending byte. /// Otherwise it returns zero. pub fn checkMemIsAddressable(qzz: []u8) usize { @@ -85,7 +85,7 @@ pub fn checkMemIsAddressable(qzz: []u8) usize { } /// Check that memory at qzz.ptr is addressable and defined for -/// qzz.len bytes. If suitable addressibility and definedness are not +/// qzz.len bytes. If suitable addressability and definedness are not /// established, Valgrind prints an error message and returns the /// address of the first offending byte. Otherwise it returns zero. pub fn checkMemIsDefined(qzz: []u8) usize { diff --git a/lib/std/zig/parser_test.zig b/lib/std/zig/parser_test.zig index 5ad8f8a07e..9176e14480 100644 --- a/lib/std/zig/parser_test.zig +++ b/lib/std/zig/parser_test.zig @@ -239,7 +239,7 @@ test "zig fmt: file ends in comment after var decl" { ); } -test "zig fmt: if statment" { +test "zig fmt: if statement" { try testCanonical( \\test "" { \\ if (optional()) |some| @@ -529,7 +529,7 @@ test "zig fmt: remove empty lines at start/end of block" { ); } -test "zig fmt: allow empty line before commment at start of block" { +test "zig fmt: allow empty line before comment at start of block" { try testCanonical( \\test { \\ @@ -4371,7 +4371,7 @@ test "zig fmt: same line doc comment returns error" { \\const Foo = struct{ \\ bar: u32, /// comment \\ foo: u32, /// comment - \\ /// commment + \\ /// comment \\}; \\ \\const a = 42; /// comment diff --git a/lib/std/zig/render.zig b/lib/std/zig/render.zig index d8a8c8e9ed..367d06f7c6 100644 --- a/lib/std/zig/render.zig +++ b/lib/std/zig/render.zig @@ -681,7 +681,7 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index, try renderToken(ais, tree, switch_token, .space); // switch keyword try renderToken(ais, tree, switch_token + 1, .none); // lparen - try renderExpression(gpa, ais, tree, condition, .none); // condtion expression + try renderExpression(gpa, ais, tree, condition, .none); // condition expression try renderToken(ais, tree, rparen, .space); // rparen ais.pushIndentNextLine(); From 6ae19fa48d7853430ba45f2de90550cd48cf5b4c Mon Sep 17 00:00:00 2001 From: David CARLIER Date: Sat, 29 Apr 2023 17:44:56 +0100 Subject: [PATCH 023/725] std.c: add essential freebsd's capsicum api subset. --- lib/std/c/freebsd.zig | 39 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/lib/std/c/freebsd.zig b/lib/std/c/freebsd.zig index e5cdc0e715..28e95d0414 100644 --- a/lib/std/c/freebsd.zig +++ b/lib/std/c/freebsd.zig @@ -476,10 +476,43 @@ pub const sockaddr = extern struct { pub const CAP_RIGHTS_VERSION = 0; -pub const cap_rights = extern struct { - rights: [CAP_RIGHTS_VERSION + 2]u64, +pub const cap_rights_t = extern struct { + cr_rights: [CAP_RIGHTS_VERSION + 2]u64, }; +pub const CAP = struct { + pub fn RIGHT(idx: u6, bit: u64) u64 { + return (@intCast(u64, 1) << (57 + idx)) | bit; + } + pub const READ = CAP.RIGHT(0, 0x0000000000000001); + pub const WRITE = CAP.RIGHT(0, 0x0000000000000002); + pub const SEEK_TELL = CAP.RIGHT(0, 0x0000000000000004); + pub const SEEK = CAP.SEEK_TELL | 0x0000000000000008; + pub const PREAD = CAP.SEEK | CAP.READ; + pub const PWRITE = CAP.SEEK | CAP.WRITE; + pub const MMAP = CAP.RIGHT(0, 0x0000000000000010); + pub const MMAP_R = CAP.MMAP | CAP.SEEK | CAP.READ; + pub const MMAP_W = CAP.MMAP | CAP.SEEK | CAP.WRITE; + pub const MMAP_X = CAP.MMAP | CAP.SEEK | 0x0000000000000020; + pub const MMAP_RW = CAP.MMAP_R | CAP.MMAP_W; + pub const MMAP_RX = CAP.MMAP_R | CAP.MMAP_X; + pub const MMAP_WX = CAP.MMAP_W | CAP.MMAP_X; + pub const MMAP_RWX = CAP.MMAP_R | CAP.MMAP_W | CAP.MMAP_X; + pub const CREATE = CAP.RIGHT(0, 0x0000000000000040); + pub const FEXECVE = CAP.RIGHT(0, 0x0000000000000080); + pub const FSYNC = CAP.RIGHT(0, 0x0000000000000100); + pub const FTRUNCATE = CAP.RIGHT(0, 0x0000000000000200); +}; + +pub extern "c" fn __cap_rights_init(version: c_int, rights: ?*cap_rights_t, ...) ?*cap_rights_t; +pub extern "c" fn __cap_rights_set(rights: ?*cap_rights_t, ...) ?*cap_rights_t; +pub extern "c" fn __cap_rights_clear(rights: ?*cap_rights_t, ...) ?*cap_rights_t; +pub extern "c" fn __cap_rights_merge(dst: ?*cap_rights_t, src: ?*const cap_rights_t) ?*cap_rights_t; +pub extern "c" fn __cap_rights_remove(dst: ?*cap_rights_t, src: ?*const cap_rights_t) ?*cap_rights_t; +pub extern "c" fn __cap_rights_contains(dst: ?*const cap_rights_t, src: ?*const cap_rights_t) bool; +pub extern "c" fn __cap_rights_is_set(rights: ?*const cap_rights_t, ...) bool; +pub extern "c" fn __cap_rights_is_valid(rights: ?*const cap_rights_t) bool; + pub const kinfo_file = extern struct { /// Size of this record. /// A zero value is for the sentinel record at the end of an array. @@ -581,7 +614,7 @@ pub const kinfo_file = extern struct { // Reserved for future use. _spare: c_int, /// Capability rights. - cap_rights: cap_rights, + cap_rights: cap_rights_t, /// Reserved for future cap_rights _cap_spare: u64, /// Path to file, if any. From e963793e37f93d84f1e5295d309ebe0c738b663d Mon Sep 17 00:00:00 2001 From: Mason Remaley Date: Mon, 1 May 2023 01:03:46 -0400 Subject: [PATCH 024/725] Updates std.meta.intToEnum to support non-exhaustive enums (#15491) This was preventing `std.json` from deserializing non-exhaustive enums. --- lib/std/meta.zig | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/lib/std/meta.zig b/lib/std/meta.zig index 97c2ff4fb0..7be3b71347 100644 --- a/lib/std/meta.zig +++ b/lib/std/meta.zig @@ -965,18 +965,33 @@ test "intToEnum with error return" { A, B, }; + const E3 = enum(i8) { A, _ }; var zero: u8 = 0; var one: u16 = 1; try testing.expect(intToEnum(E1, zero) catch unreachable == E1.A); try testing.expect(intToEnum(E2, one) catch unreachable == E2.B); + try testing.expect(intToEnum(E3, zero) catch unreachable == E3.A); + try testing.expect(intToEnum(E3, 127) catch unreachable == @intToEnum(E3, 127)); + try testing.expect(intToEnum(E3, -128) catch unreachable == @intToEnum(E3, -128)); try testing.expectError(error.InvalidEnumTag, intToEnum(E1, one)); + try testing.expectError(error.InvalidEnumTag, intToEnum(E3, 128)); + try testing.expectError(error.InvalidEnumTag, intToEnum(E3, -129)); } pub const IntToEnumError = error{InvalidEnumTag}; pub fn intToEnum(comptime EnumTag: type, tag_int: anytype) IntToEnumError!EnumTag { - inline for (@typeInfo(EnumTag).Enum.fields) |f| { + const enum_info = @typeInfo(EnumTag).Enum; + + if (!enum_info.is_exhaustive) { + if (std.math.cast(enum_info.tag_type, tag_int)) |tag| { + return @intToEnum(EnumTag, tag); + } + return error.InvalidEnumTag; + } + + inline for (enum_info.fields) |f| { const this_tag_value = @field(EnumTag, f.name); if (tag_int == @enumToInt(this_tag_value)) { return this_tag_value; From 0f0f005e927be5e9d813e40c8c6c6580fd4f5697 Mon Sep 17 00:00:00 2001 From: Martin Wickham Date: Sat, 4 Jun 2022 17:34:21 -0500 Subject: [PATCH 025/725] std.windows: use posix semantics to delete files, if available Justification: When a file is deleted on Windows, it may not be immediately removed from the directory. This can cause problems with future scans of that directory, which will see the partially deleted file. Under some workloads and system configurations, Windows files may appear to be deleted immediately. This is the PR with requested fixup. Thanks to @SpexGuy for the original PR. --- lib/std/os/windows.zig | 75 +++++++++++++++++++++++++++++++----------- 1 file changed, 56 insertions(+), 19 deletions(-) diff --git a/lib/std/os/windows.zig b/lib/std/os/windows.zig index 22ffc850e6..37ec7f09a3 100644 --- a/lib/std/os/windows.zig +++ b/lib/std/os/windows.zig @@ -937,25 +937,50 @@ pub fn DeleteFile(sub_path_w: []const u16, options: DeleteFileOptions) DeleteFil .DELETE_PENDING => return, else => return unexpectedStatus(rc), } - var file_dispo = FILE_DISPOSITION_INFORMATION{ - .DeleteFile = TRUE, - }; - rc = ntdll.NtSetInformationFile( - tmp_handle, - &io, - &file_dispo, - @sizeOf(FILE_DISPOSITION_INFORMATION), - .FileDispositionInformation, - ); - CloseHandle(tmp_handle); - switch (rc) { - .SUCCESS => return, - .DIRECTORY_NOT_EMPTY => return error.DirNotEmpty, - .INVALID_PARAMETER => unreachable, - .CANNOT_DELETE => return error.AccessDenied, - .MEDIA_WRITE_PROTECTED => return error.AccessDenied, - .ACCESS_DENIED => return error.AccessDenied, - else => return unexpectedStatus(rc), + defer CloseHandle(tmp_handle); + if (comptime builtin.target.os.version_range.windows.min.isAtLeast(.win10_rs1)) { + // Deletion with posix semantics. + var info = FILE_DISPOSITION_INFORMATION_EX{ + .Flags = FILE_DISPOSITION_DELETE | + FILE_DISPOSITION_POSIX_SEMANTICS | + FILE_DISPOSITION_ON_CLOSE | + FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE, + }; + + rc = ntdll.NtSetInformationFile( + tmp_handle, + &io, + &info, + @sizeOf(FILE_DISPOSITION_INFORMATION_EX), + .FileDispositionInformationEx, + ); + switch (rc) { + .SUCCESS => {}, + .CANNOT_DELETE => return error.FileBusy, // file is currently mapped + else => return unexpectedStatus(rc), + } + } else { + // Deletion with file pending semantics, which requires waiting or moving + // files to get them removed (from here). + var file_dispo = FILE_DISPOSITION_INFORMATION{ + .DeleteFile = TRUE, + }; + rc = ntdll.NtSetInformationFile( + tmp_handle, + &io, + &file_dispo, + @sizeOf(FILE_DISPOSITION_INFORMATION), + .FileDispositionInformation, + ); + switch (rc) { + .SUCCESS => {}, + .DIRECTORY_NOT_EMPTY => return error.DirNotEmpty, + .INVALID_PARAMETER => unreachable, + .CANNOT_DELETE => return error.AccessDenied, + .MEDIA_WRITE_PROTECTED => return error.AccessDenied, + .ACCESS_DENIED => return error.AccessDenied, + else => return unexpectedStatus(rc), + } } } @@ -2397,6 +2422,18 @@ pub const FILE_NAME_INFORMATION = extern struct { FileName: [1]WCHAR, }; +pub const FILE_DISPOSITION_INFORMATION_EX = extern struct { + /// combination of FILE_DISPOSITION_* flags + Flags: ULONG, +}; + +const FILE_DISPOSITION_DO_NOT_DELETE: ULONG = 0x00000000; +const FILE_DISPOSITION_DELETE: ULONG = 0x00000001; +const FILE_DISPOSITION_POSIX_SEMANTICS: ULONG = 0x00000002; +const FILE_DISPOSITION_FORCE_IMAGE_SECTION_CHECK: ULONG = 0x00000004; +const FILE_DISPOSITION_ON_CLOSE: ULONG = 0x00000008; +const FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE: ULONG = 0x00000010; + pub const FILE_RENAME_INFORMATION = extern struct { ReplaceIfExists: BOOLEAN, RootDirectory: ?HANDLE, From be50dbf1ce03f5dc5deef86882ab3505363b683a Mon Sep 17 00:00:00 2001 From: Jan Philipp Hafer Date: Mon, 1 May 2023 12:45:41 +0200 Subject: [PATCH 026/725] apply suggestion by user @xEgoist FILE_DISPOSITION_ON_CLOSE is used to set/clear the FILE_DELETE_ON_CLOSE, but we do not use that anymore and FILE_DISPOSITION_POSIX_SEMANTICS already implies unmapping of the handle and removal fo it on close. --- lib/std/os/windows.zig | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/std/os/windows.zig b/lib/std/os/windows.zig index 37ec7f09a3..e6ce95713c 100644 --- a/lib/std/os/windows.zig +++ b/lib/std/os/windows.zig @@ -943,7 +943,6 @@ pub fn DeleteFile(sub_path_w: []const u16, options: DeleteFileOptions) DeleteFil var info = FILE_DISPOSITION_INFORMATION_EX{ .Flags = FILE_DISPOSITION_DELETE | FILE_DISPOSITION_POSIX_SEMANTICS | - FILE_DISPOSITION_ON_CLOSE | FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE, }; From 7594d2c0977497c81db0c394f775832689bad492 Mon Sep 17 00:00:00 2001 From: Jan Philipp Hafer Date: Mon, 1 May 2023 18:22:28 +0200 Subject: [PATCH 027/725] address review by user @squeek502 --- lib/std/fs/test.zig | 35 +++++++++++++++++++++++++++-------- lib/std/os/windows.zig | 25 +++++++++++-------------- 2 files changed, 38 insertions(+), 22 deletions(-) diff --git a/lib/std/fs/test.zig b/lib/std/fs/test.zig index 15c8307f58..660ec0c381 100644 --- a/lib/std/fs/test.zig +++ b/lib/std/fs/test.zig @@ -1416,23 +1416,42 @@ test "File.PermissionsUnix" { try testing.expect(!permissions_unix.unixHas(.other, .execute)); } -test "delete a read-only file on windows" { - if (builtin.os.tag != .windows) return error.SkipZigTest; +test "delete a read-only file on windows with file pending semantics" { + if (builtin.os.tag != .windows or builtin.target.os.version_range.windows.min.isAtLeast(.win10_rs1)) + return error.SkipZigTest; + + var tmp = tmpDir(.{}); + defer tmp.cleanup(); + { + const file = try tmp.dir.createFile("test_file", .{ .read = true }); + defer file.close(); + // Create a file and make it read-only + const metadata = try file.metadata(); + var permissions = metadata.permissions(); + permissions.setReadOnly(true); + try file.setPermissions(permissions); + try testing.expectError(error.AccessDenied, tmp.dir.deleteFile("test_file")); + // Now make the file not read-only + permissions.setReadOnly(false); + try file.setPermissions(permissions); + } + try tmp.dir.deleteFile("test_file"); +} + +test "delete a read-only file on windows with posix semantis" { + if (builtin.os.tag != .windows or !builtin.target.os.version_range.windows.min.isAtLeast(.win10_rs1)) + return error.SkipZigTest; var tmp = tmpDir(.{}); defer tmp.cleanup(); const file = try tmp.dir.createFile("test_file", .{ .read = true }); + defer file.close(); // Create a file and make it read-only const metadata = try file.metadata(); var permissions = metadata.permissions(); permissions.setReadOnly(true); try file.setPermissions(permissions); - try testing.expectError(error.AccessDenied, tmp.dir.deleteFile("test_file")); - // Now make the file not read-only - permissions.setReadOnly(false); - try file.setPermissions(permissions); - file.close(); - try tmp.dir.deleteFile("test_file"); + try tmp.dir.deleteFile("test_file"); // file is unmapped and deleted once last handle closed } test "delete a setAsCwd directory on Windows" { diff --git a/lib/std/os/windows.zig b/lib/std/os/windows.zig index e6ce95713c..ef2643792e 100644 --- a/lib/std/os/windows.zig +++ b/lib/std/os/windows.zig @@ -938,6 +938,7 @@ pub fn DeleteFile(sub_path_w: []const u16, options: DeleteFileOptions) DeleteFil else => return unexpectedStatus(rc), } defer CloseHandle(tmp_handle); + if (comptime builtin.target.os.version_range.windows.min.isAtLeast(.win10_rs1)) { // Deletion with posix semantics. var info = FILE_DISPOSITION_INFORMATION_EX{ @@ -953,17 +954,13 @@ pub fn DeleteFile(sub_path_w: []const u16, options: DeleteFileOptions) DeleteFil @sizeOf(FILE_DISPOSITION_INFORMATION_EX), .FileDispositionInformationEx, ); - switch (rc) { - .SUCCESS => {}, - .CANNOT_DELETE => return error.FileBusy, // file is currently mapped - else => return unexpectedStatus(rc), - } } else { // Deletion with file pending semantics, which requires waiting or moving // files to get them removed (from here). var file_dispo = FILE_DISPOSITION_INFORMATION{ .DeleteFile = TRUE, }; + rc = ntdll.NtSetInformationFile( tmp_handle, &io, @@ -971,15 +968,15 @@ pub fn DeleteFile(sub_path_w: []const u16, options: DeleteFileOptions) DeleteFil @sizeOf(FILE_DISPOSITION_INFORMATION), .FileDispositionInformation, ); - switch (rc) { - .SUCCESS => {}, - .DIRECTORY_NOT_EMPTY => return error.DirNotEmpty, - .INVALID_PARAMETER => unreachable, - .CANNOT_DELETE => return error.AccessDenied, - .MEDIA_WRITE_PROTECTED => return error.AccessDenied, - .ACCESS_DENIED => return error.AccessDenied, - else => return unexpectedStatus(rc), - } + } + switch (rc) { + .SUCCESS => {}, + .DIRECTORY_NOT_EMPTY => return error.DirNotEmpty, + .INVALID_PARAMETER => unreachable, + .CANNOT_DELETE => return error.AccessDenied, + .MEDIA_WRITE_PROTECTED => return error.AccessDenied, + .ACCESS_DENIED => return error.AccessDenied, + else => return unexpectedStatus(rc), } } From 28923474401051a9aa0bddd60904b9be64943dba Mon Sep 17 00:00:00 2001 From: jcalabro Date: Mon, 1 May 2023 12:57:05 -0400 Subject: [PATCH 028/725] Fix PBKDF2 docstring comment --- lib/std/crypto/pbkdf2.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/std/crypto/pbkdf2.zig b/lib/std/crypto/pbkdf2.zig index 7c6df5444d..115fd38b3d 100644 --- a/lib/std/crypto/pbkdf2.zig +++ b/lib/std/crypto/pbkdf2.zig @@ -49,7 +49,7 @@ const WeakParametersError = std.crypto.errors.WeakParametersError; /// Larger iteration counts improve security by increasing the time required to compute /// the dk. It is common to tune this parameter to achieve approximately 100ms. /// -/// Prf: Pseudo-random function to use. A common choice is `std.crypto.auth.hmac.HmacSha256`. +/// Prf: Pseudo-random function to use. A common choice is `std.crypto.auth.hmac.sha2.HmacSha256`. pub fn pbkdf2(dk: []u8, password: []const u8, salt: []const u8, rounds: u32, comptime Prf: type) (WeakParametersError || OutputTooLongError)!void { if (rounds < 1) return error.WeakParameters; From 7c9891d7b7d09060630693231702f27669dd0dc9 Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Wed, 26 Apr 2023 22:51:35 -0400 Subject: [PATCH 029/725] x86_64: use std.log for debug logging --- src/arch/x86_64/CodeGen.zig | 137 +++++++++++++++++++++++++----------- src/print_air.zig | 12 +++- 2 files changed, 104 insertions(+), 45 deletions(-) diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index be972d7aea..b862252561 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -7,6 +7,8 @@ const leb128 = std.leb; const link = @import("../../link.zig"); const log = std.log.scoped(.codegen); const tracking_log = std.log.scoped(.tracking); +const verbose_tracking_log = std.log.scoped(.verbose_tracking); +const wip_mir_log = std.log.scoped(.wip_mir); const math = std.math; const mem = std.mem; const trace = @import("../../tracy.zig").trace; @@ -48,9 +50,6 @@ const sse = abi.RegisterClass.sse; const InnerError = CodeGenError || error{OutOfRegisters}; -const debug_wip_mir = false; -const debug_tracking = false; - gpa: Allocator, air: Air, liveness: Liveness, @@ -575,12 +574,6 @@ pub fn generate( assert(fn_owner_decl.has_tv); const fn_type = fn_owner_decl.ty; - if (debug_wip_mir) { - const stderr = std.io.getStdErr().writer(); - fn_owner_decl.renderFullyQualifiedName(mod, stderr) catch {}; - stderr.writeAll(":\n") catch {}; - } - const gpa = bin_file.allocator; var function = Self{ .gpa = gpa, @@ -614,6 +607,8 @@ pub fn generate( if (builtin.mode == .Debug) function.mir_to_air_map.deinit(gpa); } + wip_mir_log.debug("{}:", .{function.fmtDecl(module_fn.owner_decl)}); + try function.frame_allocs.resize(gpa, FrameIndex.named_count); function.frame_allocs.set( @enumToInt(FrameIndex.stack_frame), @@ -715,48 +710,104 @@ pub fn generate( } } -fn dumpWipMir(self: *Self, inst: Mir.Inst) !void { - if (!debug_wip_mir) return; - const stderr = std.io.getStdErr().writer(); +const FormatDeclData = struct { + mod: *Module, + decl_index: Module.Decl.Index, +}; +fn formatDecl( + data: FormatDeclData, + comptime _: []const u8, + _: std.fmt.FormatOptions, + writer: anytype, +) @TypeOf(writer).Error!void { + try data.mod.declPtr(data.decl_index).renderFullyQualifiedName(data.mod, writer); +} +fn fmtDecl(self: *Self, decl_index: Module.Decl.Index) std.fmt.Formatter(formatDecl) { + return .{ .data = .{ + .mod = self.bin_file.options.module.?, + .decl_index = decl_index, + } }; +} +const FormatAirData = struct { + self: *Self, + inst: Air.Inst.Index, +}; +fn formatAir( + data: FormatAirData, + comptime _: []const u8, + _: std.fmt.FormatOptions, + writer: anytype, +) @TypeOf(writer).Error!void { + @import("../../print_air.zig").dumpInst( + data.inst, + data.self.bin_file.options.module.?, + data.self.air, + data.self.liveness, + ); +} +fn fmtAir(self: *Self, inst: Air.Inst.Index) std.fmt.Formatter(formatAir) { + return .{ .data = .{ .self = self, .inst = inst } }; +} + +const FormatWipMirData = struct { + self: *Self, + inst: Mir.Inst.Index, +}; +fn formatWipMir( + data: FormatWipMirData, + comptime _: []const u8, + _: std.fmt.FormatOptions, + writer: anytype, +) @TypeOf(writer).Error!void { var lower = Lower{ - .allocator = self.gpa, + .allocator = data.self.gpa, .mir = .{ - .instructions = self.mir_instructions.slice(), - .extra = self.mir_extra.items, + .instructions = data.self.mir_instructions.slice(), + .extra = data.self.mir_extra.items, .frame_locs = (std.MultiArrayList(Mir.FrameLoc){}).slice(), }, - .target = self.target, - .src_loc = self.src_loc, + .target = data.self.target, + .src_loc = data.self.src_loc, }; - for (lower.lowerMir(inst) catch |err| switch (err) { + for (lower.lowerMir(data.self.mir_instructions.get(data.inst)) catch |err| switch (err) { error.LowerFail => { defer { - lower.err_msg.?.deinit(self.gpa); + lower.err_msg.?.deinit(data.self.gpa); lower.err_msg = null; } - try stderr.print("{s}\n", .{lower.err_msg.?.msg}); + try writer.writeAll(lower.err_msg.?.msg); return; }, - error.InvalidInstruction, error.CannotEncode => |e| { - try stderr.writeAll(switch (e) { - error.InvalidInstruction => "CodeGen failed to find a viable instruction.\n", - error.CannotEncode => "CodeGen failed to encode the instruction.\n", + error.OutOfMemory, error.InvalidInstruction, error.CannotEncode => |e| { + try writer.writeAll(switch (e) { + error.OutOfMemory => "Out of memory", + error.InvalidInstruction => "CodeGen failed to find a viable instruction.", + error.CannotEncode => "CodeGen failed to encode the instruction.", }); return; }, else => |e| return e, - }) |lower_inst| { - try stderr.print(" | {}\n", .{lower_inst}); - } + }) |lower_inst| try writer.print(" | {}", .{lower_inst}); +} +fn fmtWipMir(self: *Self, inst: Mir.Inst.Index) std.fmt.Formatter(formatWipMir) { + return .{ .data = .{ .self = self, .inst = inst } }; } -fn dumpTracking(self: *Self) !void { - if (!debug_tracking) return; - const stderr = std.io.getStdErr().writer(); - - var it = self.inst_tracking.iterator(); - while (it.next()) |entry| try stderr.print("%{d} = {}\n", .{ entry.key_ptr.*, entry.value_ptr.* }); +const FormatTrackingData = struct { + self: *Self, +}; +fn formatTracking( + data: FormatTrackingData, + comptime _: []const u8, + _: std.fmt.FormatOptions, + writer: anytype, +) @TypeOf(writer).Error!void { + var it = data.self.inst_tracking.iterator(); + while (it.next()) |entry| try writer.print("\n%{d} = {}", .{ entry.key_ptr.*, entry.value_ptr.* }); +} +fn fmtTracking(self: *Self) std.fmt.Formatter(formatTracking) { + return .{ .data = .{ .self = self } }; } fn addInst(self: *Self, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index { @@ -764,7 +815,14 @@ fn addInst(self: *Self, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index { try self.mir_instructions.ensureUnusedCapacity(gpa, 1); const result_index = @intCast(Mir.Inst.Index, self.mir_instructions.len); self.mir_instructions.appendAssumeCapacity(inst); - self.dumpWipMir(inst) catch {}; + switch (inst.tag) { + else => wip_mir_log.debug("{}", .{self.fmtWipMir(result_index)}), + .dbg_line, + .dbg_prologue_end, + .dbg_epilogue_begin, + .dead, + => {}, + } return result_index; } @@ -1186,13 +1244,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { } if (self.liveness.isUnused(inst) and !self.air.mustLower(inst)) continue; - if (debug_wip_mir) @import("../../print_air.zig").dumpInst( - inst, - self.bin_file.options.module.?, - self.air, - self.liveness, - ); - self.dumpTracking() catch {}; + wip_mir_log.debug("{}", .{self.fmtAir(inst)}); + verbose_tracking_log.debug("{}", .{self.fmtTracking()}); const old_air_bookkeeping = self.air_bookkeeping; try self.inst_tracking.ensureUnusedCapacity(self.gpa, 1); @@ -1453,7 +1506,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { } } } - self.dumpTracking() catch {}; + verbose_tracking_log.debug("{}", .{self.fmtTracking()}); } fn getValue(self: *Self, value: MCValue, inst: ?Air.Inst.Index) void { diff --git a/src/print_air.zig b/src/print_air.zig index 2d7995842f..d90d31ec67 100644 --- a/src/print_air.zig +++ b/src/print_air.zig @@ -94,14 +94,20 @@ const Writer = struct { for (w.air.instructions.items(.tag), 0..) |tag, i| { const inst = @intCast(Air.Inst.Index, i); switch (tag) { - .constant, .const_ty => try w.writeInst(s, inst), + .constant, .const_ty => { + try w.writeInst(s, inst); + try s.writeByte('\n'); + }, else => continue, } } } fn writeBody(w: *Writer, s: anytype, body: []const Air.Inst.Index) @TypeOf(s).Error!void { - for (body) |inst| try w.writeInst(s, inst); + for (body) |inst| { + try w.writeInst(s, inst); + try s.writeByte('\n'); + } } fn writeInst(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { @@ -336,7 +342,7 @@ const Writer = struct { .work_group_id, => try w.writeWorkDimension(s, inst), } - try s.writeAll(")\n"); + try s.writeByte(')'); } fn writeBinOp(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { From 4ec49da5f6a6a8e77cdb66b8f814718bf11fffef Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Fri, 28 Apr 2023 20:39:38 -0400 Subject: [PATCH 030/725] x86_64: implement a bunch of floating point stuff --- src/arch/x86_64/CodeGen.zig | 438 +++++++++++++++++++++++++++------- src/arch/x86_64/Encoding.zig | 27 ++- src/arch/x86_64/Lower.zig | 6 + src/arch/x86_64/Mir.zig | 12 + src/arch/x86_64/encoder.zig | 2 +- src/arch/x86_64/encodings.zig | 14 ++ src/codegen.zig | 103 ++++++-- 7 files changed, 486 insertions(+), 116 deletions(-) diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index b862252561..d9c7298c95 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -1297,9 +1297,10 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .ceil, .round, .trunc_float, - .neg, => try self.airUnaryMath(inst), + .neg => try self.airNeg(inst), + .add_with_overflow => try self.airAddSubWithOverflow(inst), .sub_with_overflow => try self.airAddSubWithOverflow(inst), .mul_with_overflow => try self.airMulWithOverflow(inst), @@ -1881,7 +1882,7 @@ pub fn spillRegisters(self: *Self, registers: []const Register) !void { /// allocated. A second call to `copyToTmpRegister` may return the same register. /// This can have a side effect of spilling instructions to the stack to free up a register. fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register { - const reg: Register = try self.register_manager.allocReg(null, try self.regClassForType(ty)); + const reg = try self.register_manager.allocReg(null, try self.regClassForType(ty)); try self.genSetReg(reg, ty, mcv); return reg; } @@ -1924,16 +1925,48 @@ fn airRetPtr(self: *Self, inst: Air.Inst.Index) !void { fn airFptrunc(self: *Self, inst: Air.Inst.Index) !void { const ty_op = self.air.instructions.items(.data)[inst].ty_op; - _ = ty_op; - return self.fail("TODO implement airFptrunc for {}", .{self.target.cpu.arch}); - // return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); + const dst_ty = self.air.typeOfIndex(inst); + const src_ty = self.air.typeOf(ty_op.operand); + if (dst_ty.floatBits(self.target.*) != 32 or src_ty.floatBits(self.target.*) != 64 or + !Target.x86.featureSetHas(self.target.cpu.features, .sse2)) + return self.fail("TODO implement airFptrunc from {} to {}", .{ + src_ty.fmt(self.bin_file.options.module.?), + dst_ty.fmt(self.bin_file.options.module.?), + }); + + const src_mcv = try self.resolveInst(ty_op.operand); + const dst_mcv = if (src_mcv.isRegister() and self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) + src_mcv + else + try self.copyToRegisterWithInstTracking(inst, dst_ty, src_mcv); + const dst_lock = self.register_manager.lockReg(dst_mcv.register); + defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); + + try self.genBinOpMir(.cvtsd2ss, src_ty, dst_mcv, src_mcv); + return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none }); } fn airFpext(self: *Self, inst: Air.Inst.Index) !void { const ty_op = self.air.instructions.items(.data)[inst].ty_op; - _ = ty_op; - return self.fail("TODO implement airFpext for {}", .{self.target.cpu.arch}); - // return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); + const dst_ty = self.air.typeOfIndex(inst); + const src_ty = self.air.typeOf(ty_op.operand); + if (dst_ty.floatBits(self.target.*) != 64 or src_ty.floatBits(self.target.*) != 32 or + !Target.x86.featureSetHas(self.target.cpu.features, .sse2)) + return self.fail("TODO implement airFpext from {} to {}", .{ + src_ty.fmt(self.bin_file.options.module.?), + dst_ty.fmt(self.bin_file.options.module.?), + }); + + const src_mcv = try self.resolveInst(ty_op.operand); + const dst_mcv = if (src_mcv.isRegister() and self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) + src_mcv + else + try self.copyToRegisterWithInstTracking(inst, dst_ty, src_mcv); + const dst_lock = self.register_manager.lockReg(dst_mcv.register); + defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); + + try self.genBinOpMir(.cvtss2sd, src_ty, dst_mcv, src_mcv); + return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none }); } fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { @@ -3953,10 +3986,65 @@ fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void { return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none }); } +fn airNeg(self: *Self, inst: Air.Inst.Index) !void { + const un_op = self.air.instructions.items(.data)[inst].un_op; + const ty = self.air.typeOf(un_op); + const ty_bits = ty.floatBits(self.target.*); + + var arena = std.heap.ArenaAllocator.init(self.gpa); + defer arena.deinit(); + + const ExpectedContents = union { + f16: Value.Payload.Float_16, + f32: Value.Payload.Float_32, + f64: Value.Payload.Float_64, + f80: Value.Payload.Float_80, + f128: Value.Payload.Float_128, + }; + var stack align(@alignOf(ExpectedContents)) = + std.heap.stackFallback(@sizeOf(ExpectedContents), arena.allocator()); + + var vec_pl = Type.Payload.Array{ + .base = .{ .tag = .vector }, + .data = .{ + .len = @divExact(128, ty_bits), + .elem_type = ty, + }, + }; + const vec_ty = Type.initPayload(&vec_pl.base); + + var sign_pl = Value.Payload.SubValue{ + .base = .{ .tag = .repeated }, + .data = try Value.floatToValue(-0.0, stack.get(), ty, self.target.*), + }; + const sign_val = Value.initPayload(&sign_pl.base); + + const sign_mcv = try self.genTypedValue(.{ .ty = vec_ty, .val = sign_val }); + + const src_mcv = try self.resolveInst(un_op); + const dst_mcv = if (src_mcv.isRegister() and self.reuseOperand(inst, un_op, 0, src_mcv)) + src_mcv + else + try self.copyToRegisterWithInstTracking(inst, ty, src_mcv); + const dst_lock = self.register_manager.lockReg(dst_mcv.register); + defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); + + try self.genBinOpMir(switch (ty_bits) { + 32 => .xorps, + 64 => .xorpd, + else => return self.fail("TODO implement airNeg for {}", .{ + ty.fmt(self.bin_file.options.module.?), + }), + }, vec_ty, dst_mcv, sign_mcv); + return self.finishAir(inst, dst_mcv, .{ un_op, .none, .none }); +} + fn airUnaryMath(self: *Self, inst: Air.Inst.Index) !void { const un_op = self.air.instructions.items(.data)[inst].un_op; _ = un_op; - return self.fail("TODO implement airUnaryMath for {}", .{self.target.cpu.arch}); + return self.fail("TODO implement airUnaryMath for {}", .{ + self.air.instructions.items(.tag)[inst], + }); //return self.finishAir(inst, result, .{ un_op, .none, .none }); } @@ -4109,7 +4197,6 @@ fn load(self: *Self, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerErro fn airLoad(self: *Self, inst: Air.Inst.Index) !void { const ty_op = self.air.instructions.items(.data)[inst].ty_op; const elem_ty = self.air.typeOfIndex(inst); - const elem_size = elem_ty.abiSize(self.target.*); const result: MCValue = result: { if (!elem_ty.hasRuntimeBitsIgnoreComptime()) break :result .none; @@ -4117,14 +4204,20 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void { const reg_locks = self.register_manager.lockRegsAssumeUnused(3, .{ .rdi, .rsi, .rcx }); defer for (reg_locks) |lock| self.register_manager.unlockReg(lock); + const ptr_ty = self.air.typeOf(ty_op.operand); + const elem_size = elem_ty.abiSize(self.target.*); + + const elem_rc = try self.regClassForType(elem_ty); + const ptr_rc = try self.regClassForType(ptr_ty); + const ptr_mcv = try self.resolveInst(ty_op.operand); - const dst_mcv = if (elem_size <= 8 and self.reuseOperand(inst, ty_op.operand, 0, ptr_mcv)) + const dst_mcv = if (elem_size <= 8 and elem_rc.supersetOf(ptr_rc) and + self.reuseOperand(inst, ty_op.operand, 0, ptr_mcv)) // The MCValue that holds the pointer can be re-used as the value. ptr_mcv else try self.allocRegOrMem(inst, true); - const ptr_ty = self.air.typeOf(ty_op.operand); if (ptr_ty.ptrInfo().data.host_size > 0) { try self.packedLoad(dst_mcv, ptr_ty, ptr_mcv); } else { @@ -4346,17 +4439,9 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { switch (src_mcv) { .load_frame => |frame_addr| { - const field_abi_size = @intCast(u32, field_ty.abiSize(self.target.*)); - const limb_abi_size = @min(field_abi_size, 8); - const limb_abi_bits = limb_abi_size * 8; - const field_byte_off = @intCast(i32, field_off / limb_abi_bits * limb_abi_size); - const field_bit_off = field_off % limb_abi_bits; - - if (field_bit_off == 0) { - const off_mcv = MCValue{ .load_frame = .{ - .index = frame_addr.index, - .off = frame_addr.off + field_byte_off, - } }; + if (field_off % 8 == 0) { + const off_mcv = + src_mcv.address().offset(@intCast(i32, @divExact(field_off, 8))).deref(); if (self.reuseOperand(inst, operand, 0, src_mcv)) break :result off_mcv; const dst_mcv = try self.allocRegOrMem(inst, true); @@ -4364,6 +4449,12 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { break :result dst_mcv; } + const field_abi_size = @intCast(u32, field_ty.abiSize(self.target.*)); + const limb_abi_size = @min(field_abi_size, 8); + const limb_abi_bits = limb_abi_size * 8; + const field_byte_off = @intCast(i32, field_off / limb_abi_bits * limb_abi_size); + const field_bit_off = field_off % limb_abi_bits; + if (field_abi_size > 8) { return self.fail("TODO implement struct_field_val with large packed field", .{}); } @@ -5181,24 +5272,69 @@ fn genBinOp( switch (tag) { .add, .addwrap, - => try self.genBinOpMir(switch (lhs_ty.tag()) { + => try self.genBinOpMir(switch (lhs_ty.zigTypeTag()) { else => .add, - .f32 => .addss, - .f64 => .addsd, + .Float => switch (lhs_ty.floatBits(self.target.*)) { + 32 => if (Target.x86.featureSetHas(self.target.cpu.features, .sse)) + .addss + else + return self.fail("TODO implement genBinOp for {s} {} without sse", .{ + @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?), + }), + 64 => if (Target.x86.featureSetHas(self.target.cpu.features, .sse2)) + .addsd + else + return self.fail("TODO implement genBinOp for {s} {} without sse2", .{ + @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?), + }), + else => return self.fail("TODO implement genBinOp for {s} {}", .{ + @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?), + }), + }, }, lhs_ty, dst_mcv, src_mcv), .sub, .subwrap, - => try self.genBinOpMir(switch (lhs_ty.tag()) { + => try self.genBinOpMir(switch (lhs_ty.zigTypeTag()) { else => .sub, - .f32 => .subss, - .f64 => .subsd, + .Float => switch (lhs_ty.floatBits(self.target.*)) { + 32 => if (Target.x86.featureSetHas(self.target.cpu.features, .sse)) + .subss + else + return self.fail("TODO implement genBinOp for {s} {} without sse", .{ + @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?), + }), + 64 => if (Target.x86.featureSetHas(self.target.cpu.features, .sse2)) + .subsd + else + return self.fail("TODO implement genBinOp for {s} {} without sse2", .{ + @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?), + }), + else => return self.fail("TODO implement genBinOp for {s} {}", .{ + @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?), + }), + }, }, lhs_ty, dst_mcv, src_mcv), - .mul => try self.genBinOpMir(switch (lhs_ty.tag()) { - .f32 => .mulss, - .f64 => .mulsd, + .mul => try self.genBinOpMir(switch (lhs_ty.zigTypeTag()) { else => return self.fail("TODO implement genBinOp for {s} {}", .{ @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?) }), + .Float => switch (lhs_ty.floatBits(self.target.*)) { + 32 => if (Target.x86.featureSetHas(self.target.cpu.features, .sse)) + .mulss + else + return self.fail("TODO implement genBinOp for {s} {} without sse", .{ + @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?), + }), + 64 => if (Target.x86.featureSetHas(self.target.cpu.features, .sse2)) + .mulsd + else + return self.fail("TODO implement genBinOp for {s} {} without sse2", .{ + @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?), + }), + else => return self.fail("TODO implement genBinOp for {s} {}", .{ + @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?), + }), + }, }, lhs_ty, dst_mcv, src_mcv), .div_float, @@ -5206,12 +5342,27 @@ fn genBinOp( .div_trunc, .div_floor, => { - try self.genBinOpMir(switch (lhs_ty.tag()) { - .f32 => .divss, - .f64 => .divsd, + try self.genBinOpMir(switch (lhs_ty.zigTypeTag()) { else => return self.fail("TODO implement genBinOp for {s} {}", .{ @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?), }), + .Float => switch (lhs_ty.floatBits(self.target.*)) { + 32 => if (Target.x86.featureSetHas(self.target.cpu.features, .sse)) + .divss + else + return self.fail("TODO implement genBinOp for {s} {} without sse", .{ + @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?), + }), + 64 => if (Target.x86.featureSetHas(self.target.cpu.features, .sse2)) + .divsd + else + return self.fail("TODO implement genBinOp for {s} {} without sse2", .{ + @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?), + }), + else => return self.fail("TODO implement genBinOp for {s} {}", .{ + @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?), + }), + }, }, lhs_ty, dst_mcv, src_mcv); switch (tag) { .div_float, @@ -5222,16 +5373,18 @@ fn genBinOp( => if (Target.x86.featureSetHas(self.target.cpu.features, .sse4_1)) { const abi_size = @intCast(u32, lhs_ty.abiSize(self.target.*)); const dst_alias = registerAlias(dst_mcv.register, abi_size); - try self.asmRegisterRegisterImmediate(switch (lhs_ty.tag()) { - .f32 => .roundss, - .f64 => .roundsd, + try self.asmRegisterRegisterImmediate(switch (lhs_ty.floatBits(self.target.*)) { + 32 => .roundss, + 64 => .roundsd, else => unreachable, }, dst_alias, dst_alias, Immediate.u(switch (tag) { .div_trunc => 0b1_0_11, .div_floor => 0b1_0_01, else => unreachable, })); - } else return self.fail("TODO implement round without sse4_1", .{}), + } else return self.fail("TODO implement genBinOp for {s} {} without sse4_1", .{ + @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?), + }), else => unreachable, } }, @@ -5453,39 +5606,68 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s )), else => unreachable, }, - .register_offset, .eflags, + .register_offset, .memory, + .indirect, .load_direct, .lea_direct, .load_got, .lea_got, .load_tlv, .lea_tlv, + .load_frame, .lea_frame, => { - assert(abi_size <= 8); + blk: { + return self.asmRegisterMemory( + mir_tag, + registerAlias(dst_reg, abi_size), + Memory.sib(Memory.PtrSize.fromSize(abi_size), switch (src_mcv) { + .memory => |addr| .{ + .base = .{ .reg = .ds }, + .disp = math.cast(i32, addr) orelse break :blk, + }, + .indirect => |reg_off| .{ + .base = .{ .reg = reg_off.reg }, + .disp = reg_off.off, + }, + .load_frame => |frame_addr| .{ + .base = .{ .frame = frame_addr.index }, + .disp = frame_addr.off, + }, + else => break :blk, + }), + ); + } + const dst_reg_lock = self.register_manager.lockReg(dst_reg); defer if (dst_reg_lock) |lock| self.register_manager.unlockReg(lock); - const reg = try self.copyToTmpRegister(ty, src_mcv); - return self.genBinOpMir(mir_tag, ty, dst_mcv, .{ .register = reg }); - }, - .indirect, .load_frame => try self.asmRegisterMemory( - mir_tag, - registerAlias(dst_reg, abi_size), - Memory.sib(Memory.PtrSize.fromSize(abi_size), switch (src_mcv) { - .indirect => |reg_off| .{ - .base = .{ .reg = reg_off.reg }, - .disp = reg_off.off, + switch (src_mcv) { + .eflags, + .register_offset, + .lea_direct, + .lea_got, + .lea_tlv, + .lea_frame, + => { + const reg = try self.copyToTmpRegister(ty, src_mcv); + return self.genBinOpMir(mir_tag, ty, dst_mcv, .{ .register = reg }); }, - .load_frame => |frame_addr| .{ - .base = .{ .frame = frame_addr.index }, - .disp = frame_addr.off, + .memory, + .load_direct, + .load_got, + .load_tlv, + => { + const addr_reg = try self.copyToTmpRegister(ty, src_mcv.address()); + return self.genBinOpMir(mir_tag, ty, dst_mcv, .{ + .indirect = .{ .reg = addr_reg }, + }); }, else => unreachable, - }), - ), + } + }, } }, .memory, .indirect, .load_got, .load_direct, .load_tlv, .load_frame => { @@ -6175,10 +6357,25 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); const src_mcv = if (flipped) lhs_mcv else rhs_mcv; - try self.genBinOpMir(switch (ty.tag()) { + try self.genBinOpMir(switch (ty.zigTypeTag()) { else => .cmp, - .f32 => .ucomiss, - .f64 => .ucomisd, + .Float => switch (ty.floatBits(self.target.*)) { + 32 => if (Target.x86.featureSetHas(self.target.cpu.features, .sse)) + .ucomiss + else + return self.fail("TODO implement airCmp for {} without sse", .{ + ty.fmt(self.bin_file.options.module.?), + }), + 64 => if (Target.x86.featureSetHas(self.target.cpu.features, .sse2)) + .ucomisd + else + return self.fail("TODO implement airCmp for {} without sse2", .{ + ty.fmt(self.bin_file.options.module.?), + }), + else => return self.fail("TODO implement airCmp for {}", .{ + ty.fmt(self.bin_file.options.module.?), + }), + }, }, ty, dst_mcv, src_mcv); const signedness = if (ty.isAbiInt()) ty.intInfo(self.target.*).signedness else .unsigned; @@ -7608,7 +7805,8 @@ fn airBitCast(self: *Self, inst: Air.Inst.Index) !void { const dst_rc = try self.regClassForType(dst_ty); const src_rc = try self.regClassForType(src_ty); const operand = try self.resolveInst(ty_op.operand); - if (dst_rc.eql(src_rc) and self.reuseOperand(inst, ty_op.operand, 0, operand)) break :result operand; + if (dst_rc.supersetOf(src_rc) and self.reuseOperand(inst, ty_op.operand, 0, operand)) + break :result operand; const operand_lock = switch (operand) { .register => |reg| self.register_manager.lockReg(reg), @@ -7648,9 +7846,59 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void { fn airIntToFloat(self: *Self, inst: Air.Inst.Index) !void { const ty_op = self.air.instructions.items(.data)[inst].ty_op; - _ = ty_op; - return self.fail("TODO implement airIntToFloat for {}", .{self.target.cpu.arch}); - //return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); + + const src_ty = self.air.typeOf(ty_op.operand); + const src_bits = @intCast(u32, src_ty.bitSize(self.target.*)); + const src_signedness = + if (src_ty.isAbiInt()) src_ty.intInfo(self.target.*).signedness else .unsigned; + const dst_ty = self.air.typeOfIndex(inst); + + const src_size = std.math.divCeil(u32, @max(switch (src_signedness) { + .signed => src_bits, + .unsigned => src_bits + 1, + }, 32), 8) catch unreachable; + if (src_size > 8) return self.fail("TODO implement airIntToFloat from {} to {}", .{ + src_ty.fmt(self.bin_file.options.module.?), + dst_ty.fmt(self.bin_file.options.module.?), + }); + + const src_mcv = try self.resolveInst(ty_op.operand); + const src_reg = switch (src_mcv) { + .register => |reg| reg, + else => try self.copyToTmpRegister(src_ty, src_mcv), + }; + const src_lock = self.register_manager.lockRegAssumeUnused(src_reg); + defer self.register_manager.unlockReg(src_lock); + + if (src_bits < src_size * 8) try self.truncateRegister(src_ty, src_reg); + + const dst_reg = try self.register_manager.allocReg(inst, try self.regClassForType(dst_ty)); + const dst_mcv = MCValue{ .register = dst_reg }; + const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg); + defer self.register_manager.unlockReg(dst_lock); + + try self.asmRegisterRegister(switch (dst_ty.floatBits(self.target.*)) { + 32 => if (Target.x86.featureSetHas(self.target.cpu.features, .sse)) + .cvtsi2ss + else + return self.fail("TODO implement airIntToFloat from {} to {} without sse", .{ + src_ty.fmt(self.bin_file.options.module.?), + dst_ty.fmt(self.bin_file.options.module.?), + }), + 64 => if (Target.x86.featureSetHas(self.target.cpu.features, .sse2)) + .cvtsi2sd + else + return self.fail("TODO implement airIntToFloat from {} to {} without sse2", .{ + src_ty.fmt(self.bin_file.options.module.?), + dst_ty.fmt(self.bin_file.options.module.?), + }), + else => return self.fail("TODO implement airIntToFloat from {} to {}", .{ + src_ty.fmt(self.bin_file.options.module.?), + dst_ty.fmt(self.bin_file.options.module.?), + }), + }, dst_reg.to128(), registerAlias(src_reg, src_size)); + + return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none }); } fn airFloatToInt(self: *Self, inst: Air.Inst.Index) !void { @@ -8717,6 +8965,7 @@ fn resolveCallingConventionValues( }, .C => { var param_reg_i: usize = 0; + var param_sse_reg_i: usize = 0; result.stack_align = 16; switch (self.target.os.tag) { @@ -8734,26 +8983,39 @@ fn resolveCallingConventionValues( // TODO: is this even possible for C calling convention? result.return_value = InstTracking.init(.none); } else { - const ret_reg = abi.getCAbiIntReturnRegs(self.target.*)[0]; - const ret_ty_size = @intCast(u31, ret_ty.abiSize(self.target.*)); - if (ret_ty_size <= 8) { - const aliased_reg = registerAlias(ret_reg, ret_ty_size); - result.return_value = .{ .short = .{ .register = aliased_reg }, .long = .none }; - } else { - const ret_indirect_reg = abi.getCAbiIntParamRegs(self.target.*)[param_reg_i]; - param_reg_i += 1; - result.return_value = .{ - .short = .{ .indirect = .{ .reg = ret_reg } }, - .long = .{ .indirect = .{ .reg = ret_indirect_reg } }, - }; + const classes = switch (self.target.os.tag) { + .windows => &[1]abi.Class{abi.classifyWindows(ret_ty, self.target.*)}, + else => mem.sliceTo(&abi.classifySystemV(ret_ty, self.target.*, .ret), .none), + }; + if (classes.len > 1) { + return self.fail("TODO handle multiple classes per type", .{}); } + const ret_reg = abi.getCAbiIntReturnRegs(self.target.*)[0]; + result.return_value = switch (classes[0]) { + .integer => InstTracking.init(.{ .register = registerAlias( + ret_reg, + @intCast(u32, ret_ty.abiSize(self.target.*)), + ) }), + .float, .sse => InstTracking.init(.{ .register = .xmm0 }), + .memory => ret: { + const ret_indirect_reg = abi.getCAbiIntParamRegs(self.target.*)[param_reg_i]; + param_reg_i += 1; + break :ret .{ + .short = .{ .indirect = .{ .reg = ret_reg } }, + .long = .{ .indirect = .{ .reg = ret_indirect_reg } }, + }; + }, + else => |class| return self.fail("TODO handle calling convention class {s}", .{ + @tagName(class), + }), + }; } // Input params for (param_types, result.args) |ty, *arg| { assert(ty.hasRuntimeBitsIgnoreComptime()); - const classes: []const abi.Class = switch (self.target.os.tag) { + const classes = switch (self.target.os.tag) { .windows => &[1]abi.Class{abi.classifyWindows(ty, self.target.*)}, else => mem.sliceTo(&abi.classifySystemV(ty, self.target.*, .arg), .none), }; @@ -8761,13 +9023,29 @@ fn resolveCallingConventionValues( return self.fail("TODO handle multiple classes per type", .{}); } switch (classes[0]) { - .integer => blk: { - if (param_reg_i >= abi.getCAbiIntParamRegs(self.target.*).len) break :blk; - const param_reg = abi.getCAbiIntParamRegs(self.target.*)[param_reg_i]; + .integer => if (param_reg_i < abi.getCAbiIntParamRegs(self.target.*).len) { + arg.* = .{ .register = abi.getCAbiIntParamRegs(self.target.*)[param_reg_i] }; param_reg_i += 1; - arg.* = .{ .register = param_reg }; continue; }, + .float, .sse => switch (self.target.os.tag) { + .windows => if (param_reg_i < 4) { + arg.* = .{ .register = @intToEnum( + Register, + @enumToInt(Register.xmm0) + param_reg_i, + ) }; + param_reg_i += 1; + continue; + }, + else => if (param_sse_reg_i < 8) { + arg.* = .{ .register = @intToEnum( + Register, + @enumToInt(Register.xmm0) + param_sse_reg_i, + ) }; + param_sse_reg_i += 1; + continue; + }, + }, .memory => {}, // fallthrough else => |class| return self.fail("TODO handle calling convention class {s}", .{ @tagName(class), diff --git a/src/arch/x86_64/Encoding.zig b/src/arch/x86_64/Encoding.zig index a977af7842..5cb7f7a2d9 100644 --- a/src/arch/x86_64/Encoding.zig +++ b/src/arch/x86_64/Encoding.zig @@ -58,7 +58,7 @@ pub fn findByMnemonic( next: for (mnemonic_to_encodings_map[@enumToInt(mnemonic)]) |data| { switch (data.mode) { .rex => if (!rex_required) continue, - .long, .sse2_long => {}, + .long, .sse_long, .sse2_long => {}, else => if (rex_required) continue, } for (input_ops, data.ops) |input_op, data_op| @@ -90,7 +90,7 @@ pub fn findByOpcode(opc: []const u8, prefixes: struct { if (prefixes.rex.w) { switch (data.mode) { .short, .fpu, .sse, .sse2, .sse4_1, .none => continue, - .long, .sse2_long, .rex => {}, + .long, .sse_long, .sse2_long, .rex => {}, } } else if (prefixes.rex.present and !prefixes.rex.isSet()) { switch (data.mode) { @@ -138,7 +138,7 @@ pub fn modRmExt(encoding: Encoding) u3 { pub fn operandBitSize(encoding: Encoding) u64 { switch (encoding.data.mode) { .short => return 16, - .long, .sse2_long => return 64, + .long, .sse_long, .sse2_long => return 64, else => {}, } const bit_size: u64 = switch (encoding.data.op_en) { @@ -163,7 +163,7 @@ pub fn format( _ = options; _ = fmt; switch (encoding.data.mode) { - .long, .sse2_long => try writer.writeAll("REX.W + "), + .long, .sse_long, .sse2_long => try writer.writeAll("REX.W + "), else => {}, } @@ -269,21 +269,25 @@ pub const Mnemonic = enum { // SSE addss, cmpss, + cvtsi2ss, divss, maxss, minss, movss, mulss, subss, ucomiss, + xorps, // SSE2 addsd, //cmpsd, + cvtsd2ss, cvtsi2sd, cvtss2sd, divsd, maxsd, minsd, movq, //movd, movsd, mulsd, subsd, ucomisd, + xorpd, // SSE4.1 roundss, roundsd, @@ -318,7 +322,7 @@ pub const Op = enum { m, moffs, sreg, - xmm, xmm_m32, xmm_m64, + xmm, xmm_m32, xmm_m64, xmm_m128, // zig fmt: on pub fn fromOperand(operand: Instruction.Operand) Op { @@ -400,7 +404,7 @@ pub const Op = enum { .imm32, .imm32s, .eax, .r32, .m32, .rm32, .rel32, .xmm_m32 => 32, .imm64, .rax, .r64, .m64, .rm64, .xmm_m64 => 64, .m80 => 80, - .m128, .xmm => 128, + .m128, .xmm, .xmm_m128 => 128, }; } @@ -423,8 +427,8 @@ pub const Op = enum { .al, .ax, .eax, .rax, .r8, .r16, .r32, .r64, .rm8, .rm16, .rm32, .rm64, - .xmm, .xmm_m32, .xmm_m64, - => true, + .xmm, .xmm_m32, .xmm_m64, .xmm_m128, + => true, else => false, }; // zig fmt: on @@ -449,7 +453,7 @@ pub const Op = enum { .rm8, .rm16, .rm32, .rm64, .m8, .m16, .m32, .m64, .m80, .m128, .m, - .xmm_m32, .xmm_m64, + .xmm_m32, .xmm_m64, .xmm_m128, => true, else => false, }; @@ -470,13 +474,13 @@ pub const Op = enum { .r8, .r16, .r32, .r64 => .general_purpose, .rm8, .rm16, .rm32, .rm64 => .general_purpose, .sreg => .segment, - .xmm, .xmm_m32, .xmm_m64 => .floating_point, + .xmm, .xmm_m32, .xmm_m64, .xmm_m128 => .floating_point, }; } pub fn isFloatingPointRegister(op: Op) bool { return switch (op) { - .xmm, .xmm_m32, .xmm_m64 => true, + .xmm, .xmm_m32, .xmm_m64, .xmm_m128 => true, else => false, }; } @@ -535,6 +539,7 @@ pub const Mode = enum { rex, long, sse, + sse_long, sse2, sse2_long, sse4_1, diff --git a/src/arch/x86_64/Lower.zig b/src/arch/x86_64/Lower.zig index af0146c6e1..a961100687 100644 --- a/src/arch/x86_64/Lower.zig +++ b/src/arch/x86_64/Lower.zig @@ -95,6 +95,7 @@ pub fn lowerMir(lower: *Lower, inst: Mir.Inst) Error![]const Instruction { .addss, .cmpss, + .cvtsi2ss, .divss, .maxss, .minss, @@ -103,8 +104,12 @@ pub fn lowerMir(lower: *Lower, inst: Mir.Inst) Error![]const Instruction { .roundss, .subss, .ucomiss, + .xorps, .addsd, .cmpsd, + .cvtsd2ss, + .cvtsi2sd, + .cvtss2sd, .divsd, .maxsd, .minsd, @@ -113,6 +118,7 @@ pub fn lowerMir(lower: *Lower, inst: Mir.Inst) Error![]const Instruction { .roundsd, .subsd, .ucomisd, + .xorpd, => try lower.mirGeneric(inst), .cmps, diff --git a/src/arch/x86_64/Mir.zig b/src/arch/x86_64/Mir.zig index c8703373d2..c14338b13d 100644 --- a/src/arch/x86_64/Mir.zig +++ b/src/arch/x86_64/Mir.zig @@ -170,6 +170,8 @@ pub const Inst = struct { addss, /// Compare scalar single-precision floating-point values cmpss, + /// Convert doubleword integer to scalar single-precision floating-point value + cvtsi2ss, /// Divide scalar single-precision floating-point values divss, /// Return maximum single-precision floating-point value @@ -186,10 +188,18 @@ pub const Inst = struct { subss, /// Unordered compare scalar single-precision floating-point values ucomiss, + /// Bitwise logical xor of packed single precision floating-point values + xorps, /// Add double precision floating point values addsd, /// Compare scalar double-precision floating-point values cmpsd, + /// Convert scalar double-precision floating-point value to scalar single-precision floating-point value + cvtsd2ss, + /// Convert doubleword integer to scalar double-precision floating-point value + cvtsi2sd, + /// Convert scalar single-precision floating-point value to scalar double-precision floating-point value + cvtss2sd, /// Divide scalar double-precision floating-point values divsd, /// Return maximum double-precision floating-point value @@ -206,6 +216,8 @@ pub const Inst = struct { subsd, /// Unordered compare scalar double-precision floating-point values ucomisd, + /// Bitwise logical xor of packed double precision floating-point values + xorpd, /// Compare string operands cmps, diff --git a/src/arch/x86_64/encoder.zig b/src/arch/x86_64/encoder.zig index 329dfca924..4c900697f5 100644 --- a/src/arch/x86_64/encoder.zig +++ b/src/arch/x86_64/encoder.zig @@ -323,7 +323,7 @@ pub const Instruction = struct { var rex = Rex{}; rex.present = inst.encoding.data.mode == .rex; switch (inst.encoding.data.mode) { - .long, .sse2_long => rex.w = true, + .long, .sse_long, .sse2_long => rex.w = true, else => {}, } diff --git a/src/arch/x86_64/encodings.zig b/src/arch/x86_64/encodings.zig index 333bdceea8..ac427c3633 100644 --- a/src/arch/x86_64/encodings.zig +++ b/src/arch/x86_64/encodings.zig @@ -834,6 +834,9 @@ pub const table = [_]Entry{ .{ .cmpss, .rmi, &.{ .xmm, .xmm_m32, .imm8 }, &.{ 0xf3, 0x0f, 0xc2 }, 0, .sse }, + .{ .cvtsi2ss, .rm, &.{ .xmm, .rm32 }, &.{ 0xf3, 0x0f, 0x2a }, 0, .sse }, + .{ .cvtsi2ss, .rm, &.{ .xmm, .rm64 }, &.{ 0xf3, 0x0f, 0x2a }, 0, .sse_long }, + .{ .divss, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x5e }, 0, .sse }, .{ .maxss, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x5f }, 0, .sse }, @@ -849,11 +852,20 @@ pub const table = [_]Entry{ .{ .ucomiss, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0x0f, 0x2e }, 0, .sse }, + .{ .xorps, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x0f, 0x57 }, 0, .sse }, + // SSE2 .{ .addsd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x58 }, 0, .sse2 }, .{ .cmpsd, .rmi, &.{ .xmm, .xmm_m64, .imm8 }, &.{ 0xf2, 0x0f, 0xc2 }, 0, .sse2 }, + .{ .cvtsd2ss, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x5a }, 0, .sse2 }, + + .{ .cvtsi2sd, .rm, &.{ .xmm, .rm32 }, &.{ 0xf2, 0x0f, 0x2a }, 0, .sse2 }, + .{ .cvtsi2sd, .rm, &.{ .xmm, .rm64 }, &.{ 0xf2, 0x0f, 0x2a }, 0, .sse2_long }, + + .{ .cvtss2sd, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x5a }, 0, .sse2 }, + .{ .divsd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x5e }, 0, .sse2 }, .{ .maxsd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x5f }, 0, .sse2 }, @@ -878,6 +890,8 @@ pub const table = [_]Entry{ .{ .ucomisd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0x66, 0x0f, 0x2e }, 0, .sse2 }, + .{ .xorpd, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x57 }, 0, .sse2 }, + // SSE4.1 .{ .roundss, .rmi, &.{ .xmm, .xmm_m32, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x0a }, 0, .sse4_1 }, .{ .roundsd, .rmi, &.{ .xmm, .xmm_m64, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x0b }, 0, .sse4_1 }, diff --git a/src/codegen.zig b/src/codegen.zig index bf80a90cc3..0043b38a5b 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -291,6 +291,20 @@ pub fn generateSymbol( }, }, .Pointer => switch (typed_value.val.tag()) { + .null_value => { + switch (target.cpu.arch.ptrBitWidth()) { + 32 => { + mem.writeInt(u32, try code.addManyAsArray(4), 0, endian); + if (typed_value.ty.isSlice()) try code.appendNTimes(0xaa, 4); + }, + 64 => { + mem.writeInt(u64, try code.addManyAsArray(8), 0, endian); + if (typed_value.ty.isSlice()) try code.appendNTimes(0xaa, 8); + }, + else => unreachable, + } + return Result.ok; + }, .zero, .one, .int_u64, .int_big_positive => { switch (target.cpu.arch.ptrBitWidth()) { 32 => { @@ -397,30 +411,15 @@ pub fn generateSymbol( }, } }, - .elem_ptr => { - const elem_ptr = typed_value.val.castTag(.elem_ptr).?.data; - const elem_size = typed_value.ty.childType().abiSize(target); - const addend = @intCast(u32, elem_ptr.index * elem_size); - const array_ptr = elem_ptr.array_ptr; - - switch (array_ptr.tag()) { - .decl_ref => { - const decl_index = array_ptr.castTag(.decl_ref).?.data; - return lowerDeclRef(bin_file, src_loc, typed_value, decl_index, code, debug_output, .{ - .parent_atom_index = reloc_info.parent_atom_index, - .addend = (reloc_info.addend orelse 0) + addend, - }); - }, - else => return Result{ - .fail = try ErrorMsg.create( - bin_file.allocator, - src_loc, - "TODO implement generateSymbol for pointer type value: '{s}'", - .{@tagName(typed_value.val.tag())}, - ), - }, - } - }, + .elem_ptr => return lowerParentPtr( + bin_file, + src_loc, + typed_value, + typed_value.val, + code, + debug_output, + reloc_info, + ), else => return Result{ .fail = try ErrorMsg.create( bin_file.allocator, @@ -838,9 +837,62 @@ pub fn generateSymbol( } } +fn lowerParentPtr( + bin_file: *link.File, + src_loc: Module.SrcLoc, + typed_value: TypedValue, + parent_ptr: Value, + code: *std.ArrayList(u8), + debug_output: DebugInfoOutput, + reloc_info: RelocInfo, +) CodeGenError!Result { + const target = bin_file.options.target; + + switch (parent_ptr.tag()) { + .elem_ptr => { + const elem_ptr = parent_ptr.castTag(.elem_ptr).?.data; + return lowerParentPtr( + bin_file, + src_loc, + typed_value, + elem_ptr.array_ptr, + code, + debug_output, + reloc_info.offset(@intCast(u32, elem_ptr.index * elem_ptr.elem_ty.abiSize(target))), + ); + }, + .decl_ref => { + const decl_index = parent_ptr.castTag(.decl_ref).?.data; + return lowerDeclRef( + bin_file, + src_loc, + typed_value, + decl_index, + code, + debug_output, + reloc_info, + ); + }, + else => |t| { + return Result{ + .fail = try ErrorMsg.create( + bin_file.allocator, + src_loc, + "TODO implement lowerParentPtr for type '{s}'", + .{@tagName(t)}, + ), + }; + }, + } +} + const RelocInfo = struct { parent_atom_index: u32, addend: ?u32 = null, + + fn offset(ri: RelocInfo, addend: u32) RelocInfo { + return .{ .parent_atom_index = ri.parent_atom_index, .addend = (ri.addend orelse 0) + addend }; + } }; fn lowerDeclRef( @@ -1095,6 +1147,9 @@ pub fn genTypedValue( .Slice => {}, else => { switch (typed_value.val.tag()) { + .null_value => { + return GenResult.mcv(.{ .immediate = 0 }); + }, .int_u64 => { return GenResult.mcv(.{ .immediate = typed_value.val.toUnsignedInt(target) }); }, From 6de457211fe4f261fab6c30f652f833ed2a144b5 Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Thu, 27 Apr 2023 03:24:48 -0400 Subject: [PATCH 031/725] behavior: update affected tests for the x86_64 backend --- test/behavior/basic.zig | 12 ++++++++---- test/behavior/bugs/13069.zig | 2 ++ test/behavior/cast.zig | 7 +++++-- test/behavior/enum.zig | 2 ++ test/behavior/eval.zig | 2 ++ test/behavior/floatop.zig | 12 ++++++++---- test/behavior/fn.zig | 4 ++++ test/behavior/generics.zig | 4 ++++ test/behavior/math.zig | 2 ++ test/behavior/maximum_minimum.zig | 4 ++++ test/behavior/pointers.zig | 5 ++++- test/behavior/struct.zig | 3 ++- test/behavior/switch.zig | 2 ++ test/behavior/union.zig | 14 ++++++++++++++ test/behavior/vector.zig | 4 ++++ 15 files changed, 67 insertions(+), 12 deletions(-) diff --git a/test/behavior/basic.zig b/test/behavior/basic.zig index 437b1b1373..86fc61c2c9 100644 --- a/test/behavior/basic.zig +++ b/test/behavior/basic.zig @@ -363,7 +363,8 @@ fn hereIsAnOpaqueType(ptr: *OpaqueA) *OpaqueA { } test "take address of parameter" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_x86_64 and + comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -391,7 +392,8 @@ test "array 2D const double ptr" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_x86_64 and + comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO const rect_2d_vertexes = [_][1]f32{ @@ -405,7 +407,8 @@ test "array 2D const double ptr with offset" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_x86_64 and + comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; const rect_2d_vertexes = [_][2]f32{ @@ -419,7 +422,8 @@ test "array 3D const double ptr with offset" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_x86_64 and + comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO const rect_3d_vertexes = [_][2][2]f32{ diff --git a/test/behavior/bugs/13069.zig b/test/behavior/bugs/13069.zig index 41c5906ee6..1c2526ef2a 100644 --- a/test/behavior/bugs/13069.zig +++ b/test/behavior/bugs/13069.zig @@ -6,6 +6,8 @@ test { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64 and + comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO var opt_x: ?[3]f32 = [_]f32{0.0} ** 3; diff --git a/test/behavior/cast.zig b/test/behavior/cast.zig index fc364da0b8..3c1d26f284 100644 --- a/test/behavior/cast.zig +++ b/test/behavior/cast.zig @@ -95,7 +95,9 @@ test "comptime_int @intToFloat" { test "@intToFloat" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64 and + comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -634,7 +636,8 @@ test "vector casts" { } test "@floatCast cast down" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64 and + comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO diff --git a/test/behavior/enum.zig b/test/behavior/enum.zig index 316275d6ac..de5c0efb8e 100644 --- a/test/behavior/enum.zig +++ b/test/behavior/enum.zig @@ -940,6 +940,8 @@ test "constant enum initialization with differing sizes" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64 and + comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO try test3_1(test3_foo); try test3_2(test3_bar); diff --git a/test/behavior/eval.zig b/test/behavior/eval.zig index 3566bdacb0..3a10a288e3 100644 --- a/test/behavior/eval.zig +++ b/test/behavior/eval.zig @@ -535,6 +535,8 @@ test "static eval list init" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64 and + comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO try expect(static_vec3.data[2] == 1.0); try expect(vec3(0.0, 0.0, 3.0).data[2] == 3.0); diff --git a/test/behavior/floatop.zig b/test/behavior/floatop.zig index 3fc2249ccc..700b419fce 100644 --- a/test/behavior/floatop.zig +++ b/test/behavior/floatop.zig @@ -904,7 +904,8 @@ test "negation f16" { } test "negation f32" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64 and + comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -924,7 +925,8 @@ test "negation f32" { } test "negation f64" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64 and + comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -1060,7 +1062,8 @@ test "nan negation f16" { } test "nan negation f32" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64 and + comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -1080,7 +1083,8 @@ test "nan negation f32" { test "nan negation f64" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64 and + comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO diff --git a/test/behavior/fn.zig b/test/behavior/fn.zig index 4ff5e20378..71b7b36c21 100644 --- a/test/behavior/fn.zig +++ b/test/behavior/fn.zig @@ -338,6 +338,8 @@ test "function call with anon list literal" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64 and + comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO const S = struct { fn doTheTest() !void { @@ -358,6 +360,8 @@ test "function call with anon list literal - 2D" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64 and + comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO const S = struct { fn doTheTest() !void { diff --git a/test/behavior/generics.zig b/test/behavior/generics.zig index 0e002b2016..c5168e420b 100644 --- a/test/behavior/generics.zig +++ b/test/behavior/generics.zig @@ -59,6 +59,8 @@ test "fn with comptime args" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64 and + comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO try expect(gimmeTheBigOne(1234, 5678) == 5678); try expect(shouldCallSameInstance(34, 12) == 34); @@ -69,6 +71,8 @@ test "anytype params" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64 and + comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO try expect(max_i32(12, 34) == 34); try expect(max_f64(1.2, 3.4) == 3.4); diff --git a/test/behavior/math.zig b/test/behavior/math.zig index 846f72e301..b7dd6b9287 100644 --- a/test/behavior/math.zig +++ b/test/behavior/math.zig @@ -203,6 +203,8 @@ test "float equality" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64 and + comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO const x: f64 = 0.012; const y: f64 = x + 1.0; diff --git a/test/behavior/maximum_minimum.zig b/test/behavior/maximum_minimum.zig index d538e2db65..9a4ae40eef 100644 --- a/test/behavior/maximum_minimum.zig +++ b/test/behavior/maximum_minimum.zig @@ -8,6 +8,8 @@ test "@max" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64 and + comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO const S = struct { fn doTheTest() !void { @@ -54,6 +56,8 @@ test "@min" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64 and + comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO const S = struct { fn doTheTest() !void { diff --git a/test/behavior/pointers.zig b/test/behavior/pointers.zig index 016b59b613..0bd8388660 100644 --- a/test/behavior/pointers.zig +++ b/test/behavior/pointers.zig @@ -206,7 +206,8 @@ test "allowzero pointer and slice" { } test "assign null directly to C pointer and test null equality" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64 and + comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -345,6 +346,8 @@ test "pointer sentinel with +inf" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64 and + comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO const S = struct { fn doTheTest() !void { diff --git a/test/behavior/struct.zig b/test/behavior/struct.zig index c3609e4a0a..e533e34cc3 100644 --- a/test/behavior/struct.zig +++ b/test/behavior/struct.zig @@ -744,7 +744,8 @@ var g_foo: S0 = S0.init(); test "packed struct with fp fields" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64 and + comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO diff --git a/test/behavior/switch.zig b/test/behavior/switch.zig index b69add6fdf..3924d1d6c1 100644 --- a/test/behavior/switch.zig +++ b/test/behavior/switch.zig @@ -231,6 +231,8 @@ test "switch prong with variable" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64 and + comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO try switchProngWithVarFn(SwitchProngWithVarEnum{ .One = 13 }); try switchProngWithVarFn(SwitchProngWithVarEnum{ .Two = 13.0 }); diff --git a/test/behavior/union.zig b/test/behavior/union.zig index 025eb4f6bd..76c5b09a89 100644 --- a/test/behavior/union.zig +++ b/test/behavior/union.zig @@ -14,6 +14,8 @@ test "basic unions with floats" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64 and + comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO var foo = FooWithFloats{ .int = 1 }; try expect(foo.int == 1); @@ -29,6 +31,8 @@ test "init union with runtime value - floats" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64 and + comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO var foo: FooWithFloats = undefined; @@ -216,6 +220,8 @@ test "union with specified enum tag" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64 and + comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO try doTest(); comptime try doTest(); @@ -225,6 +231,8 @@ test "packed union generates correctly aligned type" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64 and + comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO const U = packed union { f1: *const fn () error{TestUnexpectedResult}!void, @@ -903,6 +911,8 @@ test "anonymous union literal syntax" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64 and + comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO const S = struct { const Number = union { @@ -1055,6 +1065,8 @@ test "containers with single-field enums" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64 and + comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO const S = struct { const A = union(enum) { f1 }; @@ -1515,6 +1527,8 @@ test "reinterpreting enum value inside packed union" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64 and + comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO const U = packed union { tag: enum { a, b }, diff --git a/test/behavior/vector.zig b/test/behavior/vector.zig index f6521f04c3..01c76310d7 100644 --- a/test/behavior/vector.zig +++ b/test/behavior/vector.zig @@ -321,6 +321,7 @@ test "load vector elements via comptime index" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO const S = struct { fn doTheTest() !void { @@ -342,6 +343,7 @@ test "store vector elements via comptime index" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO const S = struct { fn doTheTest() !void { @@ -369,6 +371,7 @@ test "load vector elements via runtime index" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO const S = struct { fn doTheTest() !void { @@ -390,6 +393,7 @@ test "store vector elements via runtime index" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO const S = struct { fn doTheTest() !void { From 1fd48815c6e22b266b318f58c6b3c828b20ace80 Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Fri, 28 Apr 2023 01:56:18 -0400 Subject: [PATCH 032/725] x86_64: cleanup unneeded code --- src/arch/x86_64/CodeGen.zig | 136 ++++++++++++++++-------------------- 1 file changed, 59 insertions(+), 77 deletions(-) diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index d9c7298c95..915b36f267 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -6595,35 +6595,26 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { if (Air.refToIndex(pl_op.operand)) |op_inst| self.processDeath(op_inst); } - const outer_state = try self.saveState(); - { - self.scope_generation += 1; - const inner_state = try self.saveState(); + self.scope_generation += 1; + const state = try self.saveState(); - for (liveness_cond_br.then_deaths) |operand| self.processDeath(operand); - try self.genBody(then_body); - try self.restoreState(inner_state, &.{}, .{ - .emit_instructions = false, - .update_tracking = true, - .resurrect = true, - .close_scope = true, - }); - - try self.performReloc(reloc); - - for (liveness_cond_br.else_deaths) |operand| self.processDeath(operand); - try self.genBody(else_body); - try self.restoreState(inner_state, &.{}, .{ - .emit_instructions = false, - .update_tracking = true, - .resurrect = true, - .close_scope = true, - }); - } - try self.restoreState(outer_state, &.{}, .{ + for (liveness_cond_br.then_deaths) |operand| self.processDeath(operand); + try self.genBody(then_body); + try self.restoreState(state, &.{}, .{ .emit_instructions = false, - .update_tracking = false, - .resurrect = false, + .update_tracking = true, + .resurrect = true, + .close_scope = true, + }); + + try self.performReloc(reloc); + + for (liveness_cond_br.else_deaths) |operand| self.processDeath(operand); + try self.genBody(else_body); + try self.restoreState(state, &.{}, .{ + .emit_instructions = false, + .update_tracking = true, + .resurrect = true, .close_scope = true, }); @@ -6996,64 +6987,55 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) !void { if (Air.refToIndex(pl_op.operand)) |op_inst| self.processDeath(op_inst); } - const outer_state = try self.saveState(); - { - self.scope_generation += 1; - const inner_state = try self.saveState(); + self.scope_generation += 1; + const state = try self.saveState(); - while (case_i < switch_br.data.cases_len) : (case_i += 1) { - const case = self.air.extraData(Air.SwitchBr.Case, extra_index); - const items = @ptrCast( - []const Air.Inst.Ref, - self.air.extra[case.end..][0..case.data.items_len], - ); - const case_body = self.air.extra[case.end + items.len ..][0..case.data.body_len]; - extra_index = case.end + items.len + case_body.len; + while (case_i < switch_br.data.cases_len) : (case_i += 1) { + const case = self.air.extraData(Air.SwitchBr.Case, extra_index); + const items = @ptrCast( + []const Air.Inst.Ref, + self.air.extra[case.end..][0..case.data.items_len], + ); + const case_body = self.air.extra[case.end + items.len ..][0..case.data.body_len]; + extra_index = case.end + items.len + case_body.len; - var relocs = try self.gpa.alloc(u32, items.len); - defer self.gpa.free(relocs); + var relocs = try self.gpa.alloc(u32, items.len); + defer self.gpa.free(relocs); - for (items, relocs) |item, *reloc| { - try self.spillEflagsIfOccupied(); - const item_mcv = try self.resolveInst(item); - try self.genBinOpMir(.cmp, condition_ty, condition, item_mcv); - reloc.* = try self.asmJccReloc(undefined, .ne); - } - - for (liveness.deaths[case_i]) |operand| self.processDeath(operand); - - try self.genBody(case_body); - try self.restoreState(inner_state, &.{}, .{ - .emit_instructions = false, - .update_tracking = true, - .resurrect = true, - .close_scope = true, - }); - - for (relocs) |reloc| try self.performReloc(reloc); + for (items, relocs) |item, *reloc| { + try self.spillEflagsIfOccupied(); + const item_mcv = try self.resolveInst(item); + try self.genBinOpMir(.cmp, condition_ty, condition, item_mcv); + reloc.* = try self.asmJccReloc(undefined, .ne); } - if (switch_br.data.else_body_len > 0) { - const else_body = self.air.extra[extra_index..][0..switch_br.data.else_body_len]; + for (liveness.deaths[case_i]) |operand| self.processDeath(operand); - const else_deaths = liveness.deaths.len - 1; - for (liveness.deaths[else_deaths]) |operand| self.processDeath(operand); + try self.genBody(case_body); + try self.restoreState(state, &.{}, .{ + .emit_instructions = false, + .update_tracking = true, + .resurrect = true, + .close_scope = true, + }); - try self.genBody(else_body); - try self.restoreState(inner_state, &.{}, .{ - .emit_instructions = false, - .update_tracking = true, - .resurrect = true, - .close_scope = true, - }); - } + for (relocs) |reloc| try self.performReloc(reloc); + } + + if (switch_br.data.else_body_len > 0) { + const else_body = self.air.extra[extra_index..][0..switch_br.data.else_body_len]; + + const else_deaths = liveness.deaths.len - 1; + for (liveness.deaths[else_deaths]) |operand| self.processDeath(operand); + + try self.genBody(else_body); + try self.restoreState(state, &.{}, .{ + .emit_instructions = false, + .update_tracking = true, + .resurrect = true, + .close_scope = true, + }); } - try self.restoreState(outer_state, &.{}, .{ - .emit_instructions = false, - .update_tracking = false, - .resurrect = false, - .close_scope = true, - }); // We already took care of pl_op.operand earlier, so we're going to pass .none here return self.finishAir(inst, .unreach, .{ .none, .none, .none }); From db76ae82607b941373064b05a348950802a21217 Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Fri, 28 Apr 2023 01:56:45 -0400 Subject: [PATCH 033/725] x86_64: fix emitting f80 globals --- src/codegen.zig | 22 ++++++++-------------- test/behavior/floatop.zig | 1 - test/behavior/math.zig | 1 - 3 files changed, 8 insertions(+), 16 deletions(-) diff --git a/src/codegen.zig b/src/codegen.zig index 0043b38a5b..f967566034 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -91,12 +91,10 @@ pub fn generateFunction( fn writeFloat(comptime F: type, f: F, target: Target, endian: std.builtin.Endian, code: []u8) void { _ = target; - const Int = @Type(.{ .Int = .{ - .signedness = .unsigned, - .bits = @typeInfo(F).Float.bits, - } }); + const bits = @typeInfo(F).Float.bits; + const Int = @Type(.{ .Int = .{ .signedness = .unsigned, .bits = bits } }); const int = @bitCast(Int, f); - mem.writeInt(Int, code[0..@sizeOf(Int)], int, endian); + mem.writeInt(Int, code[0..@divExact(bits, 8)], int, endian); } pub fn generateLazySymbol( @@ -187,18 +185,14 @@ pub fn generateSymbol( }; }, .Float => { - const float_bits = typed_value.ty.floatBits(target); - switch (float_bits) { + switch (typed_value.ty.floatBits(target)) { 16 => writeFloat(f16, typed_value.val.toFloat(f16), target, endian, try code.addManyAsArray(2)), 32 => writeFloat(f32, typed_value.val.toFloat(f32), target, endian, try code.addManyAsArray(4)), 64 => writeFloat(f64, typed_value.val.toFloat(f64), target, endian, try code.addManyAsArray(8)), - 80 => return Result{ - .fail = try ErrorMsg.create( - bin_file.allocator, - src_loc, - "TODO handle f80 in generateSymbol", - .{}, - ), + 80 => { + writeFloat(f80, typed_value.val.toFloat(f80), target, endian, try code.addManyAsArray(10)); + const abi_size = math.cast(usize, typed_value.ty.abiSize(target)) orelse return error.Overflow; + try code.appendNTimes(0, abi_size - 10); }, 128 => writeFloat(f128, typed_value.val.toFloat(f128), target, endian, try code.addManyAsArray(16)), else => unreachable, diff --git a/test/behavior/floatop.zig b/test/behavior/floatop.zig index 700b419fce..f713cd035c 100644 --- a/test/behavior/floatop.zig +++ b/test/behavior/floatop.zig @@ -1023,7 +1023,6 @@ test "comptime fixed-width float zero divided by zero produces NaN" { test "comptime fixed-width float non-zero divided by zero produces signed Inf" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO diff --git a/test/behavior/math.zig b/test/behavior/math.zig index b7dd6b9287..03a92a83e9 100644 --- a/test/behavior/math.zig +++ b/test/behavior/math.zig @@ -1535,7 +1535,6 @@ test "signed zeros are represented properly" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO const S = struct { From 50f96c2949bd7d396eaaf391ffd5fd55e59ebac1 Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Fri, 28 Apr 2023 02:24:29 -0400 Subject: [PATCH 034/725] x86_64: fix stack realignment --- src/arch/x86_64/CodeGen.zig | 7 ++++--- test/behavior/align.zig | 5 ----- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 915b36f267..955a0ba843 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -1673,15 +1673,16 @@ fn allocFrameIndex(self: *Self, alloc: FrameAlloc) !FrameIndex { const frame_allocs_slice = self.frame_allocs.slice(); const frame_size = frame_allocs_slice.items(.abi_size); const frame_align = frame_allocs_slice.items(.abi_align); + + const stack_frame_align = &frame_align[@enumToInt(FrameIndex.stack_frame)]; + stack_frame_align.* = @max(stack_frame_align.*, alloc.abi_align); + for (self.free_frame_indices.keys(), 0..) |frame_index, free_i| { const abi_size = frame_size[@enumToInt(frame_index)]; if (abi_size != alloc.abi_size) continue; const abi_align = &frame_align[@enumToInt(frame_index)]; abi_align.* = @max(abi_align.*, alloc.abi_align); - const stack_frame_align = &frame_align[@enumToInt(FrameIndex.stack_frame)]; - stack_frame_align.* = @max(stack_frame_align.*, alloc.abi_align); - _ = self.free_frame_indices.swapRemoveAt(free_i); return frame_index; } diff --git a/test/behavior/align.zig b/test/behavior/align.zig index 7755cdaa7d..bfc9997dd2 100644 --- a/test/behavior/align.zig +++ b/test/behavior/align.zig @@ -282,7 +282,6 @@ fn give() anyerror!u128 { test "page aligned array on stack" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -491,10 +490,6 @@ test "read 128-bit field from default aligned struct in global memory" { } test "struct field explicit alignment" { - if (builtin.zig_backend == .stage2_x86_64) { - // Careful enabling this test, fails randomly. - return error.SkipZigTest; - } if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO From aaef5288f886c86e4257c5c67122a0be8a64c134 Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Fri, 28 Apr 2023 17:35:17 -0400 Subject: [PATCH 035/725] x86_64: fix 128-bit cmpxchg --- src/arch/x86_64/CodeGen.zig | 134 ++++++++++++++++++------------------ 1 file changed, 67 insertions(+), 67 deletions(-) diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 955a0ba843..99b3c913a0 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -219,9 +219,9 @@ pub const MCValue = union(enum) { .dead, .undef, .immediate, + .eflags, .register, .register_offset, - .eflags, .register_overflow, .lea_direct, .lea_got, @@ -297,6 +297,41 @@ pub const MCValue = union(enum) { }; } + fn mem(mcv: MCValue, ptr_size: Memory.PtrSize) Memory { + return switch (mcv) { + .none, + .unreach, + .dead, + .undef, + .immediate, + .eflags, + .register, + .register_offset, + .register_overflow, + .load_direct, + .lea_direct, + .load_got, + .lea_got, + .load_tlv, + .lea_tlv, + .lea_frame, + .reserved_frame, + => unreachable, + .memory => |addr| if (math.cast(i32, @bitCast(i64, addr))) |small_addr| + Memory.sib(ptr_size, .{ .base = .{ .reg = .ds }, .disp = small_addr }) + else + Memory.moffs(.ds, addr), + .indirect => |reg_off| Memory.sib(ptr_size, .{ + .base = .{ .reg = reg_off.reg }, + .disp = reg_off.off, + }), + .load_frame => |frame_addr| Memory.sib(ptr_size, .{ + .base = .{ .frame = frame_addr.index }, + .disp = frame_addr.off, + }), + }; + } + pub fn format( mcv: MCValue, comptime _: []const u8, @@ -7936,70 +7971,50 @@ fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void { const extra = self.air.extraData(Air.Cmpxchg, ty_pl.payload).data; const ptr_ty = self.air.typeOf(extra.ptr); - const ptr_mcv = try self.resolveInst(extra.ptr); const val_ty = self.air.typeOf(extra.expected_value); const val_abi_size = @intCast(u32, val_ty.abiSize(self.target.*)); try self.spillRegisters(&.{ .rax, .rdx, .rbx, .rcx }); const regs_lock = self.register_manager.lockRegsAssumeUnused(4, .{ .rax, .rdx, .rbx, .rcx }); - for (regs_lock) |lock| self.register_manager.unlockReg(lock); + defer for (regs_lock) |lock| self.register_manager.unlockReg(lock); const exp_mcv = try self.resolveInst(extra.expected_value); - if (val_abi_size > 8) switch (exp_mcv) { - .load_frame => |frame_addr| { - try self.genSetReg(.rax, Type.usize, .{ .load_frame = .{ - .index = frame_addr.index, - .off = frame_addr.off + 0, - } }); - try self.genSetReg(.rdx, Type.usize, .{ .load_frame = .{ - .index = frame_addr.index, - .off = frame_addr.off + 8, - } }); - }, - else => return self.fail("TODO implement cmpxchg for {s}", .{@tagName(exp_mcv)}), + if (val_abi_size > 8) { + try self.genSetReg(.rax, Type.usize, exp_mcv); + try self.genSetReg(.rdx, Type.usize, exp_mcv.address().offset(8).deref()); } else try self.genSetReg(.rax, val_ty, exp_mcv); - const rax_lock = self.register_manager.lockRegAssumeUnused(.rax); - defer self.register_manager.unlockReg(rax_lock); const new_mcv = try self.resolveInst(extra.new_value); - const new_reg: Register = if (val_abi_size > 8) switch (new_mcv) { - .load_frame => |frame_addr| new: { - try self.genSetReg(.rbx, Type.usize, .{ .load_frame = .{ - .index = frame_addr.index, - .off = frame_addr.off + 0, - } }); - try self.genSetReg(.rcx, Type.usize, .{ .load_frame = .{ - .index = frame_addr.index, - .off = frame_addr.off + 8, - } }); - break :new undefined; - }, - else => return self.fail("TODO implement cmpxchg for {s}", .{@tagName(exp_mcv)}), + const new_reg = if (val_abi_size > 8) new: { + try self.genSetReg(.rbx, Type.usize, new_mcv); + try self.genSetReg(.rcx, Type.usize, new_mcv.address().offset(8).deref()); + break :new null; } else try self.copyToTmpRegister(val_ty, new_mcv); - const new_lock = self.register_manager.lockRegAssumeUnused(new_reg); - defer self.register_manager.unlockReg(new_lock); + const new_lock = if (new_reg) |reg| self.register_manager.lockRegAssumeUnused(reg) else null; + defer if (new_lock) |lock| self.register_manager.unlockReg(lock); + const ptr_mcv = try self.resolveInst(extra.ptr); const ptr_size = Memory.PtrSize.fromSize(val_abi_size); const ptr_mem = switch (ptr_mcv) { - .register => |reg| Memory.sib(ptr_size, .{ .base = .{ .reg = reg } }), - .lea_frame => |frame_addr| Memory.sib(ptr_size, .{ - .base = .{ .frame = frame_addr.index }, - .disp = frame_addr.off, + .immediate, .register, .register_offset, .lea_frame => ptr_mcv.deref().mem(ptr_size), + else => Memory.sib(ptr_size, .{ + .base = .{ .reg = try self.copyToTmpRegister(ptr_ty, ptr_mcv) }, }), - else => Memory.sib(ptr_size, .{ .base = .{ - .reg = try self.copyToTmpRegister(ptr_ty, ptr_mcv), - } }), }; - const mem_lock = switch (ptr_mem.base()) { + switch (ptr_mem) { + .sib, .rip => {}, + .moffs => return self.fail("TODO airCmpxchg with {s}", .{@tagName(ptr_mcv)}), + } + const ptr_lock = switch (ptr_mem.base()) { .none, .frame => null, .reg => |reg| self.register_manager.lockReg(reg), }; - defer if (mem_lock) |lock| self.register_manager.unlockReg(lock); + defer if (ptr_lock) |lock| self.register_manager.unlockReg(lock); try self.spillEflagsIfOccupied(); if (val_abi_size <= 8) { _ = try self.addInst(.{ .tag = .cmpxchg, .ops = .lock_mr_sib, .data = .{ .rx = .{ - .r = registerAlias(new_reg, val_abi_size), + .r = registerAlias(new_reg.?, val_abi_size), .payload = try self.addExtra(Mir.MemorySib.encode(ptr_mem)), } } }); } else { @@ -8017,24 +8032,9 @@ fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void { } const dst_mcv = try self.allocRegOrMem(inst, false); - try self.genSetMem( - .{ .frame = dst_mcv.load_frame.index }, - dst_mcv.load_frame.off + 16, - Type.bool, - .{ .eflags = .ne }, - ); - try self.genSetMem( - .{ .frame = dst_mcv.load_frame.index }, - dst_mcv.load_frame.off + 8, - Type.usize, - .{ .register = .rdx }, - ); - try self.genSetMem( - .{ .frame = dst_mcv.load_frame.index }, - dst_mcv.load_frame.off + 0, - Type.usize, - .{ .register = .rax }, - ); + try self.genCopy(Type.usize, dst_mcv, .{ .register = .rax }); + try self.genCopy(Type.usize, dst_mcv.address().offset(8).deref(), .{ .register = .rdx }); + try self.genCopy(Type.bool, dst_mcv.address().offset(16).deref(), .{ .eflags = .ne }); break :result dst_mcv; }; return self.finishAir(inst, result, .{ extra.ptr, extra.expected_value, extra.new_value }); @@ -8065,15 +8065,15 @@ fn atomicOp( const val_abi_size = @intCast(u32, val_ty.abiSize(self.target.*)); const ptr_size = Memory.PtrSize.fromSize(val_abi_size); const ptr_mem = switch (ptr_mcv) { - .register => |reg| Memory.sib(ptr_size, .{ .base = .{ .reg = reg } }), - .lea_frame => |frame_addr| Memory.sib(ptr_size, .{ - .base = .{ .frame = frame_addr.index }, - .disp = frame_addr.off, + .immediate, .register, .register_offset, .lea_frame => ptr_mcv.deref().mem(ptr_size), + else => Memory.sib(ptr_size, .{ + .base = .{ .reg = try self.copyToTmpRegister(ptr_ty, ptr_mcv) }, }), - else => Memory.sib(ptr_size, .{ .base = .{ - .reg = try self.copyToTmpRegister(ptr_ty, ptr_mcv), - } }), }; + switch (ptr_mem) { + .sib, .rip => {}, + .moffs => return self.fail("TODO airCmpxchg with {s}", .{@tagName(ptr_mcv)}), + } const mem_lock = switch (ptr_mem.base()) { .none, .frame => null, .reg => |reg| self.register_manager.lockReg(reg), From 00ae3592e6d054276b61404808d016dc2ef7ced5 Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Fri, 28 Apr 2023 19:38:18 -0400 Subject: [PATCH 036/725] test_runner: use const to control verbose output --- lib/test_runner.zig | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/lib/test_runner.zig b/lib/test_runner.zig index 20d7b02e26..f5bb0150a7 100644 --- a/lib/test_runner.zig +++ b/lib/test_runner.zig @@ -234,25 +234,33 @@ pub fn log( /// work-in-progress backends can handle it. pub fn mainSimple() anyerror!void { const enable_print = false; + const print_all = false; var passed: u64 = 0; var skipped: u64 = 0; var failed: u64 = 0; const stderr = if (enable_print) std.io.getStdErr() else {}; for (builtin.test_functions) |test_fn| { + if (enable_print and print_all) { + stderr.writeAll(test_fn.name) catch {}; + stderr.writeAll("... ") catch {}; + } test_fn.func() catch |err| { - if (enable_print) stderr.writeAll(test_fn.name) catch {}; + if (enable_print and !print_all) { + stderr.writeAll(test_fn.name) catch {}; + stderr.writeAll("... ") catch {}; + } if (err != error.SkipZigTest) { - if (enable_print) stderr.writeAll("... FAIL\n") catch {}; + if (enable_print) stderr.writeAll("FAIL\n") catch {}; failed += 1; if (!enable_print) return err; continue; } - if (enable_print) stderr.writeAll("... SKIP\n") catch {}; + if (enable_print) stderr.writeAll("SKIP\n") catch {}; skipped += 1; continue; }; - //if (enable_print) stderr.writeAll("... PASS\n") catch {}; + if (enable_print and print_all) stderr.writeAll("PASS\n") catch {}; passed += 1; } if (enable_print) { From c3889600424e3720dc07b22397129f82f2111d72 Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Fri, 28 Apr 2023 20:02:28 -0400 Subject: [PATCH 037/725] x86_64: fix large not and atomicrmw --- src/arch/x86_64/CodeGen.zig | 200 ++++++++++++++++-------------------- test/behavior/atomics.zig | 1 - test/behavior/math.zig | 1 - 3 files changed, 86 insertions(+), 116 deletions(-) diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 99b3c913a0..670dc6840c 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -2050,13 +2050,10 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { registerAlias(src_reg, min_abi_size), ); }, - .load_frame => |frame_addr| try self.asmRegisterMemory( + .memory, .indirect, .load_frame => try self.asmRegisterMemory( tag, dst_alias, - Memory.sib(Memory.PtrSize.fromSize(min_abi_size), .{ - .base = .{ .frame = frame_addr.index }, - .disp = frame_addr.off, - }), + src_mcv.mem(Memory.PtrSize.fromSize(min_abi_size)), ), else => return self.fail("TODO airIntCast from {s} to {s}", .{ @tagName(src_mcv), @@ -2738,19 +2735,9 @@ fn genIntMulDivOpMir( }; switch (mat_rhs) { .register => |reg| try self.asmRegister(tag, registerAlias(reg, abi_size)), - .indirect, .load_frame => try self.asmMemory( + .memory, .indirect, .load_frame => try self.asmMemory( tag, - Memory.sib(Memory.PtrSize.fromSize(abi_size), switch (mat_rhs) { - .indirect => |reg_off| .{ - .base = .{ .reg = reg_off.reg }, - .disp = reg_off.off, - }, - .load_frame => |frame_addr| .{ - .base = .{ .frame = frame_addr.index }, - .disp = frame_addr.off, - }, - else => unreachable, - }), + mat_rhs.mem(Memory.PtrSize.fromSize(abi_size)), ), else => unreachable, } @@ -4628,9 +4615,6 @@ fn genUnOp(self: *Self, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_air: if (src_ty.zigTypeTag() == .Vector) { return self.fail("TODO implement genUnOp for {}", .{src_ty.fmt(self.bin_file.options.module.?)}); } - if (src_ty.abiSize(self.target.*) > 8) { - return self.fail("TODO implement genUnOp for {}", .{src_ty.fmt(self.bin_file.options.module.?)}); - } switch (src_mcv) { .eflags => |cc| switch (tag) { @@ -4646,13 +4630,13 @@ fn genUnOp(self: *Self, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_air: }; defer if (src_lock) |lock| self.register_manager.unlockReg(lock); - const dst_mcv: MCValue = if (maybe_inst) |inst| - if (self.reuseOperand(inst, src_air, 0, src_mcv)) - src_mcv - else - try self.copyToRegisterWithInstTracking(inst, src_ty, src_mcv) - else - .{ .register = try self.copyToTmpRegister(src_ty, src_mcv) }; + const dst_mcv: MCValue = dst: { + if (maybe_inst) |inst| if (self.reuseOperand(inst, src_air, 0, src_mcv)) break :dst src_mcv; + + const dst_mcv = try self.allocRegOrMemAdvanced(src_ty, maybe_inst, true); + try self.genCopy(src_ty, dst_mcv, src_mcv); + break :dst dst_mcv; + }; const dst_lock = switch (dst_mcv) { .register => |reg| self.register_manager.lockReg(reg), else => null, @@ -4661,19 +4645,33 @@ fn genUnOp(self: *Self, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_air: switch (tag) { .not => { + const limb_abi_size = @intCast(u16, @min(src_ty.abiSize(self.target.*), 8)); const int_info = if (src_ty.tag() == .bool) std.builtin.Type.Int{ .signedness = .unsigned, .bits = 1 } else src_ty.intInfo(self.target.*); - const extra_bits = self.regExtraBits(src_ty); - if (int_info.signedness == .unsigned and extra_bits > 0) { - const mask = (@as(u64, 1) << @intCast(u6, src_ty.bitSize(self.target.*))) - 1; - try self.genBinOpMir(.xor, src_ty, dst_mcv, .{ .immediate = mask }); - } else try self.genUnOpMir(.not, src_ty, dst_mcv); + var byte_off: i32 = 0; + while (byte_off * 8 < int_info.bits) : (byte_off += limb_abi_size) { + var limb_pl = Type.Payload.Bits{ + .base = .{ .tag = switch (int_info.signedness) { + .signed => .int_signed, + .unsigned => .int_unsigned, + } }, + .data = @intCast(u16, @min(int_info.bits - byte_off * 8, limb_abi_size * 8)), + }; + const limb_ty = Type.initPayload(&limb_pl.base); + const limb_mcv = switch (byte_off) { + 0 => dst_mcv, + else => dst_mcv.address().offset(byte_off).deref(), + }; + + if (limb_pl.base.tag == .int_unsigned and self.regExtraBits(limb_ty) > 0) { + const mask = @as(u64, math.maxInt(u64)) >> @intCast(u6, 64 - limb_pl.data); + try self.genBinOpMir(.xor, limb_ty, limb_mcv, .{ .immediate = mask }); + } else try self.genUnOpMir(.not, limb_ty, limb_mcv); + } }, - .neg => try self.genUnOpMir(.neg, src_ty, dst_mcv), - else => unreachable, } return dst_mcv; @@ -4714,17 +4712,7 @@ fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValue }, .indirect, .load_frame => try self.asmMemory( mir_tag, - Memory.sib(Memory.PtrSize.fromSize(abi_size), switch (dst_mcv) { - .indirect => |reg_off| .{ - .base = .{ .reg = reg_off.reg }, - .disp = reg_off.off, - }, - .load_frame => |frame_addr| .{ - .base = .{ .frame = frame_addr.index }, - .disp = frame_addr.off, - }, - else => unreachable, - }), + dst_mcv.mem(Memory.PtrSize.fromSize(abi_size)), ), } } @@ -8179,12 +8167,9 @@ fn atomicOp( registerAlias(val_reg, cmov_abi_size), cc, ), - .load_frame => |frame_addr| try self.asmCmovccRegisterMemory( + .memory, .indirect, .load_frame => try self.asmCmovccRegisterMemory( registerAlias(tmp_reg, cmov_abi_size), - Memory.sib(Memory.PtrSize.fromSize(cmov_abi_size), .{ - .base = .{ .frame = frame_addr.index }, - .disp = frame_addr.off, - }), + val_mcv.mem(Memory.PtrSize.fromSize(cmov_abi_size)), cc, ), else => { @@ -8207,72 +8192,62 @@ fn atomicOp( } else { try self.asmRegisterMemory(.mov, .rax, Memory.sib(.qword, .{ .base = ptr_mem.sib.base, - .scale_index = ptr_mem.sib.scale_index, + .scale_index = ptr_mem.scaleIndex(), .disp = ptr_mem.sib.disp + 0, })); try self.asmRegisterMemory(.mov, .rdx, Memory.sib(.qword, .{ .base = ptr_mem.sib.base, - .scale_index = ptr_mem.sib.scale_index, + .scale_index = ptr_mem.scaleIndex(), .disp = ptr_mem.sib.disp + 8, })); const loop = @intCast(u32, self.mir_instructions.len); - switch (val_mcv) { - .load_frame => |frame_addr| { - const val_lo_mem = Memory.sib(.qword, .{ - .base = .{ .frame = frame_addr.index }, - .disp = frame_addr.off + 0, - }); - const val_hi_mem = Memory.sib(.qword, .{ - .base = .{ .frame = frame_addr.index }, - .disp = frame_addr.off + 8, - }); - - if (rmw_op != std.builtin.AtomicRmwOp.Xchg) { - try self.asmRegisterRegister(.mov, .rbx, .rax); - try self.asmRegisterRegister(.mov, .rcx, .rdx); - } - if (rmw_op) |op| switch (op) { - .Xchg => { - try self.asmRegisterMemory(.mov, .rbx, val_lo_mem); - try self.asmRegisterMemory(.mov, .rcx, val_hi_mem); - }, - .Add => { - try self.asmRegisterMemory(.add, .rbx, val_lo_mem); - try self.asmRegisterMemory(.adc, .rcx, val_hi_mem); - }, - .Sub => { - try self.asmRegisterMemory(.sub, .rbx, val_lo_mem); - try self.asmRegisterMemory(.sbb, .rcx, val_hi_mem); - }, - .And => { - try self.asmRegisterMemory(.@"and", .rbx, val_lo_mem); - try self.asmRegisterMemory(.@"and", .rcx, val_hi_mem); - }, - .Nand => { - try self.asmRegisterMemory(.@"and", .rbx, val_lo_mem); - try self.asmRegisterMemory(.@"and", .rcx, val_hi_mem); - try self.asmRegister(.not, .rbx); - try self.asmRegister(.not, .rcx); - }, - .Or => { - try self.asmRegisterMemory(.@"or", .rbx, val_lo_mem); - try self.asmRegisterMemory(.@"or", .rcx, val_hi_mem); - }, - .Xor => { - try self.asmRegisterMemory(.xor, .rbx, val_lo_mem); - try self.asmRegisterMemory(.xor, .rcx, val_hi_mem); - }, - else => return self.fail( - "TODO implement x86 atomic loop for large abi {s}", - .{@tagName(op)}, - ), - }; - }, - else => return self.fail( - "TODO implement x86 atomic loop for large abi {s}", - .{@tagName(val_mcv)}, - ), + const val_mem_mcv: MCValue = switch (val_mcv) { + .memory, .indirect, .load_frame => val_mcv, + else => .{ .indirect = .{ + .reg = try self.copyToTmpRegister(Type.usize, val_mcv.address()), + } }, + }; + const val_lo_mem = val_mem_mcv.mem(.qword); + const val_hi_mem = val_mem_mcv.address().offset(8).deref().mem(.qword); + if (rmw_op != std.builtin.AtomicRmwOp.Xchg) { + try self.asmRegisterRegister(.mov, .rbx, .rax); + try self.asmRegisterRegister(.mov, .rcx, .rdx); } + if (rmw_op) |op| switch (op) { + .Xchg => { + try self.asmRegisterMemory(.mov, .rbx, val_lo_mem); + try self.asmRegisterMemory(.mov, .rcx, val_hi_mem); + }, + .Add => { + try self.asmRegisterMemory(.add, .rbx, val_lo_mem); + try self.asmRegisterMemory(.adc, .rcx, val_hi_mem); + }, + .Sub => { + try self.asmRegisterMemory(.sub, .rbx, val_lo_mem); + try self.asmRegisterMemory(.sbb, .rcx, val_hi_mem); + }, + .And => { + try self.asmRegisterMemory(.@"and", .rbx, val_lo_mem); + try self.asmRegisterMemory(.@"and", .rcx, val_hi_mem); + }, + .Nand => { + try self.asmRegisterMemory(.@"and", .rbx, val_lo_mem); + try self.asmRegisterMemory(.@"and", .rcx, val_hi_mem); + try self.asmRegister(.not, .rbx); + try self.asmRegister(.not, .rcx); + }, + .Or => { + try self.asmRegisterMemory(.@"or", .rbx, val_lo_mem); + try self.asmRegisterMemory(.@"or", .rcx, val_hi_mem); + }, + .Xor => { + try self.asmRegisterMemory(.xor, .rbx, val_lo_mem); + try self.asmRegisterMemory(.xor, .rcx, val_hi_mem); + }, + else => return self.fail("TODO implement x86 atomic loop for {} {s}", .{ + val_ty.fmt(self.bin_file.options.module.?), @tagName(op), + }), + }; _ = try self.addInst(.{ .tag = .cmpxchgb, .ops = .lock_m_sib, .data = .{ .payload = try self.addExtra(Mir.MemorySib.encode(ptr_mem)), } }); @@ -9177,15 +9152,16 @@ fn truncateRegister(self: *Self, ty: Type, reg: Register) !void { } fn regBitSize(self: *Self, ty: Type) u64 { + const abi_size = ty.abiSize(self.target.*); return switch (ty.zigTypeTag()) { - else => switch (ty.abiSize(self.target.*)) { + else => switch (abi_size) { 1 => 8, 2 => 16, 3...4 => 32, 5...8 => 64, else => unreachable, }, - .Float => switch (ty.abiSize(self.target.*)) { + .Float => switch (abi_size) { 1...16 => 128, 17...32 => 256, else => unreachable, @@ -9197,10 +9173,6 @@ fn regExtraBits(self: *Self, ty: Type) u64 { return self.regBitSize(ty) - ty.bitSize(self.target.*); } -fn hasAvxSupport(target: Target) bool { - return Target.x86.featureSetHasAny(target.cpu.features, .{ .avx, .avx2 }); -} - fn getSymbolIndexForDecl(self: *Self, decl_index: Module.Decl.Index) !u32 { if (self.bin_file.cast(link.File.MachO)) |macho_file| { const atom = try macho_file.getOrCreateAtomForDecl(decl_index); diff --git a/test/behavior/atomics.zig b/test/behavior/atomics.zig index 19afa79683..56854d43d8 100644 --- a/test/behavior/atomics.zig +++ b/test/behavior/atomics.zig @@ -112,7 +112,6 @@ test "128-bit cmpxchg" { if (!supports_128_bit_atomics) return error.SkipZigTest; if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO diff --git a/test/behavior/math.zig b/test/behavior/math.zig index 03a92a83e9..01b927b913 100644 --- a/test/behavior/math.zig +++ b/test/behavior/math.zig @@ -379,7 +379,6 @@ fn testBinaryNot(x: u16) !void { test "binary not 128-bit" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO From 3c2636a83dbb964f80f93131b30222ad3889a7e9 Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Sat, 29 Apr 2023 17:58:09 -0400 Subject: [PATCH 038/725] x86_64: implement more forms of wide mul with overflow --- src/arch/x86_64/CodeGen.zig | 263 +++++++++++++++++------------------- 1 file changed, 122 insertions(+), 141 deletions(-) diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 670dc6840c..a09759951d 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -2434,12 +2434,7 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { const frame_index = try self.allocFrameIndex(FrameAlloc.initType(tuple_ty, self.target.*)); - try self.genSetFrameTruncatedOverflowCompare( - tuple_ty, - frame_index, - partial_mcv.register, - cc, - ); + try self.genSetFrameTruncatedOverflowCompare(tuple_ty, frame_index, partial_mcv, cc); break :result .{ .load_frame = .{ .index = frame_index } }; }, else => unreachable, @@ -2511,12 +2506,7 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { const frame_index = try self.allocFrameIndex(FrameAlloc.initType(tuple_ty, self.target.*)); - try self.genSetFrameTruncatedOverflowCompare( - tuple_ty, - frame_index, - partial_mcv.register, - cc, - ); + try self.genSetFrameTruncatedOverflowCompare(tuple_ty, frame_index, partial_mcv, cc); break :result .{ .load_frame = .{ .index = frame_index } }; }, else => unreachable, @@ -2529,173 +2519,164 @@ fn genSetFrameTruncatedOverflowCompare( self: *Self, tuple_ty: Type, frame_index: FrameIndex, - reg: Register, + src_mcv: MCValue, cc: Condition, ) !void { - const reg_lock = self.register_manager.lockReg(reg); - defer if (reg_lock) |lock| self.register_manager.unlockReg(lock); + const src_lock = switch (src_mcv) { + .register => |reg| self.register_manager.lockReg(reg), + else => null, + }; + defer if (src_lock) |lock| self.register_manager.unlockReg(lock); const ty = tuple_ty.structFieldType(0); const int_info = ty.intInfo(self.target.*); - const extended_ty = switch (int_info.signedness) { - .signed => Type.isize, - .unsigned => ty, + + var hi_limb_pl = Type.Payload.Bits{ + .base = .{ .tag = switch (int_info.signedness) { + .signed => .int_signed, + .unsigned => .int_unsigned, + } }, + .data = (int_info.bits - 1) % 64 + 1, }; + const hi_limb_ty = Type.initPayload(&hi_limb_pl.base); + + var rest_pl = Type.Payload.Bits{ + .base = .{ .tag = .int_unsigned }, + .data = int_info.bits - hi_limb_pl.data, + }; + const rest_ty = Type.initPayload(&rest_pl.base); const temp_regs = try self.register_manager.allocRegs(3, .{ null, null, null }, gp); - const temp_regs_locks = self.register_manager.lockRegsAssumeUnused(3, temp_regs); - defer for (temp_regs_locks) |rreg| { - self.register_manager.unlockReg(rreg); - }; + const temp_locks = self.register_manager.lockRegsAssumeUnused(3, temp_regs); + defer for (temp_locks) |lock| self.register_manager.unlockReg(lock); const overflow_reg = temp_regs[0]; try self.asmSetccRegister(overflow_reg.to8(), cc); const scratch_reg = temp_regs[1]; - try self.genSetReg(scratch_reg, extended_ty, .{ .register = reg }); - try self.truncateRegister(ty, scratch_reg); - try self.genBinOpMir( - .cmp, - extended_ty, - .{ .register = reg }, - .{ .register = scratch_reg }, - ); + const hi_limb_off = if (int_info.bits <= 64) 0 else (int_info.bits - 1) / 64 * 8; + const hi_limb_mcv = if (hi_limb_off > 0) + src_mcv.address().offset(int_info.bits / 64 * 8).deref() + else + src_mcv; + try self.genSetReg(scratch_reg, hi_limb_ty, hi_limb_mcv); + try self.truncateRegister(hi_limb_ty, scratch_reg); + try self.genBinOpMir(.cmp, hi_limb_ty, .{ .register = scratch_reg }, hi_limb_mcv); const eq_reg = temp_regs[2]; try self.asmSetccRegister(eq_reg.to8(), .ne); - try self.genBinOpMir( - .@"or", - Type.u8, - .{ .register = overflow_reg }, - .{ .register = eq_reg }, - ); + try self.genBinOpMir(.@"or", Type.u8, .{ .register = overflow_reg }, .{ .register = eq_reg }); + const payload_off = @intCast(i32, tuple_ty.structFieldOffset(0, self.target.*)); + if (hi_limb_off > 0) try self.genSetMem(.{ .frame = frame_index }, payload_off, rest_ty, src_mcv); + try self.genSetMem( + .{ .frame = frame_index }, + payload_off + hi_limb_off, + hi_limb_ty, + .{ .register = scratch_reg }, + ); try self.genSetMem( .{ .frame = frame_index }, @intCast(i32, tuple_ty.structFieldOffset(1, self.target.*)), tuple_ty.structFieldType(1), .{ .register = overflow_reg.to8() }, ); - try self.genSetMem( - .{ .frame = frame_index }, - @intCast(i32, tuple_ty.structFieldOffset(0, self.target.*)), - ty, - .{ .register = scratch_reg }, - ); } fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; - const result: MCValue = result: { - const dst_ty = self.air.typeOf(bin_op.lhs); - switch (dst_ty.zigTypeTag()) { - .Vector => return self.fail("TODO implement mul_with_overflow for Vector type", .{}), - .Int => { - try self.spillEflagsIfOccupied(); + const dst_ty = self.air.typeOf(bin_op.lhs); + const result: MCValue = switch (dst_ty.zigTypeTag()) { + .Vector => return self.fail("TODO implement mul_with_overflow for Vector type", .{}), + .Int => result: { + try self.spillEflagsIfOccupied(); + try self.spillRegisters(&.{ .rax, .rdx }); - const dst_info = dst_ty.intInfo(self.target.*); - const cc: Condition = switch (dst_info.signedness) { - .unsigned => .c, - .signed => .o, + const dst_info = dst_ty.intInfo(self.target.*); + const cc: Condition = switch (dst_info.signedness) { + .unsigned => .c, + .signed => .o, + }; + + const lhs_active_bits = self.activeIntBits(bin_op.lhs); + const rhs_active_bits = self.activeIntBits(bin_op.rhs); + var src_pl = Type.Payload.Bits{ .base = .{ .tag = switch (dst_info.signedness) { + .signed => .int_signed, + .unsigned => .int_unsigned, + } }, .data = math.max3(lhs_active_bits, rhs_active_bits, dst_info.bits / 2) }; + const src_ty = Type.initPayload(&src_pl.base); + + const lhs = try self.resolveInst(bin_op.lhs); + const rhs = try self.resolveInst(bin_op.rhs); + + const tuple_ty = self.air.typeOfIndex(inst); + const extra_bits = if (dst_info.bits <= 64) + self.regExtraBits(dst_ty) + else + dst_info.bits % 64; + const partial_mcv = if (dst_info.signedness == .signed and extra_bits > 0) dst: { + const rhs_lock: ?RegisterLock = switch (rhs) { + .register => |reg| self.register_manager.lockRegAssumeUnused(reg), + else => null, }; + defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); - const tuple_ty = self.air.typeOfIndex(inst); - if (dst_info.bits >= 8 and math.isPowerOfTwo(dst_info.bits)) { - var src_pl = Type.Payload.Bits{ .base = .{ .tag = switch (dst_info.signedness) { - .signed => .int_signed, - .unsigned => .int_unsigned, - } }, .data = math.max3( - self.activeIntBits(bin_op.lhs), - self.activeIntBits(bin_op.rhs), - dst_info.bits / 2, - ) }; - const src_ty = Type.initPayload(&src_pl.base); + const dst_reg: Register = blk: { + if (lhs.isRegister()) break :blk lhs.register; + break :blk try self.copyToTmpRegister(dst_ty, lhs); + }; + const dst_mcv = MCValue{ .register = dst_reg }; + const dst_reg_lock = self.register_manager.lockRegAssumeUnused(dst_reg); + defer self.register_manager.unlockReg(dst_reg_lock); - try self.spillRegisters(&.{ .rax, .rdx }); - const lhs = try self.resolveInst(bin_op.lhs); - const rhs = try self.resolveInst(bin_op.rhs); + const rhs_mcv: MCValue = blk: { + if (rhs.isRegister() or rhs.isMemory()) break :blk rhs; + break :blk MCValue{ .register = try self.copyToTmpRegister(dst_ty, rhs) }; + }; + const rhs_mcv_lock: ?RegisterLock = switch (rhs_mcv) { + .register => |reg| self.register_manager.lockReg(reg), + else => null, + }; + defer if (rhs_mcv_lock) |lock| self.register_manager.unlockReg(lock); - const partial_mcv = try self.genMulDivBinOp(.mul, null, dst_ty, src_ty, lhs, rhs); - switch (partial_mcv) { - .register => |reg| { - self.eflags_inst = inst; - break :result .{ .register_overflow = .{ .reg = reg, .eflags = cc } }; - }, - else => {}, - } + try self.genIntMulComplexOpMir(Type.isize, dst_mcv, rhs_mcv); + break :dst dst_mcv; + } else try self.genMulDivBinOp(.mul, null, dst_ty, src_ty, lhs, rhs); - // For now, this is the only supported multiply that doesn't fit in a register. - assert(dst_info.bits == 128 and src_pl.data == 64); + switch (partial_mcv) { + .register => |reg| if (extra_bits == 0) { + self.eflags_inst = inst; + break :result .{ .register_overflow = .{ .reg = reg, .eflags = cc } }; + } else { const frame_index = try self.allocFrameIndex(FrameAlloc.initType(tuple_ty, self.target.*)); - try self.genSetMem( - .{ .frame = frame_index }, - @intCast(i32, tuple_ty.structFieldOffset(1, self.target.*)), - tuple_ty.structFieldType(1), - .{ .immediate = 0 }, // overflow is impossible for 64-bit*64-bit -> 128-bit - ); - try self.genSetMem( - .{ .frame = frame_index }, - @intCast(i32, tuple_ty.structFieldOffset(0, self.target.*)), - tuple_ty.structFieldType(0), - partial_mcv, - ); + try self.genSetFrameTruncatedOverflowCompare(tuple_ty, frame_index, partial_mcv, cc); break :result .{ .load_frame = .{ .index = frame_index } }; - } + }, + // For now, this is the only supported multiply that doesn't fit in a register. + else => assert(dst_info.bits <= 128 and src_pl.data == 64), + } - const dst_reg: Register = dst_reg: { - switch (dst_info.signedness) { - .signed => { - const lhs = try self.resolveInst(bin_op.lhs); - const rhs = try self.resolveInst(bin_op.rhs); - - const rhs_lock: ?RegisterLock = switch (rhs) { - .register => |reg| self.register_manager.lockRegAssumeUnused(reg), - else => null, - }; - defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); - - const dst_reg: Register = blk: { - if (lhs.isRegister()) break :blk lhs.register; - break :blk try self.copyToTmpRegister(dst_ty, lhs); - }; - const dst_reg_lock = self.register_manager.lockRegAssumeUnused(dst_reg); - defer self.register_manager.unlockReg(dst_reg_lock); - - const rhs_mcv: MCValue = blk: { - if (rhs.isRegister() or rhs.isMemory()) break :blk rhs; - break :blk MCValue{ .register = try self.copyToTmpRegister(dst_ty, rhs) }; - }; - const rhs_mcv_lock: ?RegisterLock = switch (rhs_mcv) { - .register => |reg| self.register_manager.lockReg(reg), - else => null, - }; - defer if (rhs_mcv_lock) |lock| self.register_manager.unlockReg(lock); - - try self.genIntMulComplexOpMir(Type.isize, .{ .register = dst_reg }, rhs_mcv); - - break :dst_reg dst_reg; - }, - .unsigned => { - try self.spillRegisters(&.{ .rax, .rdx }); - - const lhs = try self.resolveInst(bin_op.lhs); - const rhs = try self.resolveInst(bin_op.rhs); - - const dst_mcv = try self.genMulDivBinOp(.mul, null, dst_ty, dst_ty, lhs, rhs); - break :dst_reg dst_mcv.register; - }, - } - }; - - const frame_index = - try self.allocFrameIndex(FrameAlloc.initType(tuple_ty, self.target.*)); - try self.genSetFrameTruncatedOverflowCompare(tuple_ty, frame_index, dst_reg, cc); - break :result .{ .load_frame = .{ .index = frame_index } }; - }, - else => unreachable, - } + const frame_index = + try self.allocFrameIndex(FrameAlloc.initType(tuple_ty, self.target.*)); + if (dst_info.bits >= lhs_active_bits + rhs_active_bits) { + try self.genSetMem( + .{ .frame = frame_index }, + @intCast(i32, tuple_ty.structFieldOffset(0, self.target.*)), + tuple_ty.structFieldType(0), + partial_mcv, + ); + try self.genSetMem( + .{ .frame = frame_index }, + @intCast(i32, tuple_ty.structFieldOffset(1, self.target.*)), + tuple_ty.structFieldType(1), + .{ .immediate = 0 }, // overflow is impossible for 64-bit*64-bit -> 128-bit + ); + } else try self.genSetFrameTruncatedOverflowCompare(tuple_ty, frame_index, partial_mcv, cc); + break :result .{ .load_frame = .{ .index = frame_index } }; + }, + else => unreachable, }; return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); } From c81878978a41f117818ac5b4918cd952f123bad7 Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Sat, 29 Apr 2023 17:56:48 -0400 Subject: [PATCH 039/725] x86_64: optimize wide mul with overflow --- src/arch/x86_64/CodeGen.zig | 61 ++++++++++++++++++++++--------------- 1 file changed, 36 insertions(+), 25 deletions(-) diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index a09759951d..7f0d07cf9b 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -2520,7 +2520,7 @@ fn genSetFrameTruncatedOverflowCompare( tuple_ty: Type, frame_index: FrameIndex, src_mcv: MCValue, - cc: Condition, + overflow_cc: ?Condition, ) !void { const src_lock = switch (src_mcv) { .register => |reg| self.register_manager.lockReg(reg), @@ -2551,7 +2551,7 @@ fn genSetFrameTruncatedOverflowCompare( defer for (temp_locks) |lock| self.register_manager.unlockReg(lock); const overflow_reg = temp_regs[0]; - try self.asmSetccRegister(overflow_reg.to8(), cc); + if (overflow_cc) |cc| try self.asmSetccRegister(overflow_reg.to8(), cc); const scratch_reg = temp_regs[1]; const hi_limb_off = if (int_info.bits <= 64) 0 else (int_info.bits - 1) / 64 * 8; @@ -2564,8 +2564,10 @@ fn genSetFrameTruncatedOverflowCompare( try self.genBinOpMir(.cmp, hi_limb_ty, .{ .register = scratch_reg }, hi_limb_mcv); const eq_reg = temp_regs[2]; - try self.asmSetccRegister(eq_reg.to8(), .ne); - try self.genBinOpMir(.@"or", Type.u8, .{ .register = overflow_reg }, .{ .register = eq_reg }); + if (overflow_cc) |_| { + try self.asmSetccRegister(eq_reg.to8(), .ne); + try self.genBinOpMir(.@"or", Type.u8, .{ .register = overflow_reg }, .{ .register = eq_reg }); + } const payload_off = @intCast(i32, tuple_ty.structFieldOffset(0, self.target.*)); if (hi_limb_off > 0) try self.genSetMem(.{ .frame = frame_index }, payload_off, rest_ty, src_mcv); @@ -2579,7 +2581,7 @@ fn genSetFrameTruncatedOverflowCompare( .{ .frame = frame_index }, @intCast(i32, tuple_ty.structFieldOffset(1, self.target.*)), tuple_ty.structFieldType(1), - .{ .register = overflow_reg.to8() }, + if (overflow_cc) |_| .{ .register = overflow_reg.to8() } else .{ .eflags = .ne }, ); } @@ -2654,27 +2656,36 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { try self.genSetFrameTruncatedOverflowCompare(tuple_ty, frame_index, partial_mcv, cc); break :result .{ .load_frame = .{ .index = frame_index } }; }, - // For now, this is the only supported multiply that doesn't fit in a register. - else => assert(dst_info.bits <= 128 and src_pl.data == 64), - } + else => { + // For now, this is the only supported multiply that doesn't fit in a register, + // so cc being set is impossible. - const frame_index = - try self.allocFrameIndex(FrameAlloc.initType(tuple_ty, self.target.*)); - if (dst_info.bits >= lhs_active_bits + rhs_active_bits) { - try self.genSetMem( - .{ .frame = frame_index }, - @intCast(i32, tuple_ty.structFieldOffset(0, self.target.*)), - tuple_ty.structFieldType(0), - partial_mcv, - ); - try self.genSetMem( - .{ .frame = frame_index }, - @intCast(i32, tuple_ty.structFieldOffset(1, self.target.*)), - tuple_ty.structFieldType(1), - .{ .immediate = 0 }, // overflow is impossible for 64-bit*64-bit -> 128-bit - ); - } else try self.genSetFrameTruncatedOverflowCompare(tuple_ty, frame_index, partial_mcv, cc); - break :result .{ .load_frame = .{ .index = frame_index } }; + assert(dst_info.bits <= 128 and src_pl.data == 64); + + const frame_index = + try self.allocFrameIndex(FrameAlloc.initType(tuple_ty, self.target.*)); + if (dst_info.bits >= lhs_active_bits + rhs_active_bits) { + try self.genSetMem( + .{ .frame = frame_index }, + @intCast(i32, tuple_ty.structFieldOffset(0, self.target.*)), + tuple_ty.structFieldType(0), + partial_mcv, + ); + try self.genSetMem( + .{ .frame = frame_index }, + @intCast(i32, tuple_ty.structFieldOffset(1, self.target.*)), + tuple_ty.structFieldType(1), + .{ .immediate = 0 }, + ); + } else try self.genSetFrameTruncatedOverflowCompare( + tuple_ty, + frame_index, + partial_mcv, + null, + ); + break :result .{ .load_frame = .{ .index = frame_index } }; + }, + } }, else => unreachable, }; From 10a4c2269d110d636e7817677fb50c6f418bff34 Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Sat, 29 Apr 2023 17:57:23 -0400 Subject: [PATCH 040/725] x86_64: enable normal start/test_runner logic on more targets --- lib/std/start.zig | 2 +- lib/test_runner.zig | 1 - test/src/Cases.zig | 6 ++++++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/std/start.zig b/lib/std/start.zig index 45e2e7da43..4177c9ba01 100644 --- a/lib/std/start.zig +++ b/lib/std/start.zig @@ -18,7 +18,7 @@ const start_sym_name = if (native_arch.isMIPS()) "__start" else "_start"; // Until then, we have simplified logic here for self-hosted. TODO remove this once // self-hosted is capable enough to handle all of the real start.zig logic. pub const simplified_logic = - (builtin.zig_backend == .stage2_x86_64 and (builtin.link_libc or builtin.os.tag == .plan9)) or + (builtin.zig_backend == .stage2_x86_64 and builtin.os.tag == .plan9) or builtin.zig_backend == .stage2_x86 or builtin.zig_backend == .stage2_aarch64 or builtin.zig_backend == .stage2_arm or diff --git a/lib/test_runner.zig b/lib/test_runner.zig index f5bb0150a7..8e29d90433 100644 --- a/lib/test_runner.zig +++ b/lib/test_runner.zig @@ -13,7 +13,6 @@ var fba = std.heap.FixedBufferAllocator.init(&cmdline_buffer); pub fn main() void { if (builtin.zig_backend == .stage2_wasm or - (builtin.zig_backend == .stage2_x86_64 and builtin.os.tag != .linux) or builtin.zig_backend == .stage2_aarch64) { return mainSimple() catch @panic("test failure"); diff --git a/test/src/Cases.zig b/test/src/Cases.zig index defe248fe6..4b023f45b0 100644 --- a/test/src/Cases.zig +++ b/test/src/Cases.zig @@ -396,6 +396,12 @@ fn addFromDirInner( // Other backends don't support new liveness format continue; } + if (backend == .stage2 and target.getOsTag() == .macos and + target.getCpuArch() == .x86_64 and builtin.cpu.arch == .aarch64) + { + // Rosetta has issues with ZLD + continue; + } const next = ctx.cases.items.len; try ctx.cases.append(.{ From f37ca3fa7370c501c630c53b370fecdeb313e3be Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Sat, 29 Apr 2023 19:31:34 -0400 Subject: [PATCH 041/725] link: cleanup lazy alignment This gets the alignment from the code that creates a lazy symbol instead of guessing it at every use. --- src/arch/x86_64/CodeGen.zig | 6 ------ src/codegen.zig | 8 ++++---- src/link/Coff.zig | 18 +++++------------- src/link/Elf.zig | 12 ++++-------- src/link/MachO.zig | 14 +++++--------- 5 files changed, 18 insertions(+), 40 deletions(-) diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 7f0d07cf9b..eee89e9ded 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -6416,7 +6416,6 @@ fn airCmpLtErrorsLen(self: *Self, inst: Air.Inst.Index) !void { if (self.bin_file.cast(link.File.Elf)) |elf_file| { const atom_index = try elf_file.getOrCreateAtomForLazySymbol( .{ .kind = .const_data, .ty = Type.anyerror }, - 4, // dword alignment ); const atom = elf_file.getAtom(atom_index); _ = try atom.getOrCreateOffsetTableEntry(elf_file); @@ -6429,14 +6428,12 @@ fn airCmpLtErrorsLen(self: *Self, inst: Air.Inst.Index) !void { } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { const atom_index = try coff_file.getOrCreateAtomForLazySymbol( .{ .kind = .const_data, .ty = Type.anyerror }, - 4, // dword alignment ); const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?; try self.genSetReg(addr_reg, Type.usize, .{ .lea_got = sym_index }); } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { const atom_index = try macho_file.getOrCreateAtomForLazySymbol( .{ .kind = .const_data, .ty = Type.anyerror }, - 4, // dword alignment ); const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?; try self.genSetReg(addr_reg, Type.usize, .{ .lea_got = sym_index }); @@ -8504,7 +8501,6 @@ fn airErrorName(self: *Self, inst: Air.Inst.Index) !void { if (self.bin_file.cast(link.File.Elf)) |elf_file| { const atom_index = try elf_file.getOrCreateAtomForLazySymbol( .{ .kind = .const_data, .ty = Type.anyerror }, - 4, // dword alignment ); const atom = elf_file.getAtom(atom_index); _ = try atom.getOrCreateOffsetTableEntry(elf_file); @@ -8517,14 +8513,12 @@ fn airErrorName(self: *Self, inst: Air.Inst.Index) !void { } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { const atom_index = try coff_file.getOrCreateAtomForLazySymbol( .{ .kind = .const_data, .ty = Type.anyerror }, - 4, // dword alignment ); const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?; try self.genSetReg(addr_reg, Type.usize, .{ .lea_got = sym_index }); } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { const atom_index = try macho_file.getOrCreateAtomForLazySymbol( .{ .kind = .const_data, .ty = Type.anyerror }, - 4, // dword alignment ); const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?; try self.genSetReg(addr_reg, Type.usize, .{ .lea_got = sym_index }); diff --git a/src/codegen.zig b/src/codegen.zig index f967566034..690e96d25c 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -104,7 +104,7 @@ pub fn generateLazySymbol( code: *std.ArrayList(u8), debug_output: DebugInfoOutput, reloc_info: RelocInfo, -) CodeGenError!Result { +) CodeGenError!struct { res: Result, alignment: u32 } { _ = debug_output; _ = reloc_info; @@ -133,13 +133,13 @@ pub fn generateLazySymbol( code.appendAssumeCapacity(0); } mem.writeInt(u32, code.items[offset..][0..4], @intCast(u32, code.items.len), endian); - return Result.ok; - } else return .{ .fail = try ErrorMsg.create( + return .{ .res = Result.ok, .alignment = 4 }; + } else return .{ .res = .{ .fail = try ErrorMsg.create( bin_file.allocator, src_loc, "TODO implement generateLazySymbol for {s} {}", .{ @tagName(lazy_sym.kind), lazy_sym.ty.fmt(mod) }, - ) }; + ) }, .alignment = undefined }; } pub fn generateSymbol( diff --git a/src/link/Coff.zig b/src/link/Coff.zig index 0af681bb5e..d20d17f2b1 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -145,7 +145,6 @@ const LazySymbolTable = std.AutoArrayHashMapUnmanaged(Module.Decl.OptionalIndex, const LazySymbolMetadata = struct { text_atom: ?Atom.Index = null, rdata_atom: ?Atom.Index = null, - alignment: u32, }; const DeclMetadata = struct { @@ -1195,13 +1194,11 @@ fn updateLazySymbol(self: *Coff, decl: Module.Decl.OptionalIndex, metadata: Lazy link.File.LazySymbol.initDecl(.code, decl, mod), atom, self.text_section_index.?, - metadata.alignment, ); if (metadata.rdata_atom) |atom| try self.updateLazySymbolAtom( link.File.LazySymbol.initDecl(.const_data, decl, mod), atom, self.rdata_section_index.?, - metadata.alignment, ); } @@ -1210,7 +1207,6 @@ fn updateLazySymbolAtom( sym: link.File.LazySymbol, atom_index: Atom.Index, section_index: u16, - required_alignment: u32, ) !void { const gpa = self.base.allocator; const mod = self.base.options.module.?; @@ -1238,7 +1234,7 @@ fn updateLazySymbolAtom( const res = try codegen.generateLazySymbol(&self.base, src, sym, &code_buffer, .none, .{ .parent_atom_index = local_sym_index, }); - const code = switch (res) { + const code = switch (res.res) { .ok => code_buffer.items, .fail => |em| { log.err("{s}", .{em.msg}); @@ -1252,11 +1248,11 @@ fn updateLazySymbolAtom( symbol.section_number = @intToEnum(coff.SectionNumber, section_index + 1); symbol.type = .{ .complex_type = .NULL, .base_type = .NULL }; - const vaddr = try self.allocateAtom(atom_index, code_len, required_alignment); + const vaddr = try self.allocateAtom(atom_index, code_len, res.alignment); errdefer self.freeAtom(atom_index); log.debug("allocated atom for {s} at 0x{x}", .{ name, vaddr }); - log.debug(" (required alignment 0x{x})", .{required_alignment}); + log.debug(" (required alignment 0x{x})", .{res.alignment}); atom.size = code_len; symbol.value = vaddr; @@ -1265,14 +1261,10 @@ fn updateLazySymbolAtom( try self.writeAtom(atom_index, code); } -pub fn getOrCreateAtomForLazySymbol( - self: *Coff, - sym: link.File.LazySymbol, - alignment: u32, -) !Atom.Index { +pub fn getOrCreateAtomForLazySymbol(self: *Coff, sym: link.File.LazySymbol) !Atom.Index { const gop = try self.lazy_syms.getOrPut(self.base.allocator, sym.getDecl()); errdefer _ = self.lazy_syms.pop(); - if (!gop.found_existing) gop.value_ptr.* = .{ .alignment = alignment }; + if (!gop.found_existing) gop.value_ptr.* = .{}; const atom = switch (sym.kind) { .code => &gop.value_ptr.text_atom, .const_data => &gop.value_ptr.rdata_atom, diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 48d952b6cc..b9c113f834 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -67,7 +67,6 @@ const Section = struct { const LazySymbolMetadata = struct { text_atom: ?Atom.Index = null, rodata_atom: ?Atom.Index = null, - alignment: u32, }; const DeclMetadata = struct { @@ -2377,10 +2376,10 @@ pub fn freeDecl(self: *Elf, decl_index: Module.Decl.Index) void { } } -pub fn getOrCreateAtomForLazySymbol(self: *Elf, sym: File.LazySymbol, alignment: u32) !Atom.Index { +pub fn getOrCreateAtomForLazySymbol(self: *Elf, sym: File.LazySymbol) !Atom.Index { const gop = try self.lazy_syms.getOrPut(self.base.allocator, sym.getDecl()); errdefer _ = self.lazy_syms.pop(); - if (!gop.found_existing) gop.value_ptr.* = .{ .alignment = alignment }; + if (!gop.found_existing) gop.value_ptr.* = .{}; const atom = switch (sym.kind) { .code => &gop.value_ptr.text_atom, .const_data => &gop.value_ptr.rodata_atom, @@ -2663,13 +2662,11 @@ fn updateLazySymbol(self: *Elf, decl: Module.Decl.OptionalIndex, metadata: LazyS File.LazySymbol.initDecl(.code, decl, mod), atom, self.text_section_index.?, - metadata.alignment, ); if (metadata.rodata_atom) |atom| try self.updateLazySymbolAtom( File.LazySymbol.initDecl(.const_data, decl, mod), atom, self.rodata_section_index.?, - metadata.alignment, ); } @@ -2678,7 +2675,6 @@ fn updateLazySymbolAtom( sym: File.LazySymbol, atom_index: Atom.Index, shdr_index: u16, - required_alignment: u32, ) !void { const gpa = self.base.allocator; const mod = self.base.options.module.?; @@ -2710,7 +2706,7 @@ fn updateLazySymbolAtom( const res = try codegen.generateLazySymbol(&self.base, src, sym, &code_buffer, .none, .{ .parent_atom_index = local_sym_index, }); - const code = switch (res) { + const code = switch (res.res) { .ok => code_buffer.items, .fail => |em| { log.err("{s}", .{em.msg}); @@ -2728,7 +2724,7 @@ fn updateLazySymbolAtom( .st_value = 0, .st_size = 0, }; - const vaddr = try self.allocateAtom(atom_index, code.len, required_alignment); + const vaddr = try self.allocateAtom(atom_index, code.len, res.alignment); errdefer self.freeAtom(atom_index); log.debug("allocated text block for {s} at 0x{x}", .{ name, vaddr }); diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 21633dea64..a57742507d 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -238,7 +238,6 @@ const LazySymbolTable = std.AutoArrayHashMapUnmanaged(Module.Decl.OptionalIndex, const LazySymbolMetadata = struct { text_atom: ?Atom.Index = null, data_const_atom: ?Atom.Index = null, - alignment: u32, }; const TlvSymbolTable = std.AutoArrayHashMapUnmanaged(SymbolWithLoc, Atom.Index); @@ -2043,13 +2042,11 @@ fn updateLazySymbol(self: *MachO, decl: Module.Decl.OptionalIndex, metadata: Laz File.LazySymbol.initDecl(.code, decl, mod), atom, self.text_section_index.?, - metadata.alignment, ); if (metadata.data_const_atom) |atom| try self.updateLazySymbolAtom( File.LazySymbol.initDecl(.const_data, decl, mod), atom, self.data_const_section_index.?, - metadata.alignment, ); } @@ -2058,7 +2055,6 @@ fn updateLazySymbolAtom( sym: File.LazySymbol, atom_index: Atom.Index, section_index: u8, - required_alignment: u32, ) !void { const gpa = self.base.allocator; const mod = self.base.options.module.?; @@ -2090,7 +2086,7 @@ fn updateLazySymbolAtom( const res = try codegen.generateLazySymbol(&self.base, src, sym, &code_buffer, .none, .{ .parent_atom_index = local_sym_index, }); - const code = switch (res) { + const code = switch (res.res) { .ok => code_buffer.items, .fail => |em| { log.err("{s}", .{em.msg}); @@ -2104,11 +2100,11 @@ fn updateLazySymbolAtom( symbol.n_sect = section_index + 1; symbol.n_desc = 0; - const vaddr = try self.allocateAtom(atom_index, code.len, required_alignment); + const vaddr = try self.allocateAtom(atom_index, code.len, res.alignment); errdefer self.freeAtom(atom_index); log.debug("allocated atom for {s} at 0x{x}", .{ name, vaddr }); - log.debug(" (required alignment 0x{x}", .{required_alignment}); + log.debug(" (required alignment 0x{x}", .{res.alignment}); atom.size = code.len; symbol.n_value = vaddr; @@ -2117,10 +2113,10 @@ fn updateLazySymbolAtom( try self.writeAtom(atom_index, code); } -pub fn getOrCreateAtomForLazySymbol(self: *MachO, sym: File.LazySymbol, alignment: u32) !Atom.Index { +pub fn getOrCreateAtomForLazySymbol(self: *MachO, sym: File.LazySymbol) !Atom.Index { const gop = try self.lazy_syms.getOrPut(self.base.allocator, sym.getDecl()); errdefer _ = self.lazy_syms.pop(); - if (!gop.found_existing) gop.value_ptr.* = .{ .alignment = alignment }; + if (!gop.found_existing) gop.value_ptr.* = .{}; const atom = switch (sym.kind) { .code => &gop.value_ptr.text_atom, .const_data => &gop.value_ptr.data_const_atom, From 372bc960b8315ea1ff17b369b0b33485d5e34cfb Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Sat, 29 Apr 2023 19:57:44 -0400 Subject: [PATCH 042/725] link: update decl-specific lazy symbols --- src/link.zig | 4 ++-- src/link/Coff.zig | 23 ++++++++++++++--------- src/link/Elf.zig | 23 ++++++++++++++--------- src/link/MachO.zig | 17 +++++++++-------- 4 files changed, 39 insertions(+), 28 deletions(-) diff --git a/src/link.zig b/src/link.zig index 672a53999f..74e3ca85fc 100644 --- a/src/link.zig +++ b/src/link.zig @@ -1120,8 +1120,8 @@ pub const File = struct { kind: Kind, ty: Type, - pub fn initDecl(kind: Kind, decl: Module.Decl.OptionalIndex, mod: *Module) LazySymbol { - return .{ .kind = kind, .ty = if (decl.unwrap()) |decl_index| + pub fn initDecl(kind: Kind, decl: ?Module.Decl.Index, mod: *Module) LazySymbol { + return .{ .kind = kind, .ty = if (decl) |decl_index| mod.declPtr(decl_index).val.castTag(.ty).?.data else Type.anyerror }; diff --git a/src/link/Coff.zig b/src/link/Coff.zig index d20d17f2b1..deac8d1fd6 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -1136,7 +1136,11 @@ pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.In return atom.getSymbolIndex().?; } -pub fn updateDecl(self: *Coff, module: *Module, decl_index: Module.Decl.Index) !void { +pub fn updateDecl( + self: *Coff, + module: *Module, + decl_index: Module.Decl.Index, +) link.File.UpdateDeclError!void { if (build_options.skip_non_native and builtin.object_format != .coff) { @panic("Attempted to compile for object format that was disabled by build configuration"); } @@ -1146,6 +1150,8 @@ pub fn updateDecl(self: *Coff, module: *Module, decl_index: Module.Decl.Index) ! const tracy = trace(@src()); defer tracy.end(); + try self.updateLazySymbol(decl_index); + const decl = module.declPtr(decl_index); if (decl.val.tag() == .extern_fn) { @@ -1188,7 +1194,8 @@ pub fn updateDecl(self: *Coff, module: *Module, decl_index: Module.Decl.Index) ! return self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index)); } -fn updateLazySymbol(self: *Coff, decl: Module.Decl.OptionalIndex, metadata: LazySymbolMetadata) !void { +fn updateLazySymbol(self: *Coff, decl: ?Module.Decl.Index) !void { + const metadata = self.lazy_syms.get(Module.Decl.OptionalIndex.init(decl)) orelse return; const mod = self.base.options.module.?; if (metadata.text_atom) |atom| try self.updateLazySymbolAtom( link.File.LazySymbol.initDecl(.code, decl, mod), @@ -1402,7 +1409,7 @@ pub fn updateDeclExports( module: *Module, decl_index: Module.Decl.Index, exports: []const *Module.Export, -) !void { +) link.File.UpdateDeclExportsError!void { if (build_options.skip_non_native and builtin.object_format != .coff) { @panic("Attempted to compile for object format that was disabled by build configuration"); } @@ -1599,12 +1606,10 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod // Most lazy symbols can be updated when the corresponding decl is, // so we only have to worry about the one without an associated decl. - if (self.lazy_syms.get(.none)) |metadata| { - self.updateLazySymbol(.none, metadata) catch |err| switch (err) { - error.CodegenFail => return error.FlushFailure, - else => |e| return e, - }; - } + self.updateLazySymbol(null) catch |err| switch (err) { + error.CodegenFail => return error.FlushFailure, + else => |e| return e, + }; const gpa = self.base.allocator; diff --git a/src/link/Elf.zig b/src/link/Elf.zig index b9c113f834..29ae97150e 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -1034,12 +1034,10 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node // Most lazy symbols can be updated when the corresponding decl is, // so we only have to worry about the one without an associated decl. - if (self.lazy_syms.get(.none)) |metadata| { - self.updateLazySymbol(.none, metadata) catch |err| switch (err) { - error.CodegenFail => return error.FlushFailure, - else => |e| return e, - }; - } + self.updateLazySymbol(null) catch |err| switch (err) { + error.CodegenFail => return error.FlushFailure, + else => |e| return e, + }; // TODO This linker code currently assumes there is only 1 compilation unit and it // corresponds to the Zig source code. @@ -2579,7 +2577,11 @@ pub fn updateFunc(self: *Elf, module: *Module, func: *Module.Fn, air: Air, liven return self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index)); } -pub fn updateDecl(self: *Elf, module: *Module, decl_index: Module.Decl.Index) !void { +pub fn updateDecl( + self: *Elf, + module: *Module, + decl_index: Module.Decl.Index, +) File.UpdateDeclError!void { if (build_options.skip_non_native and builtin.object_format != .elf) { @panic("Attempted to compile for object format that was disabled by build configuration"); } @@ -2590,6 +2592,8 @@ pub fn updateDecl(self: *Elf, module: *Module, decl_index: Module.Decl.Index) !v const tracy = trace(@src()); defer tracy.end(); + try self.updateLazySymbol(decl_index); + const decl = module.declPtr(decl_index); if (decl.val.tag() == .extern_fn) { @@ -2656,7 +2660,8 @@ pub fn updateDecl(self: *Elf, module: *Module, decl_index: Module.Decl.Index) !v return self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index)); } -fn updateLazySymbol(self: *Elf, decl: Module.Decl.OptionalIndex, metadata: LazySymbolMetadata) !void { +fn updateLazySymbol(self: *Elf, decl: ?Module.Decl.Index) !void { + const metadata = self.lazy_syms.get(Module.Decl.OptionalIndex.init(decl)) orelse return; const mod = self.base.options.module.?; if (metadata.text_atom) |atom| try self.updateLazySymbolAtom( File.LazySymbol.initDecl(.code, decl, mod), @@ -2810,7 +2815,7 @@ pub fn updateDeclExports( module: *Module, decl_index: Module.Decl.Index, exports: []const *Module.Export, -) !void { +) File.UpdateDeclExportsError!void { if (build_options.skip_non_native and builtin.object_format != .elf) { @panic("Attempted to compile for object format that was disabled by build configuration"); } diff --git a/src/link/MachO.zig b/src/link/MachO.zig index a57742507d..5136bd84a2 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -495,12 +495,10 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No // Most lazy symbols can be updated when the corresponding decl is, // so we only have to worry about the one without an associated decl. - if (self.lazy_syms.get(.none)) |metadata| { - self.updateLazySymbol(.none, metadata) catch |err| switch (err) { - error.CodegenFail => return error.FlushFailure, - else => |e| return e, - }; - } + self.updateLazySymbol(null) catch |err| switch (err) { + error.CodegenFail => return error.FlushFailure, + else => |e| return e, + }; const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented; @@ -1962,6 +1960,8 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index) const tracy = trace(@src()); defer tracy.end(); + try self.updateLazySymbol(decl_index); + const decl = module.declPtr(decl_index); if (decl.val.tag() == .extern_fn) { @@ -2036,7 +2036,8 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index) try self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index)); } -fn updateLazySymbol(self: *MachO, decl: Module.Decl.OptionalIndex, metadata: LazySymbolMetadata) !void { +fn updateLazySymbol(self: *MachO, decl: ?Module.Decl.Index) !void { + const metadata = self.lazy_syms.get(Module.Decl.OptionalIndex.init(decl)) orelse return; const mod = self.base.options.module.?; if (metadata.text_atom) |atom| try self.updateLazySymbolAtom( File.LazySymbol.initDecl(.code, decl, mod), @@ -2353,7 +2354,7 @@ pub fn updateDeclExports( module: *Module, decl_index: Module.Decl.Index, exports: []const *Module.Export, -) !void { +) File.UpdateDeclExportsError!void { if (build_options.skip_non_native and builtin.object_format != .macho) { @panic("Attempted to compile for object format that was disabled by build configuration"); } From 19bd7d12b0186f0e45c77c564251d6355966b2ef Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Sun, 30 Apr 2023 07:30:32 -0400 Subject: [PATCH 043/725] x86_64: factor out lazy_sym --- src/arch/x86_64/CodeGen.zig | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index eee89e9ded..99fb516b45 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -6413,10 +6413,10 @@ fn airCmpLtErrorsLen(self: *Self, inst: Air.Inst.Index) !void { const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg); defer self.register_manager.unlockReg(addr_lock); + const mod = self.bin_file.options.module.?; + const lazy_sym = link.File.LazySymbol.initDecl(.const_data, null, mod); if (self.bin_file.cast(link.File.Elf)) |elf_file| { - const atom_index = try elf_file.getOrCreateAtomForLazySymbol( - .{ .kind = .const_data, .ty = Type.anyerror }, - ); + const atom_index = try elf_file.getOrCreateAtomForLazySymbol(lazy_sym); const atom = elf_file.getAtom(atom_index); _ = try atom.getOrCreateOffsetTableEntry(elf_file); const got_addr = atom.getOffsetTableAddress(elf_file); @@ -6426,15 +6426,11 @@ fn airCmpLtErrorsLen(self: *Self, inst: Air.Inst.Index) !void { Memory.sib(.qword, .{ .base = .{ .reg = .ds }, .disp = @intCast(i32, got_addr) }), ); } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { - const atom_index = try coff_file.getOrCreateAtomForLazySymbol( - .{ .kind = .const_data, .ty = Type.anyerror }, - ); + const atom_index = try coff_file.getOrCreateAtomForLazySymbol(lazy_sym); const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?; try self.genSetReg(addr_reg, Type.usize, .{ .lea_got = sym_index }); } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { - const atom_index = try macho_file.getOrCreateAtomForLazySymbol( - .{ .kind = .const_data, .ty = Type.anyerror }, - ); + const atom_index = try macho_file.getOrCreateAtomForLazySymbol(lazy_sym); const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?; try self.genSetReg(addr_reg, Type.usize, .{ .lea_got = sym_index }); } else { @@ -8498,10 +8494,10 @@ fn airErrorName(self: *Self, inst: Air.Inst.Index) !void { const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg); defer self.register_manager.unlockReg(addr_lock); + const mod = self.bin_file.options.module.?; + const lazy_sym = link.File.LazySymbol.initDecl(.const_data, null, mod); if (self.bin_file.cast(link.File.Elf)) |elf_file| { - const atom_index = try elf_file.getOrCreateAtomForLazySymbol( - .{ .kind = .const_data, .ty = Type.anyerror }, - ); + const atom_index = try elf_file.getOrCreateAtomForLazySymbol(lazy_sym); const atom = elf_file.getAtom(atom_index); _ = try atom.getOrCreateOffsetTableEntry(elf_file); const got_addr = atom.getOffsetTableAddress(elf_file); @@ -8511,15 +8507,11 @@ fn airErrorName(self: *Self, inst: Air.Inst.Index) !void { Memory.sib(.qword, .{ .base = .{ .reg = .ds }, .disp = @intCast(i32, got_addr) }), ); } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { - const atom_index = try coff_file.getOrCreateAtomForLazySymbol( - .{ .kind = .const_data, .ty = Type.anyerror }, - ); + const atom_index = try coff_file.getOrCreateAtomForLazySymbol(lazy_sym); const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?; try self.genSetReg(addr_reg, Type.usize, .{ .lea_got = sym_index }); } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { - const atom_index = try macho_file.getOrCreateAtomForLazySymbol( - .{ .kind = .const_data, .ty = Type.anyerror }, - ); + const atom_index = try macho_file.getOrCreateAtomForLazySymbol(lazy_sym); const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?; try self.genSetReg(addr_reg, Type.usize, .{ .lea_got = sym_index }); } else { From 0489a63a432b31ce0fd9d6ec6c8e2fb72a920573 Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Sun, 30 Apr 2023 21:13:29 -0400 Subject: [PATCH 044/725] Sema: use trap for backends that don't support panic_fn Debuggers also catch trap, but the code is not allowed to continue. --- src/Sema.zig | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/Sema.zig b/src/Sema.zig index 71a1215dcd..79f2fd7fca 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -23287,8 +23287,7 @@ fn panicWithMsg( const arena = sema.arena; if (!mod.backendSupportsFeature(.panic_fn)) { - _ = try block.addNoOp(.breakpoint); - _ = try block.addNoOp(.unreach); + _ = try block.addNoOp(.trap); return; } const panic_fn = try sema.getBuiltin("panic"); @@ -23336,8 +23335,7 @@ fn panicUnwrapError( { if (!sema.mod.backendSupportsFeature(.panic_unwrap_error)) { - _ = try fail_block.addNoOp(.breakpoint); - _ = try fail_block.addNoOp(.unreach); + _ = try fail_block.addNoOp(.trap); } else { const panic_fn = try sema.getBuiltin("panicUnwrapError"); const err = try fail_block.addTyOp(unwrap_err_tag, Type.anyerror, operand); @@ -23462,8 +23460,7 @@ fn safetyCheckFormatted( defer fail_block.instructions.deinit(gpa); if (!sema.mod.backendSupportsFeature(.safety_check_formatted)) { - _ = try fail_block.addNoOp(.breakpoint); - _ = try fail_block.addNoOp(.unreach); + _ = try fail_block.addNoOp(.trap); } else { const panic_fn = try sema.getBuiltin(func); _ = try sema.analyzeCall(&fail_block, panic_fn, sema.src, sema.src, .auto, false, args, null); From 47a34d038dd114533c3fcb130e03249ad846fe9c Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Sun, 30 Apr 2023 21:47:19 -0400 Subject: [PATCH 045/725] x86_64: implement tagName --- src/arch/x86_64/CodeGen.zig | 292 ++++++++++++++++++++++++++++++++---- src/codegen.zig | 40 ++++- src/link/Coff.zig | 33 ++-- src/link/Elf.zig | 31 ++-- src/link/MachO.zig | 33 ++-- test/behavior/enum.zig | 5 - test/behavior/memset.zig | 2 - test/behavior/type.zig | 2 - test/behavior/union.zig | 1 - 9 files changed, 368 insertions(+), 71 deletions(-) diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 99fb516b45..71dcbfa461 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -56,7 +56,10 @@ liveness: Liveness, bin_file: *link.File, debug_output: DebugInfoOutput, target: *const std.Target, -mod_fn: *const Module.Fn, +owner: union(enum) { + mod_fn: *const Module.Fn, + decl: Module.Decl.Index, +}, err_msg: ?*ErrorMsg, args: []MCValue, ret_mcv: InstTracking, @@ -617,7 +620,7 @@ pub fn generate( .target = &bin_file.options.target, .bin_file = bin_file, .debug_output = debug_output, - .mod_fn = module_fn, + .owner = .{ .mod_fn = module_fn }, .err_msg = null, .args = undefined, // populated after `resolveCallingConventionValues` .ret_mcv = undefined, // populated after `resolveCallingConventionValues` @@ -745,6 +748,92 @@ pub fn generate( } } +pub fn generateLazy( + bin_file: *link.File, + src_loc: Module.SrcLoc, + lazy_sym: link.File.LazySymbol, + code: *std.ArrayList(u8), + debug_output: DebugInfoOutput, +) CodeGenError!Result { + const gpa = bin_file.allocator; + var function = Self{ + .gpa = gpa, + .air = undefined, + .liveness = undefined, + .target = &bin_file.options.target, + .bin_file = bin_file, + .debug_output = debug_output, + .owner = .{ .decl = lazy_sym.ty.getOwnerDecl() }, + .err_msg = null, + .args = undefined, + .ret_mcv = undefined, + .fn_type = undefined, + .arg_index = undefined, + .src_loc = src_loc, + .end_di_line = undefined, // no debug info yet + .end_di_column = undefined, // no debug info yet + }; + defer { + function.mir_instructions.deinit(gpa); + function.mir_extra.deinit(gpa); + } + + function.genLazy(lazy_sym) catch |err| switch (err) { + error.CodegenFail => return Result{ .fail = function.err_msg.? }, + error.OutOfRegisters => return Result{ + .fail = try ErrorMsg.create(bin_file.allocator, src_loc, "CodeGen ran out of registers. This is a bug in the Zig compiler.", .{}), + }, + else => |e| return e, + }; + + var mir = Mir{ + .instructions = function.mir_instructions.toOwnedSlice(), + .extra = try function.mir_extra.toOwnedSlice(bin_file.allocator), + .frame_locs = function.frame_locs.toOwnedSlice(), + }; + defer mir.deinit(bin_file.allocator); + + var emit = Emit{ + .lower = .{ + .allocator = bin_file.allocator, + .mir = mir, + .target = &bin_file.options.target, + .src_loc = src_loc, + }, + .bin_file = bin_file, + .debug_output = debug_output, + .code = code, + .prev_di_pc = undefined, // no debug info yet + .prev_di_line = undefined, // no debug info yet + .prev_di_column = undefined, // no debug info yet + }; + defer emit.deinit(); + emit.emitMir() catch |err| switch (err) { + error.LowerFail, error.EmitFail => return Result{ .fail = emit.lower.err_msg.? }, + error.InvalidInstruction, error.CannotEncode => |e| { + const msg = switch (e) { + error.InvalidInstruction => "CodeGen failed to find a viable instruction.", + error.CannotEncode => "CodeGen failed to encode the instruction.", + }; + return Result{ + .fail = try ErrorMsg.create( + bin_file.allocator, + src_loc, + "{s} This is a bug in the Zig compiler.", + .{msg}, + ), + }; + }, + else => |e| return e, + }; + + if (function.err_msg) |em| { + return Result{ .fail = em }; + } else { + return Result.ok; + } +} + const FormatDeclData = struct { mod: *Module, decl_index: Module.Decl.Index, @@ -1545,6 +1634,103 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { verbose_tracking_log.debug("{}", .{self.fmtTracking()}); } +fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void { + switch (lazy_sym.ty.zigTypeTag()) { + .Enum => { + const enum_ty = lazy_sym.ty; + wip_mir_log.debug("{}.@tagName:", .{enum_ty.fmt(self.bin_file.options.module.?)}); + + const param_regs = abi.getCAbiIntParamRegs(self.target.*); + const param_locks = self.register_manager.lockRegsAssumeUnused(2, param_regs[0..2].*); + defer for (param_locks) |lock| self.register_manager.unlockReg(lock); + + const ret_reg = param_regs[0]; + const enum_mcv = MCValue{ .register = param_regs[1] }; + + var exitlude_jump_relocs = try self.gpa.alloc(u32, enum_ty.enumFieldCount()); + defer self.gpa.free(exitlude_jump_relocs); + + const data_reg = try self.register_manager.allocReg(null, gp); + const data_lock = self.register_manager.lockRegAssumeUnused(data_reg); + defer self.register_manager.unlockReg(data_lock); + + const data_lazy_sym = link.File.LazySymbol{ .kind = .const_data, .ty = enum_ty }; + if (self.bin_file.cast(link.File.Elf)) |elf_file| { + const atom_index = elf_file.getOrCreateAtomForLazySymbol(data_lazy_sym) catch |err| + return self.fail("{s} creating lazy symbol", .{@errorName(err)}); + const atom = elf_file.getAtom(atom_index); + _ = try atom.getOrCreateOffsetTableEntry(elf_file); + const got_addr = atom.getOffsetTableAddress(elf_file); + try self.asmRegisterMemory( + .mov, + data_reg.to64(), + Memory.sib(.qword, .{ .base = .{ .reg = .ds }, .disp = @intCast(i32, got_addr) }), + ); + } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { + const atom_index = coff_file.getOrCreateAtomForLazySymbol(data_lazy_sym) catch |err| + return self.fail("{s} creating lazy symbol", .{@errorName(err)}); + const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?; + try self.genSetReg(data_reg, Type.usize, .{ .lea_got = sym_index }); + } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { + const atom_index = macho_file.getOrCreateAtomForLazySymbol(data_lazy_sym) catch |err| + return self.fail("{s} creating lazy symbol", .{@errorName(err)}); + const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?; + try self.genSetReg(data_reg, Type.usize, .{ .lea_got = sym_index }); + } else { + return self.fail("TODO implement {s} for {}", .{ + @tagName(lazy_sym.kind), + lazy_sym.ty.fmt(self.bin_file.options.module.?), + }); + } + + var data_off: i32 = 0; + for ( + exitlude_jump_relocs, + enum_ty.enumFields().keys(), + 0.., + ) |*exitlude_jump_reloc, tag_name, index| { + var tag_pl = Value.Payload.U32{ + .base = .{ .tag = .enum_field_index }, + .data = @intCast(u32, index), + }; + const tag_val = Value.initPayload(&tag_pl.base); + const tag_mcv = try self.genTypedValue(.{ .ty = enum_ty, .val = tag_val }); + try self.genBinOpMir(.cmp, enum_ty, enum_mcv, tag_mcv); + const skip_reloc = try self.asmJccReloc(undefined, .ne); + + try self.genSetMem( + .{ .reg = ret_reg }, + 0, + Type.usize, + .{ .register_offset = .{ .reg = data_reg, .off = data_off } }, + ); + try self.genSetMem(.{ .reg = ret_reg }, 8, Type.usize, .{ .immediate = tag_name.len }); + + exitlude_jump_reloc.* = try self.asmJmpReloc(undefined); + try self.performReloc(skip_reloc); + + data_off += @intCast(i32, tag_name.len + 1); + } + + try self.airTrap(); + + for (exitlude_jump_relocs) |reloc| try self.performReloc(reloc); + try self.asmOpOnly(.ret); + }, + else => return self.fail( + "TODO implement {s} for {}", + .{ @tagName(lazy_sym.kind), lazy_sym.ty.fmt(self.bin_file.options.module.?) }, + ), + } +} + +fn getOwnerDecl(self: *const Self) Module.Decl.Index { + return switch (self.owner) { + .mod_fn => |mod_fn| mod_fn.owner_decl, + .decl => |index| index, + }; +} + fn getValue(self: *Self, value: MCValue, inst: ?Air.Inst.Index) void { const reg = value.getReg() orelse return; if (self.register_manager.isRegFree(reg)) { @@ -6020,7 +6206,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { const ty = self.air.typeOfIndex(inst); const src_index = self.air.instructions.items(.data)[inst].arg.src_index; - const name = self.mod_fn.getParamName(self.bin_file.options.module.?, src_index); + const name = self.owner.mod_fn.getParamName(self.bin_file.options.module.?, src_index); try self.genArgDbgInfo(ty, name, dst_mcv); break :result dst_mcv; @@ -6044,7 +6230,7 @@ fn genArgDbgInfo(self: Self, ty: Type, name: [:0]const u8, mcv: MCValue) !void { //}, else => unreachable, // not a valid function parameter }; - try dw.genArgDbgInfo(name, ty, self.mod_fn.owner_decl, loc); + try dw.genArgDbgInfo(name, ty, self.getOwnerDecl(), loc); }, .plan9 => {}, .none => {}, @@ -6085,7 +6271,7 @@ fn genVarDbgInfo( break :blk .nop; }, }; - try dw.genVarDbgInfo(name, ty, self.mod_fn.owner_decl, is_ptr, loc); + try dw.genVarDbgInfo(name, ty, self.getOwnerDecl(), is_ptr, loc); }, .plan9 => {}, .none => {}, @@ -6243,7 +6429,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier const decl_name = mem.sliceTo(mod.declPtr(extern_fn.owner_decl).name, 0); const lib_name = mem.sliceTo(extern_fn.lib_name, 0); if (self.bin_file.cast(link.File.Coff)) |coff_file| { - const atom_index = try self.getSymbolIndexForDecl(self.mod_fn.owner_decl); + const atom_index = try self.getSymbolIndexForDecl(self.getOwnerDecl()); const sym_index = try coff_file.getGlobalSymbol(decl_name, lib_name); _ = try self.addInst(.{ .tag = .mov_linker, @@ -6257,7 +6443,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier try self.asmRegister(.call, .rax); } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { const sym_index = try macho_file.getGlobalSymbol(decl_name, lib_name); - const atom_index = try self.getSymbolIndexForDecl(self.mod_fn.owner_decl); + const atom_index = try self.getSymbolIndexForDecl(self.getOwnerDecl()); _ = try self.addInst(.{ .tag = .call_extern, .ops = undefined, @@ -6416,7 +6602,8 @@ fn airCmpLtErrorsLen(self: *Self, inst: Air.Inst.Index) !void { const mod = self.bin_file.options.module.?; const lazy_sym = link.File.LazySymbol.initDecl(.const_data, null, mod); if (self.bin_file.cast(link.File.Elf)) |elf_file| { - const atom_index = try elf_file.getOrCreateAtomForLazySymbol(lazy_sym); + const atom_index = elf_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err| + return self.fail("{s} creating lazy symbol", .{@errorName(err)}); const atom = elf_file.getAtom(atom_index); _ = try atom.getOrCreateOffsetTableEntry(elf_file); const got_addr = atom.getOffsetTableAddress(elf_file); @@ -6426,11 +6613,13 @@ fn airCmpLtErrorsLen(self: *Self, inst: Air.Inst.Index) !void { Memory.sib(.qword, .{ .base = .{ .reg = .ds }, .disp = @intCast(i32, got_addr) }), ); } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { - const atom_index = try coff_file.getOrCreateAtomForLazySymbol(lazy_sym); + const atom_index = coff_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err| + return self.fail("{s} creating lazy symbol", .{@errorName(err)}); const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?; try self.genSetReg(addr_reg, Type.usize, .{ .lea_got = sym_index }); } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { - const atom_index = try macho_file.getOrCreateAtomForLazySymbol(lazy_sym); + const atom_index = macho_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err| + return self.fail("{s} creating lazy symbol", .{@errorName(err)}); const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?; try self.genSetReg(addr_reg, Type.usize, .{ .lea_got = sym_index }); } else { @@ -7530,7 +7719,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr }), ), .load_direct => |sym_index| if (try self.movMirTag(ty) == .mov) { - const atom_index = try self.getSymbolIndexForDecl(self.mod_fn.owner_decl); + const atom_index = try self.getSymbolIndexForDecl(self.getOwnerDecl()); _ = try self.addInst(.{ .tag = .mov_linker, .ops = .direct_reloc, @@ -7557,7 +7746,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr ); }, .lea_direct, .lea_got => |sym_index| { - const atom_index = try self.getSymbolIndexForDecl(self.mod_fn.owner_decl); + const atom_index = try self.getSymbolIndexForDecl(self.getOwnerDecl()); _ = try self.addInst(.{ .tag = switch (src_mcv) { .lea_direct => .lea_linker, @@ -7577,7 +7766,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr }); }, .lea_tlv => |sym_index| { - const atom_index = try self.getSymbolIndexForDecl(self.mod_fn.owner_decl); + const atom_index = try self.getSymbolIndexForDecl(self.getOwnerDecl()); if (self.bin_file.cast(link.File.MachO)) |_| { _ = try self.addInst(.{ .tag = .lea_linker, @@ -8475,10 +8664,64 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void { fn airTagName(self: *Self, inst: Air.Inst.Index) !void { const un_op = self.air.instructions.items(.data)[inst].un_op; + const inst_ty = self.air.typeOfIndex(inst); + const enum_ty = self.air.typeOf(un_op); + + // We need a properly aligned and sized call frame to be able to call this function. + { + const needed_call_frame = FrameAlloc.init(.{ + .size = inst_ty.abiSize(self.target.*), + .alignment = inst_ty.abiAlignment(self.target.*), + }); + const frame_allocs_slice = self.frame_allocs.slice(); + const stack_frame_size = + &frame_allocs_slice.items(.abi_size)[@enumToInt(FrameIndex.call_frame)]; + stack_frame_size.* = @max(stack_frame_size.*, needed_call_frame.abi_size); + const stack_frame_align = + &frame_allocs_slice.items(.abi_align)[@enumToInt(FrameIndex.call_frame)]; + stack_frame_align.* = @max(stack_frame_align.*, needed_call_frame.abi_align); + } + + try self.spillEflagsIfOccupied(); + try self.spillRegisters(abi.getCallerPreservedRegs(self.target.*)); + + const param_regs = abi.getCAbiIntParamRegs(self.target.*); + + const dst_mcv = try self.allocRegOrMem(inst, false); + try self.genSetReg(param_regs[0], Type.usize, dst_mcv.address()); + const operand = try self.resolveInst(un_op); - _ = operand; - return self.fail("TODO implement airTagName for x86_64", .{}); - //return self.finishAir(inst, result, .{ un_op, .none, .none }); + try self.genSetReg(param_regs[1], enum_ty, operand); + + const mod = self.bin_file.options.module.?; + const lazy_sym = link.File.LazySymbol.initDecl(.code, enum_ty.getOwnerDecl(), mod); + if (self.bin_file.cast(link.File.Elf)) |elf_file| { + const atom_index = elf_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err| + return self.fail("{s} creating lazy symbol", .{@errorName(err)}); + const atom = elf_file.getAtom(atom_index); + _ = try atom.getOrCreateOffsetTableEntry(elf_file); + const got_addr = atom.getOffsetTableAddress(elf_file); + try self.asmMemory( + .call, + Memory.sib(.qword, .{ .base = .{ .reg = .ds }, .disp = @intCast(i32, got_addr) }), + ); + } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { + const atom_index = coff_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err| + return self.fail("{s} creating lazy symbol", .{@errorName(err)}); + const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?; + try self.genSetReg(.rax, Type.usize, .{ .lea_got = sym_index }); + try self.asmRegister(.call, .rax); + } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { + const atom_index = macho_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err| + return self.fail("{s} creating lazy symbol", .{@errorName(err)}); + const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?; + try self.genSetReg(.rax, Type.usize, .{ .lea_got = sym_index }); + try self.asmRegister(.call, .rax); + } else { + return self.fail("TODO implement airTagName for x86_64 {s}", .{@tagName(self.bin_file.tag)}); + } + + return self.finishAir(inst, dst_mcv, .{ un_op, .none, .none }); } fn airErrorName(self: *Self, inst: Air.Inst.Index) !void { @@ -8497,7 +8740,8 @@ fn airErrorName(self: *Self, inst: Air.Inst.Index) !void { const mod = self.bin_file.options.module.?; const lazy_sym = link.File.LazySymbol.initDecl(.const_data, null, mod); if (self.bin_file.cast(link.File.Elf)) |elf_file| { - const atom_index = try elf_file.getOrCreateAtomForLazySymbol(lazy_sym); + const atom_index = elf_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err| + return self.fail("{s} creating lazy symbol", .{@errorName(err)}); const atom = elf_file.getAtom(atom_index); _ = try atom.getOrCreateOffsetTableEntry(elf_file); const got_addr = atom.getOffsetTableAddress(elf_file); @@ -8507,11 +8751,13 @@ fn airErrorName(self: *Self, inst: Air.Inst.Index) !void { Memory.sib(.qword, .{ .base = .{ .reg = .ds }, .disp = @intCast(i32, got_addr) }), ); } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { - const atom_index = try coff_file.getOrCreateAtomForLazySymbol(lazy_sym); + const atom_index = coff_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err| + return self.fail("{s} creating lazy symbol", .{@errorName(err)}); const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?; try self.genSetReg(addr_reg, Type.usize, .{ .lea_got = sym_index }); } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { - const atom_index = try macho_file.getOrCreateAtomForLazySymbol(lazy_sym); + const atom_index = macho_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err| + return self.fail("{s} creating lazy symbol", .{@errorName(err)}); const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?; try self.genSetReg(addr_reg, Type.usize, .{ .lea_got = sym_index }); } else { @@ -8833,12 +9079,7 @@ fn limitImmediateType(self: *Self, operand: Air.Inst.Ref, comptime T: type) !MCV } fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue { - const mcv: MCValue = switch (try codegen.genTypedValue( - self.bin_file, - self.src_loc, - arg_tv, - self.mod_fn.owner_decl, - )) { + return switch (try codegen.genTypedValue(self.bin_file, self.src_loc, arg_tv, self.getOwnerDecl())) { .mcv => |mcv| switch (mcv) { .none => .none, .undef => .undef, @@ -8853,7 +9094,6 @@ fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue { return error.CodegenFail; }, }; - return mcv; } const CallMCValues = struct { diff --git a/src/codegen.zig b/src/codegen.zig index 690e96d25c..078feb409d 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -7,6 +7,7 @@ const link = @import("link.zig"); const log = std.log.scoped(.codegen); const mem = std.mem; const math = std.math; +const target_util = @import("target.zig"); const trace = @import("tracy.zig").trace; const Air = @import("Air.zig"); @@ -89,6 +90,19 @@ pub fn generateFunction( } } +pub fn generateLazyFunction( + bin_file: *link.File, + src_loc: Module.SrcLoc, + lazy_sym: link.File.LazySymbol, + code: *std.ArrayList(u8), + debug_output: DebugInfoOutput, +) CodeGenError!Result { + switch (bin_file.options.target.cpu.arch) { + .x86_64 => return @import("arch/x86_64/CodeGen.zig").generateLazy(bin_file, src_loc, lazy_sym, code, debug_output), + else => unreachable, + } +} + fn writeFloat(comptime F: type, f: F, target: Target, endian: std.builtin.Endian, code: []u8) void { _ = target; const bits = @typeInfo(F).Float.bits; @@ -101,11 +115,11 @@ pub fn generateLazySymbol( bin_file: *link.File, src_loc: Module.SrcLoc, lazy_sym: link.File.LazySymbol, + alignment: *u32, code: *std.ArrayList(u8), debug_output: DebugInfoOutput, reloc_info: RelocInfo, -) CodeGenError!struct { res: Result, alignment: u32 } { - _ = debug_output; +) CodeGenError!Result { _ = reloc_info; const tracy = trace(@src()); @@ -120,7 +134,13 @@ pub fn generateLazySymbol( lazy_sym.ty.fmt(mod), }); - if (lazy_sym.kind == .const_data and lazy_sym.ty.isAnyError()) { + if (lazy_sym.kind == .code) { + alignment.* = target_util.defaultFunctionAlignment(target); + return generateLazyFunction(bin_file, src_loc, lazy_sym, code, debug_output); + } + + if (lazy_sym.ty.isAnyError()) { + alignment.* = 4; const err_names = mod.error_name_list.items; mem.writeInt(u32, try code.addManyAsArray(4), @intCast(u32, err_names.len), endian); var offset = code.items.len; @@ -133,13 +153,21 @@ pub fn generateLazySymbol( code.appendAssumeCapacity(0); } mem.writeInt(u32, code.items[offset..][0..4], @intCast(u32, code.items.len), endian); - return .{ .res = Result.ok, .alignment = 4 }; - } else return .{ .res = .{ .fail = try ErrorMsg.create( + return Result.ok; + } else if (lazy_sym.ty.zigTypeTag() == .Enum) { + alignment.* = 1; + for (lazy_sym.ty.enumFields().keys()) |tag_name| { + try code.ensureUnusedCapacity(tag_name.len + 1); + code.appendSliceAssumeCapacity(tag_name); + code.appendAssumeCapacity(0); + } + return Result.ok; + } else return .{ .fail = try ErrorMsg.create( bin_file.allocator, src_loc, "TODO implement generateLazySymbol for {s} {}", .{ @tagName(lazy_sym.kind), lazy_sym.ty.fmt(mod) }, - ) }, .alignment = undefined }; + ) }; } pub fn generateSymbol( diff --git a/src/link/Coff.zig b/src/link/Coff.zig index deac8d1fd6..41d4617e53 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -1218,6 +1218,7 @@ fn updateLazySymbolAtom( const gpa = self.base.allocator; const mod = self.base.options.module.?; + var required_alignment: u32 = undefined; var code_buffer = std.ArrayList(u8).init(gpa); defer code_buffer.deinit(); @@ -1238,10 +1239,16 @@ fn updateLazySymbolAtom( .parent_decl_node = undefined, .lazy = .unneeded, }; - const res = try codegen.generateLazySymbol(&self.base, src, sym, &code_buffer, .none, .{ - .parent_atom_index = local_sym_index, - }); - const code = switch (res.res) { + const res = try codegen.generateLazySymbol( + &self.base, + src, + sym, + &required_alignment, + &code_buffer, + .none, + .{ .parent_atom_index = local_sym_index }, + ); + const code = switch (res) { .ok => code_buffer.items, .fail => |em| { log.err("{s}", .{em.msg}); @@ -1255,11 +1262,11 @@ fn updateLazySymbolAtom( symbol.section_number = @intToEnum(coff.SectionNumber, section_index + 1); symbol.type = .{ .complex_type = .NULL, .base_type = .NULL }; - const vaddr = try self.allocateAtom(atom_index, code_len, res.alignment); + const vaddr = try self.allocateAtom(atom_index, code_len, required_alignment); errdefer self.freeAtom(atom_index); log.debug("allocated atom for {s} at 0x{x}", .{ name, vaddr }); - log.debug(" (required alignment 0x{x})", .{res.alignment}); + log.debug(" (required alignment 0x{x})", .{required_alignment}); atom.size = code_len; symbol.value = vaddr; @@ -1270,14 +1277,20 @@ fn updateLazySymbolAtom( pub fn getOrCreateAtomForLazySymbol(self: *Coff, sym: link.File.LazySymbol) !Atom.Index { const gop = try self.lazy_syms.getOrPut(self.base.allocator, sym.getDecl()); - errdefer _ = self.lazy_syms.pop(); + errdefer _ = if (!gop.found_existing) self.lazy_syms.pop(); if (!gop.found_existing) gop.value_ptr.* = .{}; - const atom = switch (sym.kind) { + const atom_ptr = switch (sym.kind) { .code => &gop.value_ptr.text_atom, .const_data => &gop.value_ptr.rdata_atom, }; - if (atom.* == null) atom.* = try self.createAtom(); - return atom.*.?; + if (atom_ptr.*) |atom| return atom; + const atom = try self.createAtom(); + atom_ptr.* = atom; + try self.updateLazySymbolAtom(sym, atom, switch (sym.kind) { + .code => self.text_section_index.?, + .const_data => self.rdata_section_index.?, + }); + return atom; } pub fn getOrCreateAtomForDecl(self: *Coff, decl_index: Module.Decl.Index) !Atom.Index { diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 29ae97150e..ec113e5c8a 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -2376,14 +2376,20 @@ pub fn freeDecl(self: *Elf, decl_index: Module.Decl.Index) void { pub fn getOrCreateAtomForLazySymbol(self: *Elf, sym: File.LazySymbol) !Atom.Index { const gop = try self.lazy_syms.getOrPut(self.base.allocator, sym.getDecl()); - errdefer _ = self.lazy_syms.pop(); + errdefer _ = if (!gop.found_existing) self.lazy_syms.pop(); if (!gop.found_existing) gop.value_ptr.* = .{}; - const atom = switch (sym.kind) { + const atom_ptr = switch (sym.kind) { .code => &gop.value_ptr.text_atom, .const_data => &gop.value_ptr.rodata_atom, }; - if (atom.* == null) atom.* = try self.createAtom(); - return atom.*.?; + if (atom_ptr.*) |atom| return atom; + const atom = try self.createAtom(); + atom_ptr.* = atom; + try self.updateLazySymbolAtom(sym, atom, switch (sym.kind) { + .code => self.text_section_index.?, + .const_data => self.rodata_section_index.?, + }); + return atom; } pub fn getOrCreateAtomForDecl(self: *Elf, decl_index: Module.Decl.Index) !Atom.Index { @@ -2684,6 +2690,7 @@ fn updateLazySymbolAtom( const gpa = self.base.allocator; const mod = self.base.options.module.?; + var required_alignment: u32 = undefined; var code_buffer = std.ArrayList(u8).init(gpa); defer code_buffer.deinit(); @@ -2708,10 +2715,16 @@ fn updateLazySymbolAtom( .parent_decl_node = undefined, .lazy = .unneeded, }; - const res = try codegen.generateLazySymbol(&self.base, src, sym, &code_buffer, .none, .{ - .parent_atom_index = local_sym_index, - }); - const code = switch (res.res) { + const res = try codegen.generateLazySymbol( + &self.base, + src, + sym, + &required_alignment, + &code_buffer, + .none, + .{ .parent_atom_index = local_sym_index }, + ); + const code = switch (res) { .ok => code_buffer.items, .fail => |em| { log.err("{s}", .{em.msg}); @@ -2729,7 +2742,7 @@ fn updateLazySymbolAtom( .st_value = 0, .st_size = 0, }; - const vaddr = try self.allocateAtom(atom_index, code.len, res.alignment); + const vaddr = try self.allocateAtom(atom_index, code.len, required_alignment); errdefer self.freeAtom(atom_index); log.debug("allocated text block for {s} at 0x{x}", .{ name, vaddr }); diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 5136bd84a2..c14168c66b 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -2060,6 +2060,7 @@ fn updateLazySymbolAtom( const gpa = self.base.allocator; const mod = self.base.options.module.?; + var required_alignment: u32 = undefined; var code_buffer = std.ArrayList(u8).init(gpa); defer code_buffer.deinit(); @@ -2084,10 +2085,16 @@ fn updateLazySymbolAtom( .parent_decl_node = undefined, .lazy = .unneeded, }; - const res = try codegen.generateLazySymbol(&self.base, src, sym, &code_buffer, .none, .{ - .parent_atom_index = local_sym_index, - }); - const code = switch (res.res) { + const res = try codegen.generateLazySymbol( + &self.base, + src, + sym, + &required_alignment, + &code_buffer, + .none, + .{ .parent_atom_index = local_sym_index }, + ); + const code = switch (res) { .ok => code_buffer.items, .fail => |em| { log.err("{s}", .{em.msg}); @@ -2101,11 +2108,11 @@ fn updateLazySymbolAtom( symbol.n_sect = section_index + 1; symbol.n_desc = 0; - const vaddr = try self.allocateAtom(atom_index, code.len, res.alignment); + const vaddr = try self.allocateAtom(atom_index, code.len, required_alignment); errdefer self.freeAtom(atom_index); log.debug("allocated atom for {s} at 0x{x}", .{ name, vaddr }); - log.debug(" (required alignment 0x{x}", .{res.alignment}); + log.debug(" (required alignment 0x{x}", .{required_alignment}); atom.size = code.len; symbol.n_value = vaddr; @@ -2116,14 +2123,20 @@ fn updateLazySymbolAtom( pub fn getOrCreateAtomForLazySymbol(self: *MachO, sym: File.LazySymbol) !Atom.Index { const gop = try self.lazy_syms.getOrPut(self.base.allocator, sym.getDecl()); - errdefer _ = self.lazy_syms.pop(); + errdefer _ = if (!gop.found_existing) self.lazy_syms.pop(); if (!gop.found_existing) gop.value_ptr.* = .{}; - const atom = switch (sym.kind) { + const atom_ptr = switch (sym.kind) { .code => &gop.value_ptr.text_atom, .const_data => &gop.value_ptr.data_const_atom, }; - if (atom.* == null) atom.* = try self.createAtom(); - return atom.*.?; + if (atom_ptr.*) |atom| return atom; + const atom = try self.createAtom(); + atom_ptr.* = atom; + try self.updateLazySymbolAtom(sym, atom, switch (sym.kind) { + .code => self.text_section_index.?, + .const_data => self.data_const_section_index.?, + }); + return atom; } fn updateThreadlocalVariable(self: *MachO, module: *Module, decl_index: Module.Decl.Index) !void { diff --git a/test/behavior/enum.zig b/test/behavior/enum.zig index de5c0efb8e..26b941bcdc 100644 --- a/test/behavior/enum.zig +++ b/test/behavior/enum.zig @@ -981,7 +981,6 @@ fn test3_2(f: Test3Foo) !void { } test "@tagName" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -997,7 +996,6 @@ fn testEnumTagNameBare(n: anytype) []const u8 { const BareNumber = enum { One, Two, Three }; test "@tagName non-exhaustive enum" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -1008,7 +1006,6 @@ test "@tagName non-exhaustive enum" { const NonExhaustive = enum(u8) { A, B, _ }; test "@tagName is null-terminated" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -1023,7 +1020,6 @@ test "@tagName is null-terminated" { } test "tag name with assigned enum values" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -1113,7 +1109,6 @@ test "enum literal in array literal" { test "tag name functions are unique" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO diff --git a/test/behavior/memset.zig b/test/behavior/memset.zig index 2cc390a3c9..89e01a0e56 100644 --- a/test/behavior/memset.zig +++ b/test/behavior/memset.zig @@ -114,7 +114,6 @@ test "memset with large array element, runtime known" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; const A = [128]u64; var buf: [5]A = undefined; @@ -132,7 +131,6 @@ test "memset with large array element, comptime known" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; const A = [128]u64; var buf: [5]A = undefined; diff --git a/test/behavior/type.zig b/test/behavior/type.zig index 0d309b9a6e..695a81b1a3 100644 --- a/test/behavior/type.zig +++ b/test/behavior/type.zig @@ -258,7 +258,6 @@ test "Type.ErrorSet" { test "Type.Struct" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -383,7 +382,6 @@ test "Type.Enum" { test "Type.Union" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO diff --git a/test/behavior/union.zig b/test/behavior/union.zig index 76c5b09a89..f90a336e76 100644 --- a/test/behavior/union.zig +++ b/test/behavior/union.zig @@ -1094,7 +1094,6 @@ test "containers with single-field enums" { test "@unionInit on union with tag but no fields" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO From 0bdfb288ccc58807355221d3e86451c33e390d01 Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Mon, 1 May 2023 00:39:31 -0400 Subject: [PATCH 046/725] x86_64: workaround tagName linker issues Pass extra pointer param with a linker ref when calling the lazy tagName function to workaround not being able to lower linker refs during codegen of a lazy func. --- src/arch/x86_64/CodeGen.zig | 79 ++++++++++++++++--------------------- 1 file changed, 34 insertions(+), 45 deletions(-) diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 71dcbfa461..6f71e0b810 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -1641,48 +1641,16 @@ fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void { wip_mir_log.debug("{}.@tagName:", .{enum_ty.fmt(self.bin_file.options.module.?)}); const param_regs = abi.getCAbiIntParamRegs(self.target.*); - const param_locks = self.register_manager.lockRegsAssumeUnused(2, param_regs[0..2].*); + const param_locks = self.register_manager.lockRegsAssumeUnused(3, param_regs[0..3].*); defer for (param_locks) |lock| self.register_manager.unlockReg(lock); const ret_reg = param_regs[0]; const enum_mcv = MCValue{ .register = param_regs[1] }; + const data_mcv = MCValue{ .register = param_regs[2] }; var exitlude_jump_relocs = try self.gpa.alloc(u32, enum_ty.enumFieldCount()); defer self.gpa.free(exitlude_jump_relocs); - const data_reg = try self.register_manager.allocReg(null, gp); - const data_lock = self.register_manager.lockRegAssumeUnused(data_reg); - defer self.register_manager.unlockReg(data_lock); - - const data_lazy_sym = link.File.LazySymbol{ .kind = .const_data, .ty = enum_ty }; - if (self.bin_file.cast(link.File.Elf)) |elf_file| { - const atom_index = elf_file.getOrCreateAtomForLazySymbol(data_lazy_sym) catch |err| - return self.fail("{s} creating lazy symbol", .{@errorName(err)}); - const atom = elf_file.getAtom(atom_index); - _ = try atom.getOrCreateOffsetTableEntry(elf_file); - const got_addr = atom.getOffsetTableAddress(elf_file); - try self.asmRegisterMemory( - .mov, - data_reg.to64(), - Memory.sib(.qword, .{ .base = .{ .reg = .ds }, .disp = @intCast(i32, got_addr) }), - ); - } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { - const atom_index = coff_file.getOrCreateAtomForLazySymbol(data_lazy_sym) catch |err| - return self.fail("{s} creating lazy symbol", .{@errorName(err)}); - const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?; - try self.genSetReg(data_reg, Type.usize, .{ .lea_got = sym_index }); - } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { - const atom_index = macho_file.getOrCreateAtomForLazySymbol(data_lazy_sym) catch |err| - return self.fail("{s} creating lazy symbol", .{@errorName(err)}); - const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?; - try self.genSetReg(data_reg, Type.usize, .{ .lea_got = sym_index }); - } else { - return self.fail("TODO implement {s} for {}", .{ - @tagName(lazy_sym.kind), - lazy_sym.ty.fmt(self.bin_file.options.module.?), - }); - } - var data_off: i32 = 0; for ( exitlude_jump_relocs, @@ -1698,12 +1666,7 @@ fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void { try self.genBinOpMir(.cmp, enum_ty, enum_mcv, tag_mcv); const skip_reloc = try self.asmJccReloc(undefined, .ne); - try self.genSetMem( - .{ .reg = ret_reg }, - 0, - Type.usize, - .{ .register_offset = .{ .reg = data_reg, .off = data_off } }, - ); + try self.genSetMem(.{ .reg = ret_reg }, 0, Type.usize, data_mcv.offset(data_off)); try self.genSetMem(.{ .reg = ret_reg }, 8, Type.usize, .{ .immediate = tag_name.len }); exitlude_jump_reloc.* = try self.asmJmpReloc(undefined); @@ -8663,6 +8626,7 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void { } fn airTagName(self: *Self, inst: Air.Inst.Index) !void { + const mod = self.bin_file.options.module.?; const un_op = self.air.instructions.items(.data)[inst].un_op; const inst_ty = self.air.typeOfIndex(inst); const enum_ty = self.air.typeOf(un_op); @@ -8693,10 +8657,35 @@ fn airTagName(self: *Self, inst: Air.Inst.Index) !void { const operand = try self.resolveInst(un_op); try self.genSetReg(param_regs[1], enum_ty, operand); - const mod = self.bin_file.options.module.?; - const lazy_sym = link.File.LazySymbol.initDecl(.code, enum_ty.getOwnerDecl(), mod); + const data_lazy_sym = link.File.LazySymbol.initDecl(.const_data, enum_ty.getOwnerDecl(), mod); if (self.bin_file.cast(link.File.Elf)) |elf_file| { - const atom_index = elf_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err| + const atom_index = elf_file.getOrCreateAtomForLazySymbol(data_lazy_sym) catch |err| + return self.fail("{s} creating lazy symbol", .{@errorName(err)}); + const atom = elf_file.getAtom(atom_index); + _ = try atom.getOrCreateOffsetTableEntry(elf_file); + const got_addr = atom.getOffsetTableAddress(elf_file); + try self.asmRegisterMemory( + .mov, + param_regs[2], + Memory.sib(.qword, .{ .base = .{ .reg = .ds }, .disp = @intCast(i32, got_addr) }), + ); + } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { + const atom_index = coff_file.getOrCreateAtomForLazySymbol(data_lazy_sym) catch |err| + return self.fail("{s} creating lazy symbol", .{@errorName(err)}); + const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?; + try self.genSetReg(param_regs[2], Type.usize, .{ .lea_got = sym_index }); + } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { + const atom_index = macho_file.getOrCreateAtomForLazySymbol(data_lazy_sym) catch |err| + return self.fail("{s} creating lazy symbol", .{@errorName(err)}); + const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?; + try self.genSetReg(param_regs[2], Type.usize, .{ .lea_got = sym_index }); + } else { + return self.fail("TODO implement airTagName for x86_64 {s}", .{@tagName(self.bin_file.tag)}); + } + + const code_lazy_sym = link.File.LazySymbol.initDecl(.code, enum_ty.getOwnerDecl(), mod); + if (self.bin_file.cast(link.File.Elf)) |elf_file| { + const atom_index = elf_file.getOrCreateAtomForLazySymbol(code_lazy_sym) catch |err| return self.fail("{s} creating lazy symbol", .{@errorName(err)}); const atom = elf_file.getAtom(atom_index); _ = try atom.getOrCreateOffsetTableEntry(elf_file); @@ -8706,13 +8695,13 @@ fn airTagName(self: *Self, inst: Air.Inst.Index) !void { Memory.sib(.qword, .{ .base = .{ .reg = .ds }, .disp = @intCast(i32, got_addr) }), ); } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { - const atom_index = coff_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err| + const atom_index = coff_file.getOrCreateAtomForLazySymbol(code_lazy_sym) catch |err| return self.fail("{s} creating lazy symbol", .{@errorName(err)}); const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?; try self.genSetReg(.rax, Type.usize, .{ .lea_got = sym_index }); try self.asmRegister(.call, .rax); } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { - const atom_index = macho_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err| + const atom_index = macho_file.getOrCreateAtomForLazySymbol(code_lazy_sym) catch |err| return self.fail("{s} creating lazy symbol", .{@errorName(err)}); const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?; try self.genSetReg(.rax, Type.usize, .{ .lea_got = sym_index }); From 7064d7dbf0157aed9b497e1158243e472082633f Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Mon, 1 May 2023 09:54:42 +0200 Subject: [PATCH 047/725] Revert "x86_64: workaround tagName linker issues" This reverts commit aac97b92532e7492b9145e1562e31c2e1fa66c15. --- src/arch/x86_64/CodeGen.zig | 79 +++++++++++++++++++++---------------- 1 file changed, 45 insertions(+), 34 deletions(-) diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 6f71e0b810..71dcbfa461 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -1641,16 +1641,48 @@ fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void { wip_mir_log.debug("{}.@tagName:", .{enum_ty.fmt(self.bin_file.options.module.?)}); const param_regs = abi.getCAbiIntParamRegs(self.target.*); - const param_locks = self.register_manager.lockRegsAssumeUnused(3, param_regs[0..3].*); + const param_locks = self.register_manager.lockRegsAssumeUnused(2, param_regs[0..2].*); defer for (param_locks) |lock| self.register_manager.unlockReg(lock); const ret_reg = param_regs[0]; const enum_mcv = MCValue{ .register = param_regs[1] }; - const data_mcv = MCValue{ .register = param_regs[2] }; var exitlude_jump_relocs = try self.gpa.alloc(u32, enum_ty.enumFieldCount()); defer self.gpa.free(exitlude_jump_relocs); + const data_reg = try self.register_manager.allocReg(null, gp); + const data_lock = self.register_manager.lockRegAssumeUnused(data_reg); + defer self.register_manager.unlockReg(data_lock); + + const data_lazy_sym = link.File.LazySymbol{ .kind = .const_data, .ty = enum_ty }; + if (self.bin_file.cast(link.File.Elf)) |elf_file| { + const atom_index = elf_file.getOrCreateAtomForLazySymbol(data_lazy_sym) catch |err| + return self.fail("{s} creating lazy symbol", .{@errorName(err)}); + const atom = elf_file.getAtom(atom_index); + _ = try atom.getOrCreateOffsetTableEntry(elf_file); + const got_addr = atom.getOffsetTableAddress(elf_file); + try self.asmRegisterMemory( + .mov, + data_reg.to64(), + Memory.sib(.qword, .{ .base = .{ .reg = .ds }, .disp = @intCast(i32, got_addr) }), + ); + } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { + const atom_index = coff_file.getOrCreateAtomForLazySymbol(data_lazy_sym) catch |err| + return self.fail("{s} creating lazy symbol", .{@errorName(err)}); + const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?; + try self.genSetReg(data_reg, Type.usize, .{ .lea_got = sym_index }); + } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { + const atom_index = macho_file.getOrCreateAtomForLazySymbol(data_lazy_sym) catch |err| + return self.fail("{s} creating lazy symbol", .{@errorName(err)}); + const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?; + try self.genSetReg(data_reg, Type.usize, .{ .lea_got = sym_index }); + } else { + return self.fail("TODO implement {s} for {}", .{ + @tagName(lazy_sym.kind), + lazy_sym.ty.fmt(self.bin_file.options.module.?), + }); + } + var data_off: i32 = 0; for ( exitlude_jump_relocs, @@ -1666,7 +1698,12 @@ fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void { try self.genBinOpMir(.cmp, enum_ty, enum_mcv, tag_mcv); const skip_reloc = try self.asmJccReloc(undefined, .ne); - try self.genSetMem(.{ .reg = ret_reg }, 0, Type.usize, data_mcv.offset(data_off)); + try self.genSetMem( + .{ .reg = ret_reg }, + 0, + Type.usize, + .{ .register_offset = .{ .reg = data_reg, .off = data_off } }, + ); try self.genSetMem(.{ .reg = ret_reg }, 8, Type.usize, .{ .immediate = tag_name.len }); exitlude_jump_reloc.* = try self.asmJmpReloc(undefined); @@ -8626,7 +8663,6 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void { } fn airTagName(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; const un_op = self.air.instructions.items(.data)[inst].un_op; const inst_ty = self.air.typeOfIndex(inst); const enum_ty = self.air.typeOf(un_op); @@ -8657,35 +8693,10 @@ fn airTagName(self: *Self, inst: Air.Inst.Index) !void { const operand = try self.resolveInst(un_op); try self.genSetReg(param_regs[1], enum_ty, operand); - const data_lazy_sym = link.File.LazySymbol.initDecl(.const_data, enum_ty.getOwnerDecl(), mod); + const mod = self.bin_file.options.module.?; + const lazy_sym = link.File.LazySymbol.initDecl(.code, enum_ty.getOwnerDecl(), mod); if (self.bin_file.cast(link.File.Elf)) |elf_file| { - const atom_index = elf_file.getOrCreateAtomForLazySymbol(data_lazy_sym) catch |err| - return self.fail("{s} creating lazy symbol", .{@errorName(err)}); - const atom = elf_file.getAtom(atom_index); - _ = try atom.getOrCreateOffsetTableEntry(elf_file); - const got_addr = atom.getOffsetTableAddress(elf_file); - try self.asmRegisterMemory( - .mov, - param_regs[2], - Memory.sib(.qword, .{ .base = .{ .reg = .ds }, .disp = @intCast(i32, got_addr) }), - ); - } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { - const atom_index = coff_file.getOrCreateAtomForLazySymbol(data_lazy_sym) catch |err| - return self.fail("{s} creating lazy symbol", .{@errorName(err)}); - const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?; - try self.genSetReg(param_regs[2], Type.usize, .{ .lea_got = sym_index }); - } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { - const atom_index = macho_file.getOrCreateAtomForLazySymbol(data_lazy_sym) catch |err| - return self.fail("{s} creating lazy symbol", .{@errorName(err)}); - const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?; - try self.genSetReg(param_regs[2], Type.usize, .{ .lea_got = sym_index }); - } else { - return self.fail("TODO implement airTagName for x86_64 {s}", .{@tagName(self.bin_file.tag)}); - } - - const code_lazy_sym = link.File.LazySymbol.initDecl(.code, enum_ty.getOwnerDecl(), mod); - if (self.bin_file.cast(link.File.Elf)) |elf_file| { - const atom_index = elf_file.getOrCreateAtomForLazySymbol(code_lazy_sym) catch |err| + const atom_index = elf_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err| return self.fail("{s} creating lazy symbol", .{@errorName(err)}); const atom = elf_file.getAtom(atom_index); _ = try atom.getOrCreateOffsetTableEntry(elf_file); @@ -8695,13 +8706,13 @@ fn airTagName(self: *Self, inst: Air.Inst.Index) !void { Memory.sib(.qword, .{ .base = .{ .reg = .ds }, .disp = @intCast(i32, got_addr) }), ); } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { - const atom_index = coff_file.getOrCreateAtomForLazySymbol(code_lazy_sym) catch |err| + const atom_index = coff_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err| return self.fail("{s} creating lazy symbol", .{@errorName(err)}); const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?; try self.genSetReg(.rax, Type.usize, .{ .lea_got = sym_index }); try self.asmRegister(.call, .rax); } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { - const atom_index = macho_file.getOrCreateAtomForLazySymbol(code_lazy_sym) catch |err| + const atom_index = macho_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err| return self.fail("{s} creating lazy symbol", .{@errorName(err)}); const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?; try self.genSetReg(.rax, Type.usize, .{ .lea_got = sym_index }); From 565f8979cc38d46b8b905f3a8b7db03238779ffc Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Mon, 1 May 2023 13:41:42 +0200 Subject: [PATCH 048/725] link: fix accessing source atom's symbol index in codegen Since the owner can either be a `Decl` or a `LazySymbol` we need to preserve this information at the codegen generate function level so that we can then correctly work out the corresponding `Atom` in the linker. --- src/arch/x86_64/CodeGen.zig | 94 +++++++++++++++++++++++-------------- src/link/MachO.zig | 7 +-- 2 files changed, 62 insertions(+), 39 deletions(-) diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 71dcbfa461..d5c5938ba0 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -56,10 +56,7 @@ liveness: Liveness, bin_file: *link.File, debug_output: DebugInfoOutput, target: *const std.Target, -owner: union(enum) { - mod_fn: *const Module.Fn, - decl: Module.Decl.Index, -}, +owner: Owner, err_msg: ?*ErrorMsg, args: []MCValue, ret_mcv: InstTracking, @@ -111,6 +108,44 @@ const mir_to_air_map_init = if (builtin.mode == .Debug) std.AutoHashMapUnmanaged const FrameAddr = struct { index: FrameIndex, off: i32 = 0 }; const RegisterOffset = struct { reg: Register, off: i32 = 0 }; +const Owner = union(enum) { + mod_fn: *const Module.Fn, + lazy_sym: link.File.LazySymbol, + + fn getOwnerDecl(owner: Owner) Module.Decl.Index { + return switch (owner) { + .mod_fn => |mod_fn| mod_fn.owner_decl, + .lazy_sym => |lazy_sym| lazy_sym.ty.getOwnerDecl(), + }; + } + + fn getSymbolIndex(owner: Owner, ctx: *Self) !u32 { + switch (owner) { + .mod_fn => |mod_fn| { + const decl_index = mod_fn.owner_decl; + if (ctx.bin_file.cast(link.File.MachO)) |macho_file| { + const atom = try macho_file.getOrCreateAtomForDecl(decl_index); + return macho_file.getAtom(atom).getSymbolIndex().?; + } else if (ctx.bin_file.cast(link.File.Coff)) |coff_file| { + const atom = try coff_file.getOrCreateAtomForDecl(decl_index); + return coff_file.getAtom(atom).getSymbolIndex().?; + } else unreachable; + }, + .lazy_sym => |lazy_sym| { + if (ctx.bin_file.cast(link.File.MachO)) |macho_file| { + const atom = macho_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err| + return ctx.fail("{s} creating lazy symbol", .{@errorName(err)}); + return macho_file.getAtom(atom).getSymbolIndex().?; + } else if (ctx.bin_file.cast(link.File.Coff)) |coff_file| { + const atom = coff_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err| + return ctx.fail("{s} creating lazy symbol", .{@errorName(err)}); + return coff_file.getAtom(atom).getSymbolIndex().?; + } else unreachable; + }, + } + } +}; + pub const MCValue = union(enum) { /// No runtime bits. `void` types, empty structs, u0, enums with 1 tag, etc. /// TODO Look into deleting this tag and using `dead` instead, since every use @@ -763,7 +798,7 @@ pub fn generateLazy( .target = &bin_file.options.target, .bin_file = bin_file, .debug_output = debug_output, - .owner = .{ .decl = lazy_sym.ty.getOwnerDecl() }, + .owner = .{ .lazy_sym = lazy_sym }, .err_msg = null, .args = undefined, .ret_mcv = undefined, @@ -1724,13 +1759,6 @@ fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void { } } -fn getOwnerDecl(self: *const Self) Module.Decl.Index { - return switch (self.owner) { - .mod_fn => |mod_fn| mod_fn.owner_decl, - .decl => |index| index, - }; -} - fn getValue(self: *Self, value: MCValue, inst: ?Air.Inst.Index) void { const reg = value.getReg() orelse return; if (self.register_manager.isRegFree(reg)) { @@ -6230,7 +6258,10 @@ fn genArgDbgInfo(self: Self, ty: Type, name: [:0]const u8, mcv: MCValue) !void { //}, else => unreachable, // not a valid function parameter }; - try dw.genArgDbgInfo(name, ty, self.getOwnerDecl(), loc); + // TODO: this might need adjusting like the linkers do. + // Instead of flattening the owner and passing Decl.Index here we may + // want to special case LazySymbol in DWARF linker too. + try dw.genArgDbgInfo(name, ty, self.owner.getOwnerDecl(), loc); }, .plan9 => {}, .none => {}, @@ -6271,7 +6302,10 @@ fn genVarDbgInfo( break :blk .nop; }, }; - try dw.genVarDbgInfo(name, ty, self.getOwnerDecl(), is_ptr, loc); + // TODO: this might need adjusting like the linkers do. + // Instead of flattening the owner and passing Decl.Index here we may + // want to special case LazySymbol in DWARF linker too. + try dw.genVarDbgInfo(name, ty, self.owner.getOwnerDecl(), is_ptr, loc); }, .plan9 => {}, .none => {}, @@ -6403,12 +6437,14 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier .base = .{ .reg = .ds }, .disp = @intCast(i32, got_addr), })); - } else if (self.bin_file.cast(link.File.Coff)) |_| { - const sym_index = try self.getSymbolIndexForDecl(func.owner_decl); + } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { + const atom = try coff_file.getOrCreateAtomForDecl(func.owner_decl); + const sym_index = coff_file.getAtom(atom).getSymbolIndex().?; try self.genSetReg(.rax, Type.usize, .{ .lea_got = sym_index }); try self.asmRegister(.call, .rax); - } else if (self.bin_file.cast(link.File.MachO)) |_| { - const sym_index = try self.getSymbolIndexForDecl(func.owner_decl); + } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { + const atom = try macho_file.getOrCreateAtomForDecl(func.owner_decl); + const sym_index = macho_file.getAtom(atom).getSymbolIndex().?; try self.genSetReg(.rax, Type.usize, .{ .lea_got = sym_index }); try self.asmRegister(.call, .rax); } else if (self.bin_file.cast(link.File.Plan9)) |p9| { @@ -6429,7 +6465,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier const decl_name = mem.sliceTo(mod.declPtr(extern_fn.owner_decl).name, 0); const lib_name = mem.sliceTo(extern_fn.lib_name, 0); if (self.bin_file.cast(link.File.Coff)) |coff_file| { - const atom_index = try self.getSymbolIndexForDecl(self.getOwnerDecl()); + const atom_index = try self.owner.getSymbolIndex(self); const sym_index = try coff_file.getGlobalSymbol(decl_name, lib_name); _ = try self.addInst(.{ .tag = .mov_linker, @@ -6442,8 +6478,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier }); try self.asmRegister(.call, .rax); } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { + const atom_index = try self.owner.getSymbolIndex(self); const sym_index = try macho_file.getGlobalSymbol(decl_name, lib_name); - const atom_index = try self.getSymbolIndexForDecl(self.getOwnerDecl()); _ = try self.addInst(.{ .tag = .call_extern, .ops = undefined, @@ -7719,7 +7755,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr }), ), .load_direct => |sym_index| if (try self.movMirTag(ty) == .mov) { - const atom_index = try self.getSymbolIndexForDecl(self.getOwnerDecl()); + const atom_index = try self.owner.getSymbolIndex(self); _ = try self.addInst(.{ .tag = .mov_linker, .ops = .direct_reloc, @@ -7746,7 +7782,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr ); }, .lea_direct, .lea_got => |sym_index| { - const atom_index = try self.getSymbolIndexForDecl(self.getOwnerDecl()); + const atom_index = try self.owner.getSymbolIndex(self); _ = try self.addInst(.{ .tag = switch (src_mcv) { .lea_direct => .lea_linker, @@ -7766,7 +7802,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr }); }, .lea_tlv => |sym_index| { - const atom_index = try self.getSymbolIndexForDecl(self.getOwnerDecl()); + const atom_index = try self.owner.getSymbolIndex(self); if (self.bin_file.cast(link.File.MachO)) |_| { _ = try self.addInst(.{ .tag = .lea_linker, @@ -9079,7 +9115,7 @@ fn limitImmediateType(self: *Self, operand: Air.Inst.Ref, comptime T: type) !MCV } fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue { - return switch (try codegen.genTypedValue(self.bin_file, self.src_loc, arg_tv, self.getOwnerDecl())) { + return switch (try codegen.genTypedValue(self.bin_file, self.src_loc, arg_tv, self.owner.getOwnerDecl())) { .mcv => |mcv| switch (mcv) { .none => .none, .undef => .undef, @@ -9390,13 +9426,3 @@ fn regBitSize(self: *Self, ty: Type) u64 { fn regExtraBits(self: *Self, ty: Type) u64 { return self.regBitSize(ty) - ty.bitSize(self.target.*); } - -fn getSymbolIndexForDecl(self: *Self, decl_index: Module.Decl.Index) !u32 { - if (self.bin_file.cast(link.File.MachO)) |macho_file| { - const atom = try macho_file.getOrCreateAtomForDecl(decl_index); - return macho_file.getAtom(atom).getSymbolIndex().?; - } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { - const atom = try coff_file.getOrCreateAtomForDecl(decl_index); - return coff_file.getAtom(atom).getSymbolIndex().?; - } else unreachable; -} diff --git a/src/link/MachO.zig b/src/link/MachO.zig index c14168c66b..458b283d4f 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -2112,7 +2112,7 @@ fn updateLazySymbolAtom( errdefer self.freeAtom(atom_index); log.debug("allocated atom for {s} at 0x{x}", .{ name, vaddr }); - log.debug(" (required alignment 0x{x}", .{required_alignment}); + log.debug(" (required alignment 0x{x})", .{required_alignment}); atom.size = code.len; symbol.n_value = vaddr; @@ -4157,9 +4157,6 @@ pub fn logSymtab(self: *MachO) void { log.debug("stubs entries:", .{}); log.debug("{}", .{self.stub_table}); - - // log.debug("threadlocal entries:", .{}); - // log.debug("{}", .{self.tlv_table}); } pub fn logAtoms(self: *MachO) void { @@ -4199,6 +4196,6 @@ pub fn logAtom(self: *MachO, atom_index: Atom.Index) void { sym.n_value, atom.size, atom.file, - sym.n_sect, + sym.n_sect + 1, }); } From 5e7f3d5daaea1e6f5e835648ffd085797b667824 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Mon, 1 May 2023 19:34:55 +0200 Subject: [PATCH 049/725] x86_64: disable advanced memset tests on Windows --- test/behavior/memset.zig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/behavior/memset.zig b/test/behavior/memset.zig index 89e01a0e56..076e1f17d9 100644 --- a/test/behavior/memset.zig +++ b/test/behavior/memset.zig @@ -114,6 +114,7 @@ test "memset with large array element, runtime known" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_x86_64 and builtin.os.tag == .windows) return error.SkipZigTest; const A = [128]u64; var buf: [5]A = undefined; @@ -131,6 +132,7 @@ test "memset with large array element, comptime known" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_x86_64 and builtin.os.tag == .windows) return error.SkipZigTest; const A = [128]u64; var buf: [5]A = undefined; From db88b414722e698a392ec65a3ef46730341aea25 Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Mon, 1 May 2023 16:58:55 -0400 Subject: [PATCH 050/725] x86_64: fix switch multi-prongs and mul/div flags clobber --- src/arch/x86_64/CodeGen.zig | 10 ++++++---- test/behavior/inline_switch.zig | 1 - test/behavior/switch.zig | 4 ---- test/behavior/union.zig | 1 - 4 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index d5c5938ba0..8e61af1c9f 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -2435,6 +2435,7 @@ fn airMulDivBinOp(self: *Self, inst: Air.Inst.Index) !void { } }; const src_ty = Type.initPayload(&src_pl.base); + try self.spillEflagsIfOccupied(); try self.spillRegisters(&.{ .rax, .rdx }); const lhs = try self.resolveInst(bin_op.lhs); const rhs = try self.resolveInst(bin_op.rhs); @@ -7236,15 +7237,16 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) !void { var relocs = try self.gpa.alloc(u32, items.len); defer self.gpa.free(relocs); - for (items, relocs) |item, *reloc| { - try self.spillEflagsIfOccupied(); + try self.spillEflagsIfOccupied(); + for (items, relocs, 0..) |item, *reloc, i| { const item_mcv = try self.resolveInst(item); try self.genBinOpMir(.cmp, condition_ty, condition, item_mcv); - reloc.* = try self.asmJccReloc(undefined, .ne); + reloc.* = try self.asmJccReloc(undefined, if (i < relocs.len - 1) .e else .ne); } for (liveness.deaths[case_i]) |operand| self.processDeath(operand); + for (relocs[0 .. relocs.len - 1]) |reloc| try self.performReloc(reloc); try self.genBody(case_body); try self.restoreState(state, &.{}, .{ .emit_instructions = false, @@ -7253,7 +7255,7 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) !void { .close_scope = true, }); - for (relocs) |reloc| try self.performReloc(reloc); + try self.performReloc(relocs[relocs.len - 1]); } if (switch_br.data.else_body_len > 0) { diff --git a/test/behavior/inline_switch.zig b/test/behavior/inline_switch.zig index dcd603c94f..6e5013d83b 100644 --- a/test/behavior/inline_switch.zig +++ b/test/behavior/inline_switch.zig @@ -94,7 +94,6 @@ test "inline else error" { test "inline else enum" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO const E2 = enum(u8) { a = 2, b = 3, c = 4, d = 5 }; diff --git a/test/behavior/switch.zig b/test/behavior/switch.zig index 3924d1d6c1..5e2d6d28c1 100644 --- a/test/behavior/switch.zig +++ b/test/behavior/switch.zig @@ -88,7 +88,6 @@ fn nonConstSwitch(foo: SwitchStatementFoo) !void { const SwitchStatementFoo = enum { A, B, C, D }; test "switch with multiple expressions" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO const x = switch (returnsFive()) { @@ -275,7 +274,6 @@ fn testSwitchEnumPtrCapture() !void { } test "switch handles all cases of number" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO try testSwitchHandleAllCases(); @@ -455,7 +453,6 @@ test "else prong of switch on error set excludes other cases" { } test "switch prongs with error set cases make a new error set type for capture value" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -532,7 +529,6 @@ test "switch with null and T peer types and inferred result location type" { test "switch prongs with cases with identical payload types" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO const Union = union(enum) { diff --git a/test/behavior/union.zig b/test/behavior/union.zig index f90a336e76..3dd8919935 100644 --- a/test/behavior/union.zig +++ b/test/behavior/union.zig @@ -1288,7 +1288,6 @@ test "return an extern union from C calling convention" { test "noreturn field in union" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO const U = union(enum) { From 3b1ea390a301dbdc992043d97cf618a94e8801de Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Mon, 1 May 2023 19:18:49 -0400 Subject: [PATCH 051/725] x86_64: cleanup lazy symbols In theory fixes updating lazy symbols during incremental compilation. --- src/arch/x86_64/CodeGen.zig | 190 +++++++++++++++--------------------- src/link/Coff.zig | 77 ++++++++------- src/link/Elf.zig | 75 +++++++------- src/link/MachO.zig | 78 ++++++++------- 4 files changed, 207 insertions(+), 213 deletions(-) diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 8e61af1c9f..a658103c1a 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -112,7 +112,7 @@ const Owner = union(enum) { mod_fn: *const Module.Fn, lazy_sym: link.File.LazySymbol, - fn getOwnerDecl(owner: Owner) Module.Decl.Index { + fn getDecl(owner: Owner) Module.Decl.Index { return switch (owner) { .mod_fn => |mod_fn| mod_fn.owner_decl, .lazy_sym => |lazy_sym| lazy_sym.ty.getOwnerDecl(), @@ -1688,35 +1688,7 @@ fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void { const data_reg = try self.register_manager.allocReg(null, gp); const data_lock = self.register_manager.lockRegAssumeUnused(data_reg); defer self.register_manager.unlockReg(data_lock); - - const data_lazy_sym = link.File.LazySymbol{ .kind = .const_data, .ty = enum_ty }; - if (self.bin_file.cast(link.File.Elf)) |elf_file| { - const atom_index = elf_file.getOrCreateAtomForLazySymbol(data_lazy_sym) catch |err| - return self.fail("{s} creating lazy symbol", .{@errorName(err)}); - const atom = elf_file.getAtom(atom_index); - _ = try atom.getOrCreateOffsetTableEntry(elf_file); - const got_addr = atom.getOffsetTableAddress(elf_file); - try self.asmRegisterMemory( - .mov, - data_reg.to64(), - Memory.sib(.qword, .{ .base = .{ .reg = .ds }, .disp = @intCast(i32, got_addr) }), - ); - } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { - const atom_index = coff_file.getOrCreateAtomForLazySymbol(data_lazy_sym) catch |err| - return self.fail("{s} creating lazy symbol", .{@errorName(err)}); - const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?; - try self.genSetReg(data_reg, Type.usize, .{ .lea_got = sym_index }); - } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { - const atom_index = macho_file.getOrCreateAtomForLazySymbol(data_lazy_sym) catch |err| - return self.fail("{s} creating lazy symbol", .{@errorName(err)}); - const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?; - try self.genSetReg(data_reg, Type.usize, .{ .lea_got = sym_index }); - } else { - return self.fail("TODO implement {s} for {}", .{ - @tagName(lazy_sym.kind), - lazy_sym.ty.fmt(self.bin_file.options.module.?), - }); - } + try self.genLazySymbolRef(.lea, data_reg, .{ .kind = .const_data, .ty = enum_ty }); var data_off: i32 = 0; for ( @@ -6262,7 +6234,7 @@ fn genArgDbgInfo(self: Self, ty: Type, name: [:0]const u8, mcv: MCValue) !void { // TODO: this might need adjusting like the linkers do. // Instead of flattening the owner and passing Decl.Index here we may // want to special case LazySymbol in DWARF linker too. - try dw.genArgDbgInfo(name, ty, self.owner.getOwnerDecl(), loc); + try dw.genArgDbgInfo(name, ty, self.owner.getDecl(), loc); }, .plan9 => {}, .none => {}, @@ -6306,7 +6278,7 @@ fn genVarDbgInfo( // TODO: this might need adjusting like the linkers do. // Instead of flattening the owner and passing Decl.Index here we may // want to special case LazySymbol in DWARF linker too. - try dw.genVarDbgInfo(name, ty, self.owner.getOwnerDecl(), is_ptr, loc); + try dw.genVarDbgInfo(name, ty, self.owner.getDecl(), is_ptr, loc); }, .plan9 => {}, .none => {}, @@ -6630,38 +6602,13 @@ fn airCmpVector(self: *Self, inst: Air.Inst.Index) !void { } fn airCmpLtErrorsLen(self: *Self, inst: Air.Inst.Index) !void { + const mod = self.bin_file.options.module.?; const un_op = self.air.instructions.items(.data)[inst].un_op; const addr_reg = try self.register_manager.allocReg(null, gp); const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg); defer self.register_manager.unlockReg(addr_lock); - - const mod = self.bin_file.options.module.?; - const lazy_sym = link.File.LazySymbol.initDecl(.const_data, null, mod); - if (self.bin_file.cast(link.File.Elf)) |elf_file| { - const atom_index = elf_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err| - return self.fail("{s} creating lazy symbol", .{@errorName(err)}); - const atom = elf_file.getAtom(atom_index); - _ = try atom.getOrCreateOffsetTableEntry(elf_file); - const got_addr = atom.getOffsetTableAddress(elf_file); - try self.asmRegisterMemory( - .mov, - addr_reg.to64(), - Memory.sib(.qword, .{ .base = .{ .reg = .ds }, .disp = @intCast(i32, got_addr) }), - ); - } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { - const atom_index = coff_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err| - return self.fail("{s} creating lazy symbol", .{@errorName(err)}); - const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?; - try self.genSetReg(addr_reg, Type.usize, .{ .lea_got = sym_index }); - } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { - const atom_index = macho_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err| - return self.fail("{s} creating lazy symbol", .{@errorName(err)}); - const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?; - try self.genSetReg(addr_reg, Type.usize, .{ .lea_got = sym_index }); - } else { - return self.fail("TODO implement airCmpLtErrorsLen for x86_64 {s}", .{@tagName(self.bin_file.tag)}); - } + try self.genLazySymbolRef(.lea, addr_reg, link.File.LazySymbol.initDecl(.const_data, null, mod)); try self.spillEflagsIfOccupied(); self.eflags_inst = inst; @@ -7999,6 +7946,67 @@ fn genInlineMemset(self: *Self, dst_ptr: MCValue, value: MCValue, len: MCValue) }); } +fn genLazySymbolRef( + self: *Self, + comptime tag: Mir.Inst.Tag, + reg: Register, + lazy_sym: link.File.LazySymbol, +) InnerError!void { + if (self.bin_file.cast(link.File.Elf)) |elf_file| { + const atom_index = elf_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err| + return self.fail("{s} creating lazy symbol", .{@errorName(err)}); + const atom = elf_file.getAtom(atom_index); + _ = try atom.getOrCreateOffsetTableEntry(elf_file); + const got_addr = atom.getOffsetTableAddress(elf_file); + const got_mem = + Memory.sib(.qword, .{ .base = .{ .reg = .ds }, .disp = @intCast(i32, got_addr) }); + switch (tag) { + .lea, .mov => try self.asmRegisterMemory(.mov, reg.to64(), got_mem), + .call => try self.asmMemory(.call, got_mem), + else => unreachable, + } + switch (tag) { + .lea, .call => {}, + .mov => try self.asmRegisterMemory( + tag, + reg.to64(), + Memory.sib(.qword, .{ .base = .{ .reg = reg.to64() } }), + ), + else => unreachable, + } + } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { + const atom_index = coff_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err| + return self.fail("{s} creating lazy symbol", .{@errorName(err)}); + const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?; + switch (tag) { + .lea, .call => try self.genSetReg(reg, Type.usize, .{ .lea_got = sym_index }), + .mov => try self.genSetReg(reg, Type.usize, .{ .load_got = sym_index }), + else => unreachable, + } + switch (tag) { + .lea, .mov => {}, + .call => try self.asmRegister(.call, reg), + else => unreachable, + } + } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { + const atom_index = macho_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err| + return self.fail("{s} creating lazy symbol", .{@errorName(err)}); + const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?; + switch (tag) { + .lea, .call => try self.genSetReg(reg, Type.usize, .{ .lea_got = sym_index }), + .mov => try self.genSetReg(reg, Type.usize, .{ .load_got = sym_index }), + else => unreachable, + } + switch (tag) { + .lea, .mov => {}, + .call => try self.asmRegister(.call, reg), + else => unreachable, + } + } else { + return self.fail("TODO implement genLazySymbol for x86_64 {s}", .{@tagName(self.bin_file.tag)}); + } +} + fn airPtrToInt(self: *Self, inst: Air.Inst.Index) !void { const un_op = self.air.instructions.items(.data)[inst].un_op; const result = result: { @@ -8701,6 +8709,7 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void { } fn airTagName(self: *Self, inst: Air.Inst.Index) !void { + const mod = self.bin_file.options.module.?; const un_op = self.air.instructions.items(.data)[inst].un_op; const inst_ty = self.air.typeOfIndex(inst); const enum_ty = self.air.typeOf(un_op); @@ -8731,38 +8740,17 @@ fn airTagName(self: *Self, inst: Air.Inst.Index) !void { const operand = try self.resolveInst(un_op); try self.genSetReg(param_regs[1], enum_ty, operand); - const mod = self.bin_file.options.module.?; - const lazy_sym = link.File.LazySymbol.initDecl(.code, enum_ty.getOwnerDecl(), mod); - if (self.bin_file.cast(link.File.Elf)) |elf_file| { - const atom_index = elf_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err| - return self.fail("{s} creating lazy symbol", .{@errorName(err)}); - const atom = elf_file.getAtom(atom_index); - _ = try atom.getOrCreateOffsetTableEntry(elf_file); - const got_addr = atom.getOffsetTableAddress(elf_file); - try self.asmMemory( - .call, - Memory.sib(.qword, .{ .base = .{ .reg = .ds }, .disp = @intCast(i32, got_addr) }), - ); - } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { - const atom_index = coff_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err| - return self.fail("{s} creating lazy symbol", .{@errorName(err)}); - const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?; - try self.genSetReg(.rax, Type.usize, .{ .lea_got = sym_index }); - try self.asmRegister(.call, .rax); - } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { - const atom_index = macho_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err| - return self.fail("{s} creating lazy symbol", .{@errorName(err)}); - const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?; - try self.genSetReg(.rax, Type.usize, .{ .lea_got = sym_index }); - try self.asmRegister(.call, .rax); - } else { - return self.fail("TODO implement airTagName for x86_64 {s}", .{@tagName(self.bin_file.tag)}); - } + try self.genLazySymbolRef( + .call, + .rax, + link.File.LazySymbol.initDecl(.code, enum_ty.getOwnerDecl(), mod), + ); return self.finishAir(inst, dst_mcv, .{ un_op, .none, .none }); } fn airErrorName(self: *Self, inst: Air.Inst.Index) !void { + const mod = self.bin_file.options.module.?; const un_op = self.air.instructions.items(.data)[inst].un_op; const err_ty = self.air.typeOf(un_op); @@ -8774,33 +8762,7 @@ fn airErrorName(self: *Self, inst: Air.Inst.Index) !void { const addr_reg = try self.register_manager.allocReg(null, gp); const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg); defer self.register_manager.unlockReg(addr_lock); - - const mod = self.bin_file.options.module.?; - const lazy_sym = link.File.LazySymbol.initDecl(.const_data, null, mod); - if (self.bin_file.cast(link.File.Elf)) |elf_file| { - const atom_index = elf_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err| - return self.fail("{s} creating lazy symbol", .{@errorName(err)}); - const atom = elf_file.getAtom(atom_index); - _ = try atom.getOrCreateOffsetTableEntry(elf_file); - const got_addr = atom.getOffsetTableAddress(elf_file); - try self.asmRegisterMemory( - .mov, - addr_reg.to64(), - Memory.sib(.qword, .{ .base = .{ .reg = .ds }, .disp = @intCast(i32, got_addr) }), - ); - } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { - const atom_index = coff_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err| - return self.fail("{s} creating lazy symbol", .{@errorName(err)}); - const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?; - try self.genSetReg(addr_reg, Type.usize, .{ .lea_got = sym_index }); - } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { - const atom_index = macho_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err| - return self.fail("{s} creating lazy symbol", .{@errorName(err)}); - const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?; - try self.genSetReg(addr_reg, Type.usize, .{ .lea_got = sym_index }); - } else { - return self.fail("TODO implement airErrorName for x86_64 {s}", .{@tagName(self.bin_file.tag)}); - } + try self.genLazySymbolRef(.lea, addr_reg, link.File.LazySymbol.initDecl(.const_data, null, mod)); const start_reg = try self.register_manager.allocReg(null, gp); const start_lock = self.register_manager.lockRegAssumeUnused(start_reg); @@ -9117,7 +9079,7 @@ fn limitImmediateType(self: *Self, operand: Air.Inst.Ref, comptime T: type) !MCV } fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue { - return switch (try codegen.genTypedValue(self.bin_file, self.src_loc, arg_tv, self.owner.getOwnerDecl())) { + return switch (try codegen.genTypedValue(self.bin_file, self.src_loc, arg_tv, self.owner.getDecl())) { .mcv => |mcv| switch (mcv) { .none => .none, .undef => .undef, diff --git a/src/link/Coff.zig b/src/link/Coff.zig index 41d4617e53..81e8c57bdd 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -143,8 +143,11 @@ const Section = struct { const LazySymbolTable = std.AutoArrayHashMapUnmanaged(Module.Decl.OptionalIndex, LazySymbolMetadata); const LazySymbolMetadata = struct { - text_atom: ?Atom.Index = null, - rdata_atom: ?Atom.Index = null, + const State = enum { unused, pending_flush, flushed }; + text_atom: Atom.Index = undefined, + rdata_atom: Atom.Index = undefined, + text_state: State = .unused, + rdata_state: State = .unused, }; const DeclMetadata = struct { @@ -1150,8 +1153,6 @@ pub fn updateDecl( const tracy = trace(@src()); defer tracy.end(); - try self.updateLazySymbol(decl_index); - const decl = module.declPtr(decl_index); if (decl.val.tag() == .extern_fn) { @@ -1194,21 +1195,6 @@ pub fn updateDecl( return self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index)); } -fn updateLazySymbol(self: *Coff, decl: ?Module.Decl.Index) !void { - const metadata = self.lazy_syms.get(Module.Decl.OptionalIndex.init(decl)) orelse return; - const mod = self.base.options.module.?; - if (metadata.text_atom) |atom| try self.updateLazySymbolAtom( - link.File.LazySymbol.initDecl(.code, decl, mod), - atom, - self.text_section_index.?, - ); - if (metadata.rdata_atom) |atom| try self.updateLazySymbolAtom( - link.File.LazySymbol.initDecl(.const_data, decl, mod), - atom, - self.rdata_section_index.?, - ); -} - fn updateLazySymbolAtom( self: *Coff, sym: link.File.LazySymbol, @@ -1279,14 +1265,19 @@ pub fn getOrCreateAtomForLazySymbol(self: *Coff, sym: link.File.LazySymbol) !Ato const gop = try self.lazy_syms.getOrPut(self.base.allocator, sym.getDecl()); errdefer _ = if (!gop.found_existing) self.lazy_syms.pop(); if (!gop.found_existing) gop.value_ptr.* = .{}; - const atom_ptr = switch (sym.kind) { - .code => &gop.value_ptr.text_atom, - .const_data => &gop.value_ptr.rdata_atom, + const metadata: struct { atom: *Atom.Index, state: *LazySymbolMetadata.State } = switch (sym.kind) { + .code => .{ .atom = &gop.value_ptr.text_atom, .state = &gop.value_ptr.text_state }, + .const_data => .{ .atom = &gop.value_ptr.rdata_atom, .state = &gop.value_ptr.rdata_state }, }; - if (atom_ptr.*) |atom| return atom; - const atom = try self.createAtom(); - atom_ptr.* = atom; - try self.updateLazySymbolAtom(sym, atom, switch (sym.kind) { + switch (metadata.state.*) { + .unused => metadata.atom.* = try self.createAtom(), + .pending_flush => return metadata.atom.*, + .flushed => {}, + } + metadata.state.* = .pending_flush; + const atom = metadata.atom.*; + // anyerror needs to be deferred until flushModule + if (sym.getDecl() != .none) try self.updateLazySymbolAtom(sym, atom, switch (sym.kind) { .code => self.text_section_index.?, .const_data => self.rdata_section_index.?, }); @@ -1617,15 +1608,35 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod sub_prog_node.activate(); defer sub_prog_node.end(); - // Most lazy symbols can be updated when the corresponding decl is, - // so we only have to worry about the one without an associated decl. - self.updateLazySymbol(null) catch |err| switch (err) { - error.CodegenFail => return error.FlushFailure, - else => |e| return e, - }; - const gpa = self.base.allocator; + const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented; + + if (self.lazy_syms.getPtr(.none)) |metadata| { + // Most lazy symbols can be updated on first use, but + // anyerror needs to wait for everything to be flushed. + if (metadata.text_state != .unused) self.updateLazySymbolAtom( + link.File.LazySymbol.initDecl(.code, null, module), + metadata.text_atom, + self.text_section_index.?, + ) catch |err| return switch (err) { + error.CodegenFail => error.FlushFailure, + else => |e| e, + }; + if (metadata.rdata_state != .unused) self.updateLazySymbolAtom( + link.File.LazySymbol.initDecl(.const_data, null, module), + metadata.rdata_atom, + self.rdata_section_index.?, + ) catch |err| return switch (err) { + error.CodegenFail => error.FlushFailure, + else => |e| e, + }; + } + for (self.lazy_syms.values()) |*metadata| { + if (metadata.text_state != .unused) metadata.text_state = .flushed; + if (metadata.rdata_state != .unused) metadata.rdata_state = .flushed; + } + while (self.unresolved.popOrNull()) |entry| { assert(entry.value); // We only expect imports generated by the incremental linker for now. const global = self.globals.items[entry.key]; diff --git a/src/link/Elf.zig b/src/link/Elf.zig index ec113e5c8a..724ec76500 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -65,8 +65,11 @@ const Section = struct { }; const LazySymbolMetadata = struct { - text_atom: ?Atom.Index = null, - rodata_atom: ?Atom.Index = null, + const State = enum { unused, pending_flush, flushed }; + text_atom: Atom.Index = undefined, + rodata_atom: Atom.Index = undefined, + text_state: State = .unused, + rodata_state: State = .unused, }; const DeclMetadata = struct { @@ -1032,17 +1035,35 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node sub_prog_node.activate(); defer sub_prog_node.end(); - // Most lazy symbols can be updated when the corresponding decl is, - // so we only have to worry about the one without an associated decl. - self.updateLazySymbol(null) catch |err| switch (err) { - error.CodegenFail => return error.FlushFailure, - else => |e| return e, - }; - // TODO This linker code currently assumes there is only 1 compilation unit and it // corresponds to the Zig source code. const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented; + if (self.lazy_syms.getPtr(.none)) |metadata| { + // Most lazy symbols can be updated on first use, but + // anyerror needs to wait for everything to be flushed. + if (metadata.text_state != .unused) self.updateLazySymbolAtom( + File.LazySymbol.initDecl(.code, null, module), + metadata.text_atom, + self.text_section_index.?, + ) catch |err| return switch (err) { + error.CodegenFail => error.FlushFailure, + else => |e| e, + }; + if (metadata.rodata_state != .unused) self.updateLazySymbolAtom( + File.LazySymbol.initDecl(.const_data, null, module), + metadata.rodata_atom, + self.rodata_section_index.?, + ) catch |err| return switch (err) { + error.CodegenFail => error.FlushFailure, + else => |e| e, + }; + } + for (self.lazy_syms.values()) |*metadata| { + if (metadata.text_state != .unused) metadata.text_state = .flushed; + if (metadata.rodata_state != .unused) metadata.rodata_state = .flushed; + } + const target_endian = self.base.options.target.cpu.arch.endian(); const foreign_endian = target_endian != builtin.cpu.arch.endian(); @@ -2378,14 +2399,19 @@ pub fn getOrCreateAtomForLazySymbol(self: *Elf, sym: File.LazySymbol) !Atom.Inde const gop = try self.lazy_syms.getOrPut(self.base.allocator, sym.getDecl()); errdefer _ = if (!gop.found_existing) self.lazy_syms.pop(); if (!gop.found_existing) gop.value_ptr.* = .{}; - const atom_ptr = switch (sym.kind) { - .code => &gop.value_ptr.text_atom, - .const_data => &gop.value_ptr.rodata_atom, + const metadata: struct { atom: *Atom.Index, state: *LazySymbolMetadata.State } = switch (sym.kind) { + .code => .{ .atom = &gop.value_ptr.text_atom, .state = &gop.value_ptr.text_state }, + .const_data => .{ .atom = &gop.value_ptr.rodata_atom, .state = &gop.value_ptr.rodata_state }, }; - if (atom_ptr.*) |atom| return atom; - const atom = try self.createAtom(); - atom_ptr.* = atom; - try self.updateLazySymbolAtom(sym, atom, switch (sym.kind) { + switch (metadata.state.*) { + .unused => metadata.atom.* = try self.createAtom(), + .pending_flush => return metadata.atom.*, + .flushed => {}, + } + metadata.state.* = .pending_flush; + const atom = metadata.atom.*; + // anyerror needs to be deferred until flushModule + if (sym.getDecl() != .none) try self.updateLazySymbolAtom(sym, atom, switch (sym.kind) { .code => self.text_section_index.?, .const_data => self.rodata_section_index.?, }); @@ -2598,8 +2624,6 @@ pub fn updateDecl( const tracy = trace(@src()); defer tracy.end(); - try self.updateLazySymbol(decl_index); - const decl = module.declPtr(decl_index); if (decl.val.tag() == .extern_fn) { @@ -2666,21 +2690,6 @@ pub fn updateDecl( return self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index)); } -fn updateLazySymbol(self: *Elf, decl: ?Module.Decl.Index) !void { - const metadata = self.lazy_syms.get(Module.Decl.OptionalIndex.init(decl)) orelse return; - const mod = self.base.options.module.?; - if (metadata.text_atom) |atom| try self.updateLazySymbolAtom( - File.LazySymbol.initDecl(.code, decl, mod), - atom, - self.text_section_index.?, - ); - if (metadata.rodata_atom) |atom| try self.updateLazySymbolAtom( - File.LazySymbol.initDecl(.const_data, decl, mod), - atom, - self.rodata_section_index.?, - ); -} - fn updateLazySymbolAtom( self: *Elf, sym: File.LazySymbol, diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 458b283d4f..a346ec756f 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -236,8 +236,11 @@ const is_hot_update_compatible = switch (builtin.target.os.tag) { const LazySymbolTable = std.AutoArrayHashMapUnmanaged(Module.Decl.OptionalIndex, LazySymbolMetadata); const LazySymbolMetadata = struct { - text_atom: ?Atom.Index = null, - data_const_atom: ?Atom.Index = null, + const State = enum { unused, pending_flush, flushed }; + text_atom: Atom.Index = undefined, + data_const_atom: Atom.Index = undefined, + text_state: State = .unused, + data_const_state: State = .unused, }; const TlvSymbolTable = std.AutoArrayHashMapUnmanaged(SymbolWithLoc, Atom.Index); @@ -493,15 +496,33 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No sub_prog_node.activate(); defer sub_prog_node.end(); - // Most lazy symbols can be updated when the corresponding decl is, - // so we only have to worry about the one without an associated decl. - self.updateLazySymbol(null) catch |err| switch (err) { - error.CodegenFail => return error.FlushFailure, - else => |e| return e, - }; - const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented; + if (self.lazy_syms.getPtr(.none)) |metadata| { + // Most lazy symbols can be updated on first use, but + // anyerror needs to wait for everything to be flushed. + if (metadata.text_state != .unused) self.updateLazySymbolAtom( + File.LazySymbol.initDecl(.code, null, module), + metadata.text_atom, + self.text_section_index.?, + ) catch |err| return switch (err) { + error.CodegenFail => error.FlushFailure, + else => |e| e, + }; + if (metadata.data_const_state != .unused) self.updateLazySymbolAtom( + File.LazySymbol.initDecl(.const_data, null, module), + metadata.data_const_atom, + self.data_const_section_index.?, + ) catch |err| return switch (err) { + error.CodegenFail => error.FlushFailure, + else => |e| e, + }; + } + for (self.lazy_syms.values()) |*metadata| { + if (metadata.text_state != .unused) metadata.text_state = .flushed; + if (metadata.data_const_state != .unused) metadata.data_const_state = .flushed; + } + if (self.d_sym) |*d_sym| { try d_sym.dwarf.flushModule(module); } @@ -1960,8 +1981,6 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index) const tracy = trace(@src()); defer tracy.end(); - try self.updateLazySymbol(decl_index); - const decl = module.declPtr(decl_index); if (decl.val.tag() == .extern_fn) { @@ -2036,21 +2055,6 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index) try self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index)); } -fn updateLazySymbol(self: *MachO, decl: ?Module.Decl.Index) !void { - const metadata = self.lazy_syms.get(Module.Decl.OptionalIndex.init(decl)) orelse return; - const mod = self.base.options.module.?; - if (metadata.text_atom) |atom| try self.updateLazySymbolAtom( - File.LazySymbol.initDecl(.code, decl, mod), - atom, - self.text_section_index.?, - ); - if (metadata.data_const_atom) |atom| try self.updateLazySymbolAtom( - File.LazySymbol.initDecl(.const_data, decl, mod), - atom, - self.data_const_section_index.?, - ); -} - fn updateLazySymbolAtom( self: *MachO, sym: File.LazySymbol, @@ -2125,14 +2129,22 @@ pub fn getOrCreateAtomForLazySymbol(self: *MachO, sym: File.LazySymbol) !Atom.In const gop = try self.lazy_syms.getOrPut(self.base.allocator, sym.getDecl()); errdefer _ = if (!gop.found_existing) self.lazy_syms.pop(); if (!gop.found_existing) gop.value_ptr.* = .{}; - const atom_ptr = switch (sym.kind) { - .code => &gop.value_ptr.text_atom, - .const_data => &gop.value_ptr.data_const_atom, + const metadata: struct { atom: *Atom.Index, state: *LazySymbolMetadata.State } = switch (sym.kind) { + .code => .{ .atom = &gop.value_ptr.text_atom, .state = &gop.value_ptr.text_state }, + .const_data => .{ + .atom = &gop.value_ptr.data_const_atom, + .state = &gop.value_ptr.data_const_state, + }, }; - if (atom_ptr.*) |atom| return atom; - const atom = try self.createAtom(); - atom_ptr.* = atom; - try self.updateLazySymbolAtom(sym, atom, switch (sym.kind) { + switch (metadata.state.*) { + .unused => metadata.atom.* = try self.createAtom(), + .pending_flush => return metadata.atom.*, + .flushed => {}, + } + metadata.state.* = .pending_flush; + const atom = metadata.atom.*; + // anyerror needs to be deferred until flushModule + if (sym.getDecl() != .none) try self.updateLazySymbolAtom(sym, atom, switch (sym.kind) { .code => self.text_section_index.?, .const_data => self.data_const_section_index.?, }); From 6f1336a50c6c2d9498bb9b3fb291cb305688c1b9 Mon Sep 17 00:00:00 2001 From: r00ster91 Date: Tue, 2 May 2023 04:41:25 +0200 Subject: [PATCH 052/725] autodoc: make the help modal toggleable Now you can simply press "?" again to toggle the help modal instead of requiring Esc. Both Esc and "?" work. --- lib/docs/index.html | 2 +- lib/docs/main.js | 13 +++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/lib/docs/index.html b/lib/docs/index.html index 6b9f95a7d0..36cfcc55cc 100644 --- a/lib/docs/index.html +++ b/lib/docs/index.html @@ -875,7 +875,7 @@