authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-08-21 14:50:37-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-08-21 14:50:37-07:00
logf9bd049c89e4d2b4d3f51a937ec2114c3cac9176
tree81bf283c8ae2e06fd3a48d18e3b4196e194392d0
parent3aeeb21b82915a3d03e75a88ded93049a5c1730c
parentdad7af0b37f352c8c390438877ef1552a316ffde

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


526 files changed, 9582 insertions(+), 4926 deletions(-)

build.zig+1-1
...@@ -38,7 +38,7 @@ pub fn build(b: *Builder) !void {...@@ -38,7 +38,7 @@ pub fn build(b: *Builder) !void {
38 const test_step = b.step("test", "Run all the tests");38 const test_step = b.step("test", "Run all the tests");
3939
40 var test_stage2 = b.addTest("src-self-hosted/test.zig");40 var test_stage2 = b.addTest("src-self-hosted/test.zig");
41 test_stage2.setBuildMode(.Debug); // note this is only the mode of the test harness41 test_stage2.setBuildMode(mode);
42 test_stage2.addPackagePath("stage2_tests", "test/stage2/test.zig");42 test_stage2.addPackagePath("stage2_tests", "test/stage2/test.zig");
4343
44 const fmt_build_zig = b.addFmt(&[_][]const u8{"build.zig"});44 const fmt_build_zig = b.addFmt(&[_][]const u8{"build.zig"});
lib/std/array_list.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std.zig");6const std = @import("std.zig");
2const debug = std.debug;7const debug = std.debug;
3const assert = debug.assert;8const assert = debug.assert;
lib/std/array_list_sentineled.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std.zig");6const std = @import("std.zig");
2const debug = std.debug;7const debug = std.debug;
3const mem = std.mem;8const mem = std.mem;
lib/std/ascii.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Does NOT look at the locale the way C89's toupper(3), isspace() et cetera does.6// Does NOT look at the locale the way C89's toupper(3), isspace() et cetera does.
2// I could have taken only a u7 to make this clear, but it would be slower7// I could have taken only a u7 to make this clear, but it would be slower
3// It is my opinion that encodings other than UTF-8 should not be supported.8// It is my opinion that encodings other than UTF-8 should not be supported.
lib/std/atomic.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1pub const Stack = @import("atomic/stack.zig").Stack;6pub const Stack = @import("atomic/stack.zig").Stack;
2pub const Queue = @import("atomic/queue.zig").Queue;7pub const Queue = @import("atomic/queue.zig").Queue;
3pub const Int = @import("atomic/int.zig").Int;8pub const Int = @import("atomic/int.zig").Int;
lib/std/atomic/int.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1/// Thread-safe, lock-free integer6/// Thread-safe, lock-free integer
2pub fn Int(comptime T: type) type {7pub fn Int(comptime T: type) type {
3 return struct {8 return struct {
lib/std/atomic/queue.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const builtin = @import("builtin");7const builtin = @import("builtin");
3const assert = std.debug.assert;8const assert = std.debug.assert;
lib/std/atomic/stack.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const assert = std.debug.assert;6const assert = std.debug.assert;
2const builtin = @import("builtin");7const builtin = @import("builtin");
3const expect = std.testing.expect;8const expect = std.testing.expect;
lib/std/base64.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std.zig");6const std = @import("std.zig");
2const assert = std.debug.assert;7const assert = std.debug.assert;
3const testing = std.testing;8const testing = std.testing;
lib/std/bloom_filter.zig+6-1
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const builtin = @import("builtin");6const builtin = @import("builtin");
2const std = @import("std.zig");7const std = @import("std.zig");
3const math = std.math;8const math = std.math;
...@@ -153,7 +158,7 @@ pub fn BloomFilter(...@@ -153,7 +158,7 @@ pub fn BloomFilter(
153}158}
154159
155fn hashFunc(out: []u8, Ki: usize, in: []const u8) void {160fn hashFunc(out: []u8, Ki: usize, in: []const u8) void {
156 var st = std.crypto.gimli.Hash.init();161 var st = std.crypto.hash.Gimli.init(.{});
157 st.update(std.mem.asBytes(&Ki));162 st.update(std.mem.asBytes(&Ki));
158 st.update(in);163 st.update(in);
159 st.final(out);164 st.final(out);
lib/std/buf_map.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std.zig");6const std = @import("std.zig");
2const StringHashMap = std.StringHashMap;7const StringHashMap = std.StringHashMap;
3const mem = std.mem;8const mem = std.mem;
lib/std/buf_set.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std.zig");6const std = @import("std.zig");
2const StringHashMap = std.StringHashMap;7const StringHashMap = std.StringHashMap;
3const mem = @import("mem.zig");8const mem = @import("mem.zig");
lib/std/build.zig+32-1
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std.zig");6const std = @import("std.zig");
2const builtin = std.builtin;7const builtin = std.builtin;
3const io = std.io;8const io = std.io;
...@@ -449,7 +454,33 @@ pub const Builder = struct {...@@ -449,7 +454,33 @@ pub const Builder = struct {
449 return null;454 return null;
450 },455 },
451 },456 },
452 .Int => panic("TODO integer options to build script", .{}),457 .Int => switch (entry.value.value) {
458 .Flag => {
459 warn("Expected -D{} to be an integer, but received a boolean.\n", .{name});
460 self.markInvalidUserInput();
461 return null;
462 },
463 .Scalar => |s| {
464 const n = std.fmt.parseInt(T, s, 10) catch |err| switch (err) {
465 error.Overflow => {
466 warn("-D{} value {} cannot fit into type {}.\n", .{ name, s, @typeName(T) });
467 self.markInvalidUserInput();
468 return null;
469 },
470 else => {
471 warn("Expected -D{} to be an integer of type {}.\n", .{ name, @typeName(T) });
472 self.markInvalidUserInput();
473 return null;
474 },
475 };
476 return n;
477 },
478 .List => {
479 warn("Expected -D{} to be an integer, but received a list.\n", .{name});
480 self.markInvalidUserInput();
481 return null;
482 },
483 },
453 .Float => panic("TODO float options to build script", .{}),484 .Float => panic("TODO float options to build script", .{}),
454 .Enum => switch (entry.value.value) {485 .Enum => switch (entry.value.value) {
455 .Flag => {486 .Flag => {
lib/std/build/check_file.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const build = std.build;7const build = std.build;
3const Step = build.Step;8const Step = build.Step;
lib/std/build/emit_raw.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std");6const std = @import("std");
27
3const Allocator = std.mem.Allocator;8const Allocator = std.mem.Allocator;
lib/std/build/fmt.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const build = @import("../build.zig");7const build = @import("../build.zig");
3const Step = build.Step;8const Step = build.Step;
lib/std/build/run.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const builtin = std.builtin;7const builtin = std.builtin;
3const build = std.build;8const build = std.build;
lib/std/build/translate_c.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const build = std.build;7const build = std.build;
3const Step = build.Step;8const Step = build.Step;
lib/std/build/write_file.zig+6-1
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const build = @import("../build.zig");7const build = @import("../build.zig");
3const Step = build.Step;8const Step = build.Step;
...@@ -53,7 +58,7 @@ pub const WriteFileStep = struct {...@@ -53,7 +58,7 @@ pub const WriteFileStep = struct {
53 // TODO port the cache system from stage1 to zig std lib. Until then we use blake2b58 // TODO port the cache system from stage1 to zig std lib. Until then we use blake2b
54 // directly and construct the path, and no "cache hit" detection happens; the files59 // directly and construct the path, and no "cache hit" detection happens; the files
55 // are always written.60 // are always written.
56 var hash = std.crypto.Blake2b384.init();61 var hash = std.crypto.hash.blake2.Blake2b384.init(.{});
5762
58 // Random bytes to make WriteFileStep unique. Refresh this with63 // Random bytes to make WriteFileStep unique. Refresh this with
59 // new random bytes when WriteFileStep implementation is modified64 // new random bytes when WriteFileStep implementation is modified
lib/std/builtin.zig+5-1
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1pub usingnamespace @import("builtin");6pub usingnamespace @import("builtin");
27
3/// Deprecated: use `std.Target`.8/// Deprecated: use `std.Target`.
...@@ -254,7 +259,6 @@ pub const TypeInfo = union(enum) {...@@ -254,7 +259,6 @@ pub const TypeInfo = union(enum) {
254 /// therefore must be kept in sync with the compiler implementation.259 /// therefore must be kept in sync with the compiler implementation.
255 pub const StructField = struct {260 pub const StructField = struct {
256 name: []const u8,261 name: []const u8,
257 offset: ?comptime_int,
258 field_type: type,262 field_type: type,
259 default_value: anytype,263 default_value: anytype,
260 };264 };
lib/std/c.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std");6const std = @import("std");
2const builtin = std.builtin;7const builtin = std.builtin;
3const page_size = std.mem.page_size;8const page_size = std.mem.page_size;
lib/std/c/ast.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std");6const std = @import("std");
2const SegmentedList = std.SegmentedList;7const SegmentedList = std.SegmentedList;
3const Token = std.c.Token;8const Token = std.c.Token;
lib/std/c/darwin.zig+8-2
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const assert = std.debug.assert;7const assert = std.debug.assert;
3const builtin = @import("builtin");8const builtin = @import("builtin");
...@@ -41,10 +46,11 @@ const mach_hdr = if (@sizeOf(usize) == 8) mach_header_64 else mach_header;...@@ -41,10 +46,11 @@ const mach_hdr = if (@sizeOf(usize) == 8) mach_header_64 else mach_header;
41/// on this operating system. However when building object files or libraries,46/// on this operating system. However when building object files or libraries,
42/// the system libc won't be linked until the final executable. So we47/// the system libc won't be linked until the final executable. So we
43/// export a weak symbol here, to be overridden by the real one.48/// export a weak symbol here, to be overridden by the real one.
44pub extern "c" var _mh_execute_header: mach_hdr = undefined;49var dummy_execute_header: mach_hdr = undefined;
50pub extern var _mh_execute_header: mach_hdr;
45comptime {51comptime {
46 if (std.Target.current.isDarwin()) {52 if (std.Target.current.isDarwin()) {
47 @export(_mh_execute_header, .{ .name = "_mh_execute_header", .linkage = .Weak });53 @export(dummy_execute_header, .{ .name = "_mh_execute_header", .linkage = .Weak });
48 }54 }
49}55}
5056
lib/std/c/dragonfly.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2usingnamespace std.c;7usingnamespace std.c;
3extern "c" threadlocal var errno: c_int;8extern "c" threadlocal var errno: c_int;
lib/std/c/emscripten.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1pub const pthread_mutex_t = extern struct {6pub const pthread_mutex_t = extern struct {
2 size: [__SIZEOF_PTHREAD_MUTEX_T]u8 align(4) = [_]u8{0} ** __SIZEOF_PTHREAD_MUTEX_T,7 size: [__SIZEOF_PTHREAD_MUTEX_T]u8 align(4) = [_]u8{0} ** __SIZEOF_PTHREAD_MUTEX_T,
3};8};
lib/std/c/freebsd.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2usingnamespace std.c;7usingnamespace std.c;
38
lib/std/c/fuchsia.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1pub const pthread_mutex_t = extern struct {6pub const pthread_mutex_t = extern struct {
2 size: [__SIZEOF_PTHREAD_MUTEX_T]u8 align(@alignOf(usize)) = [_]u8{0} ** __SIZEOF_PTHREAD_MUTEX_T,7 size: [__SIZEOF_PTHREAD_MUTEX_T]u8 align(@alignOf(usize)) = [_]u8{0} ** __SIZEOF_PTHREAD_MUTEX_T,
3};8};
lib/std/c/haiku.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1pub const pthread_mutex_t = extern struct {6pub const pthread_mutex_t = extern struct {
2 flags: u32 = 0,7 flags: u32 = 0,
3 lock: i32 = 0,8 lock: i32 = 0,
lib/std/c/hermit.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1pub const pthread_mutex_t = extern struct {6pub const pthread_mutex_t = extern struct {
2 inner: usize = ~@as(usize, 0),7 inner: usize = ~@as(usize, 0),
3};8};
lib/std/c/linux.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const builtin = @import("builtin");6const builtin = @import("builtin");
2const std = @import("../std.zig");7const std = @import("../std.zig");
3const maxInt = std.math.maxInt;8const maxInt = std.math.maxInt;
lib/std/c/minix.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const builtin = @import("builtin");6const builtin = @import("builtin");
2pub const pthread_mutex_t = extern struct {7pub const pthread_mutex_t = extern struct {
3 size: [__SIZEOF_PTHREAD_MUTEX_T]u8 align(@alignOf(usize)) = [_]u8{0} ** __SIZEOF_PTHREAD_MUTEX_T,8 size: [__SIZEOF_PTHREAD_MUTEX_T]u8 align(@alignOf(usize)) = [_]u8{0} ** __SIZEOF_PTHREAD_MUTEX_T,
lib/std/c/netbsd.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const builtin = std.builtin;7const builtin = std.builtin;
38
lib/std/c/openbsd.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1pub const pthread_mutex_t = extern struct {6pub const pthread_mutex_t = extern struct {
2 inner: ?*c_void = null,7 inner: ?*c_void = null,
3};8};
lib/std/c/parse.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std");6const std = @import("std");
2const mem = std.mem;7const mem = std.mem;
3const assert = std.debug.assert;8const assert = std.debug.assert;
lib/std/c/solaris.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1pub const pthread_mutex_t = extern struct {6pub const pthread_mutex_t = extern struct {
2 __pthread_mutex_flag1: u16 = 0,7 __pthread_mutex_flag1: u16 = 0,
3 __pthread_mutex_flag2: u8 = 0,8 __pthread_mutex_flag2: u8 = 0,
lib/std/c/tokenizer.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std");6const std = @import("std");
2const mem = std.mem;7const mem = std.mem;
38
lib/std/c/windows.zig+5
...@@ -1 +1,6 @@...@@ -1 +1,6 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1pub extern "c" fn _errno() *c_int;6pub extern "c" fn _errno() *c_int;
lib/std/cache_hash.zig+11-6
...@@ -1,5 +1,10 @@...@@ -1,5 +1,10 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std.zig");6const std = @import("std.zig");
2const Blake3 = std.crypto.Blake3;7const Blake3 = std.crypto.hash.Blake3;
3const fs = std.fs;8const fs = std.fs;
4const base64 = std.base64;9const base64 = std.base64;
5const ArrayList = std.ArrayList;10const ArrayList = std.ArrayList;
...@@ -51,7 +56,7 @@ pub const CacheHash = struct {...@@ -51,7 +56,7 @@ pub const CacheHash = struct {
51 pub fn init(allocator: *Allocator, dir: fs.Dir, manifest_dir_path: []const u8) !CacheHash {56 pub fn init(allocator: *Allocator, dir: fs.Dir, manifest_dir_path: []const u8) !CacheHash {
52 return CacheHash{57 return CacheHash{
53 .allocator = allocator,58 .allocator = allocator,
54 .blake3 = Blake3.init(),59 .blake3 = Blake3.init(.{}),
55 .manifest_dir = try dir.makeOpenPath(manifest_dir_path, .{}),60 .manifest_dir = try dir.makeOpenPath(manifest_dir_path, .{}),
56 .manifest_file = null,61 .manifest_file = null,
57 .manifest_dirty = false,62 .manifest_dirty = false,
...@@ -132,7 +137,7 @@ pub const CacheHash = struct {...@@ -132,7 +137,7 @@ pub const CacheHash = struct {
132137
133 base64_encoder.encode(self.b64_digest[0..], &bin_digest);138 base64_encoder.encode(self.b64_digest[0..], &bin_digest);
134139
135 self.blake3 = Blake3.init();140 self.blake3 = Blake3.init(.{});
136 self.blake3.update(&bin_digest);141 self.blake3.update(&bin_digest);
137142
138 const manifest_file_path = try fmt.allocPrint(self.allocator, "{}.txt", .{self.b64_digest});143 const manifest_file_path = try fmt.allocPrint(self.allocator, "{}.txt", .{self.b64_digest});
...@@ -251,7 +256,7 @@ pub const CacheHash = struct {...@@ -251,7 +256,7 @@ pub const CacheHash = struct {
251 // cache miss256 // cache miss
252 // keep the manifest file open257 // keep the manifest file open
253 // reset the hash258 // reset the hash
254 self.blake3 = Blake3.init();259 self.blake3 = Blake3.init(.{});
255 self.blake3.update(&bin_digest);260 self.blake3.update(&bin_digest);
256261
257 // Remove files not in the initial hash262 // Remove files not in the initial hash
...@@ -299,7 +304,7 @@ pub const CacheHash = struct {...@@ -299,7 +304,7 @@ pub const CacheHash = struct {
299304
300 // Hash while reading from disk, to keep the contents in the cpu cache while305 // Hash while reading from disk, to keep the contents in the cpu cache while
301 // doing hashing.306 // doing hashing.
302 var blake3 = Blake3.init();307 var blake3 = Blake3.init(.{});
303 var off: usize = 0;308 var off: usize = 0;
304 while (true) {309 while (true) {
305 // give me everything you've got, captain310 // give me everything you've got, captain
...@@ -429,7 +434,7 @@ pub const CacheHash = struct {...@@ -429,7 +434,7 @@ pub const CacheHash = struct {
429};434};
430435
431fn hashFile(file: fs.File, bin_digest: []u8) !void {436fn hashFile(file: fs.File, bin_digest: []u8) !void {
432 var blake3 = Blake3.init();437 var blake3 = Blake3.init(.{});
433 var buf: [1024]u8 = undefined;438 var buf: [1024]u8 = undefined;
434439
435 while (true) {440 while (true) {
lib/std/child_process.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std.zig");6const std = @import("std.zig");
2const cstr = std.cstr;7const cstr = std.cstr;
3const unicode = std.unicode;8const unicode = std.unicode;
lib/std/coff.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const builtin = @import("builtin");6const builtin = @import("builtin");
2const std = @import("std.zig");7const std = @import("std.zig");
3const io = std.io;8const io = std.io;
lib/std/comptime_string_map.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std.zig");6const std = @import("std.zig");
2const mem = std.mem;7const mem = std.mem;
38
lib/std/crypto.zig+74-56
...@@ -1,55 +1,68 @@...@@ -1,55 +1,68 @@
1pub const Md5 = @import("crypto/md5.zig").Md5;1// SPDX-License-Identifier: MIT
2pub const Sha1 = @import("crypto/sha1.zig").Sha1;2// Copyright (c) 2015-2020 Zig Contributors
33// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4const sha2 = @import("crypto/sha2.zig");4// The MIT license requires this copyright notice to be included in all copies
5pub const Sha224 = sha2.Sha224;5// and substantial portions of the software.
6pub const Sha256 = sha2.Sha256;6
7pub const Sha384 = sha2.Sha384;7/// Hash functions.
8pub const Sha512 = sha2.Sha512;8pub const hash = struct {
99 pub const Md5 = @import("crypto/md5.zig").Md5;
10const sha3 = @import("crypto/sha3.zig");10 pub const Sha1 = @import("crypto/sha1.zig").Sha1;
11pub const Sha3_224 = sha3.Sha3_224;11 pub const sha2 = @import("crypto/sha2.zig");
12pub const Sha3_256 = sha3.Sha3_256;12 pub const sha3 = @import("crypto/sha3.zig");
13pub const Sha3_384 = sha3.Sha3_384;13 pub const blake2 = @import("crypto/blake2.zig");
14pub const Sha3_512 = sha3.Sha3_512;14 pub const Blake3 = @import("crypto/blake3.zig").Blake3;
15 pub const Gimli = @import("crypto/gimli.zig").Hash;
16};
1517
16pub const gimli = @import("crypto/gimli.zig");18/// Authentication (MAC) functions.
19pub const auth = struct {
20 pub const hmac = @import("crypto/hmac.zig");
21};
1722
18const blake2 = @import("crypto/blake2.zig");23/// Authenticated Encryption with Associated Data
19pub const Blake2s224 = blake2.Blake2s224;24pub const aead = struct {
20pub const Blake2s256 = blake2.Blake2s256;25 const chacha20 = @import("crypto/chacha20.zig");
21pub const Blake2b384 = blake2.Blake2b384;
22pub const Blake2b512 = blake2.Blake2b512;
2326
24pub const Blake3 = @import("crypto/blake3.zig").Blake3;27 pub const Gimli = @import("crypto/gimli.zig").Aead;
28 pub const ChaCha20Poly1305 = chacha20.Chacha20Poly1305;
29 pub const XChaCha20Poly1305 = chacha20.XChacha20Poly1305;
30};
2531
26const hmac = @import("crypto/hmac.zig");32/// MAC functions requiring single-use secret keys.
27pub const HmacMd5 = hmac.HmacMd5;33pub const onetimeauth = struct {
28pub const HmacSha1 = hmac.HmacSha1;34 pub const Poly1305 = @import("crypto/poly1305.zig").Poly1305;
29pub const HmacSha256 = hmac.HmacSha256;35};
30pub const HmacBlake2s256 = hmac.HmacBlake2s256;
3136
32pub const chacha20 = @import("crypto/chacha20.zig");37/// Core functions, that should rarely be used directly by applications.
33pub const chaCha20IETF = chacha20.chaCha20IETF;38pub const core = struct {
34pub const chaCha20With64BitNonce = chacha20.chaCha20With64BitNonce;39 pub const aes = @import("crypto/aes.zig");
35pub const xChaCha20IETF = chacha20.xChaCha20IETF;40 pub const Gimli = @import("crypto/gimli.zig").State;
41};
3642
37pub const Poly1305 = @import("crypto/poly1305.zig").Poly1305;43/// Elliptic-curve arithmetic.
44pub const ecc = struct {
45 pub const Curve25519 = @import("crypto/25519/curve25519.zig").Curve25519;
46 pub const Edwards25519 = @import("crypto/25519/edwards25519.zig").Edwards25519;
47 pub const Ristretto255 = @import("crypto/25519/ristretto255.zig").Ristretto255;
48};
3849
39const import_aes = @import("crypto/aes.zig");50/// Diffie-Hellman key exchange functions.
40pub const AES128 = import_aes.AES128;51pub const dh = struct {
41pub const AES256 = import_aes.AES256;52 pub const X25519 = @import("crypto/25519/x25519.zig").X25519;
53};
4254
43pub const Curve25519 = @import("crypto/25519/curve25519.zig").Curve25519;55/// Digital signature functions.
44pub const Ed25519 = @import("crypto/25519/ed25519.zig").Ed25519;56pub const sign = struct {
45pub const Edwards25519 = @import("crypto/25519/edwards25519.zig").Edwards25519;57 pub const Ed25519 = @import("crypto/25519/ed25519.zig").Ed25519;
46pub const X25519 = @import("crypto/25519/x25519.zig").X25519;58};
47pub const Ristretto255 = @import("crypto/25519/ristretto255.zig").Ristretto255;
4859
49pub const aead = struct {60/// Stream ciphers. These do not provide any kind of authentication.
50 pub const Gimli = gimli.Aead;61/// Most applications should be using AEAD constructions instead of stream ciphers directly.
51 pub const ChaCha20Poly1305 = chacha20.Chacha20Poly1305;62pub const stream = struct {
52 pub const XChaCha20Poly1305 = chacha20.XChacha20Poly1305;63 pub const ChaCha20IETF = @import("crypto/chacha20.zig").ChaCha20IETF;
64 pub const XChaCha20IETF = @import("crypto/chacha20.zig").XChaCha20IETF;
65 pub const ChaCha20With64BitNonce = @import("crypto/chacha20.zig").ChaCha20With64BitNonce;
53};66};
5467
55const std = @import("std.zig");68const std = @import("std.zig");
...@@ -78,27 +91,32 @@ test "crypto" {...@@ -78,27 +91,32 @@ test "crypto" {
7891
79test "issue #4532: no index out of bounds" {92test "issue #4532: no index out of bounds" {
80 const types = [_]type{93 const types = [_]type{
81 Md5,94 hash.Md5,
82 Sha1,95 hash.Sha1,
83 Sha224,96 hash.sha2.Sha224,
84 Sha256,97 hash.sha2.Sha256,
85 Sha384,98 hash.sha2.Sha384,
86 Sha512,99 hash.sha2.Sha512,
87 Blake2s224,100 hash.sha3.Sha3_224,
88 Blake2s256,101 hash.sha3.Sha3_256,
89 Blake2b384,102 hash.sha3.Sha3_384,
90 Blake2b512,103 hash.sha3.Sha3_512,
104 hash.blake2.Blake2s224,
105 hash.blake2.Blake2s256,
106 hash.blake2.Blake2b384,
107 hash.blake2.Blake2b512,
108 hash.Gimli,
91 };109 };
92110
93 inline for (types) |Hasher| {111 inline for (types) |Hasher| {
94 var block = [_]u8{'#'} ** Hasher.block_length;112 var block = [_]u8{'#'} ** Hasher.block_length;
95 var out1: [Hasher.digest_length]u8 = undefined;113 var out1: [Hasher.digest_length]u8 = undefined;
96 var out2: [Hasher.digest_length]u8 = undefined;114 var out2: [Hasher.digest_length]u8 = undefined;
97115 const h0 = Hasher.init(.{});
98 var h = Hasher.init();116 var h = h0;
99 h.update(block[0..]);117 h.update(block[0..]);
100 h.final(out1[0..]);118 h.final(out1[0..]);
101 h.reset();119 h = h0;
102 h.update(block[0..1]);120 h.update(block[0..1]);
103 h.update(block[1..]);121 h.update(block[1..]);
104 h.final(out2[0..]);122 h.final(out2[0..]);
lib/std/crypto/25519/curve25519.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std");6const std = @import("std");
27
3/// Group operations over Curve25519.8/// Group operations over Curve25519.
lib/std/crypto/25519/ed25519.zig+11-6
...@@ -1,7 +1,12 @@...@@ -1,7 +1,12 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std");6const std = @import("std");
2const fmt = std.fmt;7const fmt = std.fmt;
3const mem = std.mem;8const mem = std.mem;
4const Sha512 = std.crypto.Sha512;9const Sha512 = std.crypto.hash.sha2.Sha512;
510
6/// Ed25519 (EdDSA) signatures.11/// Ed25519 (EdDSA) signatures.
7pub const Ed25519 = struct {12pub const Ed25519 = struct {
...@@ -28,7 +33,7 @@ pub const Ed25519 = struct {...@@ -28,7 +33,7 @@ pub const Ed25519 = struct {
28 /// from which the actual secret is derived.33 /// from which the actual secret is derived.
29 pub fn createKeyPair(seed: [seed_length]u8) ![keypair_length]u8 {34 pub fn createKeyPair(seed: [seed_length]u8) ![keypair_length]u8 {
30 var az: [Sha512.digest_length]u8 = undefined;35 var az: [Sha512.digest_length]u8 = undefined;
31 var h = Sha512.init();36 var h = Sha512.init(.{});
32 h.update(&seed);37 h.update(&seed);
33 h.final(&az);38 h.final(&az);
34 const p = try Curve.basePoint.clampedMul(az[0..32].*);39 const p = try Curve.basePoint.clampedMul(az[0..32].*);
...@@ -51,11 +56,11 @@ pub const Ed25519 = struct {...@@ -51,11 +56,11 @@ pub const Ed25519 = struct {
51 pub fn sign(msg: []const u8, key_pair: [keypair_length]u8, noise: ?[noise_length]u8) ![signature_length]u8 {56 pub fn sign(msg: []const u8, key_pair: [keypair_length]u8, noise: ?[noise_length]u8) ![signature_length]u8 {
52 const public_key = key_pair[32..];57 const public_key = key_pair[32..];
53 var az: [Sha512.digest_length]u8 = undefined;58 var az: [Sha512.digest_length]u8 = undefined;
54 var h = Sha512.init();59 var h = Sha512.init(.{});
55 h.update(key_pair[0..seed_length]);60 h.update(key_pair[0..seed_length]);
56 h.final(&az);61 h.final(&az);
5762
58 h = Sha512.init();63 h = Sha512.init(.{});
59 if (noise) |*z| {64 if (noise) |*z| {
60 h.update(z);65 h.update(z);
61 }66 }
...@@ -69,7 +74,7 @@ pub const Ed25519 = struct {...@@ -69,7 +74,7 @@ pub const Ed25519 = struct {
69 var sig: [signature_length]u8 = undefined;74 var sig: [signature_length]u8 = undefined;
70 mem.copy(u8, sig[0..32], &r.toBytes());75 mem.copy(u8, sig[0..32], &r.toBytes());
71 mem.copy(u8, sig[32..], public_key);76 mem.copy(u8, sig[32..], public_key);
72 h = Sha512.init();77 h = Sha512.init(.{});
73 h.update(&sig);78 h.update(&sig);
74 h.update(msg);79 h.update(msg);
75 var hram64: [Sha512.digest_length]u8 = undefined;80 var hram64: [Sha512.digest_length]u8 = undefined;
...@@ -93,7 +98,7 @@ pub const Ed25519 = struct {...@@ -93,7 +98,7 @@ pub const Ed25519 = struct {
93 const a = try Curve.fromBytes(public_key);98 const a = try Curve.fromBytes(public_key);
94 try a.rejectIdentity();99 try a.rejectIdentity();
95100
96 var h = Sha512.init();101 var h = Sha512.init(.{});
97 h.update(r);102 h.update(r);
98 h.update(&public_key);103 h.update(&public_key);
99 h.update(msg);104 h.update(msg);
lib/std/crypto/25519/edwards25519.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std");6const std = @import("std");
2const fmt = std.fmt;7const fmt = std.fmt;
38
lib/std/crypto/25519/field.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std");6const std = @import("std");
2const readIntLittle = std.mem.readIntLittle;7const readIntLittle = std.mem.readIntLittle;
3const writeIntLittle = std.mem.writeIntLittle;8const writeIntLittle = std.mem.writeIntLittle;
lib/std/crypto/25519/ristretto255.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std");6const std = @import("std");
2const fmt = std.fmt;7const fmt = std.fmt;
38
lib/std/crypto/25519/scalar.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std");6const std = @import("std");
2const mem = std.mem;7const mem = std.mem;
38
lib/std/crypto/25519/x25519.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std");6const std = @import("std");
2const mem = std.mem;7const mem = std.mem;
3const fmt = std.fmt;8const fmt = std.fmt;
lib/std/crypto/aes.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Based on Go stdlib implementation6// Based on Go stdlib implementation
27
3const std = @import("../std.zig");8const std = @import("../std.zig");
lib/std/crypto/benchmark.zig+25-19
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// zig run benchmark.zig --release-fast --override-lib-dir ..6// zig run benchmark.zig --release-fast --override-lib-dir ..
27
3const builtin = @import("builtin");8const builtin = @import("builtin");
...@@ -17,20 +22,20 @@ const Crypto = struct {...@@ -17,20 +22,20 @@ const Crypto = struct {
17};22};
1823
19const hashes = [_]Crypto{24const hashes = [_]Crypto{
20 Crypto{ .ty = crypto.Md5, .name = "md5" },25 Crypto{ .ty = crypto.hash.Md5, .name = "md5" },
21 Crypto{ .ty = crypto.Sha1, .name = "sha1" },26 Crypto{ .ty = crypto.hash.Sha1, .name = "sha1" },
22 Crypto{ .ty = crypto.Sha256, .name = "sha256" },27 Crypto{ .ty = crypto.hash.sha2.Sha256, .name = "sha256" },
23 Crypto{ .ty = crypto.Sha512, .name = "sha512" },28 Crypto{ .ty = crypto.hash.sha2.Sha512, .name = "sha512" },
24 Crypto{ .ty = crypto.Sha3_256, .name = "sha3-256" },29 Crypto{ .ty = crypto.hash.sha3.Sha3_256, .name = "sha3-256" },
25 Crypto{ .ty = crypto.Sha3_512, .name = "sha3-512" },30 Crypto{ .ty = crypto.hash.sha3.Sha3_512, .name = "sha3-512" },
26 Crypto{ .ty = crypto.gimli.Hash, .name = "gimli-hash" },31 Crypto{ .ty = crypto.hash.Gimli, .name = "gimli-hash" },
27 Crypto{ .ty = crypto.Blake2s256, .name = "blake2s" },32 Crypto{ .ty = crypto.hash.blake2.Blake2s256, .name = "blake2s" },
28 Crypto{ .ty = crypto.Blake2b512, .name = "blake2b" },33 Crypto{ .ty = crypto.hash.blake2.Blake2b512, .name = "blake2b" },
29 Crypto{ .ty = crypto.Blake3, .name = "blake3" },34 Crypto{ .ty = crypto.hash.Blake3, .name = "blake3" },
30};35};
3136
32pub fn benchmarkHash(comptime Hash: anytype, comptime bytes: comptime_int) !u64 {37pub fn benchmarkHash(comptime Hash: anytype, comptime bytes: comptime_int) !u64 {
33 var h = Hash.init();38 var h = Hash.init(.{});
3439
35 var block: [Hash.digest_length]u8 = undefined;40 var block: [Hash.digest_length]u8 = undefined;
36 prng.random.bytes(block[0..]);41 prng.random.bytes(block[0..]);
...@@ -50,19 +55,20 @@ pub fn benchmarkHash(comptime Hash: anytype, comptime bytes: comptime_int) !u64...@@ -50,19 +55,20 @@ pub fn benchmarkHash(comptime Hash: anytype, comptime bytes: comptime_int) !u64
50}55}
5156
52const macs = [_]Crypto{57const macs = [_]Crypto{
53 Crypto{ .ty = crypto.Poly1305, .name = "poly1305" },58 Crypto{ .ty = crypto.onetimeauth.Poly1305, .name = "poly1305" },
54 Crypto{ .ty = crypto.HmacMd5, .name = "hmac-md5" },59 Crypto{ .ty = crypto.auth.hmac.HmacMd5, .name = "hmac-md5" },
55 Crypto{ .ty = crypto.HmacSha1, .name = "hmac-sha1" },60 Crypto{ .ty = crypto.auth.hmac.HmacSha1, .name = "hmac-sha1" },
56 Crypto{ .ty = crypto.HmacSha256, .name = "hmac-sha256" },61 Crypto{ .ty = crypto.auth.hmac.sha2.HmacSha256, .name = "hmac-sha256" },
62 Crypto{ .ty = crypto.auth.hmac.sha2.HmacSha512, .name = "hmac-sha512" },
57};63};
5864
59pub fn benchmarkMac(comptime Mac: anytype, comptime bytes: comptime_int) !u64 {65pub fn benchmarkMac(comptime Mac: anytype, comptime bytes: comptime_int) !u64 {
60 std.debug.assert(32 >= Mac.mac_length and 32 >= Mac.minimum_key_length);66 std.debug.assert(64 >= Mac.mac_length and 32 >= Mac.minimum_key_length);
6167
62 var in: [1 * MiB]u8 = undefined;68 var in: [1 * MiB]u8 = undefined;
63 prng.random.bytes(in[0..]);69 prng.random.bytes(in[0..]);
6470
65 var key: [32]u8 = undefined;71 var key: [64]u8 = undefined;
66 prng.random.bytes(key[0..]);72 prng.random.bytes(key[0..]);
6773
68 var offset: usize = 0;74 var offset: usize = 0;
...@@ -79,7 +85,7 @@ pub fn benchmarkMac(comptime Mac: anytype, comptime bytes: comptime_int) !u64 {...@@ -79,7 +85,7 @@ pub fn benchmarkMac(comptime Mac: anytype, comptime bytes: comptime_int) !u64 {
79 return throughput;85 return throughput;
80}86}
8187
82const exchanges = [_]Crypto{Crypto{ .ty = crypto.X25519, .name = "x25519" }};88const exchanges = [_]Crypto{Crypto{ .ty = crypto.dh.X25519, .name = "x25519" }};
8389
84pub fn benchmarkKeyExchange(comptime DhKeyExchange: anytype, comptime exchange_count: comptime_int) !u64 {90pub fn benchmarkKeyExchange(comptime DhKeyExchange: anytype, comptime exchange_count: comptime_int) !u64 {
85 std.debug.assert(DhKeyExchange.minimum_key_length >= DhKeyExchange.secret_length);91 std.debug.assert(DhKeyExchange.minimum_key_length >= DhKeyExchange.secret_length);
...@@ -106,7 +112,7 @@ pub fn benchmarkKeyExchange(comptime DhKeyExchange: anytype, comptime exchange_c...@@ -106,7 +112,7 @@ pub fn benchmarkKeyExchange(comptime DhKeyExchange: anytype, comptime exchange_c
106 return throughput;112 return throughput;
107}113}
108114
109const signatures = [_]Crypto{Crypto{ .ty = crypto.Ed25519, .name = "ed25519" }};115const signatures = [_]Crypto{Crypto{ .ty = crypto.sign.Ed25519, .name = "ed25519" }};
110116
111pub fn benchmarkSignatures(comptime Signature: anytype, comptime signatures_count: comptime_int) !u64 {117pub fn benchmarkSignatures(comptime Signature: anytype, comptime signatures_count: comptime_int) !u64 {
112 var seed: [Signature.seed_length]u8 = undefined;118 var seed: [Signature.seed_length]u8 = undefined;
lib/std/crypto/blake2.zig+107-78
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const mem = @import("../mem.zig");6const mem = @import("../mem.zig");
2const builtin = @import("builtin");7const builtin = @import("builtin");
3const debug = @import("../debug.zig");8const debug = @import("../debug.zig");
...@@ -35,6 +40,7 @@ pub fn Blake2s(comptime out_len: usize) type {...@@ -35,6 +40,7 @@ pub fn Blake2s(comptime out_len: usize) type {
35 const Self = @This();40 const Self = @This();
36 pub const block_length = 64;41 pub const block_length = 64;
37 pub const digest_length = out_len / 8;42 pub const digest_length = out_len / 8;
43 pub const Options = struct { key: ?[]const u8 = null, salt: ?[8]u8 = null, context: ?[8]u8 = null };
3844
39 const iv = [8]u32{45 const iv = [8]u32{
40 0x6A09E667,46 0x6A09E667,
...@@ -66,42 +72,36 @@ pub fn Blake2s(comptime out_len: usize) type {...@@ -66,42 +72,36 @@ pub fn Blake2s(comptime out_len: usize) type {
66 buf: [64]u8,72 buf: [64]u8,
67 buf_len: u8,73 buf_len: u8,
6874
69 key: []const u8,75 pub fn init(options: Options) Self {
70
71 pub fn init() Self {
72 return init_keyed("");
73 }
74
75 pub fn init_keyed(key: []const u8) Self {
76 debug.assert(8 <= out_len and out_len <= 512);76 debug.assert(8 <= out_len and out_len <= 512);
7777
78 var s: Self = undefined;78 var d: Self = undefined;
79 s.key = key;
80 s.reset();
81 return s;
82 }
83
84 pub fn reset(d: *Self) void {
85 mem.copy(u32, d.h[0..], iv[0..]);79 mem.copy(u32, d.h[0..], iv[0..]);
8680
81 const key_len = if (options.key) |key| key.len else 0;
87 // default parameters82 // default parameters
88 d.h[0] ^= 0x01010000 ^ @truncate(u32, d.key.len << 8) ^ @intCast(u32, out_len >> 3);83 d.h[0] ^= 0x01010000 ^ @truncate(u32, key_len << 8) ^ @intCast(u32, out_len >> 3);
89 d.t = 0;84 d.t = 0;
90 d.buf_len = 0;85 d.buf_len = 0;
9186
92 if (d.key.len > 0) {87 if (options.salt) |salt| {
93 mem.set(u8, d.buf[d.key.len..], 0);88 d.h[4] ^= mem.readIntLittle(u32, salt[0..4]);
94 d.update(d.key);89 d.h[5] ^= mem.readIntLittle(u32, salt[4..8]);
90 }
91 if (options.context) |context| {
92 d.h[6] ^= mem.readIntLittle(u32, context[0..4]);
93 d.h[7] ^= mem.readIntLittle(u32, context[4..8]);
94 }
95 if (key_len > 0) {
96 mem.set(u8, d.buf[key_len..], 0);
97 d.update(options.key.?);
95 d.buf_len = 64;98 d.buf_len = 64;
96 }99 }
100 return d;
97 }101 }
98102
99 pub fn hash(b: []const u8, out: []u8) void {103 pub fn hash(b: []const u8, out: []u8, options: Options) void {
100 Self.hash_keyed("", b, out);104 var d = Self.init(options);
101 }
102
103 pub fn hash_keyed(key: []const u8, b: []const u8, out: []u8) void {
104 var d = Self.init_keyed(key);
105 d.update(b);105 d.update(b);
106 d.final(out);106 d.final(out);
107 }107 }
...@@ -210,7 +210,7 @@ test "blake2s224 single" {...@@ -210,7 +210,7 @@ test "blake2s224 single" {
210}210}
211211
212test "blake2s224 streaming" {212test "blake2s224 streaming" {
213 var h = Blake2s224.init();213 var h = Blake2s224.init(.{});
214 var out: [28]u8 = undefined;214 var out: [28]u8 = undefined;
215215
216 const h1 = "1fa1291e65248b37b3433475b2a0dd63d54a11ecc4e3e034e7bc1ef4";216 const h1 = "1fa1291e65248b37b3433475b2a0dd63d54a11ecc4e3e034e7bc1ef4";
...@@ -220,12 +220,12 @@ test "blake2s224 streaming" {...@@ -220,12 +220,12 @@ test "blake2s224 streaming" {
220220
221 const h2 = "0b033fc226df7abde29f67a05d3dc62cf271ef3dfea4d387407fbd55";221 const h2 = "0b033fc226df7abde29f67a05d3dc62cf271ef3dfea4d387407fbd55";
222222
223 h.reset();223 h = Blake2s224.init(.{});
224 h.update("abc");224 h.update("abc");
225 h.final(out[0..]);225 h.final(out[0..]);
226 htest.assertEqual(h2, out[0..]);226 htest.assertEqual(h2, out[0..]);
227227
228 h.reset();228 h = Blake2s224.init(.{});
229 h.update("a");229 h.update("a");
230 h.update("b");230 h.update("b");
231 h.update("c");231 h.update("c");
...@@ -234,16 +234,29 @@ test "blake2s224 streaming" {...@@ -234,16 +234,29 @@ test "blake2s224 streaming" {
234234
235 const h3 = "557381a78facd2b298640f4e32113e58967d61420af1aa939d0cfe01";235 const h3 = "557381a78facd2b298640f4e32113e58967d61420af1aa939d0cfe01";
236236
237 h.reset();237 h = Blake2s224.init(.{});
238 h.update("a" ** 32);238 h.update("a" ** 32);
239 h.update("b" ** 32);239 h.update("b" ** 32);
240 h.final(out[0..]);240 h.final(out[0..]);
241 htest.assertEqual(h3, out[0..]);241 htest.assertEqual(h3, out[0..]);
242242
243 h.reset();243 h = Blake2s224.init(.{});
244 h.update("a" ** 32 ++ "b" ** 32);244 h.update("a" ** 32 ++ "b" ** 32);
245 h.final(out[0..]);245 h.final(out[0..]);
246 htest.assertEqual(h3, out[0..]);246 htest.assertEqual(h3, out[0..]);
247
248 const h4 = "a4d6a9d253441b80e5dfd60a04db169ffab77aec56a2855c402828c3";
249
250 h = Blake2s224.init(.{ .context = [_]u8{0x69} ** 8, .salt = [_]u8{0x42} ** 8 });
251 h.update("a" ** 32);
252 h.update("b" ** 32);
253 h.final(out[0..]);
254 htest.assertEqual(h4, out[0..]);
255
256 h = Blake2s224.init(.{ .context = [_]u8{0x69} ** 8, .salt = [_]u8{0x42} ** 8 });
257 h.update("a" ** 32 ++ "b" ** 32);
258 h.final(out[0..]);
259 htest.assertEqual(h4, out[0..]);
247}260}
248261
249test "comptime blake2s224" {262test "comptime blake2s224" {
...@@ -256,7 +269,7 @@ test "comptime blake2s224" {...@@ -256,7 +269,7 @@ test "comptime blake2s224" {
256269
257 htest.assertEqualHash(Blake2s224, h1, block[0..]);270 htest.assertEqualHash(Blake2s224, h1, block[0..]);
258271
259 var h = Blake2s224.init();272 var h = Blake2s224.init(.{});
260 h.update(&block);273 h.update(&block);
261 h.final(out[0..]);274 h.final(out[0..]);
262275
...@@ -279,7 +292,7 @@ test "blake2s256 single" {...@@ -279,7 +292,7 @@ test "blake2s256 single" {
279}292}
280293
281test "blake2s256 streaming" {294test "blake2s256 streaming" {
282 var h = Blake2s256.init();295 var h = Blake2s256.init(.{});
283 var out: [32]u8 = undefined;296 var out: [32]u8 = undefined;
284297
285 const h1 = "69217a3079908094e11121d042354a7c1f55b6482ca1a51e1b250dfd1ed0eef9";298 const h1 = "69217a3079908094e11121d042354a7c1f55b6482ca1a51e1b250dfd1ed0eef9";
...@@ -289,12 +302,12 @@ test "blake2s256 streaming" {...@@ -289,12 +302,12 @@ test "blake2s256 streaming" {
289302
290 const h2 = "508c5e8c327c14e2e1a72ba34eeb452f37458b209ed63a294d999b4c86675982";303 const h2 = "508c5e8c327c14e2e1a72ba34eeb452f37458b209ed63a294d999b4c86675982";
291304
292 h.reset();305 h = Blake2s256.init(.{});
293 h.update("abc");306 h.update("abc");
294 h.final(out[0..]);307 h.final(out[0..]);
295 htest.assertEqual(h2, out[0..]);308 htest.assertEqual(h2, out[0..]);
296309
297 h.reset();310 h = Blake2s256.init(.{});
298 h.update("a");311 h.update("a");
299 h.update("b");312 h.update("b");
300 h.update("c");313 h.update("c");
...@@ -303,13 +316,13 @@ test "blake2s256 streaming" {...@@ -303,13 +316,13 @@ test "blake2s256 streaming" {
303316
304 const h3 = "8d8711dade07a6b92b9a3ea1f40bee9b2c53ff3edd2a273dec170b0163568977";317 const h3 = "8d8711dade07a6b92b9a3ea1f40bee9b2c53ff3edd2a273dec170b0163568977";
305318
306 h.reset();319 h = Blake2s256.init(.{});
307 h.update("a" ** 32);320 h.update("a" ** 32);
308 h.update("b" ** 32);321 h.update("b" ** 32);
309 h.final(out[0..]);322 h.final(out[0..]);
310 htest.assertEqual(h3, out[0..]);323 htest.assertEqual(h3, out[0..]);
311324
312 h.reset();325 h = Blake2s256.init(.{});
313 h.update("a" ** 32 ++ "b" ** 32);326 h.update("a" ** 32 ++ "b" ** 32);
314 h.final(out[0..]);327 h.final(out[0..]);
315 htest.assertEqual(h3, out[0..]);328 htest.assertEqual(h3, out[0..]);
...@@ -321,16 +334,16 @@ test "blake2s256 keyed" {...@@ -321,16 +334,16 @@ test "blake2s256 keyed" {
321 const h1 = "10f918da4d74fab3302e48a5d67d03804b1ec95372a62a0f33b7c9fa28ba1ae6";334 const h1 = "10f918da4d74fab3302e48a5d67d03804b1ec95372a62a0f33b7c9fa28ba1ae6";
322 const key = "secret_key";335 const key = "secret_key";
323336
324 Blake2s256.hash_keyed(key, "a" ** 64 ++ "b" ** 64, &out);337 Blake2s256.hash("a" ** 64 ++ "b" ** 64, &out, .{ .key = key });
325 htest.assertEqual(h1, out[0..]);338 htest.assertEqual(h1, out[0..]);
326339
327 var h = Blake2s256.init_keyed(key);340 var h = Blake2s256.init(.{ .key = key });
328 h.update("a" ** 64 ++ "b" ** 64);341 h.update("a" ** 64 ++ "b" ** 64);
329 h.final(out[0..]);342 h.final(out[0..]);
330343
331 htest.assertEqual(h1, out[0..]);344 htest.assertEqual(h1, out[0..]);
332345
333 h.reset();346 h = Blake2s256.init(.{ .key = key });
334 h.update("a" ** 64);347 h.update("a" ** 64);
335 h.update("b" ** 64);348 h.update("b" ** 64);
336 h.final(out[0..]);349 h.final(out[0..]);
...@@ -348,7 +361,7 @@ test "comptime blake2s256" {...@@ -348,7 +361,7 @@ test "comptime blake2s256" {
348361
349 htest.assertEqualHash(Blake2s256, h1, block[0..]);362 htest.assertEqualHash(Blake2s256, h1, block[0..]);
350363
351 var h = Blake2s256.init();364 var h = Blake2s256.init(.{});
352 h.update(&block);365 h.update(&block);
353 h.final(out[0..]);366 h.final(out[0..]);
354367
...@@ -359,6 +372,7 @@ test "comptime blake2s256" {...@@ -359,6 +372,7 @@ test "comptime blake2s256" {
359/////////////////////372/////////////////////
360// Blake2b373// Blake2b
361374
375pub const Blake2b256 = Blake2b(256);
362pub const Blake2b384 = Blake2b(384);376pub const Blake2b384 = Blake2b(384);
363pub const Blake2b512 = Blake2b(512);377pub const Blake2b512 = Blake2b(512);
364378
...@@ -367,6 +381,7 @@ pub fn Blake2b(comptime out_len: usize) type {...@@ -367,6 +381,7 @@ pub fn Blake2b(comptime out_len: usize) type {
367 const Self = @This();381 const Self = @This();
368 pub const block_length = 128;382 pub const block_length = 128;
369 pub const digest_length = out_len / 8;383 pub const digest_length = out_len / 8;
384 pub const Options = struct { key: ?[]const u8 = null, salt: ?[16]u8 = null, context: ?[16]u8 = null };
370385
371 const iv = [8]u64{386 const iv = [8]u64{
372 0x6a09e667f3bcc908,387 0x6a09e667f3bcc908,
...@@ -400,42 +415,36 @@ pub fn Blake2b(comptime out_len: usize) type {...@@ -400,42 +415,36 @@ pub fn Blake2b(comptime out_len: usize) type {
400 buf: [128]u8,415 buf: [128]u8,
401 buf_len: u8,416 buf_len: u8,
402417
403 key: []const u8,418 pub fn init(options: Options) Self {
404
405 pub fn init() Self {
406 return init_keyed("");
407 }
408
409 pub fn init_keyed(key: []const u8) Self {
410 debug.assert(8 <= out_len and out_len <= 512);419 debug.assert(8 <= out_len and out_len <= 512);
411420
412 var s: Self = undefined;421 var d: Self = undefined;
413 s.key = key;
414 s.reset();
415 return s;
416 }
417
418 pub fn reset(d: *Self) void {
419 mem.copy(u64, d.h[0..], iv[0..]);422 mem.copy(u64, d.h[0..], iv[0..]);
420423
424 const key_len = if (options.key) |key| key.len else 0;
421 // default parameters425 // default parameters
422 d.h[0] ^= 0x01010000 ^ (d.key.len << 8) ^ (out_len >> 3);426 d.h[0] ^= 0x01010000 ^ (key_len << 8) ^ (out_len >> 3);
423 d.t = 0;427 d.t = 0;
424 d.buf_len = 0;428 d.buf_len = 0;
425429
426 if (d.key.len > 0) {430 if (options.salt) |salt| {
427 mem.set(u8, d.buf[d.key.len..], 0);431 d.h[4] ^= mem.readIntLittle(u64, salt[0..8]);
428 d.update(d.key);432 d.h[5] ^= mem.readIntLittle(u64, salt[8..16]);
433 }
434 if (options.context) |context| {
435 d.h[6] ^= mem.readIntLittle(u64, context[0..8]);
436 d.h[7] ^= mem.readIntLittle(u64, context[8..16]);
437 }
438 if (key_len > 0) {
439 mem.set(u8, d.buf[key_len..], 0);
440 d.update(options.key.?);
429 d.buf_len = 128;441 d.buf_len = 128;
430 }442 }
443 return d;
431 }444 }
432445
433 pub fn hash(b: []const u8, out: []u8) void {446 pub fn hash(b: []const u8, out: []u8, options: Options) void {
434 Self.hash_keyed("", b, out);447 var d = Self.init(options);
435 }
436
437 pub fn hash_keyed(key: []const u8, b: []const u8, out: []u8) void {
438 var d = Self.init_keyed(key);
439 d.update(b);448 d.update(b);
440 d.final(out);449 d.final(out);
441 }450 }
...@@ -542,7 +551,7 @@ test "blake2b384 single" {...@@ -542,7 +551,7 @@ test "blake2b384 single" {
542}551}
543552
544test "blake2b384 streaming" {553test "blake2b384 streaming" {
545 var h = Blake2b384.init();554 var h = Blake2b384.init(.{});
546 var out: [48]u8 = undefined;555 var out: [48]u8 = undefined;
547556
548 const h1 = "b32811423377f52d7862286ee1a72ee540524380fda1724a6f25d7978c6fd3244a6caf0498812673c5e05ef583825100";557 const h1 = "b32811423377f52d7862286ee1a72ee540524380fda1724a6f25d7978c6fd3244a6caf0498812673c5e05ef583825100";
...@@ -552,12 +561,12 @@ test "blake2b384 streaming" {...@@ -552,12 +561,12 @@ test "blake2b384 streaming" {
552561
553 const h2 = "6f56a82c8e7ef526dfe182eb5212f7db9df1317e57815dbda46083fc30f54ee6c66ba83be64b302d7cba6ce15bb556f4";562 const h2 = "6f56a82c8e7ef526dfe182eb5212f7db9df1317e57815dbda46083fc30f54ee6c66ba83be64b302d7cba6ce15bb556f4";
554563
555 h.reset();564 h = Blake2b384.init(.{});
556 h.update("abc");565 h.update("abc");
557 h.final(out[0..]);566 h.final(out[0..]);
558 htest.assertEqual(h2, out[0..]);567 htest.assertEqual(h2, out[0..]);
559568
560 h.reset();569 h = Blake2b384.init(.{});
561 h.update("a");570 h.update("a");
562 h.update("b");571 h.update("b");
563 h.update("c");572 h.update("c");
...@@ -566,16 +575,36 @@ test "blake2b384 streaming" {...@@ -566,16 +575,36 @@ test "blake2b384 streaming" {
566575
567 const h3 = "b7283f0172fecbbd7eca32ce10d8a6c06b453cb3cf675b33eb4246f0da2bb94a6c0bdd6eec0b5fd71ec4fd51be80bf4c";576 const h3 = "b7283f0172fecbbd7eca32ce10d8a6c06b453cb3cf675b33eb4246f0da2bb94a6c0bdd6eec0b5fd71ec4fd51be80bf4c";
568577
569 h.reset();578 h = Blake2b384.init(.{});
570 h.update("a" ** 64 ++ "b" ** 64);579 h.update("a" ** 64 ++ "b" ** 64);
571 h.final(out[0..]);580 h.final(out[0..]);
572 htest.assertEqual(h3, out[0..]);581 htest.assertEqual(h3, out[0..]);
573582
574 h.reset();583 h = Blake2b384.init(.{});
584 h.update("a" ** 64);
585 h.update("b" ** 64);
586 h.final(out[0..]);
587 htest.assertEqual(h3, out[0..]);
588
589 h = Blake2b384.init(.{});
575 h.update("a" ** 64);590 h.update("a" ** 64);
576 h.update("b" ** 64);591 h.update("b" ** 64);
577 h.final(out[0..]);592 h.final(out[0..]);
578 htest.assertEqual(h3, out[0..]);593 htest.assertEqual(h3, out[0..]);
594
595 const h4 = "934c48fcb197031c71f583d92f98703510805e72142e0b46f5752d1e971bc86c355d556035613ff7a4154b4de09dac5c";
596
597 h = Blake2b384.init(.{ .context = [_]u8{0x69} ** 16, .salt = [_]u8{0x42} ** 16 });
598 h.update("a" ** 64);
599 h.update("b" ** 64);
600 h.final(out[0..]);
601 htest.assertEqual(h4, out[0..]);
602
603 h = Blake2b384.init(.{ .context = [_]u8{0x69} ** 16, .salt = [_]u8{0x42} ** 16 });
604 h.update("a" ** 64);
605 h.update("b" ** 64);
606 h.final(out[0..]);
607 htest.assertEqual(h4, out[0..]);
579}608}
580609
581test "comptime blake2b384" {610test "comptime blake2b384" {
...@@ -588,7 +617,7 @@ test "comptime blake2b384" {...@@ -588,7 +617,7 @@ test "comptime blake2b384" {
588617
589 htest.assertEqualHash(Blake2b384, h1, block[0..]);618 htest.assertEqualHash(Blake2b384, h1, block[0..]);
590619
591 var h = Blake2b384.init();620 var h = Blake2b384.init(.{});
592 h.update(&block);621 h.update(&block);
593 h.final(out[0..]);622 h.final(out[0..]);
594623
...@@ -611,7 +640,7 @@ test "blake2b512 single" {...@@ -611,7 +640,7 @@ test "blake2b512 single" {
611}640}
612641
613test "blake2b512 streaming" {642test "blake2b512 streaming" {
614 var h = Blake2b512.init();643 var h = Blake2b512.init(.{});
615 var out: [64]u8 = undefined;644 var out: [64]u8 = undefined;
616645
617 const h1 = "786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce";646 const h1 = "786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce";
...@@ -621,12 +650,12 @@ test "blake2b512 streaming" {...@@ -621,12 +650,12 @@ test "blake2b512 streaming" {
621650
622 const h2 = "ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d17d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923";651 const h2 = "ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d17d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923";
623652
624 h.reset();653 h = Blake2b512.init(.{});
625 h.update("abc");654 h.update("abc");
626 h.final(out[0..]);655 h.final(out[0..]);
627 htest.assertEqual(h2, out[0..]);656 htest.assertEqual(h2, out[0..]);
628657
629 h.reset();658 h = Blake2b512.init(.{});
630 h.update("a");659 h.update("a");
631 h.update("b");660 h.update("b");
632 h.update("c");661 h.update("c");
...@@ -635,12 +664,12 @@ test "blake2b512 streaming" {...@@ -635,12 +664,12 @@ test "blake2b512 streaming" {
635664
636 const h3 = "049980af04d6a2cf16b4b49793c3ed7e40732073788806f2c989ebe9547bda0541d63abe298ec8955d08af48ae731f2e8a0bd6d201655a5473b4aa79d211b920";665 const h3 = "049980af04d6a2cf16b4b49793c3ed7e40732073788806f2c989ebe9547bda0541d63abe298ec8955d08af48ae731f2e8a0bd6d201655a5473b4aa79d211b920";
637666
638 h.reset();667 h = Blake2b512.init(.{});
639 h.update("a" ** 64 ++ "b" ** 64);668 h.update("a" ** 64 ++ "b" ** 64);
640 h.final(out[0..]);669 h.final(out[0..]);
641 htest.assertEqual(h3, out[0..]);670 htest.assertEqual(h3, out[0..]);
642671
643 h.reset();672 h = Blake2b512.init(.{});
644 h.update("a" ** 64);673 h.update("a" ** 64);
645 h.update("b" ** 64);674 h.update("b" ** 64);
646 h.final(out[0..]);675 h.final(out[0..]);
...@@ -653,16 +682,16 @@ test "blake2b512 keyed" {...@@ -653,16 +682,16 @@ test "blake2b512 keyed" {
653 const h1 = "8a978060ccaf582f388f37454363071ac9a67e3a704585fd879fb8a419a447e389c7c6de790faa20a7a7dccf197de736bc5b40b98a930b36df5bee7555750c4d";682 const h1 = "8a978060ccaf582f388f37454363071ac9a67e3a704585fd879fb8a419a447e389c7c6de790faa20a7a7dccf197de736bc5b40b98a930b36df5bee7555750c4d";
654 const key = "secret_key";683 const key = "secret_key";
655684
656 Blake2b512.hash_keyed(key, "a" ** 64 ++ "b" ** 64, &out);685 Blake2b512.hash("a" ** 64 ++ "b" ** 64, &out, .{ .key = key });
657 htest.assertEqual(h1, out[0..]);686 htest.assertEqual(h1, out[0..]);
658687
659 var h = Blake2b512.init_keyed(key);688 var h = Blake2b512.init(.{ .key = key });
660 h.update("a" ** 64 ++ "b" ** 64);689 h.update("a" ** 64 ++ "b" ** 64);
661 h.final(out[0..]);690 h.final(out[0..]);
662691
663 htest.assertEqual(h1, out[0..]);692 htest.assertEqual(h1, out[0..]);
664693
665 h.reset();694 h = Blake2b512.init(.{ .key = key });
666 h.update("a" ** 64);695 h.update("a" ** 64);
667 h.update("b" ** 64);696 h.update("b" ** 64);
668 h.final(out[0..]);697 h.final(out[0..]);
...@@ -680,7 +709,7 @@ test "comptime blake2b512" {...@@ -680,7 +709,7 @@ test "comptime blake2b512" {
680709
681 htest.assertEqualHash(Blake2b512, h1, block[0..]);710 htest.assertEqualHash(Blake2b512, h1, block[0..]);
682711
683 var h = Blake2b512.init();712 var h = Blake2b512.init(.{});
684 h.update(&block);713 h.update(&block);
685 h.final(out[0..]);714 h.final(out[0..]);
686715
lib/std/crypto/blake3.zig+29-23
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Translated from BLAKE3 reference implementation.6// Translated from BLAKE3 reference implementation.
2// Source: https://github.com/BLAKE3-team/BLAKE37// Source: https://github.com/BLAKE3-team/BLAKE3
38
...@@ -274,6 +279,9 @@ fn parent_cv(...@@ -274,6 +279,9 @@ fn parent_cv(
274279
275/// An incremental hasher that can accept any number of writes.280/// An incremental hasher that can accept any number of writes.
276pub const Blake3 = struct {281pub const Blake3 = struct {
282 pub const Options = struct { key: ?[KEY_LEN]u8 = null };
283 pub const KdfOptions = struct {};
284
277 chunk_state: ChunkState,285 chunk_state: ChunkState,
278 key: [8]u32,286 key: [8]u32,
279 cv_stack: [54][8]u32 = undefined, // Space for 54 subtree chaining values:287 cv_stack: [54][8]u32 = undefined, // Space for 54 subtree chaining values:
...@@ -291,21 +299,20 @@ pub const Blake3 = struct {...@@ -291,21 +299,20 @@ pub const Blake3 = struct {
291 };299 };
292 }300 }
293301
294 /// Construct a new `Blake3` for the regular hash function.302 /// Construct a new `Blake3` for the hash function, with an optional key
295 pub fn init() Blake3 {303 pub fn init(options: Options) Blake3 {
296 return Blake3.init_internal(IV, 0);304 if (options.key) |key| {
297 }305 var key_words: [8]u32 = undefined;
298306 words_from_little_endian_bytes(key_words[0..], key[0..]);
299 /// Construct a new `Blake3` for the keyed hash function.307 return Blake3.init_internal(key_words, KEYED_HASH);
300 pub fn init_keyed(key: [KEY_LEN]u8) Blake3 {308 } else {
301 var key_words: [8]u32 = undefined;309 return Blake3.init_internal(IV, 0);
302 words_from_little_endian_bytes(key_words[0..], key[0..]);310 }
303 return Blake3.init_internal(key_words, KEYED_HASH);
304 }311 }
305312
306 /// Construct a new `Blake3` for the key derivation function. The context313 /// Construct a new `Blake3` for the key derivation function. The context
307 /// string should be hardcoded, globally unique, and application-specific.314 /// string should be hardcoded, globally unique, and application-specific.
308 pub fn init_derive_key(context: []const u8) Blake3 {315 pub fn initKdf(context: []const u8, options: KdfOptions) Blake3 {
309 var context_hasher = Blake3.init_internal(IV, DERIVE_KEY_CONTEXT);316 var context_hasher = Blake3.init_internal(IV, DERIVE_KEY_CONTEXT);
310 context_hasher.update(context);317 context_hasher.update(context);
311 var context_key: [KEY_LEN]u8 = undefined;318 var context_key: [KEY_LEN]u8 = undefined;
...@@ -315,18 +322,12 @@ pub const Blake3 = struct {...@@ -315,18 +322,12 @@ pub const Blake3 = struct {
315 return Blake3.init_internal(context_key_words, DERIVE_KEY_MATERIAL);322 return Blake3.init_internal(context_key_words, DERIVE_KEY_MATERIAL);
316 }323 }
317324
318 pub fn hash(in: []const u8, out: []u8) void {325 pub fn hash(in: []const u8, out: []u8, options: Options) void {
319 var hasher = Blake3.init();326 var hasher = Blake3.init(options);
320 hasher.update(in);327 hasher.update(in);
321 hasher.final(out);328 hasher.final(out);
322 }329 }
323330
324 /// Reset the `Blake3` to its initial state.
325 pub fn reset(self: *Blake3) void {
326 self.chunk_state = ChunkState.init(self.key, 0, self.flags);
327 self.cv_stack_len = 0;
328 }
329
330 fn push_cv(self: *Blake3, cv: [8]u32) void {331 fn push_cv(self: *Blake3, cv: [8]u32) void {
331 self.cv_stack[self.cv_stack_len] = cv;332 self.cv_stack[self.cv_stack_len] = cv;
332 self.cv_stack_len += 1;333 self.cv_stack_len += 1;
...@@ -561,6 +562,9 @@ const reference_test = ReferenceTest{...@@ -561,6 +562,9 @@ const reference_test = ReferenceTest{
561};562};
562563
563fn test_blake3(hasher: *Blake3, input_len: usize, expected_hex: [262]u8) void {564fn test_blake3(hasher: *Blake3, input_len: usize, expected_hex: [262]u8) void {
565 // Save initial state
566 const initial_state = hasher.*;
567
564 // Setup input pattern568 // Setup input pattern
565 var input_pattern: [251]u8 = undefined;569 var input_pattern: [251]u8 = undefined;
566 for (input_pattern) |*e, i| e.* = @truncate(u8, i);570 for (input_pattern) |*e, i| e.* = @truncate(u8, i);
...@@ -576,18 +580,20 @@ fn test_blake3(hasher: *Blake3, input_len: usize, expected_hex: [262]u8) void {...@@ -576,18 +580,20 @@ fn test_blake3(hasher: *Blake3, input_len: usize, expected_hex: [262]u8) void {
576 // Read final hash value580 // Read final hash value
577 var actual_bytes: [expected_hex.len / 2]u8 = undefined;581 var actual_bytes: [expected_hex.len / 2]u8 = undefined;
578 hasher.final(actual_bytes[0..]);582 hasher.final(actual_bytes[0..]);
579 hasher.reset();
580583
581 // Compare to expected value584 // Compare to expected value
582 var expected_bytes: [expected_hex.len / 2]u8 = undefined;585 var expected_bytes: [expected_hex.len / 2]u8 = undefined;
583 fmt.hexToBytes(expected_bytes[0..], expected_hex[0..]) catch unreachable;586 fmt.hexToBytes(expected_bytes[0..], expected_hex[0..]) catch unreachable;
584 testing.expectEqual(actual_bytes, expected_bytes);587 testing.expectEqual(actual_bytes, expected_bytes);
588
589 // Restore initial state
590 hasher.* = initial_state;
585}591}
586592
587test "BLAKE3 reference test cases" {593test "BLAKE3 reference test cases" {
588 var hash = &Blake3.init();594 var hash = &Blake3.init(.{});
589 var keyed_hash = &Blake3.init_keyed(reference_test.key.*);595 var keyed_hash = &Blake3.init(.{ .key = reference_test.key.* });
590 var derive_key = &Blake3.init_derive_key(reference_test.context_string);596 var derive_key = &Blake3.initKdf(reference_test.context_string, .{});
591597
592 for (reference_test.cases) |t| {598 for (reference_test.cases) |t| {
593 test_blake3(hash, t.input_len, t.hash.*);599 test_blake3(hash, t.input_len, t.hash.*);
lib/std/crypto/chacha20.zig+79-68
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Based on public domain Supercop by Daniel J. Bernstein6// Based on public domain Supercop by Daniel J. Bernstein
27
3const std = @import("../std.zig");8const std = @import("../std.zig");
...@@ -7,7 +12,7 @@ const assert = std.debug.assert;...@@ -7,7 +12,7 @@ const assert = std.debug.assert;
7const testing = std.testing;12const testing = std.testing;
8const builtin = @import("builtin");13const builtin = @import("builtin");
9const maxInt = std.math.maxInt;14const maxInt = std.math.maxInt;
10const Poly1305 = std.crypto.Poly1305;15const Poly1305 = std.crypto.onetimeauth.Poly1305;
1116
12const QuarterRound = struct {17const QuarterRound = struct {
13 a: usize,18 a: usize,
...@@ -132,56 +137,60 @@ fn keyToWords(key: [32]u8) [8]u32 {...@@ -132,56 +137,60 @@ fn keyToWords(key: [32]u8) [8]u32 {
132///137///
133/// ChaCha20 is self-reversing. To decrypt just run the cipher with the same138/// ChaCha20 is self-reversing. To decrypt just run the cipher with the same
134/// counter, nonce, and key.139/// counter, nonce, and key.
135pub fn chaCha20IETF(out: []u8, in: []const u8, counter: u32, key: [32]u8, nonce: [12]u8) void {140pub const ChaCha20IETF = struct {
136 assert(in.len >= out.len);141 pub fn xor(out: []u8, in: []const u8, counter: u32, key: [32]u8, nonce: [12]u8) void {
137 assert((in.len >> 6) + counter <= maxInt(u32));142 assert(in.len >= out.len);
138143 assert((in.len >> 6) + counter <= maxInt(u32));
139 var c: [4]u32 = undefined;144
140 c[0] = counter;145 var c: [4]u32 = undefined;
141 c[1] = mem.readIntLittle(u32, nonce[0..4]);146 c[0] = counter;
142 c[2] = mem.readIntLittle(u32, nonce[4..8]);147 c[1] = mem.readIntLittle(u32, nonce[0..4]);
143 c[3] = mem.readIntLittle(u32, nonce[8..12]);148 c[2] = mem.readIntLittle(u32, nonce[4..8]);
144 chaCha20_internal(out, in, keyToWords(key), c);149 c[3] = mem.readIntLittle(u32, nonce[8..12]);
145}150 chaCha20_internal(out, in, keyToWords(key), c);
151 }
152};
146153
147/// This is the original ChaCha20 before RFC 7539, which recommends using the154/// This is the original ChaCha20 before RFC 7539, which recommends using the
148/// orgininal version on applications such as disk or file encryption that might155/// orgininal version on applications such as disk or file encryption that might
149/// exceed the 256 GiB limit of the 96-bit nonce version.156/// exceed the 256 GiB limit of the 96-bit nonce version.
150pub fn chaCha20With64BitNonce(out: []u8, in: []const u8, counter: u64, key: [32]u8, nonce: [8]u8) void {157pub const ChaCha20With64BitNonce = struct {
151 assert(in.len >= out.len);158 pub fn xor(out: []u8, in: []const u8, counter: u64, key: [32]u8, nonce: [8]u8) void {
152 assert(counter +% (in.len >> 6) >= counter);159 assert(in.len >= out.len);
153160 assert(counter +% (in.len >> 6) >= counter);
154 var cursor: usize = 0;161
155 const k = keyToWords(key);162 var cursor: usize = 0;
156 var c: [4]u32 = undefined;163 const k = keyToWords(key);
157 c[0] = @truncate(u32, counter);164 var c: [4]u32 = undefined;
158 c[1] = @truncate(u32, counter >> 32);165 c[0] = @truncate(u32, counter);
159 c[2] = mem.readIntLittle(u32, nonce[0..4]);166 c[1] = @truncate(u32, counter >> 32);
160 c[3] = mem.readIntLittle(u32, nonce[4..8]);167 c[2] = mem.readIntLittle(u32, nonce[0..4]);
161168 c[3] = mem.readIntLittle(u32, nonce[4..8]);
162 const block_size = (1 << 6);169
163 // The full block size is greater than the address space on a 32bit machine170 const block_size = (1 << 6);
164 const big_block = if (@sizeOf(usize) > 4) (block_size << 32) else maxInt(usize);171 // The full block size is greater than the address space on a 32bit machine
165172 const big_block = if (@sizeOf(usize) > 4) (block_size << 32) else maxInt(usize);
166 // first partial big block173
167 if (((@intCast(u64, maxInt(u32) - @truncate(u32, counter)) + 1) << 6) < in.len) {174 // first partial big block
168 chaCha20_internal(out[cursor..big_block], in[cursor..big_block], k, c);175 if (((@intCast(u64, maxInt(u32) - @truncate(u32, counter)) + 1) << 6) < in.len) {
169 cursor = big_block - cursor;176 chaCha20_internal(out[cursor..big_block], in[cursor..big_block], k, c);
170 c[1] += 1;177 cursor = big_block - cursor;
171 if (comptime @sizeOf(usize) > 4) {178 c[1] += 1;
172 // A big block is giant: 256 GiB, but we can avoid this limitation179 if (comptime @sizeOf(usize) > 4) {
173 var remaining_blocks: u32 = @intCast(u32, (in.len / big_block));180 // A big block is giant: 256 GiB, but we can avoid this limitation
174 var i: u32 = 0;181 var remaining_blocks: u32 = @intCast(u32, (in.len / big_block));
175 while (remaining_blocks > 0) : (remaining_blocks -= 1) {182 var i: u32 = 0;
176 chaCha20_internal(out[cursor .. cursor + big_block], in[cursor .. cursor + big_block], k, c);183 while (remaining_blocks > 0) : (remaining_blocks -= 1) {
177 c[1] += 1; // upper 32-bit of counter, generic chaCha20_internal() doesn't know about this.184 chaCha20_internal(out[cursor .. cursor + big_block], in[cursor .. cursor + big_block], k, c);
178 cursor += big_block;185 c[1] += 1; // upper 32-bit of counter, generic chaCha20_internal() doesn't know about this.
186 cursor += big_block;
187 }
179 }188 }
180 }189 }
181 }
182190
183 chaCha20_internal(out[cursor..], in[cursor..], k, c);191 chaCha20_internal(out[cursor..], in[cursor..], k, c);
184}192 }
193};
185194
186// https://tools.ietf.org/html/rfc7539#section-2.4.2195// https://tools.ietf.org/html/rfc7539#section-2.4.2
187test "crypto.chacha20 test vector sunscreen" {196test "crypto.chacha20 test vector sunscreen" {
...@@ -216,12 +225,12 @@ test "crypto.chacha20 test vector sunscreen" {...@@ -216,12 +225,12 @@ test "crypto.chacha20 test vector sunscreen" {
216 0, 0, 0, 0,225 0, 0, 0, 0,
217 };226 };
218227
219 chaCha20IETF(result[0..], input[0..], 1, key, nonce);228 ChaCha20IETF.xor(result[0..], input[0..], 1, key, nonce);
220 testing.expectEqualSlices(u8, &expected_result, &result);229 testing.expectEqualSlices(u8, &expected_result, &result);
221230
222 // Chacha20 is self-reversing.231 // Chacha20 is self-reversing.
223 var plaintext: [114]u8 = undefined;232 var plaintext: [114]u8 = undefined;
224 chaCha20IETF(plaintext[0..], result[0..], 1, key, nonce);233 ChaCha20IETF.xor(plaintext[0..], result[0..], 1, key, nonce);
225 testing.expect(mem.order(u8, input, &plaintext) == .eq);234 testing.expect(mem.order(u8, input, &plaintext) == .eq);
226}235}
227236
...@@ -256,7 +265,7 @@ test "crypto.chacha20 test vector 1" {...@@ -256,7 +265,7 @@ test "crypto.chacha20 test vector 1" {
256 };265 };
257 const nonce = [_]u8{ 0, 0, 0, 0, 0, 0, 0, 0 };266 const nonce = [_]u8{ 0, 0, 0, 0, 0, 0, 0, 0 };
258267
259 chaCha20With64BitNonce(result[0..], input[0..], 0, key, nonce);268 ChaCha20With64BitNonce.xor(result[0..], input[0..], 0, key, nonce);
260 testing.expectEqualSlices(u8, &expected_result, &result);269 testing.expectEqualSlices(u8, &expected_result, &result);
261}270}
262271
...@@ -290,7 +299,7 @@ test "crypto.chacha20 test vector 2" {...@@ -290,7 +299,7 @@ test "crypto.chacha20 test vector 2" {
290 };299 };
291 const nonce = [_]u8{ 0, 0, 0, 0, 0, 0, 0, 0 };300 const nonce = [_]u8{ 0, 0, 0, 0, 0, 0, 0, 0 };
292301
293 chaCha20With64BitNonce(result[0..], input[0..], 0, key, nonce);302 ChaCha20With64BitNonce.xor(result[0..], input[0..], 0, key, nonce);
294 testing.expectEqualSlices(u8, &expected_result, &result);303 testing.expectEqualSlices(u8, &expected_result, &result);
295}304}
296305
...@@ -324,7 +333,7 @@ test "crypto.chacha20 test vector 3" {...@@ -324,7 +333,7 @@ test "crypto.chacha20 test vector 3" {
324 };333 };
325 const nonce = [_]u8{ 0, 0, 0, 0, 0, 0, 0, 1 };334 const nonce = [_]u8{ 0, 0, 0, 0, 0, 0, 0, 1 };
326335
327 chaCha20With64BitNonce(result[0..], input[0..], 0, key, nonce);336 ChaCha20With64BitNonce.xor(result[0..], input[0..], 0, key, nonce);
328 testing.expectEqualSlices(u8, &expected_result, &result);337 testing.expectEqualSlices(u8, &expected_result, &result);
329}338}
330339
...@@ -358,7 +367,7 @@ test "crypto.chacha20 test vector 4" {...@@ -358,7 +367,7 @@ test "crypto.chacha20 test vector 4" {
358 };367 };
359 const nonce = [_]u8{ 1, 0, 0, 0, 0, 0, 0, 0 };368 const nonce = [_]u8{ 1, 0, 0, 0, 0, 0, 0, 0 };
360369
361 chaCha20With64BitNonce(result[0..], input[0..], 0, key, nonce);370 ChaCha20With64BitNonce.xor(result[0..], input[0..], 0, key, nonce);
362 testing.expectEqualSlices(u8, &expected_result, &result);371 testing.expectEqualSlices(u8, &expected_result, &result);
363}372}
364373
...@@ -430,21 +439,21 @@ test "crypto.chacha20 test vector 5" {...@@ -430,21 +439,21 @@ test "crypto.chacha20 test vector 5" {
430 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,439 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
431 };440 };
432441
433 chaCha20With64BitNonce(result[0..], input[0..], 0, key, nonce);442 ChaCha20With64BitNonce.xor(result[0..], input[0..], 0, key, nonce);
434 testing.expectEqualSlices(u8, &expected_result, &result);443 testing.expectEqualSlices(u8, &expected_result, &result);
435}444}
436445
437pub const chacha20poly1305_tag_size = 16;446pub const chacha20poly1305_tag_size = 16;
438447
439pub fn chacha20poly1305SealDetached(ciphertext: []u8, tag: *[chacha20poly1305_tag_size]u8, plaintext: []const u8, data: []const u8, key: [32]u8, nonce: [12]u8) void {448fn chacha20poly1305SealDetached(ciphertext: []u8, tag: *[chacha20poly1305_tag_size]u8, plaintext: []const u8, data: []const u8, key: [32]u8, nonce: [12]u8) void {
440 assert(ciphertext.len >= plaintext.len);449 assert(ciphertext.len >= plaintext.len);
441450
442 // derive poly1305 key451 // derive poly1305 key
443 var polyKey = [_]u8{0} ** 32;452 var polyKey = [_]u8{0} ** 32;
444 chaCha20IETF(polyKey[0..], polyKey[0..], 0, key, nonce);453 ChaCha20IETF.xor(polyKey[0..], polyKey[0..], 0, key, nonce);
445454
446 // encrypt plaintext455 // encrypt plaintext
447 chaCha20IETF(ciphertext[0..plaintext.len], plaintext, 1, key, nonce);456 ChaCha20IETF.xor(ciphertext[0..plaintext.len], plaintext, 1, key, nonce);
448457
449 // construct mac458 // construct mac
450 var mac = Poly1305.init(polyKey[0..]);459 var mac = Poly1305.init(polyKey[0..]);
...@@ -467,18 +476,18 @@ pub fn chacha20poly1305SealDetached(ciphertext: []u8, tag: *[chacha20poly1305_ta...@@ -467,18 +476,18 @@ pub fn chacha20poly1305SealDetached(ciphertext: []u8, tag: *[chacha20poly1305_ta
467 mac.final(tag);476 mac.final(tag);
468}477}
469478
470pub fn chacha20poly1305Seal(ciphertextAndTag: []u8, plaintext: []const u8, data: []const u8, key: [32]u8, nonce: [12]u8) void {479fn chacha20poly1305Seal(ciphertextAndTag: []u8, plaintext: []const u8, data: []const u8, key: [32]u8, nonce: [12]u8) void {
471 return chacha20poly1305SealDetached(ciphertextAndTag[0..plaintext.len], ciphertextAndTag[plaintext.len..][0..chacha20poly1305_tag_size], plaintext, data, key, nonce);480 return chacha20poly1305SealDetached(ciphertextAndTag[0..plaintext.len], ciphertextAndTag[plaintext.len..][0..chacha20poly1305_tag_size], plaintext, data, key, nonce);
472}481}
473482
474/// Verifies and decrypts an authenticated message produced by chacha20poly1305SealDetached.483/// Verifies and decrypts an authenticated message produced by chacha20poly1305SealDetached.
475pub fn chacha20poly1305OpenDetached(dst: []u8, ciphertext: []const u8, tag: *const [chacha20poly1305_tag_size]u8, data: []const u8, key: [32]u8, nonce: [12]u8) !void {484fn chacha20poly1305OpenDetached(dst: []u8, ciphertext: []const u8, tag: *const [chacha20poly1305_tag_size]u8, data: []const u8, key: [32]u8, nonce: [12]u8) !void {
476 // split ciphertext and tag485 // split ciphertext and tag
477 assert(dst.len >= ciphertext.len);486 assert(dst.len >= ciphertext.len);
478487
479 // derive poly1305 key488 // derive poly1305 key
480 var polyKey = [_]u8{0} ** 32;489 var polyKey = [_]u8{0} ** 32;
481 chaCha20IETF(polyKey[0..], polyKey[0..], 0, key, nonce);490 ChaCha20IETF.xor(polyKey[0..], polyKey[0..], 0, key, nonce);
482491
483 // construct mac492 // construct mac
484 var mac = Poly1305.init(polyKey[0..]);493 var mac = Poly1305.init(polyKey[0..]);
...@@ -514,11 +523,11 @@ pub fn chacha20poly1305OpenDetached(dst: []u8, ciphertext: []const u8, tag: *con...@@ -514,11 +523,11 @@ pub fn chacha20poly1305OpenDetached(dst: []u8, ciphertext: []const u8, tag: *con
514 }523 }
515524
516 // decrypt ciphertext525 // decrypt ciphertext
517 chaCha20IETF(dst[0..ciphertext.len], ciphertext, 1, key, nonce);526 ChaCha20IETF.xor(dst[0..ciphertext.len], ciphertext, 1, key, nonce);
518}527}
519528
520/// Verifies and decrypts an authenticated message produced by chacha20poly1305Seal.529/// Verifies and decrypts an authenticated message produced by chacha20poly1305Seal.
521pub fn chacha20poly1305Open(dst: []u8, ciphertextAndTag: []const u8, data: []const u8, key: [32]u8, nonce: [12]u8) !void {530fn chacha20poly1305Open(dst: []u8, ciphertextAndTag: []const u8, data: []const u8, key: [32]u8, nonce: [12]u8) !void {
522 if (ciphertextAndTag.len < chacha20poly1305_tag_size) {531 if (ciphertextAndTag.len < chacha20poly1305_tag_size) {
523 return error.InvalidMessage;532 return error.InvalidMessage;
524 }533 }
...@@ -557,31 +566,33 @@ fn extend(key: [32]u8, nonce: [24]u8) struct { key: [32]u8, nonce: [12]u8 } {...@@ -557,31 +566,33 @@ fn extend(key: [32]u8, nonce: [24]u8) struct { key: [32]u8, nonce: [12]u8 } {
557 };566 };
558}567}
559568
560pub fn xChaCha20IETF(out: []u8, in: []const u8, counter: u32, key: [32]u8, nonce: [24]u8) void {569pub const XChaCha20IETF = struct {
561 const extended = extend(key, nonce);570 pub fn xor(out: []u8, in: []const u8, counter: u32, key: [32]u8, nonce: [24]u8) void {
562 chaCha20IETF(out, in, counter, extended.key, extended.nonce);571 const extended = extend(key, nonce);
563}572 ChaCha20IETF.xor(out, in, counter, extended.key, extended.nonce);
573 }
574};
564575
565pub const xchacha20poly1305_tag_size = 16;576pub const xchacha20poly1305_tag_size = 16;
566577
567pub fn xchacha20poly1305SealDetached(ciphertext: []u8, tag: *[chacha20poly1305_tag_size]u8, plaintext: []const u8, data: []const u8, key: [32]u8, nonce: [24]u8) void {578fn xchacha20poly1305SealDetached(ciphertext: []u8, tag: *[chacha20poly1305_tag_size]u8, plaintext: []const u8, data: []const u8, key: [32]u8, nonce: [24]u8) void {
568 const extended = extend(key, nonce);579 const extended = extend(key, nonce);
569 return chacha20poly1305SealDetached(ciphertext, tag, plaintext, data, extended.key, extended.nonce);580 return chacha20poly1305SealDetached(ciphertext, tag, plaintext, data, extended.key, extended.nonce);
570}581}
571582
572pub fn xchacha20poly1305Seal(ciphertextAndTag: []u8, plaintext: []const u8, data: []const u8, key: [32]u8, nonce: [24]u8) void {583fn xchacha20poly1305Seal(ciphertextAndTag: []u8, plaintext: []const u8, data: []const u8, key: [32]u8, nonce: [24]u8) void {
573 const extended = extend(key, nonce);584 const extended = extend(key, nonce);
574 return chacha20poly1305Seal(ciphertextAndTag, plaintext, data, extended.key, extended.nonce);585 return chacha20poly1305Seal(ciphertextAndTag, plaintext, data, extended.key, extended.nonce);
575}586}
576587
577/// Verifies and decrypts an authenticated message produced by xchacha20poly1305SealDetached.588/// Verifies and decrypts an authenticated message produced by xchacha20poly1305SealDetached.
578pub fn xchacha20poly1305OpenDetached(plaintext: []u8, ciphertext: []const u8, tag: *const [chacha20poly1305_tag_size]u8, data: []const u8, key: [32]u8, nonce: [24]u8) !void {589fn xchacha20poly1305OpenDetached(plaintext: []u8, ciphertext: []const u8, tag: *const [chacha20poly1305_tag_size]u8, data: []const u8, key: [32]u8, nonce: [24]u8) !void {
579 const extended = extend(key, nonce);590 const extended = extend(key, nonce);
580 return try chacha20poly1305OpenDetached(plaintext, ciphertext, tag, data, extended.key, extended.nonce);591 return try chacha20poly1305OpenDetached(plaintext, ciphertext, tag, data, extended.key, extended.nonce);
581}592}
582593
583/// Verifies and decrypts an authenticated message produced by xchacha20poly1305Seal.594/// Verifies and decrypts an authenticated message produced by xchacha20poly1305Seal.
584pub fn xchacha20poly1305Open(ciphertextAndTag: []u8, msgAndTag: []const u8, data: []const u8, key: [32]u8, nonce: [24]u8) !void {595fn xchacha20poly1305Open(ciphertextAndTag: []u8, msgAndTag: []const u8, data: []const u8, key: [32]u8, nonce: [24]u8) !void {
585 const extended = extend(key, nonce);596 const extended = extend(key, nonce);
586 return try chacha20poly1305Open(ciphertextAndTag, msgAndTag, data, extended.key, extended.nonce);597 return try chacha20poly1305Open(ciphertextAndTag, msgAndTag, data, extended.key, extended.nonce);
587}598}
...@@ -709,7 +720,7 @@ test "crypto.xchacha20" {...@@ -709,7 +720,7 @@ test "crypto.xchacha20" {
709 const input = "Ladies and Gentlemen of the class of '99: If I could offer you only one tip for the future, sunscreen would be it.";720 const input = "Ladies and Gentlemen of the class of '99: If I could offer you only one tip for the future, sunscreen would be it.";
710 {721 {
711 var ciphertext: [input.len]u8 = undefined;722 var ciphertext: [input.len]u8 = undefined;
712 xChaCha20IETF(ciphertext[0..], input[0..], 0, key, nonce);723 XChaCha20IETF.xor(ciphertext[0..], input[0..], 0, key, nonce);
713 var buf: [2 * ciphertext.len]u8 = undefined;724 var buf: [2 * ciphertext.len]u8 = undefined;
714 testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{ciphertext}), "E0A1BCF939654AFDBDC1746EC49832647C19D891F0D1A81FC0C1703B4514BDEA584B512F6908C2C5E9DD18D5CBC1805DE5803FE3B9CA5F193FB8359E91FAB0C3BB40309A292EB1CF49685C65C4A3ADF4F11DB0CD2B6B67FBC174BC2E860E8F769FD3565BBFAD1C845E05A0FED9BE167C240D");725 testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{ciphertext}), "E0A1BCF939654AFDBDC1746EC49832647C19D891F0D1A81FC0C1703B4514BDEA584B512F6908C2C5E9DD18D5CBC1805DE5803FE3B9CA5F193FB8359E91FAB0C3BB40309A292EB1CF49685C65C4A3ADF4F11DB0CD2B6B67FBC174BC2E860E8F769FD3565BBFAD1C845E05A0FED9BE167C240D");
715 }726 }
lib/std/crypto/gimli.zig+13-7
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Gimli is a 384-bit permutation designed to achieve high security with high6// Gimli is a 384-bit permutation designed to achieve high security with high
2// performance across a broad range of platforms, including 64-bit Intel/AMD7// performance across a broad range of platforms, including 64-bit Intel/AMD
3// server CPUs, 64-bit and 32-bit ARM smartphone CPUs, 32-bit ARM8// server CPUs, 64-bit and 32-bit ARM smartphone CPUs, 32-bit ARM
...@@ -104,13 +109,14 @@ pub const Hash = struct {...@@ -104,13 +109,14 @@ pub const Hash = struct {
104 state: State,109 state: State,
105 buf_off: usize,110 buf_off: usize,
106111
112 pub const block_length = State.RATE;
113 pub const Options = struct {};
114
107 const Self = @This();115 const Self = @This();
108116
109 pub fn init() Self {117 pub fn init(options: Options) Self {
110 return Self{118 return Self{
111 .state = State{119 .state = State{ .data = [_]u32{0} ** (State.BLOCKBYTES / 4) },
112 .data = [_]u32{0} ** (State.BLOCKBYTES / 4),
113 },
114 .buf_off = 0,120 .buf_off = 0,
115 };121 };
116 }122 }
...@@ -155,8 +161,8 @@ pub const Hash = struct {...@@ -155,8 +161,8 @@ pub const Hash = struct {
155 }161 }
156};162};
157163
158pub fn hash(out: []u8, in: []const u8) void {164pub fn hash(out: []u8, in: []const u8, options: Hash.Options) void {
159 var st = Hash.init();165 var st = Hash.init(options);
160 st.update(in);166 st.update(in);
161 st.final(out);167 st.final(out);
162}168}
...@@ -169,7 +175,7 @@ test "hash" {...@@ -169,7 +175,7 @@ test "hash" {
169 var msg: [58 / 2]u8 = undefined;175 var msg: [58 / 2]u8 = undefined;
170 try std.fmt.hexToBytes(&msg, "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C");176 try std.fmt.hexToBytes(&msg, "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C");
171 var md: [32]u8 = undefined;177 var md: [32]u8 = undefined;
172 hash(&md, &msg);178 hash(&md, &msg, .{});
173 htest.assertEqual("1C9A03DC6A5DDC5444CFC6F4B154CFF5CF081633B2CEA4D7D0AE7CCFED5AAA44", &md);179 htest.assertEqual("1C9A03DC6A5DDC5444CFC6F4B154CFF5CF081633B2CEA4D7D0AE7CCFED5AAA44", &md);
174}180}
175181
lib/std/crypto/hmac.zig+27-13
...@@ -1,12 +1,26 @@...@@ -1,12 +1,26 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const crypto = std.crypto;7const crypto = std.crypto;
3const debug = std.debug;8const debug = std.debug;
4const mem = std.mem;9const mem = std.mem;
510
6pub const HmacMd5 = Hmac(crypto.Md5);11pub const HmacMd5 = Hmac(crypto.hash.Md5);
7pub const HmacSha1 = Hmac(crypto.Sha1);12pub const HmacSha1 = Hmac(crypto.hash.Sha1);
8pub const HmacSha256 = Hmac(crypto.Sha256);13
9pub const HmacBlake2s256 = Hmac(crypto.Blake2s256);14pub const sha2 = struct {
15 pub const HmacSha224 = Hmac(crypto.hash.sha2.Sha224);
16 pub const HmacSha256 = Hmac(crypto.hash.sha2.Sha256);
17 pub const HmacSha384 = Hmac(crypto.hash.sha2.Sha384);
18 pub const HmacSha512 = Hmac(crypto.hash.sha2.Sha512);
19};
20
21pub const blake2 = struct {
22 pub const HmacBlake2s256 = Hmac(crypto.hash.blake2.Blake2s256);
23};
1024
11pub fn Hmac(comptime Hash: type) type {25pub fn Hmac(comptime Hash: type) type {
12 return struct {26 return struct {
...@@ -31,7 +45,7 @@ pub fn Hmac(comptime Hash: type) type {...@@ -31,7 +45,7 @@ pub fn Hmac(comptime Hash: type) type {
3145
32 // Normalize key length to block size of hash46 // Normalize key length to block size of hash
33 if (key.len > Hash.block_length) {47 if (key.len > Hash.block_length) {
34 Hash.hash(key, ctx.scratch[0..mac_length]);48 Hash.hash(key, ctx.scratch[0..mac_length], .{});
35 mem.set(u8, ctx.scratch[mac_length..Hash.block_length], 0);49 mem.set(u8, ctx.scratch[mac_length..Hash.block_length], 0);
36 } else if (key.len < Hash.block_length) {50 } else if (key.len < Hash.block_length) {
37 mem.copy(u8, ctx.scratch[0..key.len], key);51 mem.copy(u8, ctx.scratch[0..key.len], key);
...@@ -48,7 +62,7 @@ pub fn Hmac(comptime Hash: type) type {...@@ -48,7 +62,7 @@ pub fn Hmac(comptime Hash: type) type {
48 b.* = ctx.scratch[i] ^ 0x36;62 b.* = ctx.scratch[i] ^ 0x36;
49 }63 }
5064
51 ctx.hash = Hash.init();65 ctx.hash = Hash.init(.{});
52 ctx.hash.update(ctx.i_key_pad[0..]);66 ctx.hash.update(ctx.i_key_pad[0..]);
53 return ctx;67 return ctx;
54 }68 }
...@@ -61,10 +75,10 @@ pub fn Hmac(comptime Hash: type) type {...@@ -61,10 +75,10 @@ pub fn Hmac(comptime Hash: type) type {
61 debug.assert(Hash.block_length >= out.len and out.len >= mac_length);75 debug.assert(Hash.block_length >= out.len and out.len >= mac_length);
6276
63 ctx.hash.final(ctx.scratch[0..mac_length]);77 ctx.hash.final(ctx.scratch[0..mac_length]);
64 ctx.hash.reset();78 var ohash = Hash.init(.{});
65 ctx.hash.update(ctx.o_key_pad[0..]);79 ohash.update(ctx.o_key_pad[0..]);
66 ctx.hash.update(ctx.scratch[0..mac_length]);80 ohash.update(ctx.scratch[0..mac_length]);
67 ctx.hash.final(out[0..mac_length]);81 ohash.final(out[0..mac_length]);
68 }82 }
69 };83 };
70}84}
...@@ -90,10 +104,10 @@ test "hmac sha1" {...@@ -90,10 +104,10 @@ test "hmac sha1" {
90}104}
91105
92test "hmac sha256" {106test "hmac sha256" {
93 var out: [HmacSha256.mac_length]u8 = undefined;107 var out: [sha2.HmacSha256.mac_length]u8 = undefined;
94 HmacSha256.create(out[0..], "", "");108 sha2.HmacSha256.create(out[0..], "", "");
95 htest.assertEqual("b613679a0814d9ec772f95d778c35fc5ff1697c493715653c6c712144292c5ad", out[0..]);109 htest.assertEqual("b613679a0814d9ec772f95d778c35fc5ff1697c493715653c6c712144292c5ad", out[0..]);
96110
97 HmacSha256.create(out[0..], "The quick brown fox jumps over the lazy dog", "key");111 sha2.HmacSha256.create(out[0..], "The quick brown fox jumps over the lazy dog", "key");
98 htest.assertEqual("f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8", out[0..]);112 htest.assertEqual("f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8", out[0..]);
99}113}
lib/std/crypto/md5.zig+27-19
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const mem = @import("../mem.zig");6const mem = @import("../mem.zig");
2const math = @import("../math.zig");7const math = @import("../math.zig");
3const endian = @import("../endian.zig");8const endian = @import("../endian.zig");
...@@ -27,10 +32,14 @@ fn Rp(a: usize, b: usize, c: usize, d: usize, k: usize, s: u32, t: u32) RoundPar...@@ -27,10 +32,14 @@ fn Rp(a: usize, b: usize, c: usize, d: usize, k: usize, s: u32, t: u32) RoundPar
27 };32 };
28}33}
2934
35/// The MD5 function is now considered cryptographically broken.
36/// Namely, it is trivial to find multiple inputs producing the same hash.
37/// For a fast-performing, cryptographically secure hash function, see SHA512/256, BLAKE2 or BLAKE3.
30pub const Md5 = struct {38pub const Md5 = struct {
31 const Self = @This();39 const Self = @This();
32 pub const block_length = 64;40 pub const block_length = 64;
33 pub const digest_length = 16;41 pub const digest_length = 16;
42 pub const Options = struct {};
3443
35 s: [4]u32,44 s: [4]u32,
36 // Streaming Cache45 // Streaming Cache
...@@ -38,23 +47,22 @@ pub const Md5 = struct {...@@ -38,23 +47,22 @@ pub const Md5 = struct {
38 buf_len: u8,47 buf_len: u8,
39 total_len: u64,48 total_len: u64,
4049
41 pub fn init() Self {50 pub fn init(options: Options) Self {
42 var d: Self = undefined;51 return Self{
43 d.reset();52 .s = [_]u32{
44 return d;53 0x67452301,
45 }54 0xEFCDAB89,
4655 0x98BADCFE,
47 pub fn reset(d: *Self) void {56 0x10325476,
48 d.s[0] = 0x67452301;57 },
49 d.s[1] = 0xEFCDAB89;58 .buf = undefined,
50 d.s[2] = 0x98BADCFE;59 .buf_len = 0,
51 d.s[3] = 0x10325476;60 .total_len = 0,
52 d.buf_len = 0;61 };
53 d.total_len = 0;
54 }62 }
5563
56 pub fn hash(b: []const u8, out: []u8) void {64 pub fn hash(b: []const u8, out: []u8, options: Options) void {
57 var d = Md5.init();65 var d = Md5.init(options);
58 d.update(b);66 d.update(b);
59 d.final(out);67 d.final(out);
60 }68 }
...@@ -250,18 +258,18 @@ test "md5 single" {...@@ -250,18 +258,18 @@ test "md5 single" {
250}258}
251259
252test "md5 streaming" {260test "md5 streaming" {
253 var h = Md5.init();261 var h = Md5.init(.{});
254 var out: [16]u8 = undefined;262 var out: [16]u8 = undefined;
255263
256 h.final(out[0..]);264 h.final(out[0..]);
257 htest.assertEqual("d41d8cd98f00b204e9800998ecf8427e", out[0..]);265 htest.assertEqual("d41d8cd98f00b204e9800998ecf8427e", out[0..]);
258266
259 h.reset();267 h = Md5.init(.{});
260 h.update("abc");268 h.update("abc");
261 h.final(out[0..]);269 h.final(out[0..]);
262 htest.assertEqual("900150983cd24fb0d6963f7d28e17f72", out[0..]);270 htest.assertEqual("900150983cd24fb0d6963f7d28e17f72", out[0..]);
263271
264 h.reset();272 h = Md5.init(.{});
265 h.update("a");273 h.update("a");
266 h.update("b");274 h.update("b");
267 h.update("c");275 h.update("c");
...@@ -274,7 +282,7 @@ test "md5 aligned final" {...@@ -274,7 +282,7 @@ test "md5 aligned final" {
274 var block = [_]u8{0} ** Md5.block_length;282 var block = [_]u8{0} ** Md5.block_length;
275 var out: [Md5.digest_length]u8 = undefined;283 var out: [Md5.digest_length]u8 = undefined;
276284
277 var h = Md5.init();285 var h = Md5.init(.{});
278 h.update(&block);286 h.update(&block);
279 h.final(out[0..]);287 h.final(out[0..]);
280}288}
lib/std/crypto/poly1305.zig+169-191
...@@ -1,221 +1,199 @@...@@ -1,221 +1,199 @@
1// Translated from monocypher which is licensed under CC-0/BSD-3.1// SPDX-License-Identifier: MIT
2//2// Copyright (c) 2015-2020 Zig Contributors
3// https://monocypher.org/3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
44// The MIT license requires this copyright notice to be included in all copies
5const std = @import("../std.zig");5// and substantial portions of the software.
6const builtin = std.builtin;6const std = @import("std");
77const mem = std.mem;
8const Endian = builtin.Endian;
9const readIntLittle = std.mem.readIntLittle;
10const writeIntLittle = std.mem.writeIntLittle;
118
12pub const Poly1305 = struct {9pub const Poly1305 = struct {
13 const Self = @This();10 pub const block_size: usize = 16;
14
15 pub const mac_length = 16;11 pub const mac_length = 16;
16 pub const minimum_key_length = 32;12 pub const minimum_key_length = 32;
1713
18 // constant multiplier (from the secret key)14 // constant multiplier (from the secret key)
19 r: [4]u32,15 r: [3]u64,
20 // accumulated hash16 // accumulated hash
21 h: [5]u32,17 h: [3]u64 = [_]u64{ 0, 0, 0 },
22 // chunk of the message
23 c: [5]u32,
24 // random number added at the end (from the secret key)18 // random number added at the end (from the secret key)
25 pad: [4]u32,19 pad: [2]u64,
26 // How many bytes are there in the chunk.20 // how many bytes are waiting to be processed in a partial block
27 c_idx: usize,21 leftover: usize = 0,
2822 // partial block buffer
29 fn secureZero(self: *Self) void {23 buf: [block_size]u8 align(16) = undefined,
30 std.mem.secureZero(u8, @ptrCast([*]u8, self)[0..@sizeOf(Poly1305)]);
31 }
3224
33 pub fn create(out: []u8, msg: []const u8, key: []const u8) void {25 pub fn init(key: []const u8) Poly1305 {
34 std.debug.assert(out.len >= mac_length);
35 std.debug.assert(key.len >= minimum_key_length);26 std.debug.assert(key.len >= minimum_key_length);
27 const t0 = mem.readIntLittle(u64, key[0..8]);
28 const t1 = mem.readIntLittle(u64, key[8..16]);
29 return Poly1305{
30 .r = [_]u64{
31 t0 & 0xffc0fffffff,
32 ((t0 >> 44) | (t1 << 20)) & 0xfffffc0ffff,
33 ((t1 >> 24)) & 0x00ffffffc0f,
34 },
35 .pad = [_]u64{
36 mem.readIntLittle(u64, key[16..24]),
37 mem.readIntLittle(u64, key[24..32]),
38 },
39 };
40 }
3641
37 var ctx = Poly1305.init(key);42 fn blocks(st: *Poly1305, m: []const u8, last: comptime bool) void {
38 ctx.update(msg);43 const hibit: u64 = if (last) 0 else 1 << 40;
39 ctx.final(out);44 const r0 = st.r[0];
45 const r1 = st.r[1];
46 const r2 = st.r[2];
47 var h0 = st.h[0];
48 var h1 = st.h[1];
49 var h2 = st.h[2];
50 const s1 = r1 * (5 << 2);
51 const s2 = r2 * (5 << 2);
52 var i: usize = 0;
53 while (i + block_size <= m.len) : (i += block_size) {
54 // h += m[i]
55 const t0 = mem.readIntLittle(u64, m[i..][0..8]);
56 const t1 = mem.readIntLittle(u64, m[i + 8 ..][0..8]);
57 h0 += @truncate(u44, t0);
58 h1 += @truncate(u44, (t0 >> 44) | (t1 << 20));
59 h2 += @truncate(u42, t1 >> 24) | hibit;
60
61 // h *= r
62 const d0 = @as(u128, h0) * r0 + @as(u128, h1) * s2 + @as(u128, h2) * s1;
63 var d1 = @as(u128, h0) * r1 + @as(u128, h1) * r0 + @as(u128, h2) * s2;
64 var d2 = @as(u128, h0) * r2 + @as(u128, h1) * r1 + @as(u128, h2) * r0;
65
66 // partial reduction
67 var carry = @intCast(u64, d0 >> 44);
68 h0 = @truncate(u44, d0);
69 d1 += carry;
70 carry = @intCast(u64, d1 >> 44);
71 h1 = @truncate(u44, d1);
72 d2 += carry;
73 carry = @intCast(u64, d2 >> 42);
74 h2 = @truncate(u42, d2);
75 h0 += @truncate(u64, carry) * 5;
76 carry = h0 >> 44;
77 h0 = @truncate(u44, h0);
78 h1 += carry;
79 }
80 st.h = [_]u64{ h0, h1, h2 };
40 }81 }
4182
42 // Initialize the MAC context.83 pub fn update(st: *Poly1305, m: []const u8) void {
43 // - key.len is sufficient size.84 var mb = m;
44 pub fn init(key: []const u8) Self {
45 var ctx: Poly1305 = undefined;
4685
47 // Initial hash is zero86 // handle leftover
48 {87 if (st.leftover > 0) {
49 var i: usize = 0;88 const want = std.math.min(block_size - st.leftover, mb.len);
50 while (i < 5) : (i += 1) {89 const mc = mb[0..want];
51 ctx.h[i] = 0;90 for (mc) |x, i| {
91 st.buf[st.leftover + i] = x;
52 }92 }
53 }93 mb = mb[want..];
54 // add 2^130 to every input block94 st.leftover += want;
55 ctx.c[4] = 1;95 if (st.leftover > block_size) {
56 polyClearC(&ctx);96 return;
57
58 // load r and pad (r has some of its bits cleared)
59 {
60 var i: usize = 0;
61 while (i < 1) : (i += 1) {
62 ctx.r[0] = readIntLittle(u32, key[0..4]) & 0x0fffffff;
63 }97 }
98 st.blocks(&st.buf, false);
99 st.leftover = 0;
64 }100 }
65 {
66 var i: usize = 1;
67 while (i < 4) : (i += 1) {
68 ctx.r[i] = readIntLittle(u32, key[i * 4 ..][0..4]) & 0x0ffffffc;
69 }
70 }
71 {
72 var i: usize = 0;
73 while (i < 4) : (i += 1) {
74 ctx.pad[i] = readIntLittle(u32, key[i * 4 + 16 ..][0..4]);
75 }
76 }
77
78 return ctx;
79 }
80
81 // h = (h + c) * r
82 // preconditions:
83 // ctx->h <= 4_ffffffff_ffffffff_ffffffff_ffffffff
84 // ctx->c <= 1_ffffffff_ffffffff_ffffffff_ffffffff
85 // ctx->r <= 0ffffffc_0ffffffc_0ffffffc_0fffffff
86 // Postcondition:
87 // ctx->h <= 4_ffffffff_ffffffff_ffffffff_ffffffff
88 fn polyBlock(ctx: *Self) void {
89 // s = h + c, without carry propagation
90 const s0 = @as(u64, ctx.h[0]) + ctx.c[0]; // s0 <= 1_fffffffe
91 const s1 = @as(u64, ctx.h[1]) + ctx.c[1]; // s1 <= 1_fffffffe
92 const s2 = @as(u64, ctx.h[2]) + ctx.c[2]; // s2 <= 1_fffffffe
93 const s3 = @as(u64, ctx.h[3]) + ctx.c[3]; // s3 <= 1_fffffffe
94 const s4 = @as(u64, ctx.h[4]) + ctx.c[4]; // s4 <= 5
95
96 // Local all the things!
97 const r0 = ctx.r[0]; // r0 <= 0fffffff
98 const r1 = ctx.r[1]; // r1 <= 0ffffffc
99 const r2 = ctx.r[2]; // r2 <= 0ffffffc
100 const r3 = ctx.r[3]; // r3 <= 0ffffffc
101 const rr0 = (r0 >> 2) * 5; // rr0 <= 13fffffb // lose 2 bits...
102 const rr1 = (r1 >> 2) + r1; // rr1 <= 13fffffb // rr1 == (r1 >> 2) * 5
103 const rr2 = (r2 >> 2) + r2; // rr2 <= 13fffffb // rr1 == (r2 >> 2) * 5
104 const rr3 = (r3 >> 2) + r3; // rr3 <= 13fffffb // rr1 == (r3 >> 2) * 5
105
106 // (h + c) * r, without carry propagation
107 const x0 = s0 * r0 + s1 * rr3 + s2 * rr2 + s3 * rr1 + s4 * rr0; //<=97ffffe007fffff8
108 const x1 = s0 * r1 + s1 * r0 + s2 * rr3 + s3 * rr2 + s4 * rr1; //<=8fffffe20ffffff6
109 const x2 = s0 * r2 + s1 * r1 + s2 * r0 + s3 * rr3 + s4 * rr2; //<=87ffffe417fffff4
110 const x3 = s0 * r3 + s1 * r2 + s2 * r1 + s3 * r0 + s4 * rr3; //<=7fffffe61ffffff2
111 const x4 = s4 * (r0 & 3); // ...recover 2 bits //<= f
112
113 // partial reduction modulo 2^130 - 5
114 const _u5 = @truncate(u32, x4 + (x3 >> 32)); // u5 <= 7ffffff5
115 const _u0 = (_u5 >> 2) * 5 + (x0 & 0xffffffff);
116 const _u1 = (_u0 >> 32) + (x1 & 0xffffffff) + (x0 >> 32);
117 const _u2 = (_u1 >> 32) + (x2 & 0xffffffff) + (x1 >> 32);
118 const _u3 = (_u2 >> 32) + (x3 & 0xffffffff) + (x2 >> 32);
119 const _u4 = (_u3 >> 32) + (_u5 & 3);
120
121 // Update the hash
122 ctx.h[0] = @truncate(u32, _u0); // u0 <= 1_9ffffff0
123 ctx.h[1] = @truncate(u32, _u1); // u1 <= 1_97ffffe0
124 ctx.h[2] = @truncate(u32, _u2); // u2 <= 1_8fffffe2
125 ctx.h[3] = @truncate(u32, _u3); // u3 <= 1_87ffffe4
126 ctx.h[4] = @truncate(u32, _u4); // u4 <= 4
127 }
128
129 // (re-)initializes the input counter and input buffer
130 fn polyClearC(ctx: *Self) void {
131 ctx.c[0] = 0;
132 ctx.c[1] = 0;
133 ctx.c[2] = 0;
134 ctx.c[3] = 0;
135 ctx.c_idx = 0;
136 }
137101
138 fn polyTakeInput(ctx: *Self, input: u8) void {102 // process full blocks
139 const word = ctx.c_idx >> 2;103 if (mb.len >= block_size) {
140 const byte = ctx.c_idx & 3;104 const want = mb.len & ~(block_size - 1);
141 ctx.c[word] |= std.math.shl(u32, input, byte * 8);105 st.blocks(mb[0..want], false);
142 ctx.c_idx += 1;106 mb = mb[want..];
143 }107 }
144108
145 fn polyUpdate(ctx: *Self, msg: []const u8) void {109 // store leftover
146 for (msg) |b| {110 if (mb.len > 0) {
147 polyTakeInput(ctx, b);111 for (mb) |x, i| {
148 if (ctx.c_idx == 16) {112 st.buf[st.leftover + i] = x;
149 polyBlock(ctx);
150 polyClearC(ctx);
151 }113 }
114 st.leftover += mb.len;
152 }115 }
153 }116 }
154117
155 fn alignTo(x: usize, block_size: usize) usize {118 pub fn final(st: *Poly1305, out: []u8) void {
156 return ((~x) +% 1) & (block_size - 1);119 std.debug.assert(out.len >= mac_length);
157 }120 if (st.leftover > 0) {
158121 var i = st.leftover;
159 // Feed data into the MAC context.122 st.buf[i] = 1;
160 pub fn update(ctx: *Self, msg: []const u8) void {123 i += 1;
161 // Align ourselves with block boundaries124 while (i < block_size) : (i += 1) {
162 const alignm = std.math.min(alignTo(ctx.c_idx, 16), msg.len);125 st.buf[i] = 0;
163 polyUpdate(ctx, msg[0..alignm]);126 }
164127 st.blocks(&st.buf, true);
165 var nmsg = msg[alignm..];
166
167 // Process the msg block by block
168 const nb_blocks = nmsg.len >> 4;
169 var i: usize = 0;
170 while (i < nb_blocks) : (i += 1) {
171 ctx.c[0] = readIntLittle(u32, nmsg[0..4]);
172 ctx.c[1] = readIntLittle(u32, nmsg[4..8]);
173 ctx.c[2] = readIntLittle(u32, nmsg[8..12]);
174 ctx.c[3] = readIntLittle(u32, nmsg[12..16]);
175 polyBlock(ctx);
176 nmsg = nmsg[16..];
177 }
178 if (nb_blocks > 0) {
179 polyClearC(ctx);
180 }128 }
181129 // fully carry h
182 // remaining bytes130 var carry = st.h[1] >> 44;
183 polyUpdate(ctx, nmsg[0..]);131 st.h[1] = @truncate(u44, st.h[1]);
132 st.h[2] += carry;
133 carry = st.h[2] >> 42;
134 st.h[2] = @truncate(u42, st.h[2]);
135 st.h[0] += carry * 5;
136 carry = st.h[0] >> 44;
137 st.h[0] = @truncate(u44, st.h[0]);
138 st.h[1] += carry;
139 carry = st.h[1] >> 44;
140 st.h[1] = @truncate(u44, st.h[1]);
141 st.h[2] += carry;
142 carry = st.h[2] >> 42;
143 st.h[2] = @truncate(u42, st.h[2]);
144 st.h[0] += carry * 5;
145 carry = st.h[0] >> 44;
146 st.h[0] = @truncate(u44, st.h[0]);
147 st.h[1] += carry;
148
149 // compute h + -p
150 var g0 = st.h[0] + 5;
151 carry = g0 >> 44;
152 g0 = @truncate(u44, g0);
153 var g1 = st.h[1] + carry;
154 carry = g1 >> 44;
155 g1 = @truncate(u44, g1);
156 var g2 = st.h[2] + carry -% (1 << 42);
157
158 // (hopefully) constant-time select h if h < p, or h + -p if h >= p
159 const mask = (g2 >> 63) -% 1;
160 g0 &= mask;
161 g1 &= mask;
162 g2 &= mask;
163 const nmask = ~mask;
164 st.h[0] = (st.h[0] & nmask) | g0;
165 st.h[1] = (st.h[1] & nmask) | g1;
166 st.h[2] = (st.h[2] & nmask) | g2;
167
168 // h = (h + pad)
169 const t0 = st.pad[0];
170 const t1 = st.pad[1];
171 st.h[0] += @truncate(u44, t0);
172 carry = st.h[0] >> 44;
173 st.h[0] = @truncate(u44, st.h[0]);
174 st.h[1] += @truncate(u44, (t0 >> 44) | (t1 << 20)) + carry;
175 carry = st.h[1] >> 44;
176 st.h[1] = @truncate(u44, st.h[1]);
177 st.h[2] += @truncate(u42, t1 >> 24) + carry;
178 st.h[2] = @truncate(u42, st.h[2]);
179
180 // mac = h % (2^128)
181 st.h[0] |= st.h[1] << 44;
182 st.h[1] = (st.h[1] >> 20) | (st.h[2] << 24);
183
184 mem.writeIntLittle(u64, out[0..8], st.h[0]);
185 mem.writeIntLittle(u64, out[8..16], st.h[1]);
186
187 std.mem.secureZero(u8, @ptrCast([*]u8, st)[0..@sizeOf(Poly1305)]);
184 }188 }
185189
186 // Finalize the MAC and output into buffer provided by caller.190 pub fn create(out: []u8, msg: []const u8, key: []const u8) void {
187 pub fn final(ctx: *Self, out: []u8) void {191 std.debug.assert(out.len >= mac_length);
188 // Process the last block (if any)192 std.debug.assert(key.len >= minimum_key_length);
189 if (ctx.c_idx != 0) {
190 // move the final 1 according to remaining input length
191 // (We may add less than 2^130 to the last input block)
192 ctx.c[4] = 0;
193 polyTakeInput(ctx, 1);
194 // one last hash update
195 polyBlock(ctx);
196 }
197193
198 // check if we should subtract 2^130-5 by performing the194 var st = Poly1305.init(key);
199 // corresponding carry propagation.195 st.update(msg);
200 const _u0 = @as(u64, 5) + ctx.h[0]; // <= 1_00000004196 st.final(out);
201 const _u1 = (_u0 >> 32) + ctx.h[1]; // <= 1_00000000
202 const _u2 = (_u1 >> 32) + ctx.h[2]; // <= 1_00000000
203 const _u3 = (_u2 >> 32) + ctx.h[3]; // <= 1_00000000
204 const _u4 = (_u3 >> 32) + ctx.h[4]; // <= 5
205 // u4 indicates how many times we should subtract 2^130-5 (0 or 1)
206
207 // h + pad, minus 2^130-5 if u4 exceeds 3
208 const uu0 = (_u4 >> 2) * 5 + ctx.h[0] + ctx.pad[0]; // <= 2_00000003
209 const uu1 = (uu0 >> 32) + ctx.h[1] + ctx.pad[1]; // <= 2_00000000
210 const uu2 = (uu1 >> 32) + ctx.h[2] + ctx.pad[2]; // <= 2_00000000
211 const uu3 = (uu2 >> 32) + ctx.h[3] + ctx.pad[3]; // <= 2_00000000
212
213 writeIntLittle(u32, out[0..4], @truncate(u32, uu0));
214 writeIntLittle(u32, out[4..8], @truncate(u32, uu1));
215 writeIntLittle(u32, out[8..12], @truncate(u32, uu2));
216 writeIntLittle(u32, out[12..16], @truncate(u32, uu3));
217
218 ctx.secureZero();
219 }197 }
220};198};
221199
lib/std/crypto/sha1.zig+29-24
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const mem = @import("../mem.zig");6const mem = @import("../mem.zig");
2const math = @import("../math.zig");7const math = @import("../math.zig");
3const endian = @import("../endian.zig");8const endian = @import("../endian.zig");
...@@ -24,35 +29,35 @@ fn Rp(a: usize, b: usize, c: usize, d: usize, e: usize, i: u32) RoundParam {...@@ -24,35 +29,35 @@ fn Rp(a: usize, b: usize, c: usize, d: usize, e: usize, i: u32) RoundParam {
24 };29 };
25}30}
2631
32/// The SHA-1 function is now considered cryptographically broken.
33/// Namely, it is feasible to find multiple inputs producing the same hash.
34/// For a fast-performing, cryptographically secure hash function, see SHA512/256, BLAKE2 or BLAKE3.
27pub const Sha1 = struct {35pub const Sha1 = struct {
28 const Self = @This();36 const Self = @This();
29 pub const block_length = 64;37 pub const block_length = 64;
30 pub const digest_length = 20;38 pub const digest_length = 20;
39 pub const Options = struct {};
3140
32 s: [5]u32,41 s: [5]u32,
33 // Streaming Cache42 // Streaming Cache
34 buf: [64]u8,43 buf: [64]u8 = undefined,
35 buf_len: u8,44 buf_len: u8 = 0,
36 total_len: u64,45 total_len: u64 = 0,
3746
38 pub fn init() Self {47 pub fn init(options: Options) Self {
39 var d: Self = undefined;48 return Self{
40 d.reset();49 .s = [_]u32{
41 return d;50 0x67452301,
42 }51 0xEFCDAB89,
4352 0x98BADCFE,
44 pub fn reset(d: *Self) void {53 0x10325476,
45 d.s[0] = 0x67452301;54 0xC3D2E1F0,
46 d.s[1] = 0xEFCDAB89;55 },
47 d.s[2] = 0x98BADCFE;56 };
48 d.s[3] = 0x10325476;
49 d.s[4] = 0xC3D2E1F0;
50 d.buf_len = 0;
51 d.total_len = 0;
52 }57 }
5358
54 pub fn hash(b: []const u8, out: []u8) void {59 pub fn hash(b: []const u8, out: []u8, options: Options) void {
55 var d = Sha1.init();60 var d = Sha1.init(options);
56 d.update(b);61 d.update(b);
57 d.final(out);62 d.final(out);
58 }63 }
...@@ -272,18 +277,18 @@ test "sha1 single" {...@@ -272,18 +277,18 @@ test "sha1 single" {
272}277}
273278
274test "sha1 streaming" {279test "sha1 streaming" {
275 var h = Sha1.init();280 var h = Sha1.init(.{});
276 var out: [20]u8 = undefined;281 var out: [20]u8 = undefined;
277282
278 h.final(out[0..]);283 h.final(out[0..]);
279 htest.assertEqual("da39a3ee5e6b4b0d3255bfef95601890afd80709", out[0..]);284 htest.assertEqual("da39a3ee5e6b4b0d3255bfef95601890afd80709", out[0..]);
280285
281 h.reset();286 h = Sha1.init(.{});
282 h.update("abc");287 h.update("abc");
283 h.final(out[0..]);288 h.final(out[0..]);
284 htest.assertEqual("a9993e364706816aba3e25717850c26c9cd0d89d", out[0..]);289 htest.assertEqual("a9993e364706816aba3e25717850c26c9cd0d89d", out[0..]);
285290
286 h.reset();291 h = Sha1.init(.{});
287 h.update("a");292 h.update("a");
288 h.update("b");293 h.update("b");
289 h.update("c");294 h.update("c");
...@@ -295,7 +300,7 @@ test "sha1 aligned final" {...@@ -295,7 +300,7 @@ test "sha1 aligned final" {
295 var block = [_]u8{0} ** Sha1.block_length;300 var block = [_]u8{0} ** Sha1.block_length;
296 var out: [Sha1.digest_length]u8 = undefined;301 var out: [Sha1.digest_length]u8 = undefined;
297302
298 var h = Sha1.init();303 var h = Sha1.init(.{});
299 h.update(&block);304 h.update(&block);
300 h.final(out[0..]);305 h.final(out[0..]);
301}306}
lib/std/crypto/sha2.zig+95-60
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const mem = @import("../mem.zig");6const mem = @import("../mem.zig");
2const math = @import("../math.zig");7const math = @import("../math.zig");
3const endian = @import("../endian.zig");8const endian = @import("../endian.zig");
...@@ -72,7 +77,10 @@ const Sha256Params = Sha2Params32{...@@ -72,7 +77,10 @@ const Sha256Params = Sha2Params32{
72 .out_len = 256,77 .out_len = 256,
73};78};
7479
80/// SHA-224
75pub const Sha224 = Sha2_32(Sha224Params);81pub const Sha224 = Sha2_32(Sha224Params);
82
83/// SHA-256
76pub const Sha256 = Sha2_32(Sha256Params);84pub const Sha256 = Sha2_32(Sha256Params);
7785
78fn Sha2_32(comptime params: Sha2Params32) type {86fn Sha2_32(comptime params: Sha2Params32) type {
...@@ -80,34 +88,31 @@ fn Sha2_32(comptime params: Sha2Params32) type {...@@ -80,34 +88,31 @@ fn Sha2_32(comptime params: Sha2Params32) type {
80 const Self = @This();88 const Self = @This();
81 pub const block_length = 64;89 pub const block_length = 64;
82 pub const digest_length = params.out_len / 8;90 pub const digest_length = params.out_len / 8;
91 pub const Options = struct {};
8392
84 s: [8]u32,93 s: [8]u32,
85 // Streaming Cache94 // Streaming Cache
86 buf: [64]u8,95 buf: [64]u8 = undefined,
87 buf_len: u8,96 buf_len: u8 = 0,
88 total_len: u64,97 total_len: u64 = 0,
8998
90 pub fn init() Self {99 pub fn init(options: Options) Self {
91 var d: Self = undefined;100 return Self{
92 d.reset();101 .s = [_]u32{
93 return d;102 params.iv0,
94 }103 params.iv1,
95104 params.iv2,
96 pub fn reset(d: *Self) void {105 params.iv3,
97 d.s[0] = params.iv0;106 params.iv4,
98 d.s[1] = params.iv1;107 params.iv5,
99 d.s[2] = params.iv2;108 params.iv6,
100 d.s[3] = params.iv3;109 params.iv7,
101 d.s[4] = params.iv4;110 },
102 d.s[5] = params.iv5;111 };
103 d.s[6] = params.iv6;
104 d.s[7] = params.iv7;
105 d.buf_len = 0;
106 d.total_len = 0;
107 }112 }
108113
109 pub fn hash(b: []const u8, out: []u8) void {114 pub fn hash(b: []const u8, out: []u8, options: Options) void {
110 var d = Self.init();115 var d = Self.init(options);
111 d.update(b);116 d.update(b);
112 d.final(out);117 d.final(out);
113 }118 }
...@@ -292,18 +297,18 @@ test "sha224 single" {...@@ -292,18 +297,18 @@ test "sha224 single" {
292}297}
293298
294test "sha224 streaming" {299test "sha224 streaming" {
295 var h = Sha224.init();300 var h = Sha224.init(.{});
296 var out: [28]u8 = undefined;301 var out: [28]u8 = undefined;
297302
298 h.final(out[0..]);303 h.final(out[0..]);
299 htest.assertEqual("d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f", out[0..]);304 htest.assertEqual("d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f", out[0..]);
300305
301 h.reset();306 h = Sha224.init(.{});
302 h.update("abc");307 h.update("abc");
303 h.final(out[0..]);308 h.final(out[0..]);
304 htest.assertEqual("23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7", out[0..]);309 htest.assertEqual("23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7", out[0..]);
305310
306 h.reset();311 h = Sha224.init(.{});
307 h.update("a");312 h.update("a");
308 h.update("b");313 h.update("b");
309 h.update("c");314 h.update("c");
...@@ -318,18 +323,18 @@ test "sha256 single" {...@@ -318,18 +323,18 @@ test "sha256 single" {
318}323}
319324
320test "sha256 streaming" {325test "sha256 streaming" {
321 var h = Sha256.init();326 var h = Sha256.init(.{});
322 var out: [32]u8 = undefined;327 var out: [32]u8 = undefined;
323328
324 h.final(out[0..]);329 h.final(out[0..]);
325 htest.assertEqual("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", out[0..]);330 htest.assertEqual("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", out[0..]);
326331
327 h.reset();332 h = Sha256.init(.{});
328 h.update("abc");333 h.update("abc");
329 h.final(out[0..]);334 h.final(out[0..]);
330 htest.assertEqual("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", out[0..]);335 htest.assertEqual("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", out[0..]);
331336
332 h.reset();337 h = Sha256.init(.{});
333 h.update("a");338 h.update("a");
334 h.update("b");339 h.update("b");
335 h.update("c");340 h.update("c");
...@@ -341,7 +346,7 @@ test "sha256 aligned final" {...@@ -341,7 +346,7 @@ test "sha256 aligned final" {
341 var block = [_]u8{0} ** Sha256.block_length;346 var block = [_]u8{0} ** Sha256.block_length;
342 var out: [Sha256.digest_length]u8 = undefined;347 var out: [Sha256.digest_length]u8 = undefined;
343348
344 var h = Sha256.init();349 var h = Sha256.init(.{});
345 h.update(&block);350 h.update(&block);
346 h.final(out[0..]);351 h.final(out[0..]);
347}352}
...@@ -413,42 +418,72 @@ const Sha512Params = Sha2Params64{...@@ -413,42 +418,72 @@ const Sha512Params = Sha2Params64{
413 .out_len = 512,418 .out_len = 512,
414};419};
415420
421const Sha512256Params = Sha2Params64{
422 .iv0 = 0x22312194FC2BF72C,
423 .iv1 = 0x9F555FA3C84C64C2,
424 .iv2 = 0x2393B86B6F53B151,
425 .iv3 = 0x963877195940EABD,
426 .iv4 = 0x96283EE2A88EFFE3,
427 .iv5 = 0xBE5E1E2553863992,
428 .iv6 = 0x2B0199FC2C85B8AA,
429 .iv7 = 0x0EB72DDC81C52CA2,
430 .out_len = 256,
431};
432
433const Sha512T256Params = Sha2Params64{
434 .iv0 = 0x6A09E667F3BCC908,
435 .iv1 = 0xBB67AE8584CAA73B,
436 .iv2 = 0x3C6EF372FE94F82B,
437 .iv3 = 0xA54FF53A5F1D36F1,
438 .iv4 = 0x510E527FADE682D1,
439 .iv5 = 0x9B05688C2B3E6C1F,
440 .iv6 = 0x1F83D9ABFB41BD6B,
441 .iv7 = 0x5BE0CD19137E2179,
442 .out_len = 256,
443};
444
445/// SHA-384
416pub const Sha384 = Sha2_64(Sha384Params);446pub const Sha384 = Sha2_64(Sha384Params);
447
448/// SHA-512
417pub const Sha512 = Sha2_64(Sha512Params);449pub const Sha512 = Sha2_64(Sha512Params);
418450
451/// SHA-512/256
452pub const Sha512256 = Sha2_64(Sha512256Params);
453
454/// Truncated SHA-512
455pub const Sha512T256 = Sha2_64(Sha512T256Params);
456
419fn Sha2_64(comptime params: Sha2Params64) type {457fn Sha2_64(comptime params: Sha2Params64) type {
420 return struct {458 return struct {
421 const Self = @This();459 const Self = @This();
422 pub const block_length = 128;460 pub const block_length = 128;
423 pub const digest_length = params.out_len / 8;461 pub const digest_length = params.out_len / 8;
462 pub const Options = struct {};
424463
425 s: [8]u64,464 s: [8]u64,
426 // Streaming Cache465 // Streaming Cache
427 buf: [128]u8,466 buf: [128]u8 = undefined,
428 buf_len: u8,467 buf_len: u8 = 0,
429 total_len: u128,468 total_len: u128 = 0,
430469
431 pub fn init() Self {470 pub fn init(options: Options) Self {
432 var d: Self = undefined;471 return Self{
433 d.reset();472 .s = [_]u64{
434 return d;473 params.iv0,
435 }474 params.iv1,
436475 params.iv2,
437 pub fn reset(d: *Self) void {476 params.iv3,
438 d.s[0] = params.iv0;477 params.iv4,
439 d.s[1] = params.iv1;478 params.iv5,
440 d.s[2] = params.iv2;479 params.iv6,
441 d.s[3] = params.iv3;480 params.iv7,
442 d.s[4] = params.iv4;481 },
443 d.s[5] = params.iv5;482 };
444 d.s[6] = params.iv6;
445 d.s[7] = params.iv7;
446 d.buf_len = 0;
447 d.total_len = 0;
448 }483 }
449484
450 pub fn hash(b: []const u8, out: []u8) void {485 pub fn hash(b: []const u8, out: []u8, options: Options) void {
451 var d = Self.init();486 var d = Self.init(options);
452 d.update(b);487 d.update(b);
453 d.final(out);488 d.final(out);
454 }489 }
...@@ -660,7 +695,7 @@ test "sha384 single" {...@@ -660,7 +695,7 @@ test "sha384 single" {
660}695}
661696
662test "sha384 streaming" {697test "sha384 streaming" {
663 var h = Sha384.init();698 var h = Sha384.init(.{});
664 var out: [48]u8 = undefined;699 var out: [48]u8 = undefined;
665700
666 const h1 = "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b";701 const h1 = "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b";
...@@ -669,12 +704,12 @@ test "sha384 streaming" {...@@ -669,12 +704,12 @@ test "sha384 streaming" {
669704
670 const h2 = "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7";705 const h2 = "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7";
671706
672 h.reset();707 h = Sha384.init(.{});
673 h.update("abc");708 h.update("abc");
674 h.final(out[0..]);709 h.final(out[0..]);
675 htest.assertEqual(h2, out[0..]);710 htest.assertEqual(h2, out[0..]);
676711
677 h.reset();712 h = Sha384.init(.{});
678 h.update("a");713 h.update("a");
679 h.update("b");714 h.update("b");
680 h.update("c");715 h.update("c");
...@@ -694,7 +729,7 @@ test "sha512 single" {...@@ -694,7 +729,7 @@ test "sha512 single" {
694}729}
695730
696test "sha512 streaming" {731test "sha512 streaming" {
697 var h = Sha512.init();732 var h = Sha512.init(.{});
698 var out: [64]u8 = undefined;733 var out: [64]u8 = undefined;
699734
700 const h1 = "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e";735 const h1 = "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e";
...@@ -703,12 +738,12 @@ test "sha512 streaming" {...@@ -703,12 +738,12 @@ test "sha512 streaming" {
703738
704 const h2 = "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f";739 const h2 = "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f";
705740
706 h.reset();741 h = Sha512.init(.{});
707 h.update("abc");742 h.update("abc");
708 h.final(out[0..]);743 h.final(out[0..]);
709 htest.assertEqual(h2, out[0..]);744 htest.assertEqual(h2, out[0..]);
710745
711 h.reset();746 h = Sha512.init(.{});
712 h.update("a");747 h.update("a");
713 h.update("b");748 h.update("b");
714 h.update("c");749 h.update("c");
...@@ -720,7 +755,7 @@ test "sha512 aligned final" {...@@ -720,7 +755,7 @@ test "sha512 aligned final" {
720 var block = [_]u8{0} ** Sha512.block_length;755 var block = [_]u8{0} ** Sha512.block_length;
721 var out: [Sha512.digest_length]u8 = undefined;756 var out: [Sha512.digest_length]u8 = undefined;
722757
723 var h = Sha512.init();758 var h = Sha512.init(.{});
724 h.update(&block);759 h.update(&block);
725 h.final(out[0..]);760 h.final(out[0..]);
726}761}
lib/std/crypto/sha3.zig+24-26
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const mem = @import("../mem.zig");6const mem = @import("../mem.zig");
2const math = @import("../math.zig");7const math = @import("../math.zig");
3const endian = @import("../endian.zig");8const endian = @import("../endian.zig");
...@@ -15,25 +20,18 @@ fn Keccak(comptime bits: usize, comptime delim: u8) type {...@@ -15,25 +20,18 @@ fn Keccak(comptime bits: usize, comptime delim: u8) type {
15 const Self = @This();20 const Self = @This();
16 pub const block_length = 200;21 pub const block_length = 200;
17 pub const digest_length = bits / 8;22 pub const digest_length = bits / 8;
23 pub const Options = struct {};
1824
19 s: [200]u8,25 s: [200]u8,
20 offset: usize,26 offset: usize,
21 rate: usize,27 rate: usize,
2228
23 pub fn init() Self {29 pub fn init(options: Options) Self {
24 var d: Self = undefined;30 return Self{ .s = [_]u8{0} ** 200, .offset = 0, .rate = 200 - (bits / 4) };
25 d.reset();
26 return d;
27 }31 }
2832
29 pub fn reset(d: *Self) void {33 pub fn hash(b: []const u8, out: []u8, options: Options) void {
30 mem.set(u8, d.s[0..], 0);34 var d = Self.init(options);
31 d.offset = 0;
32 d.rate = 200 - (bits / 4);
33 }
34
35 pub fn hash(b: []const u8, out: []u8) void {
36 var d = Self.init();
37 d.update(b);35 d.update(b);
38 d.final(out);36 d.final(out);
39 }37 }
...@@ -178,18 +176,18 @@ test "sha3-224 single" {...@@ -178,18 +176,18 @@ test "sha3-224 single" {
178}176}
179177
180test "sha3-224 streaming" {178test "sha3-224 streaming" {
181 var h = Sha3_224.init();179 var h = Sha3_224.init(.{});
182 var out: [28]u8 = undefined;180 var out: [28]u8 = undefined;
183181
184 h.final(out[0..]);182 h.final(out[0..]);
185 htest.assertEqual("6b4e03423667dbb73b6e15454f0eb1abd4597f9a1b078e3f5b5a6bc7", out[0..]);183 htest.assertEqual("6b4e03423667dbb73b6e15454f0eb1abd4597f9a1b078e3f5b5a6bc7", out[0..]);
186184
187 h.reset();185 h = Sha3_224.init(.{});
188 h.update("abc");186 h.update("abc");
189 h.final(out[0..]);187 h.final(out[0..]);
190 htest.assertEqual("e642824c3f8cf24ad09234ee7d3c766fc9a3a5168d0c94ad73b46fdf", out[0..]);188 htest.assertEqual("e642824c3f8cf24ad09234ee7d3c766fc9a3a5168d0c94ad73b46fdf", out[0..]);
191189
192 h.reset();190 h = Sha3_224.init(.{});
193 h.update("a");191 h.update("a");
194 h.update("b");192 h.update("b");
195 h.update("c");193 h.update("c");
...@@ -204,18 +202,18 @@ test "sha3-256 single" {...@@ -204,18 +202,18 @@ test "sha3-256 single" {
204}202}
205203
206test "sha3-256 streaming" {204test "sha3-256 streaming" {
207 var h = Sha3_256.init();205 var h = Sha3_256.init(.{});
208 var out: [32]u8 = undefined;206 var out: [32]u8 = undefined;
209207
210 h.final(out[0..]);208 h.final(out[0..]);
211 htest.assertEqual("a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a", out[0..]);209 htest.assertEqual("a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a", out[0..]);
212210
213 h.reset();211 h = Sha3_256.init(.{});
214 h.update("abc");212 h.update("abc");
215 h.final(out[0..]);213 h.final(out[0..]);
216 htest.assertEqual("3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532", out[0..]);214 htest.assertEqual("3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532", out[0..]);
217215
218 h.reset();216 h = Sha3_256.init(.{});
219 h.update("a");217 h.update("a");
220 h.update("b");218 h.update("b");
221 h.update("c");219 h.update("c");
...@@ -227,7 +225,7 @@ test "sha3-256 aligned final" {...@@ -227,7 +225,7 @@ test "sha3-256 aligned final" {
227 var block = [_]u8{0} ** Sha3_256.block_length;225 var block = [_]u8{0} ** Sha3_256.block_length;
228 var out: [Sha3_256.digest_length]u8 = undefined;226 var out: [Sha3_256.digest_length]u8 = undefined;
229227
230 var h = Sha3_256.init();228 var h = Sha3_256.init(.{});
231 h.update(&block);229 h.update(&block);
232 h.final(out[0..]);230 h.final(out[0..]);
233}231}
...@@ -242,7 +240,7 @@ test "sha3-384 single" {...@@ -242,7 +240,7 @@ test "sha3-384 single" {
242}240}
243241
244test "sha3-384 streaming" {242test "sha3-384 streaming" {
245 var h = Sha3_384.init();243 var h = Sha3_384.init(.{});
246 var out: [48]u8 = undefined;244 var out: [48]u8 = undefined;
247245
248 const h1 = "0c63a75b845e4f7d01107d852e4c2485c51a50aaaa94fc61995e71bbee983a2ac3713831264adb47fb6bd1e058d5f004";246 const h1 = "0c63a75b845e4f7d01107d852e4c2485c51a50aaaa94fc61995e71bbee983a2ac3713831264adb47fb6bd1e058d5f004";
...@@ -250,12 +248,12 @@ test "sha3-384 streaming" {...@@ -250,12 +248,12 @@ test "sha3-384 streaming" {
250 htest.assertEqual(h1, out[0..]);248 htest.assertEqual(h1, out[0..]);
251249
252 const h2 = "ec01498288516fc926459f58e2c6ad8df9b473cb0fc08c2596da7cf0e49be4b298d88cea927ac7f539f1edf228376d25";250 const h2 = "ec01498288516fc926459f58e2c6ad8df9b473cb0fc08c2596da7cf0e49be4b298d88cea927ac7f539f1edf228376d25";
253 h.reset();251 h = Sha3_384.init(.{});
254 h.update("abc");252 h.update("abc");
255 h.final(out[0..]);253 h.final(out[0..]);
256 htest.assertEqual(h2, out[0..]);254 htest.assertEqual(h2, out[0..]);
257255
258 h.reset();256 h = Sha3_384.init(.{});
259 h.update("a");257 h.update("a");
260 h.update("b");258 h.update("b");
261 h.update("c");259 h.update("c");
...@@ -273,7 +271,7 @@ test "sha3-512 single" {...@@ -273,7 +271,7 @@ test "sha3-512 single" {
273}271}
274272
275test "sha3-512 streaming" {273test "sha3-512 streaming" {
276 var h = Sha3_512.init();274 var h = Sha3_512.init(.{});
277 var out: [64]u8 = undefined;275 var out: [64]u8 = undefined;
278276
279 const h1 = "a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a615b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26";277 const h1 = "a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a615b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26";
...@@ -281,12 +279,12 @@ test "sha3-512 streaming" {...@@ -281,12 +279,12 @@ test "sha3-512 streaming" {
281 htest.assertEqual(h1, out[0..]);279 htest.assertEqual(h1, out[0..]);
282280
283 const h2 = "b751850b1a57168a5693cd924b6b096e08f621827444f70d884f5d0240d2712e10e116e9192af3c91a7ec57647e3934057340b4cf408d5a56592f8274eec53f0";281 const h2 = "b751850b1a57168a5693cd924b6b096e08f621827444f70d884f5d0240d2712e10e116e9192af3c91a7ec57647e3934057340b4cf408d5a56592f8274eec53f0";
284 h.reset();282 h = Sha3_512.init(.{});
285 h.update("abc");283 h.update("abc");
286 h.final(out[0..]);284 h.final(out[0..]);
287 htest.assertEqual(h2, out[0..]);285 htest.assertEqual(h2, out[0..]);
288286
289 h.reset();287 h = Sha3_512.init(.{});
290 h.update("a");288 h.update("a");
291 h.update("b");289 h.update("b");
292 h.update("c");290 h.update("c");
...@@ -298,7 +296,7 @@ test "sha3-512 aligned final" {...@@ -298,7 +296,7 @@ test "sha3-512 aligned final" {
298 var block = [_]u8{0} ** Sha3_512.block_length;296 var block = [_]u8{0} ** Sha3_512.block_length;
299 var out: [Sha3_512.digest_length]u8 = undefined;297 var out: [Sha3_512.digest_length]u8 = undefined;
300298
301 var h = Sha3_512.init();299 var h = Sha3_512.init(.{});
302 h.update(&block);300 h.update(&block);
303 h.final(out[0..]);301 h.final(out[0..]);
304}302}
lib/std/crypto/test.zig+6-1
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const testing = std.testing;7const testing = std.testing;
3const mem = std.mem;8const mem = std.mem;
...@@ -6,7 +11,7 @@ const fmt = std.fmt;...@@ -6,7 +11,7 @@ const fmt = std.fmt;
6// Hash using the specified hasher `H` asserting `expected == H(input)`.11// Hash using the specified hasher `H` asserting `expected == H(input)`.
7pub fn assertEqualHash(comptime Hasher: anytype, comptime expected: []const u8, input: []const u8) void {12pub fn assertEqualHash(comptime Hasher: anytype, comptime expected: []const u8, input: []const u8) void {
8 var h: [expected.len / 2]u8 = undefined;13 var h: [expected.len / 2]u8 = undefined;
9 Hasher.hash(input, h[0..]);14 Hasher.hash(input, h[0..], .{});
1015
11 assertEqual(expected, &h);16 assertEqual(expected, &h);
12}17}
lib/std/cstr.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std.zig");6const std = @import("std.zig");
2const builtin = @import("builtin");7const builtin = @import("builtin");
3const debug = std.debug;8const debug = std.debug;
lib/std/debug.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std.zig");6const std = @import("std.zig");
2const builtin = std.builtin;7const builtin = std.builtin;
3const math = std.math;8const math = std.math;
lib/std/debug/leb128.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std");6const std = @import("std");
2const testing = std.testing;7const testing = std.testing;
38
lib/std/dwarf.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std.zig");6const std = @import("std.zig");
2const builtin = @import("builtin");7const builtin = @import("builtin");
3const debug = std.debug;8const debug = std.debug;
lib/std/dwarf_bits.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1pub const TAG_padding = 0x00;6pub const TAG_padding = 0x00;
2pub const TAG_array_type = 0x01;7pub const TAG_array_type = 0x01;
3pub const TAG_class_type = 0x02;8pub const TAG_class_type = 0x02;
lib/std/dynamic_library.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const builtin = @import("builtin");6const builtin = @import("builtin");
27
3const std = @import("std.zig");8const std = @import("std.zig");
lib/std/elf.zig+6
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std.zig");6const std = @import("std.zig");
2const builtin = std.builtin;7const builtin = std.builtin;
3const io = std.io;8const io = std.io;
...@@ -558,6 +563,7 @@ fn preadNoEof(file: std.fs.File, buf: []u8, offset: u64) !void {...@@ -558,6 +563,7 @@ fn preadNoEof(file: std.fs.File, buf: []u8, offset: u64) !void {
558 error.InputOutput => return error.FileSystem,563 error.InputOutput => return error.FileSystem,
559 error.Unexpected => return error.Unexpected,564 error.Unexpected => return error.Unexpected,
560 error.WouldBlock => return error.Unexpected,565 error.WouldBlock => return error.Unexpected,
566 error.NotOpenForReading => return error.Unexpected,
561 error.AccessDenied => return error.Unexpected,567 error.AccessDenied => return error.Unexpected,
562 };568 };
563 if (len == 0) return error.UnexpectedEndOfFile;569 if (len == 0) return error.UnexpectedEndOfFile;
lib/std/event.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1pub const Channel = @import("event/channel.zig").Channel;6pub const Channel = @import("event/channel.zig").Channel;
2pub const Future = @import("event/future.zig").Future;7pub const Future = @import("event/future.zig").Future;
3pub const Group = @import("event/group.zig").Group;8pub const Group = @import("event/group.zig").Group;
lib/std/event/batch.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const testing = std.testing;7const testing = std.testing;
38
lib/std/event/channel.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const builtin = @import("builtin");7const builtin = @import("builtin");
3const assert = std.debug.assert;8const assert = std.debug.assert;
lib/std/event/future.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const assert = std.debug.assert;7const assert = std.debug.assert;
3const testing = std.testing;8const testing = std.testing;
lib/std/event/group.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const builtin = @import("builtin");7const builtin = @import("builtin");
3const Lock = std.event.Lock;8const Lock = std.event.Lock;
lib/std/event/lock.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const builtin = @import("builtin");7const builtin = @import("builtin");
3const assert = std.debug.assert;8const assert = std.debug.assert;
lib/std/event/locked.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const Lock = std.event.Lock;7const Lock = std.event.Lock;
38
lib/std/event/loop.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const builtin = @import("builtin");7const builtin = @import("builtin");
3const root = @import("root");8const root = @import("root");
lib/std/event/rwlock.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const builtin = @import("builtin");7const builtin = @import("builtin");
3const assert = std.debug.assert;8const assert = std.debug.assert;
lib/std/event/rwlocked.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const RwLock = std.event.RwLock;7const RwLock = std.event.RwLock;
38
lib/std/fifo.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// FIFO of fixed size items6// FIFO of fixed size items
2// Usually used for e.g. byte buffers7// Usually used for e.g. byte buffers
38
lib/std/fmt.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std.zig");6const std = @import("std.zig");
2const math = std.math;7const math = std.math;
3const assert = std.debug.assert;8const assert = std.debug.assert;
lib/std/fmt/errol.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const enum3 = @import("errol/enum3.zig").enum3;7const enum3 = @import("errol/enum3.zig").enum3;
3const enum3_data = @import("errol/enum3.zig").enum3_data;8const enum3_data = @import("errol/enum3.zig").enum3_data;
lib/std/fmt/errol/enum3.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1pub const enum3 = [_]u64{6pub const enum3 = [_]u64{
2 0x4e2e2785c3a2a20b,7 0x4e2e2785c3a2a20b,
3 0x240a28877a09a4e1,8 0x240a28877a09a4e1,
lib/std/fmt/errol/lookup.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1pub const HP = struct {6pub const HP = struct {
2 val: f64,7 val: f64,
3 off: f64,8 off: f64,
lib/std/fmt/parse_float.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Adapted from https://github.com/grzegorz-kraszewski/stringtofloat.6// Adapted from https://github.com/grzegorz-kraszewski/stringtofloat.
27
3// MIT License8// MIT License
lib/std/fs.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const builtin = @import("builtin");6const builtin = @import("builtin");
2const std = @import("std.zig");7const std = @import("std.zig");
3const os = std.os;8const os = std.os;
lib/std/fs/file.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const builtin = @import("builtin");7const builtin = @import("builtin");
3const os = std.os;8const os = std.os;
lib/std/fs/get_app_data_dir.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const builtin = @import("builtin");7const builtin = @import("builtin");
3const unicode = std.unicode;8const unicode = std.unicode;
lib/std/fs/path.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const builtin = @import("builtin");6const builtin = @import("builtin");
2const std = @import("../std.zig");7const std = @import("../std.zig");
3const debug = std.debug;8const debug = std.debug;
lib/std/fs/test.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const testing = std.testing;7const testing = std.testing;
3const builtin = std.builtin;8const builtin = std.builtin;
lib/std/fs/wasi.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std");6const std = @import("std");
2const os = std.os;7const os = std.os;
3const mem = std.mem;8const mem = std.mem;
lib/std/fs/watch.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const builtin = @import("builtin");7const builtin = @import("builtin");
3const event = std.event;8const event = std.event;
lib/std/hash.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const adler = @import("hash/adler.zig");6const adler = @import("hash/adler.zig");
2pub const Adler32 = adler.Adler32;7pub const Adler32 = adler.Adler32;
38
lib/std/hash/adler.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Adler32 checksum.6// Adler32 checksum.
2//7//
3// https://tools.ietf.org/html/rfc1950#section-98// https://tools.ietf.org/html/rfc1950#section-9
lib/std/hash/auto_hash.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std");6const std = @import("std");
2const builtin = @import("builtin");7const builtin = @import("builtin");
3const assert = std.debug.assert;8const assert = std.debug.assert;
lib/std/hash/benchmark.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// zig run benchmark.zig --release-fast --override-lib-dir ..6// zig run benchmark.zig --release-fast --override-lib-dir ..
27
3const builtin = @import("builtin");8const builtin = @import("builtin");
lib/std/hash/cityhash.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std");6const std = @import("std");
2const builtin = @import("builtin");7const builtin = @import("builtin");
38
lib/std/hash/crc.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// There are two implementations of CRC32 implemented with the following key characteristics:6// There are two implementations of CRC32 implemented with the following key characteristics:
2//7//
3// - Crc32WithPoly uses 8Kb of tables but is ~10x faster than the small method.8// - Crc32WithPoly uses 8Kb of tables but is ~10x faster than the small method.
lib/std/hash/fnv.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// FNV1a - Fowler-Noll-Vo hash function6// FNV1a - Fowler-Noll-Vo hash function
2//7//
3// FNV1a is a fast, non-cryptographic hash function with fairly good distribution properties.8// FNV1a is a fast, non-cryptographic hash function with fairly good distribution properties.
lib/std/hash/murmur.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std");6const std = @import("std");
2const builtin = @import("builtin");7const builtin = @import("builtin");
3const testing = std.testing;8const testing = std.testing;
lib/std/hash/siphash.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Siphash6// Siphash
2//7//
3// SipHash is a moderately fast, non-cryptographic keyed hash function designed for resistance8// SipHash is a moderately fast, non-cryptographic keyed hash function designed for resistance
lib/std/hash/wyhash.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std");6const std = @import("std");
2const mem = std.mem;7const mem = std.mem;
38
lib/std/hash_map.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std.zig");6const std = @import("std.zig");
2const debug = std.debug;7const debug = std.debug;
3const assert = debug.assert;8const assert = debug.assert;
lib/std/heap.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std.zig");6const std = @import("std.zig");
2const root = @import("root");7const root = @import("root");
3const debug = std.debug;8const debug = std.debug;
lib/std/heap/arena_allocator.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const assert = std.debug.assert;7const assert = std.debug.assert;
3const mem = std.mem;8const mem = std.mem;
lib/std/heap/general_purpose_allocator.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1//! # General Purpose Allocator6//! # General Purpose Allocator
2//!7//!
3//! ## Design Priorities8//! ## Design Priorities
lib/std/heap/logging_allocator.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const Allocator = std.mem.Allocator;7const Allocator = std.mem.Allocator;
38
lib/std/http.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1test "std.http" {6test "std.http" {
2 _ = @import("http/headers.zig");7 _ = @import("http/headers.zig");
3}8}
lib/std/http/headers.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// HTTP Header data structure/type6// HTTP Header data structure/type
2// Based on lua-http's http.header module7// Based on lua-http's http.header module
3//8//
lib/std/io.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std.zig");6const std = @import("std.zig");
2const builtin = @import("builtin");7const builtin = @import("builtin");
3const root = @import("root");8const root = @import("root");
lib/std/io/bit_in_stream.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1/// Deprecated: use `std.io.bit_reader.BitReader`6/// Deprecated: use `std.io.bit_reader.BitReader`
2pub const BitInStream = @import("./bit_reader.zig").BitReader;7pub const BitInStream = @import("./bit_reader.zig").BitReader;
38
lib/std/io/bit_out_stream.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1/// Deprecated: use `std.io.bit_writer.BitWriter`6/// Deprecated: use `std.io.bit_writer.BitWriter`
2pub const BitOutStream = @import("./bit_writer.zig").BitWriter;7pub const BitOutStream = @import("./bit_writer.zig").BitWriter;
38
lib/std/io/bit_reader.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const builtin = std.builtin;7const builtin = std.builtin;
3const io = std.io;8const io = std.io;
lib/std/io/bit_writer.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const builtin = std.builtin;7const builtin = std.builtin;
3const io = std.io;8const io = std.io;
lib/std/io/buffered_atomic_file.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const mem = std.mem;7const mem = std.mem;
3const fs = std.fs;8const fs = std.fs;
lib/std/io/buffered_in_stream.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1/// Deprecated: use `std.io.buffered_reader.BufferedReader`6/// Deprecated: use `std.io.buffered_reader.BufferedReader`
2pub const BufferedInStream = @import("./buffered_reader.zig").BufferedReader;7pub const BufferedInStream = @import("./buffered_reader.zig").BufferedReader;
38
lib/std/io/buffered_out_stream.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1/// Deprecated: use `std.io.buffered_writer.BufferedWriter`6/// Deprecated: use `std.io.buffered_writer.BufferedWriter`
2pub const BufferedOutStream = @import("./buffered_writer.zig").BufferedWriter;7pub const BufferedOutStream = @import("./buffered_writer.zig").BufferedWriter;
38
lib/std/io/buffered_reader.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const io = std.io;7const io = std.io;
3const assert = std.debug.assert;8const assert = std.debug.assert;
lib/std/io/buffered_writer.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const io = std.io;7const io = std.io;
38
lib/std/io/c_out_stream.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1/// Deprecated: use `std.io.c_writer.CWriter`6/// Deprecated: use `std.io.c_writer.CWriter`
2pub const COutStream = @import("./c_writer.zig").CWriter;7pub const COutStream = @import("./c_writer.zig").CWriter;
38
lib/std/io/c_writer.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const builtin = std.builtin;7const builtin = std.builtin;
3const io = std.io;8const io = std.io;
lib/std/io/counting_out_stream.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1/// Deprecated: use `std.io.counting_writer.CountingWriter`6/// Deprecated: use `std.io.counting_writer.CountingWriter`
2pub const CountingOutStream = @import("./counting_writer.zig").CountingWriter;7pub const CountingOutStream = @import("./counting_writer.zig").CountingWriter;
38
lib/std/io/counting_writer.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const io = std.io;7const io = std.io;
3const testing = std.testing;8const testing = std.testing;
lib/std/io/fixed_buffer_stream.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const io = std.io;7const io = std.io;
3const testing = std.testing;8const testing = std.testing;
lib/std/io/in_stream.zig+5
...@@ -1,2 +1,7 @@...@@ -1,2 +1,7 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1/// Deprecated: use `std.io.reader.Reader`6/// Deprecated: use `std.io.reader.Reader`
2pub const InStream = @import("./reader.zig").Reader;7pub const InStream = @import("./reader.zig").Reader;
lib/std/io/multi_out_stream.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1/// Deprecated: use `std.io.multi_writer.MultiWriter`6/// Deprecated: use `std.io.multi_writer.MultiWriter`
2pub const MultiOutStream = @import("./multi_writer.zig").MultiWriter;7pub const MultiOutStream = @import("./multi_writer.zig").MultiWriter;
38
lib/std/io/multi_writer.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const io = std.io;7const io = std.io;
3const testing = std.testing;8const testing = std.testing;
lib/std/io/out_stream.zig+5
...@@ -1,2 +1,7 @@...@@ -1,2 +1,7 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1/// Deprecated: use `std.io.writer.Writer`6/// Deprecated: use `std.io.writer.Writer`
2pub const OutStream = @import("./writer.zig").Writer;7pub const OutStream = @import("./writer.zig").Writer;
lib/std/io/peek_stream.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const io = std.io;7const io = std.io;
3const mem = std.mem;8const mem = std.mem;
lib/std/io/reader.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const builtin = std.builtin;7const builtin = std.builtin;
3const math = std.math;8const math = std.math;
lib/std/io/seekable_stream.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
27
3pub fn SeekableStream(8pub fn SeekableStream(
lib/std/io/serialization.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const builtin = std.builtin;7const builtin = std.builtin;
3const io = std.io;8const io = std.io;
lib/std/io/stream_source.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const io = std.io;7const io = std.io;
3const testing = std.testing;8const testing = std.testing;
lib/std/io/test.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std");6const std = @import("std");
2const builtin = std.builtin;7const builtin = std.builtin;
3const io = std.io;8const io = std.io;
lib/std/io/writer.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const builtin = std.builtin;7const builtin = std.builtin;
3const mem = std.mem;8const mem = std.mem;
lib/std/json.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// JSON parser conforming to RFC8259.6// JSON parser conforming to RFC8259.
2//7//
3// https://tools.ietf.org/html/rfc82598// https://tools.ietf.org/html/rfc8259
lib/std/json/test.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// RFC 8529 conformance tests.6// RFC 8529 conformance tests.
2//7//
3// Tests are taken from https://github.com/nst/JSONTestSuite8// Tests are taken from https://github.com/nst/JSONTestSuite
lib/std/json/write_stream.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const assert = std.debug.assert;7const assert = std.debug.assert;
3const maxInt = std.math.maxInt;8const maxInt = std.math.maxInt;
lib/std/linked_list.zig+38-91
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std.zig");6const std = @import("std.zig");
2const debug = std.debug;7const debug = std.debug;
3const assert = debug.assert;8const assert = debug.assert;
...@@ -178,21 +183,9 @@ pub fn TailQueue(comptime T: type) type {...@@ -178,21 +183,9 @@ pub fn TailQueue(comptime T: type) type {
178 }183 }
179 };184 };
180185
181 first: ?*Node,186 first: ?*Node = null,
182 last: ?*Node,187 last: ?*Node = null,
183 len: usize,188 len: usize = 0,
184
185 /// Initialize a linked list.
186 ///
187 /// Returns:
188 /// An empty linked list.
189 pub fn init() Self {
190 return Self{
191 .first = null,
192 .last = null,
193 .len = 0,
194 };
195 }
196189
197 /// Insert a new node after an existing one.190 /// Insert a new node after an existing one.
198 ///191 ///
...@@ -335,65 +328,24 @@ pub fn TailQueue(comptime T: type) type {...@@ -335,65 +328,24 @@ pub fn TailQueue(comptime T: type) type {
335 list.remove(first);328 list.remove(first);
336 return first;329 return first;
337 }330 }
338
339 /// Allocate a new node.
340 ///
341 /// Arguments:
342 /// allocator: Dynamic memory allocator.
343 ///
344 /// Returns:
345 /// A pointer to the new node.
346 pub fn allocateNode(list: *Self, allocator: *Allocator) !*Node {
347 return allocator.create(Node);
348 }
349
350 /// Deallocate a node.
351 ///
352 /// Arguments:
353 /// node: Pointer to the node to deallocate.
354 /// allocator: Dynamic memory allocator.
355 pub fn destroyNode(list: *Self, node: *Node, allocator: *Allocator) void {
356 allocator.destroy(node);
357 }
358
359 /// Allocate and initialize a node and its data.
360 ///
361 /// Arguments:
362 /// data: The data to put inside the node.
363 /// allocator: Dynamic memory allocator.
364 ///
365 /// Returns:
366 /// A pointer to the new node.
367 pub fn createNode(list: *Self, data: T, allocator: *Allocator) !*Node {
368 var node = try list.allocateNode(allocator);
369 node.* = Node.init(data);
370 return node;
371 }
372 };331 };
373}332}
374333
375test "basic TailQueue test" {334test "basic TailQueue test" {
376 const allocator = testing.allocator;335 const L = TailQueue(u32);
377 var list = TailQueue(u32).init();336 var list = L{};
378337
379 var one = try list.createNode(1, allocator);338 var one = L.Node{ .data = 1 };
380 var two = try list.createNode(2, allocator);339 var two = L.Node{ .data = 2 };
381 var three = try list.createNode(3, allocator);340 var three = L.Node{ .data = 3 };
382 var four = try list.createNode(4, allocator);341 var four = L.Node{ .data = 4 };
383 var five = try list.createNode(5, allocator);342 var five = L.Node{ .data = 5 };
384 defer {
385 list.destroyNode(one, allocator);
386 list.destroyNode(two, allocator);
387 list.destroyNode(three, allocator);
388 list.destroyNode(four, allocator);
389 list.destroyNode(five, allocator);
390 }
391343
392 list.append(two); // {2}344 list.append(&two); // {2}
393 list.append(five); // {2, 5}345 list.append(&five); // {2, 5}
394 list.prepend(one); // {1, 2, 5}346 list.prepend(&one); // {1, 2, 5}
395 list.insertBefore(five, four); // {1, 2, 4, 5}347 list.insertBefore(&five, &four); // {1, 2, 4, 5}
396 list.insertAfter(two, three); // {1, 2, 3, 4, 5}348 list.insertAfter(&two, &three); // {1, 2, 3, 4, 5}
397349
398 // Traverse forwards.350 // Traverse forwards.
399 {351 {
...@@ -417,7 +369,7 @@ test "basic TailQueue test" {...@@ -417,7 +369,7 @@ test "basic TailQueue test" {
417369
418 var first = list.popFirst(); // {2, 3, 4, 5}370 var first = list.popFirst(); // {2, 3, 4, 5}
419 var last = list.pop(); // {2, 3, 4}371 var last = list.pop(); // {2, 3, 4}
420 list.remove(three); // {2, 4}372 list.remove(&three); // {2, 4}
421373
422 testing.expect(list.first.?.data == 2);374 testing.expect(list.first.?.data == 2);
423 testing.expect(list.last.?.data == 4);375 testing.expect(list.last.?.data == 4);
...@@ -425,30 +377,25 @@ test "basic TailQueue test" {...@@ -425,30 +377,25 @@ test "basic TailQueue test" {
425}377}
426378
427test "TailQueue concatenation" {379test "TailQueue concatenation" {
428 const allocator = testing.allocator;380 const L = TailQueue(u32);
429 var list1 = TailQueue(u32).init();381 var list1 = L{};
430 var list2 = TailQueue(u32).init();382 var list2 = L{};
431383
432 var one = try list1.createNode(1, allocator);384 var one = L.Node{ .data = 1 };
433 defer list1.destroyNode(one, allocator);385 var two = L.Node{ .data = 2 };
434 var two = try list1.createNode(2, allocator);386 var three = L.Node{ .data = 3 };
435 defer list1.destroyNode(two, allocator);387 var four = L.Node{ .data = 4 };
436 var three = try list1.createNode(3, allocator);388 var five = L.Node{ .data = 5 };
437 defer list1.destroyNode(three, allocator);389
438 var four = try list1.createNode(4, allocator);390 list1.append(&one);
439 defer list1.destroyNode(four, allocator);391 list1.append(&two);
440 var five = try list1.createNode(5, allocator);392 list2.append(&three);
441 defer list1.destroyNode(five, allocator);393 list2.append(&four);
442394 list2.append(&five);
443 list1.append(one);
444 list1.append(two);
445 list2.append(three);
446 list2.append(four);
447 list2.append(five);
448395
449 list1.concatByMoving(&list2);396 list1.concatByMoving(&list2);
450397
451 testing.expect(list1.last == five);398 testing.expect(list1.last == &five);
452 testing.expect(list1.len == 5);399 testing.expect(list1.len == 5);
453 testing.expect(list2.first == null);400 testing.expect(list2.first == null);
454 testing.expect(list2.last == null);401 testing.expect(list2.last == null);
lib/std/log.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std.zig");6const std = @import("std.zig");
2const builtin = std.builtin;7const builtin = std.builtin;
3const root = @import("root");8const root = @import("root");
lib/std/macho.zig+17
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1pub const mach_header = extern struct {6pub const mach_header = extern struct {
2 magic: u32,7 magic: u32,
3 cputype: cpu_type_t,8 cputype: cpu_type_t,
...@@ -703,3 +708,15 @@ pub const cpu_type_t = integer_t;...@@ -703,3 +708,15 @@ pub const cpu_type_t = integer_t;
703pub const cpu_subtype_t = integer_t;708pub const cpu_subtype_t = integer_t;
704pub const integer_t = c_int;709pub const integer_t = c_int;
705pub const vm_prot_t = c_int;710pub const vm_prot_t = c_int;
711
712/// CPU type targeting 64-bit Intel-based Macs
713pub const CPU_TYPE_X86_64: cpu_type_t = 0x01000007;
714
715/// CPU type targeting 64-bit ARM-based Macs
716pub const CPU_TYPE_ARM64: cpu_type_t = 0x0100000C;
717
718/// All Intel-based Macs
719pub const CPU_SUBTYPE_X86_64_ALL: cpu_subtype_t = 0x3;
720
721/// All ARM-based Macs
722pub const CPU_SUBTYPE_ARM_ALL: cpu_subtype_t = 0x0;
lib/std/math.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std.zig");6const std = @import("std.zig");
2const assert = std.debug.assert;7const assert = std.debug.assert;
3const testing = std.testing;8const testing = std.testing;
lib/std/math/acos.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Ported from musl, which is licensed under the MIT license:6// Ported from musl, which is licensed under the MIT license:
2// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT7// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
3//8//
lib/std/math/acosh.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Ported from musl, which is licensed under the MIT license:6// Ported from musl, which is licensed under the MIT license:
2// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT7// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
3//8//
lib/std/math/asin.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Ported from musl, which is licensed under the MIT license:6// Ported from musl, which is licensed under the MIT license:
2// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT7// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
3//8//
lib/std/math/asinh.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Ported from musl, which is licensed under the MIT license:6// Ported from musl, which is licensed under the MIT license:
2// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT7// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
3//8//
lib/std/math/atan.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Ported from musl, which is licensed under the MIT license:6// Ported from musl, which is licensed under the MIT license:
2// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT7// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
3//8//
lib/std/math/atan2.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Ported from musl, which is licensed under the MIT license:6// Ported from musl, which is licensed under the MIT license:
2// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT7// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
3//8//
lib/std/math/atanh.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Ported from musl, which is licensed under the MIT license:6// Ported from musl, which is licensed under the MIT license:
2// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT7// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
3//8//
lib/std/math/big.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const assert = std.debug.assert;7const assert = std.debug.assert;
38
lib/std/math/big/int.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../../std.zig");6const std = @import("../../std.zig");
2const math = std.math;7const math = std.math;
3const Limb = std.math.big.Limb;8const Limb = std.math.big.Limb;
lib/std/math/big/int_test.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../../std.zig");6const std = @import("../../std.zig");
2const mem = std.mem;7const mem = std.mem;
3const testing = std.testing;8const testing = std.testing;
lib/std/math/big/rational.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../../std.zig");6const std = @import("../../std.zig");
2const debug = std.debug;7const debug = std.debug;
3const math = std.math;8const math = std.math;
lib/std/math/cbrt.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Ported from musl, which is licensed under the MIT license:6// Ported from musl, which is licensed under the MIT license:
2// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT7// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
3//8//
lib/std/math/ceil.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Ported from musl, which is licensed under the MIT license:6// Ported from musl, which is licensed under the MIT license:
2// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT7// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
3//8//
lib/std/math/complex.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const testing = std.testing;7const testing = std.testing;
3const math = std.math;8const math = std.math;
lib/std/math/complex/abs.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../../std.zig");6const std = @import("../../std.zig");
2const testing = std.testing;7const testing = std.testing;
3const math = std.math;8const math = std.math;
lib/std/math/complex/acos.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../../std.zig");6const std = @import("../../std.zig");
2const testing = std.testing;7const testing = std.testing;
3const math = std.math;8const math = std.math;
lib/std/math/complex/acosh.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../../std.zig");6const std = @import("../../std.zig");
2const testing = std.testing;7const testing = std.testing;
3const math = std.math;8const math = std.math;
lib/std/math/complex/arg.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../../std.zig");6const std = @import("../../std.zig");
2const testing = std.testing;7const testing = std.testing;
3const math = std.math;8const math = std.math;
lib/std/math/complex/asin.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../../std.zig");6const std = @import("../../std.zig");
2const testing = std.testing;7const testing = std.testing;
3const math = std.math;8const math = std.math;
lib/std/math/complex/asinh.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../../std.zig");6const std = @import("../../std.zig");
2const testing = std.testing;7const testing = std.testing;
3const math = std.math;8const math = std.math;
lib/std/math/complex/atan.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Ported from musl, which is licensed under the MIT license:6// Ported from musl, which is licensed under the MIT license:
2// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT7// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
3//8//
lib/std/math/complex/atanh.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../../std.zig");6const std = @import("../../std.zig");
2const testing = std.testing;7const testing = std.testing;
3const math = std.math;8const math = std.math;
lib/std/math/complex/conj.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../../std.zig");6const std = @import("../../std.zig");
2const testing = std.testing;7const testing = std.testing;
3const math = std.math;8const math = std.math;
lib/std/math/complex/cos.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../../std.zig");6const std = @import("../../std.zig");
2const testing = std.testing;7const testing = std.testing;
3const math = std.math;8const math = std.math;
lib/std/math/complex/cosh.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Ported from musl, which is licensed under the MIT license:6// Ported from musl, which is licensed under the MIT license:
2// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT7// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
3//8//
lib/std/math/complex/exp.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Ported from musl, which is licensed under the MIT license:6// Ported from musl, which is licensed under the MIT license:
2// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT7// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
3//8//
lib/std/math/complex/ldexp.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Ported from musl, which is licensed under the MIT license:6// Ported from musl, which is licensed under the MIT license:
2// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT7// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
3//8//
lib/std/math/complex/log.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../../std.zig");6const std = @import("../../std.zig");
2const testing = std.testing;7const testing = std.testing;
3const math = std.math;8const math = std.math;
lib/std/math/complex/pow.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../../std.zig");6const std = @import("../../std.zig");
2const testing = std.testing;7const testing = std.testing;
3const math = std.math;8const math = std.math;
lib/std/math/complex/proj.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../../std.zig");6const std = @import("../../std.zig");
2const testing = std.testing;7const testing = std.testing;
3const math = std.math;8const math = std.math;
lib/std/math/complex/sin.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../../std.zig");6const std = @import("../../std.zig");
2const testing = std.testing;7const testing = std.testing;
3const math = std.math;8const math = std.math;
lib/std/math/complex/sinh.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Ported from musl, which is licensed under the MIT license:6// Ported from musl, which is licensed under the MIT license:
2// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT7// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
3//8//
lib/std/math/complex/sqrt.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Ported from musl, which is licensed under the MIT license:6// Ported from musl, which is licensed under the MIT license:
2// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT7// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
3//8//
lib/std/math/complex/tan.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../../std.zig");6const std = @import("../../std.zig");
2const testing = std.testing;7const testing = std.testing;
3const math = std.math;8const math = std.math;
lib/std/math/complex/tanh.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Ported from musl, which is licensed under the MIT license:6// Ported from musl, which is licensed under the MIT license:
2// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT7// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
3//8//
lib/std/math/copysign.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Ported from musl, which is licensed under the MIT license:6// Ported from musl, which is licensed under the MIT license:
2// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT7// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
3//8//
lib/std/math/cos.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Ported from go, which is licensed under a BSD-3 license.6// Ported from go, which is licensed under a BSD-3 license.
2// https://golang.org/LICENSE7// https://golang.org/LICENSE
3//8//
lib/std/math/cosh.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Ported from musl, which is licensed under the MIT license:6// Ported from musl, which is licensed under the MIT license:
2// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT7// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
3//8//
lib/std/math/exp.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Ported from musl, which is licensed under the MIT license:6// Ported from musl, which is licensed under the MIT license:
2// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT7// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
3//8//
lib/std/math/exp2.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Ported from musl, which is licensed under the MIT license:6// Ported from musl, which is licensed under the MIT license:
2// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT7// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
3//8//
lib/std/math/expm1.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Ported from musl, which is licensed under the MIT license:6// Ported from musl, which is licensed under the MIT license:
2// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT7// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
3//8//
lib/std/math/expo2.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Ported from musl, which is licensed under the MIT license:6// Ported from musl, which is licensed under the MIT license:
2// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT7// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
3//8//
lib/std/math/fabs.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Ported from musl, which is licensed under the MIT license:6// Ported from musl, which is licensed under the MIT license:
2// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT7// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
3//8//
lib/std/math/floor.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Ported from musl, which is licensed under the MIT license:6// Ported from musl, which is licensed under the MIT license:
2// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT7// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
3//8//
lib/std/math/fma.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Ported from musl, which is licensed under the MIT license:6// Ported from musl, which is licensed under the MIT license:
2// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT7// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
3//8//
lib/std/math/frexp.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Ported from musl, which is licensed under the MIT license:6// Ported from musl, which is licensed under the MIT license:
2// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT7// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
3//8//
lib/std/math/hypot.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Ported from musl, which is licensed under the MIT license:6// Ported from musl, which is licensed under the MIT license:
2// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT7// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
3//8//
lib/std/math/ilogb.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Ported from musl, which is licensed under the MIT license:6// Ported from musl, which is licensed under the MIT license:
2// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT7// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
3//8//
lib/std/math/inf.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const math = std.math;7const math = std.math;
38
lib/std/math/isfinite.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const math = std.math;7const math = std.math;
3const expect = std.testing.expect;8const expect = std.testing.expect;
lib/std/math/isinf.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const math = std.math;7const math = std.math;
3const expect = std.testing.expect;8const expect = std.testing.expect;
lib/std/math/isnan.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const math = std.math;7const math = std.math;
3const expect = std.testing.expect;8const expect = std.testing.expect;
lib/std/math/isnormal.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const math = std.math;7const math = std.math;
3const expect = std.testing.expect;8const expect = std.testing.expect;
lib/std/math/ln.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Ported from musl, which is licensed under the MIT license:6// Ported from musl, which is licensed under the MIT license:
2// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT7// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
3//8//
lib/std/math/log.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Ported from musl, which is licensed under the MIT license:6// Ported from musl, which is licensed under the MIT license:
2// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT7// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
3//8//
lib/std/math/log10.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Ported from musl, which is licensed under the MIT license:6// Ported from musl, which is licensed under the MIT license:
2// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT7// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
3//8//
lib/std/math/log1p.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Ported from musl, which is licensed under the MIT license:6// Ported from musl, which is licensed under the MIT license:
2// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT7// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
3//8//
lib/std/math/log2.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Ported from musl, which is licensed under the MIT license:6// Ported from musl, which is licensed under the MIT license:
2// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT7// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
3//8//
lib/std/math/modf.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Ported from musl, which is licensed under the MIT license:6// Ported from musl, which is licensed under the MIT license:
2// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT7// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
3//8//
lib/std/math/nan.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const math = @import("../math.zig");6const math = @import("../math.zig");
27
3/// Returns the nan representation for type T.8/// Returns the nan representation for type T.
lib/std/math/pow.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Ported from go, which is licensed under a BSD-3 license.6// Ported from go, which is licensed under a BSD-3 license.
2// https://golang.org/LICENSE7// https://golang.org/LICENSE
3//8//
lib/std/math/powi.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Based on Rust, which is licensed under the MIT license.6// Based on Rust, which is licensed under the MIT license.
2// https://github.com/rust-lang/rust/blob/360432f1e8794de58cd94f34c9c17ad65871e5b5/LICENSE-MIT7// https://github.com/rust-lang/rust/blob/360432f1e8794de58cd94f34c9c17ad65871e5b5/LICENSE-MIT
3//8//
lib/std/math/round.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Ported from musl, which is licensed under the MIT license:6// Ported from musl, which is licensed under the MIT license:
2// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT7// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
3//8//
lib/std/math/scalbn.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Ported from musl, which is licensed under the MIT license:6// Ported from musl, which is licensed under the MIT license:
2// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT7// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
3//8//
lib/std/math/signbit.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const math = std.math;7const math = std.math;
3const expect = std.testing.expect;8const expect = std.testing.expect;
lib/std/math/sin.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Ported from go, which is licensed under a BSD-3 license.6// Ported from go, which is licensed under a BSD-3 license.
2// https://golang.org/LICENSE7// https://golang.org/LICENSE
3//8//
lib/std/math/sinh.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Ported from musl, which is licensed under the MIT license:6// Ported from musl, which is licensed under the MIT license:
2// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT7// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
3//8//
lib/std/math/sqrt.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const math = std.math;7const math = std.math;
3const expect = std.testing.expect;8const expect = std.testing.expect;
lib/std/math/tan.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Ported from go, which is licensed under a BSD-3 license.6// Ported from go, which is licensed under a BSD-3 license.
2// https://golang.org/LICENSE7// https://golang.org/LICENSE
3//8//
lib/std/math/tanh.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Ported from musl, which is licensed under the MIT license:6// Ported from musl, which is licensed under the MIT license:
2// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT7// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
3//8//
lib/std/math/trunc.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Ported from musl, which is licensed under the MIT license:6// Ported from musl, which is licensed under the MIT license:
2// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT7// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
3//8//
lib/std/mem.zig+24-1
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std.zig");6const std = @import("std.zig");
2const debug = std.debug;7const debug = std.debug;
3const assert = debug.assert;8const assert = debug.assert;
...@@ -221,9 +226,19 @@ pub fn zeroes(comptime T: type) T {...@@ -221,9 +226,19 @@ pub fn zeroes(comptime T: type) T {
221 .Vector => |info| {226 .Vector => |info| {
222 return @splat(info.len, zeroes(info.child));227 return @splat(info.len, zeroes(info.child));
223 },228 },
229 .Union => |info| {
230 if (comptime meta.containerLayout(T) == .Extern) {
231 // The C language specification states that (global) unions
232 // should be zero initialized to the first named member.
233 var item: T = undefined;
234 @field(item, info.fields[0].name) = zeroes(@TypeOf(@field(item, info.fields[0].name)));
235 return item;
236 }
237
238 @compileError("Can't set a " ++ @typeName(T) ++ " to zero.");
239 },
224 .ErrorUnion,240 .ErrorUnion,
225 .ErrorSet,241 .ErrorSet,
226 .Union,
227 .Fn,242 .Fn,
228 .BoundFn,243 .BoundFn,
229 .Type,244 .Type,
...@@ -312,6 +327,14 @@ test "mem.zeroes" {...@@ -312,6 +327,14 @@ test "mem.zeroes" {
312 for (b.sentinel) |e| {327 for (b.sentinel) |e| {
313 testing.expectEqual(@as(u8, 0), e);328 testing.expectEqual(@as(u8, 0), e);
314 }329 }
330
331 const C_union = extern union {
332 a: u8,
333 b: u32,
334 };
335
336 var c = zeroes(C_union);
337 testing.expectEqual(@as(u8, 0), c.a);
315}338}
316339
317/// Sets a slice to zeroes.340/// Sets a slice to zeroes.
lib/std/mem/Allocator.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1//! The standard memory allocation interface.6//! The standard memory allocation interface.
27
3const std = @import("../std.zig");8const std = @import("../std.zig");
lib/std/meta.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std.zig");6const std = @import("std.zig");
2const builtin = @import("builtin");7const builtin = @import("builtin");
3const debug = std.debug;8const debug = std.debug;
lib/std/meta/trailer_flags.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const meta = std.meta;7const meta = std.meta;
3const testing = std.testing;8const testing = std.testing;
lib/std/meta/trait.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const builtin = std.builtin;7const builtin = std.builtin;
3const mem = std.mem;8const mem = std.mem;
lib/std/mutex.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std.zig");6const std = @import("std.zig");
2const builtin = @import("builtin");7const builtin = @import("builtin");
3const os = std.os;8const os = std.os;
lib/std/net.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std.zig");6const std = @import("std.zig");
2const builtin = @import("builtin");7const builtin = @import("builtin");
3const assert = std.debug.assert;8const assert = std.debug.assert;
lib/std/net/test.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const builtin = std.builtin;7const builtin = std.builtin;
3const net = std.net;8const net = std.net;
lib/std/once.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std.zig");6const std = @import("std.zig");
2const builtin = std.builtin;7const builtin = std.builtin;
3const testing = std.testing;8const testing = std.testing;
lib/std/os.zig+24-17
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// This file contains thin wrappers around OS-specific APIs, with these6// This file contains thin wrappers around OS-specific APIs, with these
2// specific goals in mind:7// specific goals in mind:
3// * Convert "errno"-style error codes into Zig errors.8// * Convert "errno"-style error codes into Zig errors.
...@@ -296,6 +301,7 @@ pub const ReadError = error{...@@ -296,6 +301,7 @@ pub const ReadError = error{
296 BrokenPipe,301 BrokenPipe,
297 ConnectionResetByPeer,302 ConnectionResetByPeer,
298 ConnectionTimedOut,303 ConnectionTimedOut,
304 NotOpenForReading,
299305
300 /// This error occurs when no global event loop is configured,306 /// This error occurs when no global event loop is configured,
301 /// and reading from the file descriptor would block.307 /// and reading from the file descriptor would block.
...@@ -332,7 +338,7 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize {...@@ -332,7 +338,7 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize {
332 wasi.EINVAL => unreachable,338 wasi.EINVAL => unreachable,
333 wasi.EFAULT => unreachable,339 wasi.EFAULT => unreachable,
334 wasi.EAGAIN => unreachable,340 wasi.EAGAIN => unreachable,
335 wasi.EBADF => unreachable, // Always a race condition.341 wasi.EBADF => return error.NotOpenForReading, // Can be a race condition.
336 wasi.EIO => return error.InputOutput,342 wasi.EIO => return error.InputOutput,
337 wasi.EISDIR => return error.IsDir,343 wasi.EISDIR => return error.IsDir,
338 wasi.ENOBUFS => return error.SystemResources,344 wasi.ENOBUFS => return error.SystemResources,
...@@ -364,7 +370,7 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize {...@@ -364,7 +370,7 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize {
364 } else {370 } else {
365 return error.WouldBlock;371 return error.WouldBlock;
366 },372 },
367 EBADF => unreachable, // Always a race condition.373 EBADF => return error.NotOpenForReading, // Can be a race condition.
368 EIO => return error.InputOutput,374 EIO => return error.InputOutput,
369 EISDIR => return error.IsDir,375 EISDIR => return error.IsDir,
370 ENOBUFS => return error.SystemResources,376 ENOBUFS => return error.SystemResources,
...@@ -402,7 +408,7 @@ pub fn readv(fd: fd_t, iov: []const iovec) ReadError!usize {...@@ -402,7 +408,7 @@ pub fn readv(fd: fd_t, iov: []const iovec) ReadError!usize {
402 wasi.EINVAL => unreachable,408 wasi.EINVAL => unreachable,
403 wasi.EFAULT => unreachable,409 wasi.EFAULT => unreachable,
404 wasi.EAGAIN => unreachable, // currently not support in WASI410 wasi.EAGAIN => unreachable, // currently not support in WASI
405 wasi.EBADF => unreachable, // always a race condition411 wasi.EBADF => return error.NotOpenForReading, // can be a race condition
406 wasi.EIO => return error.InputOutput,412 wasi.EIO => return error.InputOutput,
407 wasi.EISDIR => return error.IsDir,413 wasi.EISDIR => return error.IsDir,
408 wasi.ENOBUFS => return error.SystemResources,414 wasi.ENOBUFS => return error.SystemResources,
...@@ -426,7 +432,7 @@ pub fn readv(fd: fd_t, iov: []const iovec) ReadError!usize {...@@ -426,7 +432,7 @@ pub fn readv(fd: fd_t, iov: []const iovec) ReadError!usize {
426 } else {432 } else {
427 return error.WouldBlock;433 return error.WouldBlock;
428 },434 },
429 EBADF => unreachable, // always a race condition435 EBADF => return error.NotOpenForReading, // can be a race condition
430 EIO => return error.InputOutput,436 EIO => return error.InputOutput,
431 EISDIR => return error.IsDir,437 EISDIR => return error.IsDir,
432 ENOBUFS => return error.SystemResources,438 ENOBUFS => return error.SystemResources,
...@@ -463,7 +469,7 @@ pub fn pread(fd: fd_t, buf: []u8, offset: u64) PReadError!usize {...@@ -463,7 +469,7 @@ pub fn pread(fd: fd_t, buf: []u8, offset: u64) PReadError!usize {
463 wasi.EINVAL => unreachable,469 wasi.EINVAL => unreachable,
464 wasi.EFAULT => unreachable,470 wasi.EFAULT => unreachable,
465 wasi.EAGAIN => unreachable,471 wasi.EAGAIN => unreachable,
466 wasi.EBADF => unreachable, // Always a race condition.472 wasi.EBADF => return error.NotOpenForReading, // Can be a race condition.
467 wasi.EIO => return error.InputOutput,473 wasi.EIO => return error.InputOutput,
468 wasi.EISDIR => return error.IsDir,474 wasi.EISDIR => return error.IsDir,
469 wasi.ENOBUFS => return error.SystemResources,475 wasi.ENOBUFS => return error.SystemResources,
...@@ -490,7 +496,7 @@ pub fn pread(fd: fd_t, buf: []u8, offset: u64) PReadError!usize {...@@ -490,7 +496,7 @@ pub fn pread(fd: fd_t, buf: []u8, offset: u64) PReadError!usize {
490 } else {496 } else {
491 return error.WouldBlock;497 return error.WouldBlock;
492 },498 },
493 EBADF => unreachable, // Always a race condition.499 EBADF => return error.NotOpenForReading, // Can be a race condition.
494 EIO => return error.InputOutput,500 EIO => return error.InputOutput,
495 EISDIR => return error.IsDir,501 EISDIR => return error.IsDir,
496 ENOBUFS => return error.SystemResources,502 ENOBUFS => return error.SystemResources,
...@@ -607,7 +613,7 @@ pub fn preadv(fd: fd_t, iov: []const iovec, offset: u64) PReadError!usize {...@@ -607,7 +613,7 @@ pub fn preadv(fd: fd_t, iov: []const iovec, offset: u64) PReadError!usize {
607 wasi.EINVAL => unreachable,613 wasi.EINVAL => unreachable,
608 wasi.EFAULT => unreachable,614 wasi.EFAULT => unreachable,
609 wasi.EAGAIN => unreachable,615 wasi.EAGAIN => unreachable,
610 wasi.EBADF => unreachable, // always a race condition616 wasi.EBADF => return error.NotOpenForReading, // can be a race condition
611 wasi.EIO => return error.InputOutput,617 wasi.EIO => return error.InputOutput,
612 wasi.EISDIR => return error.IsDir,618 wasi.EISDIR => return error.IsDir,
613 wasi.ENOBUFS => return error.SystemResources,619 wasi.ENOBUFS => return error.SystemResources,
...@@ -635,7 +641,7 @@ pub fn preadv(fd: fd_t, iov: []const iovec, offset: u64) PReadError!usize {...@@ -635,7 +641,7 @@ pub fn preadv(fd: fd_t, iov: []const iovec, offset: u64) PReadError!usize {
635 } else {641 } else {
636 return error.WouldBlock;642 return error.WouldBlock;
637 },643 },
638 EBADF => unreachable, // always a race condition644 EBADF => return error.NotOpenForReading, // can be a race condition
639 EIO => return error.InputOutput,645 EIO => return error.InputOutput,
640 EISDIR => return error.IsDir,646 EISDIR => return error.IsDir,
641 ENOBUFS => return error.SystemResources,647 ENOBUFS => return error.SystemResources,
...@@ -660,6 +666,7 @@ pub const WriteError = error{...@@ -660,6 +666,7 @@ pub const WriteError = error{
660 BrokenPipe,666 BrokenPipe,
661 SystemResources,667 SystemResources,
662 OperationAborted,668 OperationAborted,
669 NotOpenForWriting,
663670
664 /// This error occurs when no global event loop is configured,671 /// This error occurs when no global event loop is configured,
665 /// and reading from the file descriptor would block.672 /// and reading from the file descriptor would block.
...@@ -704,7 +711,7 @@ pub fn write(fd: fd_t, bytes: []const u8) WriteError!usize {...@@ -704,7 +711,7 @@ pub fn write(fd: fd_t, bytes: []const u8) WriteError!usize {
704 wasi.EINVAL => unreachable,711 wasi.EINVAL => unreachable,
705 wasi.EFAULT => unreachable,712 wasi.EFAULT => unreachable,
706 wasi.EAGAIN => unreachable,713 wasi.EAGAIN => unreachable,
707 wasi.EBADF => unreachable, // Always a race condition.714 wasi.EBADF => return error.NotOpenForWriting, // can be a race condition.
708 wasi.EDESTADDRREQ => unreachable, // `connect` was never called.715 wasi.EDESTADDRREQ => unreachable, // `connect` was never called.
709 wasi.EDQUOT => return error.DiskQuota,716 wasi.EDQUOT => return error.DiskQuota,
710 wasi.EFBIG => return error.FileTooBig,717 wasi.EFBIG => return error.FileTooBig,
...@@ -736,7 +743,7 @@ pub fn write(fd: fd_t, bytes: []const u8) WriteError!usize {...@@ -736,7 +743,7 @@ pub fn write(fd: fd_t, bytes: []const u8) WriteError!usize {
736 } else {743 } else {
737 return error.WouldBlock;744 return error.WouldBlock;
738 },745 },
739 EBADF => unreachable, // Always a race condition.746 EBADF => return error.NotOpenForWriting, // can be a race condition.
740 EDESTADDRREQ => unreachable, // `connect` was never called.747 EDESTADDRREQ => unreachable, // `connect` was never called.
741 EDQUOT => return error.DiskQuota,748 EDQUOT => return error.DiskQuota,
742 EFBIG => return error.FileTooBig,749 EFBIG => return error.FileTooBig,
...@@ -782,7 +789,7 @@ pub fn writev(fd: fd_t, iov: []const iovec_const) WriteError!usize {...@@ -782,7 +789,7 @@ pub fn writev(fd: fd_t, iov: []const iovec_const) WriteError!usize {
782 wasi.EINVAL => unreachable,789 wasi.EINVAL => unreachable,
783 wasi.EFAULT => unreachable,790 wasi.EFAULT => unreachable,
784 wasi.EAGAIN => unreachable,791 wasi.EAGAIN => unreachable,
785 wasi.EBADF => unreachable, // Always a race condition.792 wasi.EBADF => return error.NotOpenForWriting, // can be a race condition.
786 wasi.EDESTADDRREQ => unreachable, // `connect` was never called.793 wasi.EDESTADDRREQ => unreachable, // `connect` was never called.
787 wasi.EDQUOT => return error.DiskQuota,794 wasi.EDQUOT => return error.DiskQuota,
788 wasi.EFBIG => return error.FileTooBig,795 wasi.EFBIG => return error.FileTooBig,
...@@ -809,7 +816,7 @@ pub fn writev(fd: fd_t, iov: []const iovec_const) WriteError!usize {...@@ -809,7 +816,7 @@ pub fn writev(fd: fd_t, iov: []const iovec_const) WriteError!usize {
809 } else {816 } else {
810 return error.WouldBlock;817 return error.WouldBlock;
811 },818 },
812 EBADF => unreachable, // Always a race condition.819 EBADF => return error.NotOpenForWriting, // Can be a race condition.
813 EDESTADDRREQ => unreachable, // `connect` was never called.820 EDESTADDRREQ => unreachable, // `connect` was never called.
814 EDQUOT => return error.DiskQuota,821 EDQUOT => return error.DiskQuota,
815 EFBIG => return error.FileTooBig,822 EFBIG => return error.FileTooBig,
...@@ -862,7 +869,7 @@ pub fn pwrite(fd: fd_t, bytes: []const u8, offset: u64) PWriteError!usize {...@@ -862,7 +869,7 @@ pub fn pwrite(fd: fd_t, bytes: []const u8, offset: u64) PWriteError!usize {
862 wasi.EINVAL => unreachable,869 wasi.EINVAL => unreachable,
863 wasi.EFAULT => unreachable,870 wasi.EFAULT => unreachable,
864 wasi.EAGAIN => unreachable,871 wasi.EAGAIN => unreachable,
865 wasi.EBADF => unreachable, // Always a race condition.872 wasi.EBADF => return error.NotOpenForWriting, // can be a race condition.
866 wasi.EDESTADDRREQ => unreachable, // `connect` was never called.873 wasi.EDESTADDRREQ => unreachable, // `connect` was never called.
867 wasi.EDQUOT => return error.DiskQuota,874 wasi.EDQUOT => return error.DiskQuota,
868 wasi.EFBIG => return error.FileTooBig,875 wasi.EFBIG => return error.FileTooBig,
...@@ -898,7 +905,7 @@ pub fn pwrite(fd: fd_t, bytes: []const u8, offset: u64) PWriteError!usize {...@@ -898,7 +905,7 @@ pub fn pwrite(fd: fd_t, bytes: []const u8, offset: u64) PWriteError!usize {
898 } else {905 } else {
899 return error.WouldBlock;906 return error.WouldBlock;
900 },907 },
901 EBADF => unreachable, // Always a race condition.908 EBADF => return error.NotOpenForWriting, // Can be a race condition.
902 EDESTADDRREQ => unreachable, // `connect` was never called.909 EDESTADDRREQ => unreachable, // `connect` was never called.
903 EDQUOT => return error.DiskQuota,910 EDQUOT => return error.DiskQuota,
904 EFBIG => return error.FileTooBig,911 EFBIG => return error.FileTooBig,
...@@ -956,7 +963,7 @@ pub fn pwritev(fd: fd_t, iov: []const iovec_const, offset: u64) PWriteError!usiz...@@ -956,7 +963,7 @@ pub fn pwritev(fd: fd_t, iov: []const iovec_const, offset: u64) PWriteError!usiz
956 wasi.EINVAL => unreachable,963 wasi.EINVAL => unreachable,
957 wasi.EFAULT => unreachable,964 wasi.EFAULT => unreachable,
958 wasi.EAGAIN => unreachable,965 wasi.EAGAIN => unreachable,
959 wasi.EBADF => unreachable, // Always a race condition.966 wasi.EBADF => return error.NotOpenForWriting, // Can be a race condition.
960 wasi.EDESTADDRREQ => unreachable, // `connect` was never called.967 wasi.EDESTADDRREQ => unreachable, // `connect` was never called.
961 wasi.EDQUOT => return error.DiskQuota,968 wasi.EDQUOT => return error.DiskQuota,
962 wasi.EFBIG => return error.FileTooBig,969 wasi.EFBIG => return error.FileTooBig,
...@@ -986,7 +993,7 @@ pub fn pwritev(fd: fd_t, iov: []const iovec_const, offset: u64) PWriteError!usiz...@@ -986,7 +993,7 @@ pub fn pwritev(fd: fd_t, iov: []const iovec_const, offset: u64) PWriteError!usiz
986 } else {993 } else {
987 return error.WouldBlock;994 return error.WouldBlock;
988 },995 },
989 EBADF => unreachable, // Always a race condition.996 EBADF => return error.NotOpenForWriting, // Can be a race condition.
990 EDESTADDRREQ => unreachable, // `connect` was never called.997 EDESTADDRREQ => unreachable, // `connect` was never called.
991 EDQUOT => return error.DiskQuota,998 EDQUOT => return error.DiskQuota,
992 EFBIG => return error.FileTooBig,999 EFBIG => return error.FileTooBig,
...@@ -1251,7 +1258,7 @@ pub fn dup2(old_fd: fd_t, new_fd: fd_t) !void {...@@ -1251,7 +1258,7 @@ pub fn dup2(old_fd: fd_t, new_fd: fd_t) !void {
1251 EBUSY, EINTR => continue,1258 EBUSY, EINTR => continue,
1252 EMFILE => return error.ProcessFdQuotaExceeded,1259 EMFILE => return error.ProcessFdQuotaExceeded,
1253 EINVAL => unreachable, // invalid parameters passed to dup21260 EINVAL => unreachable, // invalid parameters passed to dup2
1254 EBADF => unreachable, // always a race condition1261 EBADF => unreachable, // invalid file descriptor
1255 else => |err| return unexpectedErrno(err),1262 else => |err| return unexpectedErrno(err),
1256 }1263 }
1257 }1264 }
lib/std/os/bits.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1//! Platform-dependent types and values that are used along with OS-specific APIs.6//! Platform-dependent types and values that are used along with OS-specific APIs.
2//! These are imported into `std.c`, `std.os`, and `std.os.linux`.7//! These are imported into `std.c`, `std.os`, and `std.os.linux`.
3//! Root source files can define `os.bits` and these will additionally be added8//! Root source files can define `os.bits` and these will additionally be added
lib/std/os/bits/darwin.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../../std.zig");6const std = @import("../../std.zig");
2const assert = std.debug.assert;7const assert = std.debug.assert;
3const maxInt = std.math.maxInt;8const maxInt = std.math.maxInt;
lib/std/os/bits/dragonfly.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../../std.zig");6const std = @import("../../std.zig");
2const maxInt = std.math.maxInt;7const maxInt = std.math.maxInt;
38
lib/std/os/bits/freebsd.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../../std.zig");6const std = @import("../../std.zig");
2const maxInt = std.math.maxInt;7const maxInt = std.math.maxInt;
38
lib/std/os/bits/linux.zig+9-1
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const builtin = @import("builtin");6const builtin = @import("builtin");
2const std = @import("../../std.zig");7const std = @import("../../std.zig");
3const maxInt = std.math.maxInt;8const maxInt = std.math.maxInt;
...@@ -19,7 +24,7 @@ pub usingnamespace switch (builtin.arch) {...@@ -19,7 +24,7 @@ pub usingnamespace switch (builtin.arch) {
19};24};
2025
21pub usingnamespace @import("linux/netlink.zig");26pub usingnamespace @import("linux/netlink.zig");
22pub const bpf = @import("linux/bpf.zig");27pub const BPF = @import("linux/bpf.zig");
2328
24const is_mips = builtin.arch.isMIPS();29const is_mips = builtin.arch.isMIPS();
2530
...@@ -770,6 +775,9 @@ pub fn S_ISSOCK(m: u32) bool {...@@ -770,6 +775,9 @@ pub fn S_ISSOCK(m: u32) bool {
770 return m & S_IFMT == S_IFSOCK;775 return m & S_IFMT == S_IFSOCK;
771}776}
772777
778pub const UTIME_NOW = 0x3fffffff;
779pub const UTIME_OMIT = 0x3ffffffe;
780
773pub const TFD_NONBLOCK = O_NONBLOCK;781pub const TFD_NONBLOCK = O_NONBLOCK;
774pub const TFD_CLOEXEC = O_CLOEXEC;782pub const TFD_CLOEXEC = O_CLOEXEC;
775783
lib/std/os/bits/linux/arm-eabi.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// arm-eabi-specific declarations that are intended to be imported into the POSIX namespace.6// arm-eabi-specific declarations that are intended to be imported into the POSIX namespace.
2const std = @import("../../../std.zig");7const std = @import("../../../std.zig");
3const linux = std.os.linux;8const linux = std.os.linux;
lib/std/os/bits/linux/arm64.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// arm64-specific declarations that are intended to be imported into the POSIX namespace.6// arm64-specific declarations that are intended to be imported into the POSIX namespace.
2// This does include Linux-only APIs.7// This does include Linux-only APIs.
38
lib/std/os/bits/linux/bpf.zig+387-18
...@@ -1,5 +1,65 @@...@@ -1,5 +1,65 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1usingnamespace std.os;6usingnamespace std.os;
2const std = @import("../../../std.zig");7const std = @import("../../../std.zig");
8const expectEqual = std.testing.expectEqual;
9const fd_t = std.os.fd_t;
10const pid_t = std.os.pid_t;
11
12// instruction classes
13pub const LD = 0x00;
14pub const LDX = 0x01;
15pub const ST = 0x02;
16pub const STX = 0x03;
17pub const ALU = 0x04;
18pub const JMP = 0x05;
19pub const RET = 0x06;
20pub const MISC = 0x07;
21
22/// 32-bit
23pub const W = 0x00;
24/// 16-bit
25pub const H = 0x08;
26/// 8-bit
27pub const B = 0x10;
28/// 64-bit
29pub const DW = 0x18;
30
31pub const IMM = 0x00;
32pub const ABS = 0x20;
33pub const IND = 0x40;
34pub const MEM = 0x60;
35pub const LEN = 0x80;
36pub const MSH = 0xa0;
37
38// alu fields
39pub const ADD = 0x00;
40pub const SUB = 0x10;
41pub const MUL = 0x20;
42pub const DIV = 0x30;
43pub const OR = 0x40;
44pub const AND = 0x50;
45pub const LSH = 0x60;
46pub const RSH = 0x70;
47pub const NEG = 0x80;
48pub const MOD = 0x90;
49pub const XOR = 0xa0;
50
51// jmp fields
52pub const JA = 0x00;
53pub const JEQ = 0x10;
54pub const JGT = 0x20;
55pub const JGE = 0x30;
56pub const JSET = 0x40;
57
58//#define BPF_SRC(code) ((code) & 0x08)
59pub const K = 0x00;
60pub const X = 0x08;
61
62pub const MAXINSNS = 4096;
363
4// instruction classes64// instruction classes
5/// jmp mode in word width65/// jmp mode in word width
...@@ -8,8 +68,6 @@ pub const JMP32 = 0x06;...@@ -8,8 +68,6 @@ pub const JMP32 = 0x06;
8pub const ALU64 = 0x07;68pub const ALU64 = 0x07;
969
10// ld/ldx fields70// ld/ldx fields
11/// double word (64-bit)
12pub const DW = 0x18;
13/// exclusive add71/// exclusive add
14pub const XADD = 0xc0;72pub const XADD = 0xc0;
1573
...@@ -148,6 +206,130 @@ pub const BPF_F_CLONE = 0x200;...@@ -148,6 +206,130 @@ pub const BPF_F_CLONE = 0x200;
148/// flag for BPF_MAP_CREATE command. Enable memory-mapping BPF map206/// flag for BPF_MAP_CREATE command. Enable memory-mapping BPF map
149pub const BPF_F_MMAPABLE = 0x400;207pub const BPF_F_MMAPABLE = 0x400;
150208
209/// These values correspond to "syscalls" within the BPF program's environment
210pub const Helper = enum(i32) {
211 unspec,
212 map_lookup_elem,
213 map_update_elem,
214 map_delete_elem,
215 probe_read,
216 ktime_get_ns,
217 trace_printk,
218 get_prandom_u32,
219 get_smp_processor_id,
220 skb_store_bytes,
221 l3_csum_replace,
222 l4_csum_replace,
223 tail_call,
224 clone_redirect,
225 get_current_pid_tgid,
226 get_current_uid_gid,
227 get_current_comm,
228 get_cgroup_classid,
229 skb_vlan_push,
230 skb_vlan_pop,
231 skb_get_tunnel_key,
232 skb_set_tunnel_key,
233 perf_event_read,
234 redirect,
235 get_route_realm,
236 perf_event_output,
237 skb_load_bytes,
238 get_stackid,
239 csum_diff,
240 skb_get_tunnel_opt,
241 skb_set_tunnel_opt,
242 skb_change_proto,
243 skb_change_type,
244 skb_under_cgroup,
245 get_hash_recalc,
246 get_current_task,
247 probe_write_user,
248 current_task_under_cgroup,
249 skb_change_tail,
250 skb_pull_data,
251 csum_update,
252 set_hash_invalid,
253 get_numa_node_id,
254 skb_change_head,
255 xdp_adjust_head,
256 probe_read_str,
257 get_socket_cookie,
258 get_socket_uid,
259 set_hash,
260 setsockopt,
261 skb_adjust_room,
262 redirect_map,
263 sk_redirect_map,
264 sock_map_update,
265 xdp_adjust_meta,
266 perf_event_read_value,
267 perf_prog_read_value,
268 getsockopt,
269 override_return,
270 sock_ops_cb_flags_set,
271 msg_redirect_map,
272 msg_apply_bytes,
273 msg_cork_bytes,
274 msg_pull_data,
275 bind,
276 xdp_adjust_tail,
277 skb_get_xfrm_state,
278 get_stack,
279 skb_load_bytes_relative,
280 fib_lookup,
281 sock_hash_update,
282 msg_redirect_hash,
283 sk_redirect_hash,
284 lwt_push_encap,
285 lwt_seg6_store_bytes,
286 lwt_seg6_adjust_srh,
287 lwt_seg6_action,
288 rc_repeat,
289 rc_keydown,
290 skb_cgroup_id,
291 get_current_cgroup_id,
292 get_local_storage,
293 sk_select_reuseport,
294 skb_ancestor_cgroup_id,
295 sk_lookup_tcp,
296 sk_lookup_udp,
297 sk_release,
298 map_push_elem,
299 map_pop_elem,
300 map_peek_elem,
301 msg_push_data,
302 msg_pop_data,
303 rc_pointer_rel,
304 spin_lock,
305 spin_unlock,
306 sk_fullsock,
307 tcp_sock,
308 skb_ecn_set_ce,
309 get_listener_sock,
310 skc_lookup_tcp,
311 tcp_check_syncookie,
312 sysctl_get_name,
313 sysctl_get_current_value,
314 sysctl_get_new_value,
315 sysctl_set_new_value,
316 strtol,
317 strtoul,
318 sk_storage_get,
319 sk_storage_delete,
320 send_signal,
321 tcp_gen_syncookie,
322 skb_output,
323 probe_read_user,
324 probe_read_kernel,
325 probe_read_user_str,
326 probe_read_kernel_str,
327 tcp_send_ack,
328 send_signal_thread,
329 jiffies64,
330 _,
331};
332
151/// a single BPF instruction333/// a single BPF instruction
152pub const Insn = packed struct {334pub const Insn = packed struct {
153 code: u8,335 code: u8,
...@@ -158,32 +340,168 @@ pub const Insn = packed struct {...@@ -158,32 +340,168 @@ pub const Insn = packed struct {
158340
159 /// r0 - r9 are general purpose 64-bit registers, r10 points to the stack341 /// r0 - r9 are general purpose 64-bit registers, r10 points to the stack
160 /// frame342 /// frame
161 pub const Reg = enum(u4) {343 pub const Reg = packed enum(u4) { r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10 };
162 r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10344 const Source = packed enum(u1) { reg, imm };
345 const AluOp = packed enum(u8) {
346 add = ADD,
347 sub = SUB,
348 mul = MUL,
349 div = DIV,
350 op_or = OR,
351 op_and = AND,
352 lsh = LSH,
353 rsh = RSH,
354 neg = NEG,
355 mod = MOD,
356 xor = XOR,
357 mov = MOV,
163 };358 };
164359
165 const alu = 0x04;360 pub const Size = packed enum(u8) {
166 const jmp = 0x05;361 byte = B,
167 const mov = 0xb0;362 half_word = H,
168 const k = 0;363 word = W,
169 const exit_code = 0x90;364 double_word = DW,
365 };
366
367 const JmpOp = packed enum(u8) {
368 ja = JA,
369 jeq = JEQ,
370 jgt = JGT,
371 jge = JGE,
372 jset = JSET,
373 };
374
375 const ImmOrReg = union(Source) {
376 imm: i32,
377 reg: Reg,
378 };
379
380 fn imm_reg(code: u8, dst: Reg, src: anytype, off: i16) Insn {
381 const imm_or_reg = if (@typeInfo(@TypeOf(src)) == .EnumLiteral)
382 ImmOrReg{ .reg = @as(Reg, src) }
383 else
384 ImmOrReg{ .imm = src };
385
386 const src_type = switch (imm_or_reg) {
387 .imm => K,
388 .reg => X,
389 };
390
391 return Insn{
392 .code = code | src_type,
393 .dst = @enumToInt(dst),
394 .src = switch (imm_or_reg) {
395 .imm => 0,
396 .reg => |r| @enumToInt(r),
397 },
398 .off = off,
399 .imm = switch (imm_or_reg) {
400 .imm => |i| i,
401 .reg => 0,
402 },
403 };
404 }
405
406 fn alu(comptime width: comptime_int, op: AluOp, dst: Reg, src: anytype) Insn {
407 const width_bitfield = switch (width) {
408 32 => ALU,
409 64 => ALU64,
410 else => @compileError("width must be 32 or 64"),
411 };
412
413 return imm_reg(width_bitfield | @enumToInt(op), dst, src, 0);
414 }
170415
171 // TODO: implement more factory functions for the other instructions416 pub fn mov(dst: Reg, src: anytype) Insn {
172 /// load immediate value into a register417 return alu(64, .mov, dst, src);
173 pub fn load_imm(dst: Reg, imm: i32) Insn {418 }
419
420 pub fn add(dst: Reg, src: anytype) Insn {
421 return alu(64, .add, dst, src);
422 }
423
424 fn jmp(op: JmpOp, dst: Reg, src: anytype, off: i16) Insn {
425 return imm_reg(JMP | @enumToInt(op), dst, src, off);
426 }
427
428 pub fn jeq(dst: Reg, src: anytype, off: i16) Insn {
429 return jmp(.jeq, dst, src, off);
430 }
431
432 pub fn stx_mem(size: Size, dst: Reg, src: Reg, off: i16) Insn {
174 return Insn{433 return Insn{
175 .code = alu | mov | k,434 .code = STX | @enumToInt(size) | MEM,
176 .dst = @enumToInt(dst),435 .dst = @enumToInt(dst),
436 .src = @enumToInt(src),
437 .off = off,
438 .imm = 0,
439 };
440 }
441
442 pub fn xadd(dst: Reg, src: Reg) Insn {
443 return Insn{
444 .code = STX | XADD | DW,
445 .dst = @enumToInt(dst),
446 .src = @enumToInt(src),
447 .off = 0,
448 .imm = 0,
449 };
450 }
451
452 /// direct packet access, R0 = *(uint *)(skb->data + imm32)
453 pub fn ld_abs(size: Size, imm: i32) Insn {
454 return Insn{
455 .code = LD | @enumToInt(size) | ABS,
456 .dst = 0,
177 .src = 0,457 .src = 0,
178 .off = 0,458 .off = 0,
179 .imm = imm,459 .imm = imm,
180 };460 };
181 }461 }
182462
463 fn ld_imm_impl1(dst: Reg, src: Reg, imm: u64) Insn {
464 return Insn{
465 .code = LD | DW | IMM,
466 .dst = @enumToInt(dst),
467 .src = @enumToInt(src),
468 .off = 0,
469 .imm = @intCast(i32, @truncate(u32, imm)),
470 };
471 }
472
473 fn ld_imm_impl2(imm: u64) Insn {
474 return Insn{
475 .code = 0,
476 .dst = 0,
477 .src = 0,
478 .off = 0,
479 .imm = @intCast(i32, @truncate(u32, imm >> 32)),
480 };
481 }
482
483 pub fn ld_map_fd1(dst: Reg, map_fd: fd_t) Insn {
484 return ld_imm_impl1(dst, @intToEnum(Reg, PSEUDO_MAP_FD), @intCast(u64, map_fd));
485 }
486
487 pub fn ld_map_fd2(map_fd: fd_t) Insn {
488 return ld_imm_impl2(@intCast(u64, map_fd));
489 }
490
491 pub fn call(helper: Helper) Insn {
492 return Insn{
493 .code = JMP | CALL,
494 .dst = 0,
495 .src = 0,
496 .off = 0,
497 .imm = @enumToInt(helper),
498 };
499 }
500
183 /// exit BPF program501 /// exit BPF program
184 pub fn exit() Insn {502 pub fn exit() Insn {
185 return Insn{503 return Insn{
186 .code = jmp | exit_code,504 .code = JMP | EXIT,
187 .dst = 0,505 .dst = 0,
188 .src = 0,506 .src = 0,
189 .off = 0,507 .off = 0,
...@@ -192,6 +510,61 @@ pub const Insn = packed struct {...@@ -192,6 +510,61 @@ pub const Insn = packed struct {
192 }510 }
193};511};
194512
513fn expect_insn(insn: Insn, val: u64) void {
514 expectEqual(@bitCast(u64, insn), val);
515}
516
517test "insn bitsize" {
518 expectEqual(@bitSizeOf(Insn), 64);
519}
520
521// mov instructions
522test "mov imm" {
523 expect_insn(Insn.mov(.r1, 1), 0x00000001000001b7);
524}
525
526test "mov reg" {
527 expect_insn(Insn.mov(.r6, .r1), 0x00000000000016bf);
528}
529
530// alu instructions
531test "add imm" {
532 expect_insn(Insn.add(.r2, -4), 0xfffffffc00000207);
533}
534
535// ld instructions
536test "ld_abs" {
537 expect_insn(Insn.ld_abs(.byte, 42), 0x0000002a00000030);
538}
539
540test "ld_map_fd" {
541 expect_insn(Insn.ld_map_fd1(.r1, 42), 0x0000002a00001118);
542 expect_insn(Insn.ld_map_fd2(42), 0x0000000000000000);
543}
544
545// st instructions
546test "stx_mem" {
547 expect_insn(Insn.stx_mem(.word, .r10, .r0, -4), 0x00000000fffc0a63);
548}
549
550test "xadd" {
551 expect_insn(Insn.xadd(.r0, .r1), 0x00000000000010db);
552}
553
554// jmp instructions
555test "jeq imm" {
556 expect_insn(Insn.jeq(.r0, 0, 2), 0x0000000000020015);
557}
558
559// other instructions
560test "call" {
561 expect_insn(Insn.call(.map_lookup_elem), 0x0000000100000085);
562}
563
564test "exit" {
565 expect_insn(Insn.exit(), 0x0000000000000095);
566}
567
195pub const Cmd = extern enum(usize) {568pub const Cmd = extern enum(usize) {
196 map_create,569 map_create,
197 map_lookup_elem,570 map_lookup_elem,
...@@ -600,7 +973,3 @@ pub const Attr = extern union {...@@ -600,7 +973,3 @@ pub const Attr = extern union {
600 enable_stats: EnableStatsAttr,973 enable_stats: EnableStatsAttr,
601 iter_create: IterCreateAttr,974 iter_create: IterCreateAttr,
602};975};
603
604pub fn bpf(cmd: Cmd, attr: *Attr, size: u32) usize {
605 return syscall3(.bpf, @enumToInt(cmd), @ptrToInt(attr), size);
606}
lib/std/os/bits/linux/errno-generic.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1/// Operation not permitted6/// Operation not permitted
2pub const EPERM = 1;7pub const EPERM = 1;
38
lib/std/os/bits/linux/errno-mips.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1pub const EPERM = 1;6pub const EPERM = 1;
2pub const ENOENT = 2;7pub const ENOENT = 2;
3pub const ESRCH = 3;8pub const ESRCH = 3;
lib/std/os/bits/linux/i386.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// i386-specific declarations that are intended to be imported into the POSIX namespace.6// i386-specific declarations that are intended to be imported into the POSIX namespace.
2// This does include Linux-only APIs.7// This does include Linux-only APIs.
38
lib/std/os/bits/linux/mips.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../../../std.zig");6const std = @import("../../../std.zig");
2const linux = std.os.linux;7const linux = std.os.linux;
3const socklen_t = linux.socklen_t;8const socklen_t = linux.socklen_t;
lib/std/os/bits/linux/netlink.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1usingnamespace @import("../linux.zig");6usingnamespace @import("../linux.zig");
27
3/// Routing/device hook8/// Routing/device hook
lib/std/os/bits/linux/riscv64.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// riscv64-specific declarations that are intended to be imported into the POSIX namespace.6// riscv64-specific declarations that are intended to be imported into the POSIX namespace.
2const std = @import("../../../std.zig");7const std = @import("../../../std.zig");
3const uid_t = std.os.linux.uid_t;8const uid_t = std.os.linux.uid_t;
lib/std/os/bits/linux/x86_64.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// x86-64-specific declarations that are intended to be imported into the POSIX namespace.6// x86-64-specific declarations that are intended to be imported into the POSIX namespace.
2const std = @import("../../../std.zig");7const std = @import("../../../std.zig");
3const pid_t = linux.pid_t;8const pid_t = linux.pid_t;
lib/std/os/bits/netbsd.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../../std.zig");6const std = @import("../../std.zig");
2const builtin = std.builtin;7const builtin = std.builtin;
3const maxInt = std.math.maxInt;8const maxInt = std.math.maxInt;
lib/std/os/bits/wasi.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Convenience types and consts used by std.os module6// Convenience types and consts used by std.os module
2pub const STDIN_FILENO = 0;7pub const STDIN_FILENO = 0;
3pub const STDOUT_FILENO = 1;8pub const STDOUT_FILENO = 1;
lib/std/os/bits/windows.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// The reference for these types and values is Microsoft Windows's ucrt (Universal C RunTime).6// The reference for these types and values is Microsoft Windows's ucrt (Universal C RunTime).
27
3usingnamespace @import("../windows/bits.zig");8usingnamespace @import("../windows/bits.zig");
lib/std/os/darwin.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const builtin = @import("builtin");6const builtin = @import("builtin");
2const std = @import("../std.zig");7const std = @import("../std.zig");
3pub usingnamespace std.c;8pub usingnamespace std.c;
lib/std/os/dragonfly.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2pub usingnamespace std.c;7pub usingnamespace std.c;
3pub usingnamespace @import("bits.zig");8pub usingnamespace @import("bits.zig");
lib/std/os/freebsd.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2pub usingnamespace std.c;7pub usingnamespace std.c;
3pub usingnamespace @import("bits.zig");8pub usingnamespace @import("bits.zig");
lib/std/os/linux.zig+9
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// This file provides the system interface functions for Linux matching those6// This file provides the system interface functions for Linux matching those
2// that are provided by libc, whether or not libc is linked. The following7// that are provided by libc, whether or not libc is linked. The following
3// abstractions are made:8// abstractions are made:
...@@ -1216,6 +1221,10 @@ pub fn copy_file_range(fd_in: fd_t, off_in: ?*i64, fd_out: fd_t, off_out: ?*i64,...@@ -1216,6 +1221,10 @@ pub fn copy_file_range(fd_in: fd_t, off_in: ?*i64, fd_out: fd_t, off_out: ?*i64,
1216 );1221 );
1217}1222}
12181223
1224pub fn bpf(cmd: BPF.Cmd, attr: *BPF.Attr, size: u32) usize {
1225 return syscall3(.bpf, @enumToInt(cmd), @ptrToInt(attr), size);
1226}
1227
1219test "" {1228test "" {
1220 if (builtin.os.tag == .linux) {1229 if (builtin.os.tag == .linux) {
1221 _ = @import("linux/test.zig");1230 _ = @import("linux/test.zig");
lib/std/os/linux/arm-eabi.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1usingnamespace @import("../bits.zig");6usingnamespace @import("../bits.zig");
27
3pub fn syscall0(number: SYS) usize {8pub fn syscall0(number: SYS) usize {
lib/std/os/linux/arm64.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1usingnamespace @import("../bits.zig");6usingnamespace @import("../bits.zig");
27
3pub fn syscall0(number: SYS) usize {8pub fn syscall0(number: SYS) usize {
lib/std/os/linux/i386.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1usingnamespace @import("../bits.zig");6usingnamespace @import("../bits.zig");
27
3pub fn syscall0(number: SYS) usize {8pub fn syscall0(number: SYS) usize {
lib/std/os/linux/mips.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1usingnamespace @import("../bits.zig");6usingnamespace @import("../bits.zig");
27
3pub fn syscall0(number: SYS) usize {8pub fn syscall0(number: SYS) usize {
lib/std/os/linux/riscv64.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1usingnamespace @import("../bits.zig");6usingnamespace @import("../bits.zig");
27
3pub fn syscall0(number: SYS) usize {8pub fn syscall0(number: SYS) usize {
lib/std/os/linux/test.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../../std.zig");6const std = @import("../../std.zig");
2const builtin = @import("builtin");7const builtin = @import("builtin");
3const linux = std.os.linux;8const linux = std.os.linux;
lib/std/os/linux/tls.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std");6const std = @import("std");
2const builtin = std.builtin;7const builtin = std.builtin;
3const os = std.os;8const os = std.os;
lib/std/os/linux/vdso.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../../std.zig");6const std = @import("../../std.zig");
2const elf = std.elf;7const elf = std.elf;
3const linux = std.os.linux;8const linux = std.os.linux;
lib/std/os/linux/x86_64.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1usingnamespace @import("../bits.zig");6usingnamespace @import("../bits.zig");
27
3pub fn syscall0(number: SYS) usize {8pub fn syscall0(number: SYS) usize {
lib/std/os/netbsd.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2pub usingnamespace std.c;7pub usingnamespace std.c;
3pub usingnamespace @import("bits.zig");8pub usingnamespace @import("bits.zig");
lib/std/os/test.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const os = std.os;7const os = std.os;
3const testing = std.testing;8const testing = std.testing;
lib/std/os/uefi.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1/// A protocol is an interface identified by a GUID.6/// A protocol is an interface identified by a GUID.
2pub const protocols = @import("uefi/protocols.zig");7pub const protocols = @import("uefi/protocols.zig");
38
lib/std/os/uefi/protocols.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1pub const LoadedImageProtocol = @import("protocols/loaded_image_protocol.zig").LoadedImageProtocol;6pub const LoadedImageProtocol = @import("protocols/loaded_image_protocol.zig").LoadedImageProtocol;
2pub const loaded_image_device_path_protocol_guid = @import("protocols/loaded_image_protocol.zig").loaded_image_device_path_protocol_guid;7pub const loaded_image_device_path_protocol_guid = @import("protocols/loaded_image_protocol.zig").loaded_image_device_path_protocol_guid;
38
lib/std/os/uefi/protocols/absolute_pointer_protocol.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const uefi = @import("std").os.uefi;6const uefi = @import("std").os.uefi;
2const Event = uefi.Event;7const Event = uefi.Event;
3const Guid = uefi.Guid;8const Guid = uefi.Guid;
lib/std/os/uefi/protocols/device_path_protocol.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const uefi = @import("std").os.uefi;6const uefi = @import("std").os.uefi;
2const Guid = uefi.Guid;7const Guid = uefi.Guid;
38
lib/std/os/uefi/protocols/edid_active_protocol.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const uefi = @import("std").os.uefi;6const uefi = @import("std").os.uefi;
2const Guid = uefi.Guid;7const Guid = uefi.Guid;
38
lib/std/os/uefi/protocols/edid_discovered_protocol.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const uefi = @import("std").os.uefi;6const uefi = @import("std").os.uefi;
2const Guid = uefi.Guid;7const Guid = uefi.Guid;
38
lib/std/os/uefi/protocols/edid_override_protocol.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const uefi = @import("std").os.uefi;6const uefi = @import("std").os.uefi;
2const Guid = uefi.Guid;7const Guid = uefi.Guid;
3const Handle = uefi.Handle;8const Handle = uefi.Handle;
lib/std/os/uefi/protocols/file_protocol.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const uefi = @import("std").os.uefi;6const uefi = @import("std").os.uefi;
2const Guid = uefi.Guid;7const Guid = uefi.Guid;
3const Time = uefi.Time;8const Time = uefi.Time;
lib/std/os/uefi/protocols/graphics_output_protocol.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const uefi = @import("std").os.uefi;6const uefi = @import("std").os.uefi;
2const Guid = uefi.Guid;7const Guid = uefi.Guid;
3const Status = uefi.Status;8const Status = uefi.Status;
lib/std/os/uefi/protocols/hii.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const uefi = @import("std").os.uefi;6const uefi = @import("std").os.uefi;
2const Guid = uefi.Guid;7const Guid = uefi.Guid;
38
lib/std/os/uefi/protocols/hii_database_protocol.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const uefi = @import("std").os.uefi;6const uefi = @import("std").os.uefi;
2const Guid = uefi.Guid;7const Guid = uefi.Guid;
3const Status = uefi.Status;8const Status = uefi.Status;
lib/std/os/uefi/protocols/hii_popup_protocol.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const uefi = @import("std").os.uefi;6const uefi = @import("std").os.uefi;
2const Guid = uefi.Guid;7const Guid = uefi.Guid;
3const Status = uefi.Status;8const Status = uefi.Status;
lib/std/os/uefi/protocols/ip6_config_protocol.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const uefi = @import("std").os.uefi;6const uefi = @import("std").os.uefi;
2const Guid = uefi.Guid;7const Guid = uefi.Guid;
3const Event = uefi.Event;8const Event = uefi.Event;
lib/std/os/uefi/protocols/ip6_protocol.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const uefi = @import("std").os.uefi;6const uefi = @import("std").os.uefi;
2const Guid = uefi.Guid;7const Guid = uefi.Guid;
3const Event = uefi.Event;8const Event = uefi.Event;
lib/std/os/uefi/protocols/ip6_service_binding_protocol.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const uefi = @import("std").os.uefi;6const uefi = @import("std").os.uefi;
2const Handle = uefi.Handle;7const Handle = uefi.Handle;
3const Guid = uefi.Guid;8const Guid = uefi.Guid;
lib/std/os/uefi/protocols/loaded_image_protocol.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const uefi = @import("std").os.uefi;6const uefi = @import("std").os.uefi;
2const Guid = uefi.Guid;7const Guid = uefi.Guid;
3const Handle = uefi.Handle;8const Handle = uefi.Handle;
lib/std/os/uefi/protocols/managed_network_protocol.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const uefi = @import("std").os.uefi;6const uefi = @import("std").os.uefi;
2const Guid = uefi.Guid;7const Guid = uefi.Guid;
3const Event = uefi.Event;8const Event = uefi.Event;
lib/std/os/uefi/protocols/managed_network_service_binding_protocol.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const uefi = @import("std").os.uefi;6const uefi = @import("std").os.uefi;
2const Handle = uefi.Handle;7const Handle = uefi.Handle;
3const Guid = uefi.Guid;8const Guid = uefi.Guid;
lib/std/os/uefi/protocols/rng_protocol.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const uefi = @import("std").os.uefi;6const uefi = @import("std").os.uefi;
2const Guid = uefi.Guid;7const Guid = uefi.Guid;
3const Status = uefi.Status;8const Status = uefi.Status;
lib/std/os/uefi/protocols/shell_parameters_protocol.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const uefi = @import("std").os.uefi;6const uefi = @import("std").os.uefi;
2const Guid = uefi.Guid;7const Guid = uefi.Guid;
3const FileHandle = uefi.FileHandle;8const FileHandle = uefi.FileHandle;
lib/std/os/uefi/protocols/simple_file_system_protocol.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const uefi = @import("std").os.uefi;6const uefi = @import("std").os.uefi;
2const Guid = uefi.Guid;7const Guid = uefi.Guid;
3const FileProtocol = uefi.protocols.FileProtocol;8const FileProtocol = uefi.protocols.FileProtocol;
lib/std/os/uefi/protocols/simple_network_protocol.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const uefi = @import("std").os.uefi;6const uefi = @import("std").os.uefi;
2const Event = uefi.Event;7const Event = uefi.Event;
3const Guid = uefi.Guid;8const Guid = uefi.Guid;
lib/std/os/uefi/protocols/simple_pointer_protocol.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const uefi = @import("std").os.uefi;6const uefi = @import("std").os.uefi;
2const Event = uefi.Event;7const Event = uefi.Event;
3const Guid = uefi.Guid;8const Guid = uefi.Guid;
lib/std/os/uefi/protocols/simple_text_input_ex_protocol.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const uefi = @import("std").os.uefi;6const uefi = @import("std").os.uefi;
2const Event = uefi.Event;7const Event = uefi.Event;
3const Guid = uefi.Guid;8const Guid = uefi.Guid;
lib/std/os/uefi/protocols/simple_text_input_protocol.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const uefi = @import("std").os.uefi;6const uefi = @import("std").os.uefi;
2const Event = uefi.Event;7const Event = uefi.Event;
3const Guid = uefi.Guid;8const Guid = uefi.Guid;
lib/std/os/uefi/protocols/simple_text_output_protocol.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const uefi = @import("std").os.uefi;6const uefi = @import("std").os.uefi;
2const Guid = uefi.Guid;7const Guid = uefi.Guid;
3const Status = uefi.Status;8const Status = uefi.Status;
lib/std/os/uefi/protocols/udp6_protocol.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const uefi = @import("std").os.uefi;6const uefi = @import("std").os.uefi;
2const Guid = uefi.Guid;7const Guid = uefi.Guid;
3const Event = uefi.Event;8const Event = uefi.Event;
lib/std/os/uefi/protocols/udp6_service_binding_protocol.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const uefi = @import("std").os.uefi;6const uefi = @import("std").os.uefi;
2const Handle = uefi.Handle;7const Handle = uefi.Handle;
3const Guid = uefi.Guid;8const Guid = uefi.Guid;
lib/std/os/uefi/status.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const high_bit = 1 << @typeInfo(usize).Int.bits - 1;6const high_bit = 1 << @typeInfo(usize).Int.bits - 1;
27
3pub const Status = extern enum(usize) {8pub const Status = extern enum(usize) {
lib/std/os/uefi/tables.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1pub const AllocateType = @import("tables/boot_services.zig").AllocateType;6pub const AllocateType = @import("tables/boot_services.zig").AllocateType;
2pub const BootServices = @import("tables/boot_services.zig").BootServices;7pub const BootServices = @import("tables/boot_services.zig").BootServices;
3pub const ConfigurationTable = @import("tables/configuration_table.zig").ConfigurationTable;8pub const ConfigurationTable = @import("tables/configuration_table.zig").ConfigurationTable;
lib/std/os/uefi/tables/boot_services.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const uefi = @import("std").os.uefi;6const uefi = @import("std").os.uefi;
2const Event = uefi.Event;7const Event = uefi.Event;
3const Guid = uefi.Guid;8const Guid = uefi.Guid;
lib/std/os/uefi/tables/configuration_table.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const uefi = @import("std").os.uefi;6const uefi = @import("std").os.uefi;
2const Guid = uefi.Guid;7const Guid = uefi.Guid;
38
lib/std/os/uefi/tables/runtime_services.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const uefi = @import("std").os.uefi;6const uefi = @import("std").os.uefi;
2const Guid = uefi.Guid;7const Guid = uefi.Guid;
3const TableHeader = uefi.tables.TableHeader;8const TableHeader = uefi.tables.TableHeader;
lib/std/os/uefi/tables/system_table.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const uefi = @import("std").os.uefi;6const uefi = @import("std").os.uefi;
2const BootServices = uefi.tables.BootServices;7const BootServices = uefi.tables.BootServices;
3const ConfigurationTable = uefi.tables.ConfigurationTable;8const ConfigurationTable = uefi.tables.ConfigurationTable;
lib/std/os/uefi/tables/table_header.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1pub const TableHeader = extern struct {6pub const TableHeader = extern struct {
2 signature: u64,7 signature: u64,
3 revision: u32,8 revision: u32,
lib/std/os/wasi.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// wasi_snapshot_preview1 spec available (in witx format) here:6// wasi_snapshot_preview1 spec available (in witx format) here:
2// * typenames -- https://github.com/WebAssembly/WASI/blob/master/phases/snapshot/witx/typenames.witx7// * typenames -- https://github.com/WebAssembly/WASI/blob/master/phases/snapshot/witx/typenames.witx
3// * module -- https://github.com/WebAssembly/WASI/blob/master/phases/snapshot/witx/wasi_snapshot_preview1.witx8// * module -- https://github.com/WebAssembly/WASI/blob/master/phases/snapshot/witx/wasi_snapshot_preview1.witx
lib/std/os/windows.zig+7
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// This file contains thin wrappers around Windows-specific APIs, with these6// This file contains thin wrappers around Windows-specific APIs, with these
2// specific goals in mind:7// specific goals in mind:
3// * Convert "errno"-style error codes into Zig errors.8// * Convert "errno"-style error codes into Zig errors.
...@@ -469,6 +474,7 @@ pub const WriteFileError = error{...@@ -469,6 +474,7 @@ pub const WriteFileError = error{
469 SystemResources,474 SystemResources,
470 OperationAborted,475 OperationAborted,
471 BrokenPipe,476 BrokenPipe,
477 NotOpenForWriting,
472 Unexpected,478 Unexpected,
473};479};
474480
...@@ -542,6 +548,7 @@ pub fn WriteFile(...@@ -542,6 +548,7 @@ pub fn WriteFile(
542 .NOT_ENOUGH_QUOTA => return error.SystemResources,548 .NOT_ENOUGH_QUOTA => return error.SystemResources,
543 .IO_PENDING => unreachable,549 .IO_PENDING => unreachable,
544 .BROKEN_PIPE => return error.BrokenPipe,550 .BROKEN_PIPE => return error.BrokenPipe,
551 .INVALID_HANDLE => return error.NotOpenForWriting,
545 else => |err| return unexpectedError(err),552 else => |err| return unexpectedError(err),
546 }553 }
547 }554 }
lib/std/os/windows/advapi32.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1usingnamespace @import("bits.zig");6usingnamespace @import("bits.zig");
27
3pub extern "advapi32" fn RegOpenKeyExW(8pub extern "advapi32" fn RegOpenKeyExW(
lib/std/os/windows/bits.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Platform-dependent types and values that are used along with OS-specific APIs.6// Platform-dependent types and values that are used along with OS-specific APIs.
27
3const builtin = @import("builtin");8const builtin = @import("builtin");
lib/std/os/windows/gdi32.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1usingnamespace @import("bits.zig");6usingnamespace @import("bits.zig");
27
3pub const PIXELFORMATDESCRIPTOR = extern struct {8pub const PIXELFORMATDESCRIPTOR = extern struct {
lib/std/os/windows/kernel32.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1usingnamespace @import("bits.zig");6usingnamespace @import("bits.zig");
27
3pub extern "kernel32" fn AddVectoredExceptionHandler(First: c_ulong, Handler: ?VECTORED_EXCEPTION_HANDLER) callconv(.Stdcall) ?*c_void;8pub extern "kernel32" fn AddVectoredExceptionHandler(First: c_ulong, Handler: ?VECTORED_EXCEPTION_HANDLER) callconv(.Stdcall) ?*c_void;
lib/std/os/windows/lang.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1pub const NEUTRAL = 0x00;6pub const NEUTRAL = 0x00;
2pub const INVARIANT = 0x7f;7pub const INVARIANT = 0x7f;
3pub const AFRIKAANS = 0x36;8pub const AFRIKAANS = 0x36;
lib/std/os/windows/ntdll.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1usingnamespace @import("bits.zig");6usingnamespace @import("bits.zig");
27
3pub extern "NtDll" fn RtlGetVersion(8pub extern "NtDll" fn RtlGetVersion(
lib/std/os/windows/ntstatus.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// NTSTATUS codes from https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/596a1078-e883-4972-9bbc-49e60bebca55?6// NTSTATUS codes from https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/596a1078-e883-4972-9bbc-49e60bebca55?
2pub const NTSTATUS = extern enum(u32) {7pub const NTSTATUS = extern enum(u32) {
3 /// The operation completed successfully.8 /// The operation completed successfully.
lib/std/os/windows/ole32.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1usingnamespace @import("bits.zig");6usingnamespace @import("bits.zig");
27
3pub extern "ole32" fn CoTaskMemFree(pv: LPVOID) callconv(.Stdcall) void;8pub extern "ole32" fn CoTaskMemFree(pv: LPVOID) callconv(.Stdcall) void;
lib/std/os/windows/psapi.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1usingnamespace @import("bits.zig");6usingnamespace @import("bits.zig");
27
3pub extern "psapi" fn EmptyWorkingSet(hProcess: HANDLE) callconv(.Stdcall) BOOL;8pub extern "psapi" fn EmptyWorkingSet(hProcess: HANDLE) callconv(.Stdcall) BOOL;
lib/std/os/windows/shell32.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1usingnamespace @import("bits.zig");6usingnamespace @import("bits.zig");
27
3pub extern "shell32" fn SHGetKnownFolderPath(rfid: *const KNOWNFOLDERID, dwFlags: DWORD, hToken: ?HANDLE, ppszPath: *[*:0]WCHAR) callconv(.Stdcall) HRESULT;8pub extern "shell32" fn SHGetKnownFolderPath(rfid: *const KNOWNFOLDERID, dwFlags: DWORD, hToken: ?HANDLE, ppszPath: *[*:0]WCHAR) callconv(.Stdcall) HRESULT;
lib/std/os/windows/sublang.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1pub const NEUTRAL = 0x00;6pub const NEUTRAL = 0x00;
2pub const DEFAULT = 0x01;7pub const DEFAULT = 0x01;
3pub const SYS_DEFAULT = 0x02;8pub const SYS_DEFAULT = 0x02;
lib/std/os/windows/user32.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1usingnamespace @import("bits.zig");6usingnamespace @import("bits.zig");
27
3// PM8// PM
lib/std/os/windows/win32error.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Codes are from https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/18d8fbe8-a967-4f1c-ae50-99ca8e491d2d6// Codes are from https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/18d8fbe8-a967-4f1c-ae50-99ca8e491d2d
2pub const Win32Error = extern enum(u16) {7pub const Win32Error = extern enum(u16) {
3 /// The operation completed successfully.8 /// The operation completed successfully.
lib/std/os/windows/ws2_32.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1usingnamespace @import("bits.zig");6usingnamespace @import("bits.zig");
27
3pub const SOCKET = *@Type(.Opaque);8pub const SOCKET = *@Type(.Opaque);
lib/std/packed_int_array.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std");6const std = @import("std");
2const builtin = @import("builtin");7const builtin = @import("builtin");
3const debug = std.debug;8const debug = std.debug;
lib/std/pdb.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const builtin = @import("builtin");6const builtin = @import("builtin");
2const std = @import("std.zig");7const std = @import("std.zig");
3const io = std.io;8const io = std.io;
lib/std/priority_queue.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std.zig");6const std = @import("std.zig");
2const Allocator = std.mem.Allocator;7const Allocator = std.mem.Allocator;
3const assert = std.debug.assert;8const assert = std.debug.assert;
lib/std/process.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std.zig");6const std = @import("std.zig");
2const builtin = std.builtin;7const builtin = std.builtin;
3const os = std.os;8const os = std.os;
lib/std/progress.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std");6const std = @import("std");
2const windows = std.os.windows;7const windows = std.os.windows;
3const testing = std.testing;8const testing = std.testing;
lib/std/rand.zig+7-2
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// The engines provided here should be initialized from an external source. For now, randomBytes6// The engines provided here should be initialized from an external source. For now, randomBytes
2// from the crypto package is the most suitable. Be sure to use a CSPRNG when required, otherwise using7// from the crypto package is the most suitable. Be sure to use a CSPRNG when required, otherwise using
3// a normal PRNG will be faster and use substantially less stack space.8// a normal PRNG will be faster and use substantially less stack space.
...@@ -732,12 +737,12 @@ test "xoroshiro sequence" {...@@ -732,12 +737,12 @@ test "xoroshiro sequence" {
732// CSPRNG737// CSPRNG
733pub const Gimli = struct {738pub const Gimli = struct {
734 random: Random,739 random: Random,
735 state: std.crypto.gimli.State,740 state: std.crypto.core.Gimli,
736741
737 pub fn init(init_s: u64) Gimli {742 pub fn init(init_s: u64) Gimli {
738 var self = Gimli{743 var self = Gimli{
739 .random = Random{ .fillFn = fill },744 .random = Random{ .fillFn = fill },
740 .state = std.crypto.gimli.State{745 .state = std.crypto.core.Gimli{
741 .data = [_]u32{0} ** (std.crypto.gimli.State.BLOCKBYTES / 4),746 .data = [_]u32{0} ** (std.crypto.gimli.State.BLOCKBYTES / 4),
742 },747 },
743 };748 };
lib/std/rand/ziggurat.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Implements ZIGNOR [1].6// Implements ZIGNOR [1].
2//7//
3// [1]: Jurgen A. Doornik (2005). [*An Improved Ziggurat Method to Generate Normal Random Samples*]8// [1]: Jurgen A. Doornik (2005). [*An Improved Ziggurat Method to Generate Normal Random Samples*]
lib/std/rb.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std");6const std = @import("std");
2const assert = std.debug.assert;7const assert = std.debug.assert;
3const testing = std.testing;8const testing = std.testing;
lib/std/reset_event.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std.zig");6const std = @import("std.zig");
2const builtin = @import("builtin");7const builtin = @import("builtin");
3const testing = std.testing;8const testing = std.testing;
lib/std/segmented_list.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std.zig");6const std = @import("std.zig");
2const assert = std.debug.assert;7const assert = std.debug.assert;
3const testing = std.testing;8const testing = std.testing;
lib/std/sort.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std.zig");6const std = @import("std.zig");
2const assert = std.debug.assert;7const assert = std.debug.assert;
3const testing = std.testing;8const testing = std.testing;
lib/std/special/build_runner.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const root = @import("@build");6const root = @import("@build");
2const std = @import("std");7const std = @import("std");
3const builtin = @import("builtin");8const builtin = @import("builtin");
lib/std/special/c.zig+6-1
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// This is Zig's multi-target implementation of libc.6// This is Zig's multi-target implementation of libc.
2// When builtin.link_libc is true, we need to export all the functions and7// When builtin.link_libc is true, we need to export all the functions and
3// provide an entire C API.8// provide an entire C API.
...@@ -35,7 +40,7 @@ comptime {...@@ -35,7 +40,7 @@ comptime {
35 }40 }
36}41}
3742
38extern var _fltused: c_int = 1;43var _fltused: c_int = 1;
3944
40extern fn main(argc: c_int, argv: [*:null]?[*:0]u8) c_int;45extern fn main(argc: c_int, argv: [*:null]?[*:0]u8) c_int;
41fn wasm_start() callconv(.C) void {46fn wasm_start() callconv(.C) void {
lib/std/special/compiler_rt.zig+6-1
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std");6const std = @import("std");
2const builtin = std.builtin;7const builtin = std.builtin;
3const is_test = builtin.is_test;8const is_test = builtin.is_test;
...@@ -335,7 +340,7 @@ fn __stack_chk_fail() callconv(.C) noreturn {...@@ -335,7 +340,7 @@ fn __stack_chk_fail() callconv(.C) noreturn {
335 @panic("stack smashing detected");340 @panic("stack smashing detected");
336}341}
337342
338extern var __stack_chk_guard: usize = blk: {343var __stack_chk_guard: usize = blk: {
339 var buf = [1]u8{0} ** @sizeOf(usize);344 var buf = [1]u8{0} ** @sizeOf(usize);
340 buf[@sizeOf(usize) - 1] = 255;345 buf[@sizeOf(usize) - 1] = 255;
341 buf[@sizeOf(usize) - 2] = '\n';346 buf[@sizeOf(usize) - 2] = '\n';
lib/std/special/compiler_rt/addXf3.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Ported from:6// Ported from:
2//7//
3// https://github.com/llvm/llvm-project/blob/02d85149a05cb1f6dc49f0ba7a2ceca53718ae17/compiler-rt/lib/builtins/fp_add_impl.inc8// https://github.com/llvm/llvm-project/blob/02d85149a05cb1f6dc49f0ba7a2ceca53718ae17/compiler-rt/lib/builtins/fp_add_impl.inc
lib/std/special/compiler_rt/addXf3_test.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Ported from:6// Ported from:
2//7//
3// https://github.com/llvm/llvm-project/blob/02d85149a05cb1f6dc49f0ba7a2ceca53718ae17/compiler-rt/test/builtins/Unit/addtf3_test.c8// https://github.com/llvm/llvm-project/blob/02d85149a05cb1f6dc49f0ba7a2ceca53718ae17/compiler-rt/test/builtins/Unit/addtf3_test.c
lib/std/special/compiler_rt/arm.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// ARM specific builtins6// ARM specific builtins
2const builtin = @import("builtin");7const builtin = @import("builtin");
38
lib/std/special/compiler_rt/ashldi3_test.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const __ashldi3 = @import("shift.zig").__ashldi3;6const __ashldi3 = @import("shift.zig").__ashldi3;
2const testing = @import("std").testing;7const testing = @import("std").testing;
38
lib/std/special/compiler_rt/ashlti3_test.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const __ashlti3 = @import("shift.zig").__ashlti3;6const __ashlti3 = @import("shift.zig").__ashlti3;
2const testing = @import("std").testing;7const testing = @import("std").testing;
38
lib/std/special/compiler_rt/ashrdi3_test.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const __ashrdi3 = @import("shift.zig").__ashrdi3;6const __ashrdi3 = @import("shift.zig").__ashrdi3;
2const testing = @import("std").testing;7const testing = @import("std").testing;
38
lib/std/special/compiler_rt/ashrti3_test.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const __ashrti3 = @import("shift.zig").__ashrti3;6const __ashrti3 = @import("shift.zig").__ashrti3;
2const testing = @import("std").testing;7const testing = @import("std").testing;
38
lib/std/special/compiler_rt/atomics.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std");6const std = @import("std");
2const builtin = std.builtin;7const builtin = std.builtin;
38
lib/std/special/compiler_rt/aulldiv.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const builtin = @import("builtin");6const builtin = @import("builtin");
27
3pub fn _alldiv(a: i64, b: i64) callconv(.Stdcall) i64 {8pub fn _alldiv(a: i64, b: i64) callconv(.Stdcall) i64 {
lib/std/special/compiler_rt/aullrem.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const builtin = @import("builtin");6const builtin = @import("builtin");
27
3pub fn _allrem(a: i64, b: i64) callconv(.Stdcall) i64 {8pub fn _allrem(a: i64, b: i64) callconv(.Stdcall) i64 {
lib/std/special/compiler_rt/clear_cache.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std");6const std = @import("std");
2const arch = std.builtin.cpu.arch;7const arch = std.builtin.cpu.arch;
3const os = std.builtin.os.tag;8const os = std.builtin.os.tag;
lib/std/special/compiler_rt/clzsi2.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const builtin = @import("builtin");6const builtin = @import("builtin");
27
3fn __clzsi2_generic(a: i32) callconv(.C) i32 {8fn __clzsi2_generic(a: i32) callconv(.C) i32 {
lib/std/special/compiler_rt/clzsi2_test.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const clzsi2 = @import("clzsi2.zig");6const clzsi2 = @import("clzsi2.zig");
2const testing = @import("std").testing;7const testing = @import("std").testing;
38
lib/std/special/compiler_rt/compareXf2.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Ported from:6// Ported from:
2//7//
3// https://github.com/llvm/llvm-project/commit/d674d96bc56c0f377879d01c9d8dfdaaa7859cdb/compiler-rt/lib/builtins/comparesf2.c8// https://github.com/llvm/llvm-project/commit/d674d96bc56c0f377879d01c9d8dfdaaa7859cdb/compiler-rt/lib/builtins/comparesf2.c
lib/std/special/compiler_rt/comparedf2_test.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Ported from:6// Ported from:
2//7//
3// https://github.com/llvm/llvm-project/commit/d674d96bc56c0f377879d01c9d8dfdaaa7859cdb/compiler-rt/test/builtins/Unit/comparedf2_test.c8// https://github.com/llvm/llvm-project/commit/d674d96bc56c0f377879d01c9d8dfdaaa7859cdb/compiler-rt/test/builtins/Unit/comparedf2_test.c
lib/std/special/compiler_rt/comparesf2_test.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Ported from:6// Ported from:
2//7//
3// https://github.com/llvm/llvm-project/commit/d674d96bc56c0f377879d01c9d8dfdaaa7859cdb/compiler-rt/test/builtins/Unit/comparesf2_test.c8// https://github.com/llvm/llvm-project/commit/d674d96bc56c0f377879d01c9d8dfdaaa7859cdb/compiler-rt/test/builtins/Unit/comparesf2_test.c
lib/std/special/compiler_rt/divdf3.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Ported from:6// Ported from:
2//7//
3// https://github.com/llvm/llvm-project/commit/d674d96bc56c0f377879d01c9d8dfdaaa7859cdb/compiler-rt/lib/builtins/divdf3.c8// https://github.com/llvm/llvm-project/commit/d674d96bc56c0f377879d01c9d8dfdaaa7859cdb/compiler-rt/lib/builtins/divdf3.c
lib/std/special/compiler_rt/divdf3_test.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Ported from:6// Ported from:
2//7//
3// https://github.com/llvm/llvm-project/commit/d674d96bc56c0f377879d01c9d8dfdaaa7859cdb/compiler-rt/test/builtins/Unit/divdf3_test.c8// https://github.com/llvm/llvm-project/commit/d674d96bc56c0f377879d01c9d8dfdaaa7859cdb/compiler-rt/test/builtins/Unit/divdf3_test.c
lib/std/special/compiler_rt/divsf3.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Ported from:6// Ported from:
2//7//
3// https://github.com/llvm/llvm-project/commit/d674d96bc56c0f377879d01c9d8dfdaaa7859cdb/compiler-rt/lib/builtins/divsf3.c8// https://github.com/llvm/llvm-project/commit/d674d96bc56c0f377879d01c9d8dfdaaa7859cdb/compiler-rt/lib/builtins/divsf3.c
lib/std/special/compiler_rt/divsf3_test.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Ported from:6// Ported from:
2//7//
3// https://github.com/llvm/llvm-project/commit/d674d96bc56c0f377879d01c9d8dfdaaa7859cdb/compiler-rt/test/builtins/Unit/divsf3_test.c8// https://github.com/llvm/llvm-project/commit/d674d96bc56c0f377879d01c9d8dfdaaa7859cdb/compiler-rt/test/builtins/Unit/divsf3_test.c
lib/std/special/compiler_rt/divtf3.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std");6const std = @import("std");
2const builtin = @import("builtin");7const builtin = @import("builtin");
38
lib/std/special/compiler_rt/divtf3_test.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std");6const std = @import("std");
2const math = std.math;7const math = std.math;
3const testing = std.testing;8const testing = std.testing;
lib/std/special/compiler_rt/divti3.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const udivmod = @import("udivmod.zig").udivmod;6const udivmod = @import("udivmod.zig").udivmod;
2const builtin = @import("builtin");7const builtin = @import("builtin");
38
lib/std/special/compiler_rt/divti3_test.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const __divti3 = @import("divti3.zig").__divti3;6const __divti3 = @import("divti3.zig").__divti3;
2const testing = @import("std").testing;7const testing = @import("std").testing;
38
lib/std/special/compiler_rt/extendXfYf2.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std");6const std = @import("std");
2const builtin = @import("builtin");7const builtin = @import("builtin");
3const is_test = builtin.is_test;8const is_test = builtin.is_test;
lib/std/special/compiler_rt/extendXfYf2_test.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const builtin = @import("builtin");6const builtin = @import("builtin");
2const __extenddftf2 = @import("extendXfYf2.zig").__extenddftf2;7const __extenddftf2 = @import("extendXfYf2.zig").__extenddftf2;
3const __extendhfsf2 = @import("extendXfYf2.zig").__extendhfsf2;8const __extendhfsf2 = @import("extendXfYf2.zig").__extendhfsf2;
lib/std/special/compiler_rt/fixdfdi.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const fixint = @import("fixint.zig").fixint;6const fixint = @import("fixint.zig").fixint;
2const builtin = @import("builtin");7const builtin = @import("builtin");
38
lib/std/special/compiler_rt/fixdfdi_test.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const __fixdfdi = @import("fixdfdi.zig").__fixdfdi;6const __fixdfdi = @import("fixdfdi.zig").__fixdfdi;
2const std = @import("std");7const std = @import("std");
3const math = std.math;8const math = std.math;
lib/std/special/compiler_rt/fixdfsi.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const fixint = @import("fixint.zig").fixint;6const fixint = @import("fixint.zig").fixint;
2const builtin = @import("builtin");7const builtin = @import("builtin");
38
lib/std/special/compiler_rt/fixdfsi_test.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const __fixdfsi = @import("fixdfsi.zig").__fixdfsi;6const __fixdfsi = @import("fixdfsi.zig").__fixdfsi;
2const std = @import("std");7const std = @import("std");
3const math = std.math;8const math = std.math;
lib/std/special/compiler_rt/fixdfti.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const fixint = @import("fixint.zig").fixint;6const fixint = @import("fixint.zig").fixint;
2const builtin = @import("builtin");7const builtin = @import("builtin");
38
lib/std/special/compiler_rt/fixdfti_test.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const __fixdfti = @import("fixdfti.zig").__fixdfti;6const __fixdfti = @import("fixdfti.zig").__fixdfti;
2const std = @import("std");7const std = @import("std");
3const math = std.math;8const math = std.math;
lib/std/special/compiler_rt/fixint.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const is_test = @import("builtin").is_test;6const is_test = @import("builtin").is_test;
2const std = @import("std");7const std = @import("std");
3const math = std.math;8const math = std.math;
lib/std/special/compiler_rt/fixint_test.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const is_test = @import("builtin").is_test;6const is_test = @import("builtin").is_test;
2const std = @import("std");7const std = @import("std");
3const math = std.math;8const math = std.math;
lib/std/special/compiler_rt/fixsfdi.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const fixint = @import("fixint.zig").fixint;6const fixint = @import("fixint.zig").fixint;
2const builtin = @import("builtin");7const builtin = @import("builtin");
38
lib/std/special/compiler_rt/fixsfdi_test.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const __fixsfdi = @import("fixsfdi.zig").__fixsfdi;6const __fixsfdi = @import("fixsfdi.zig").__fixsfdi;
2const std = @import("std");7const std = @import("std");
3const math = std.math;8const math = std.math;
lib/std/special/compiler_rt/fixsfsi.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const fixint = @import("fixint.zig").fixint;6const fixint = @import("fixint.zig").fixint;
2const builtin = @import("builtin");7const builtin = @import("builtin");
38
lib/std/special/compiler_rt/fixsfsi_test.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const __fixsfsi = @import("fixsfsi.zig").__fixsfsi;6const __fixsfsi = @import("fixsfsi.zig").__fixsfsi;
2const std = @import("std");7const std = @import("std");
3const math = std.math;8const math = std.math;
lib/std/special/compiler_rt/fixsfti.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const fixint = @import("fixint.zig").fixint;6const fixint = @import("fixint.zig").fixint;
2const builtin = @import("builtin");7const builtin = @import("builtin");
38
lib/std/special/compiler_rt/fixsfti_test.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const __fixsfti = @import("fixsfti.zig").__fixsfti;6const __fixsfti = @import("fixsfti.zig").__fixsfti;
2const std = @import("std");7const std = @import("std");
3const math = std.math;8const math = std.math;
lib/std/special/compiler_rt/fixtfdi.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const fixint = @import("fixint.zig").fixint;6const fixint = @import("fixint.zig").fixint;
2const builtin = @import("builtin");7const builtin = @import("builtin");
38
lib/std/special/compiler_rt/fixtfdi_test.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const __fixtfdi = @import("fixtfdi.zig").__fixtfdi;6const __fixtfdi = @import("fixtfdi.zig").__fixtfdi;
2const std = @import("std");7const std = @import("std");
3const math = std.math;8const math = std.math;
lib/std/special/compiler_rt/fixtfsi.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const fixint = @import("fixint.zig").fixint;6const fixint = @import("fixint.zig").fixint;
2const builtin = @import("builtin");7const builtin = @import("builtin");
38
lib/std/special/compiler_rt/fixtfsi_test.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const __fixtfsi = @import("fixtfsi.zig").__fixtfsi;6const __fixtfsi = @import("fixtfsi.zig").__fixtfsi;
2const std = @import("std");7const std = @import("std");
3const math = std.math;8const math = std.math;
lib/std/special/compiler_rt/fixtfti.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const fixint = @import("fixint.zig").fixint;6const fixint = @import("fixint.zig").fixint;
2const builtin = @import("builtin");7const builtin = @import("builtin");
38
lib/std/special/compiler_rt/fixtfti_test.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const __fixtfti = @import("fixtfti.zig").__fixtfti;6const __fixtfti = @import("fixtfti.zig").__fixtfti;
2const std = @import("std");7const std = @import("std");
3const math = std.math;8const math = std.math;
lib/std/special/compiler_rt/fixuint.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const is_test = @import("builtin").is_test;6const is_test = @import("builtin").is_test;
2const Log2Int = @import("std").math.Log2Int;7const Log2Int = @import("std").math.Log2Int;
38
lib/std/special/compiler_rt/fixunsdfdi.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const fixuint = @import("fixuint.zig").fixuint;6const fixuint = @import("fixuint.zig").fixuint;
2const builtin = @import("builtin");7const builtin = @import("builtin");
38
lib/std/special/compiler_rt/fixunsdfdi_test.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const __fixunsdfdi = @import("fixunsdfdi.zig").__fixunsdfdi;6const __fixunsdfdi = @import("fixunsdfdi.zig").__fixunsdfdi;
2const testing = @import("std").testing;7const testing = @import("std").testing;
38
lib/std/special/compiler_rt/fixunsdfsi.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const fixuint = @import("fixuint.zig").fixuint;6const fixuint = @import("fixuint.zig").fixuint;
2const builtin = @import("builtin");7const builtin = @import("builtin");
38
lib/std/special/compiler_rt/fixunsdfsi_test.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const __fixunsdfsi = @import("fixunsdfsi.zig").__fixunsdfsi;6const __fixunsdfsi = @import("fixunsdfsi.zig").__fixunsdfsi;
2const testing = @import("std").testing;7const testing = @import("std").testing;
38
lib/std/special/compiler_rt/fixunsdfti.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const fixuint = @import("fixuint.zig").fixuint;6const fixuint = @import("fixuint.zig").fixuint;
2const builtin = @import("builtin");7const builtin = @import("builtin");
38
lib/std/special/compiler_rt/fixunsdfti_test.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const __fixunsdfti = @import("fixunsdfti.zig").__fixunsdfti;6const __fixunsdfti = @import("fixunsdfti.zig").__fixunsdfti;
2const testing = @import("std").testing;7const testing = @import("std").testing;
38
lib/std/special/compiler_rt/fixunssfdi.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const fixuint = @import("fixuint.zig").fixuint;6const fixuint = @import("fixuint.zig").fixuint;
2const builtin = @import("builtin");7const builtin = @import("builtin");
38
lib/std/special/compiler_rt/fixunssfdi_test.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const __fixunssfdi = @import("fixunssfdi.zig").__fixunssfdi;6const __fixunssfdi = @import("fixunssfdi.zig").__fixunssfdi;
2const testing = @import("std").testing;7const testing = @import("std").testing;
38
lib/std/special/compiler_rt/fixunssfsi.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const fixuint = @import("fixuint.zig").fixuint;6const fixuint = @import("fixuint.zig").fixuint;
2const builtin = @import("builtin");7const builtin = @import("builtin");
38
lib/std/special/compiler_rt/fixunssfsi_test.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const __fixunssfsi = @import("fixunssfsi.zig").__fixunssfsi;6const __fixunssfsi = @import("fixunssfsi.zig").__fixunssfsi;
2const testing = @import("std").testing;7const testing = @import("std").testing;
38
lib/std/special/compiler_rt/fixunssfti.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const fixuint = @import("fixuint.zig").fixuint;6const fixuint = @import("fixuint.zig").fixuint;
2const builtin = @import("builtin");7const builtin = @import("builtin");
38
lib/std/special/compiler_rt/fixunssfti_test.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const __fixunssfti = @import("fixunssfti.zig").__fixunssfti;6const __fixunssfti = @import("fixunssfti.zig").__fixunssfti;
2const testing = @import("std").testing;7const testing = @import("std").testing;
38
lib/std/special/compiler_rt/fixunstfdi.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const fixuint = @import("fixuint.zig").fixuint;6const fixuint = @import("fixuint.zig").fixuint;
2const builtin = @import("builtin");7const builtin = @import("builtin");
38
lib/std/special/compiler_rt/fixunstfdi_test.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const __fixunstfdi = @import("fixunstfdi.zig").__fixunstfdi;6const __fixunstfdi = @import("fixunstfdi.zig").__fixunstfdi;
2const testing = @import("std").testing;7const testing = @import("std").testing;
38
lib/std/special/compiler_rt/fixunstfsi.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const fixuint = @import("fixuint.zig").fixuint;6const fixuint = @import("fixuint.zig").fixuint;
2const builtin = @import("builtin");7const builtin = @import("builtin");
38
lib/std/special/compiler_rt/fixunstfsi_test.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const __fixunstfsi = @import("fixunstfsi.zig").__fixunstfsi;6const __fixunstfsi = @import("fixunstfsi.zig").__fixunstfsi;
2const testing = @import("std").testing;7const testing = @import("std").testing;
38
lib/std/special/compiler_rt/fixunstfti.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const fixuint = @import("fixuint.zig").fixuint;6const fixuint = @import("fixuint.zig").fixuint;
2const builtin = @import("builtin");7const builtin = @import("builtin");
38
lib/std/special/compiler_rt/fixunstfti_test.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const __fixunstfti = @import("fixunstfti.zig").__fixunstfti;6const __fixunstfti = @import("fixunstfti.zig").__fixunstfti;
2const testing = @import("std").testing;7const testing = @import("std").testing;
38
lib/std/special/compiler_rt/floatdidf.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const builtin = @import("builtin");6const builtin = @import("builtin");
2const std = @import("std");7const std = @import("std");
38
lib/std/special/compiler_rt/floatdidf_test.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const __floatdidf = @import("floatdidf.zig").__floatdidf;6const __floatdidf = @import("floatdidf.zig").__floatdidf;
2const testing = @import("std").testing;7const testing = @import("std").testing;
38
lib/std/special/compiler_rt/floatditf.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const builtin = @import("builtin");6const builtin = @import("builtin");
2const is_test = builtin.is_test;7const is_test = builtin.is_test;
3const std = @import("std");8const std = @import("std");
lib/std/special/compiler_rt/floatditf_test.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const __floatditf = @import("floatditf.zig").__floatditf;6const __floatditf = @import("floatditf.zig").__floatditf;
2const testing = @import("std").testing;7const testing = @import("std").testing;
38
lib/std/special/compiler_rt/floatsiXf.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const builtin = @import("builtin");6const builtin = @import("builtin");
2const std = @import("std");7const std = @import("std");
3const maxInt = std.math.maxInt;8const maxInt = std.math.maxInt;
lib/std/special/compiler_rt/floattidf.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const builtin = @import("builtin");6const builtin = @import("builtin");
2const is_test = builtin.is_test;7const is_test = builtin.is_test;
3const std = @import("std");8const std = @import("std");
lib/std/special/compiler_rt/floattidf_test.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const __floattidf = @import("floattidf.zig").__floattidf;6const __floattidf = @import("floattidf.zig").__floattidf;
2const testing = @import("std").testing;7const testing = @import("std").testing;
38
lib/std/special/compiler_rt/floattisf.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const builtin = @import("builtin");6const builtin = @import("builtin");
2const is_test = builtin.is_test;7const is_test = builtin.is_test;
3const std = @import("std");8const std = @import("std");
lib/std/special/compiler_rt/floattisf_test.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const __floattisf = @import("floattisf.zig").__floattisf;6const __floattisf = @import("floattisf.zig").__floattisf;
2const testing = @import("std").testing;7const testing = @import("std").testing;
38
lib/std/special/compiler_rt/floattitf.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const builtin = @import("builtin");6const builtin = @import("builtin");
2const is_test = builtin.is_test;7const is_test = builtin.is_test;
3const std = @import("std");8const std = @import("std");
lib/std/special/compiler_rt/floattitf_test.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const __floattitf = @import("floattitf.zig").__floattitf;6const __floattitf = @import("floattitf.zig").__floattitf;
2const testing = @import("std").testing;7const testing = @import("std").testing;
38
lib/std/special/compiler_rt/floatundidf.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const builtin = @import("builtin");6const builtin = @import("builtin");
2const std = @import("std");7const std = @import("std");
38
lib/std/special/compiler_rt/floatundidf_test.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const __floatundidf = @import("floatundidf.zig").__floatundidf;6const __floatundidf = @import("floatundidf.zig").__floatundidf;
2const testing = @import("std").testing;7const testing = @import("std").testing;
38
lib/std/special/compiler_rt/floatundisf.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const builtin = @import("builtin");6const builtin = @import("builtin");
2const std = @import("std");7const std = @import("std");
3const maxInt = std.math.maxInt;8const maxInt = std.math.maxInt;
lib/std/special/compiler_rt/floatunditf.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const builtin = @import("builtin");6const builtin = @import("builtin");
2const is_test = builtin.is_test;7const is_test = builtin.is_test;
3const std = @import("std");8const std = @import("std");
lib/std/special/compiler_rt/floatunditf_test.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const __floatunditf = @import("floatunditf.zig").__floatunditf;6const __floatunditf = @import("floatunditf.zig").__floatunditf;
27
3fn test__floatunditf(a: u64, expected_hi: u64, expected_lo: u64) void {8fn test__floatunditf(a: u64, expected_hi: u64, expected_lo: u64) void {
lib/std/special/compiler_rt/floatunsidf.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const builtin = @import("builtin");6const builtin = @import("builtin");
2const std = @import("std");7const std = @import("std");
3const maxInt = std.math.maxInt;8const maxInt = std.math.maxInt;
lib/std/special/compiler_rt/floatunsisf.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const builtin = @import("builtin");6const builtin = @import("builtin");
2const std = @import("std");7const std = @import("std");
3const maxInt = std.math.maxInt;8const maxInt = std.math.maxInt;
lib/std/special/compiler_rt/floatunsitf.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const builtin = @import("builtin");6const builtin = @import("builtin");
2const is_test = builtin.is_test;7const is_test = builtin.is_test;
3const std = @import("std");8const std = @import("std");
lib/std/special/compiler_rt/floatunsitf_test.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const __floatunsitf = @import("floatunsitf.zig").__floatunsitf;6const __floatunsitf = @import("floatunsitf.zig").__floatunsitf;
27
3fn test__floatunsitf(a: u64, expected_hi: u64, expected_lo: u64) void {8fn test__floatunsitf(a: u64, expected_hi: u64, expected_lo: u64) void {
lib/std/special/compiler_rt/floatuntidf.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const builtin = @import("builtin");6const builtin = @import("builtin");
2const is_test = builtin.is_test;7const is_test = builtin.is_test;
3const std = @import("std");8const std = @import("std");
lib/std/special/compiler_rt/floatuntidf_test.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const __floatuntidf = @import("floatuntidf.zig").__floatuntidf;6const __floatuntidf = @import("floatuntidf.zig").__floatuntidf;
2const testing = @import("std").testing;7const testing = @import("std").testing;
38
lib/std/special/compiler_rt/floatuntisf.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const builtin = @import("builtin");6const builtin = @import("builtin");
2const is_test = builtin.is_test;7const is_test = builtin.is_test;
3const std = @import("std");8const std = @import("std");
lib/std/special/compiler_rt/floatuntisf_test.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const __floatuntisf = @import("floatuntisf.zig").__floatuntisf;6const __floatuntisf = @import("floatuntisf.zig").__floatuntisf;
2const testing = @import("std").testing;7const testing = @import("std").testing;
38
lib/std/special/compiler_rt/floatuntitf.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const builtin = @import("builtin");6const builtin = @import("builtin");
2const is_test = builtin.is_test;7const is_test = builtin.is_test;
3const std = @import("std");8const std = @import("std");
lib/std/special/compiler_rt/floatuntitf_test.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const __floatuntitf = @import("floatuntitf.zig").__floatuntitf;6const __floatuntitf = @import("floatuntitf.zig").__floatuntitf;
2const testing = @import("std").testing;7const testing = @import("std").testing;
38
lib/std/special/compiler_rt/int.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Builtin functions that operate on integer types6// Builtin functions that operate on integer types
2const builtin = @import("builtin");7const builtin = @import("builtin");
3const testing = @import("std").testing;8const testing = @import("std").testing;
lib/std/special/compiler_rt/lshrdi3_test.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const __lshrdi3 = @import("shift.zig").__lshrdi3;6const __lshrdi3 = @import("shift.zig").__lshrdi3;
2const testing = @import("std").testing;7const testing = @import("std").testing;
38
lib/std/special/compiler_rt/lshrti3_test.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const __lshrti3 = @import("shift.zig").__lshrti3;6const __lshrti3 = @import("shift.zig").__lshrti3;
2const testing = @import("std").testing;7const testing = @import("std").testing;
38
lib/std/special/compiler_rt/modti3.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Ported from:6// Ported from:
2//7//
3// https://github.com/llvm/llvm-project/blob/2ffb1b0413efa9a24eb3c49e710e36f92e2cb50b/compiler-rt/lib/builtins/modti3.c8// https://github.com/llvm/llvm-project/blob/2ffb1b0413efa9a24eb3c49e710e36f92e2cb50b/compiler-rt/lib/builtins/modti3.c
lib/std/special/compiler_rt/modti3_test.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const __modti3 = @import("modti3.zig").__modti3;6const __modti3 = @import("modti3.zig").__modti3;
2const testing = @import("std").testing;7const testing = @import("std").testing;
38
lib/std/special/compiler_rt/mulXf3.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Ported from:6// Ported from:
2//7//
3// https://github.com/llvm/llvm-project/blob/2ffb1b0413efa9a24eb3c49e710e36f92e2cb50b/compiler-rt/lib/builtins/fp_mul_impl.inc8// https://github.com/llvm/llvm-project/blob/2ffb1b0413efa9a24eb3c49e710e36f92e2cb50b/compiler-rt/lib/builtins/fp_mul_impl.inc
lib/std/special/compiler_rt/mulXf3_test.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Ported from:6// Ported from:
2//7//
3// https://github.com/llvm/llvm-project/blob/2ffb1b0413efa9a24eb3c49e710e36f92e2cb50b/compiler-rt/test/builtins/Unit/multf3_test.c8// https://github.com/llvm/llvm-project/blob/2ffb1b0413efa9a24eb3c49e710e36f92e2cb50b/compiler-rt/test/builtins/Unit/multf3_test.c
lib/std/special/compiler_rt/muldi3.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const builtin = @import("builtin");6const builtin = @import("builtin");
27
3// Ported from8// Ported from
lib/std/special/compiler_rt/muldi3_test.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const __muldi3 = @import("muldi3.zig").__muldi3;6const __muldi3 = @import("muldi3.zig").__muldi3;
2const testing = @import("std").testing;7const testing = @import("std").testing;
38
lib/std/special/compiler_rt/mulodi4.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const builtin = @import("builtin");6const builtin = @import("builtin");
2const compiler_rt = @import("../compiler_rt.zig");7const compiler_rt = @import("../compiler_rt.zig");
3const maxInt = std.math.maxInt;8const maxInt = std.math.maxInt;
lib/std/special/compiler_rt/mulodi4_test.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const __mulodi4 = @import("mulodi4.zig").__mulodi4;6const __mulodi4 = @import("mulodi4.zig").__mulodi4;
2const testing = @import("std").testing;7const testing = @import("std").testing;
38
lib/std/special/compiler_rt/muloti4.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const builtin = @import("builtin");6const builtin = @import("builtin");
2const compiler_rt = @import("../compiler_rt.zig");7const compiler_rt = @import("../compiler_rt.zig");
38
lib/std/special/compiler_rt/muloti4_test.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const __muloti4 = @import("muloti4.zig").__muloti4;6const __muloti4 = @import("muloti4.zig").__muloti4;
2const testing = @import("std").testing;7const testing = @import("std").testing;
38
lib/std/special/compiler_rt/multi3.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const builtin = @import("builtin");6const builtin = @import("builtin");
2const compiler_rt = @import("../compiler_rt.zig");7const compiler_rt = @import("../compiler_rt.zig");
38
lib/std/special/compiler_rt/multi3_test.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const __multi3 = @import("multi3.zig").__multi3;6const __multi3 = @import("multi3.zig").__multi3;
2const testing = @import("std").testing;7const testing = @import("std").testing;
38
lib/std/special/compiler_rt/negXf2.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std");6const std = @import("std");
27
3pub fn __negsf2(a: f32) callconv(.C) f32 {8pub fn __negsf2(a: f32) callconv(.C) f32 {
lib/std/special/compiler_rt/popcountdi2.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const builtin = @import("builtin");6const builtin = @import("builtin");
2const compiler_rt = @import("../compiler_rt.zig");7const compiler_rt = @import("../compiler_rt.zig");
38
lib/std/special/compiler_rt/popcountdi2_test.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const __popcountdi2 = @import("popcountdi2.zig").__popcountdi2;6const __popcountdi2 = @import("popcountdi2.zig").__popcountdi2;
2const testing = @import("std").testing;7const testing = @import("std").testing;
38
lib/std/special/compiler_rt/shift.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std");6const std = @import("std");
2const builtin = std.builtin;7const builtin = std.builtin;
3const Log2Int = std.math.Log2Int;8const Log2Int = std.math.Log2Int;
lib/std/special/compiler_rt/stack_probe.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const builtin = @import("builtin");6const builtin = @import("builtin");
27
3// Zig's own stack-probe routine (available only on x86 and x86_64)8// Zig's own stack-probe routine (available only on x86 and x86_64)
lib/std/special/compiler_rt/truncXfYf2.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std");6const std = @import("std");
27
3pub fn __truncsfhf2(a: f32) callconv(.C) u16 {8pub fn __truncsfhf2(a: f32) callconv(.C) u16 {
lib/std/special/compiler_rt/truncXfYf2_test.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const __truncsfhf2 = @import("truncXfYf2.zig").__truncsfhf2;6const __truncsfhf2 = @import("truncXfYf2.zig").__truncsfhf2;
27
3fn test__truncsfhf2(a: u32, expected: u16) void {8fn test__truncsfhf2(a: u32, expected: u16) void {
lib/std/special/compiler_rt/udivmod.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const builtin = @import("builtin");6const builtin = @import("builtin");
2const is_test = builtin.is_test;7const is_test = builtin.is_test;
38
lib/std/special/compiler_rt/udivmoddi4_test.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Disable formatting to avoid unnecessary source repository bloat.6// Disable formatting to avoid unnecessary source repository bloat.
2// zig fmt: off7// zig fmt: off
3const __udivmoddi4 = @import("int.zig").__udivmoddi4;8const __udivmoddi4 = @import("int.zig").__udivmoddi4;
lib/std/special/compiler_rt/udivmodti4.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const udivmod = @import("udivmod.zig").udivmod;6const udivmod = @import("udivmod.zig").udivmod;
2const builtin = @import("builtin");7const builtin = @import("builtin");
3const compiler_rt = @import("../compiler_rt.zig");8const compiler_rt = @import("../compiler_rt.zig");
lib/std/special/compiler_rt/udivmodti4_test.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// Disable formatting to avoid unnecessary source repository bloat.6// Disable formatting to avoid unnecessary source repository bloat.
2// zig fmt: off7// zig fmt: off
3const __udivmodti4 = @import("udivmodti4.zig").__udivmodti4;8const __udivmodti4 = @import("udivmodti4.zig").__udivmodti4;
lib/std/special/compiler_rt/udivti3.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const udivmodti4 = @import("udivmodti4.zig");6const udivmodti4 = @import("udivmodti4.zig");
2const builtin = @import("builtin");7const builtin = @import("builtin");
38
lib/std/special/compiler_rt/umodti3.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const udivmodti4 = @import("udivmodti4.zig");6const udivmodti4 = @import("udivmodti4.zig");
2const builtin = @import("builtin");7const builtin = @import("builtin");
3const compiler_rt = @import("../compiler_rt.zig");8const compiler_rt = @import("../compiler_rt.zig");
lib/std/special/init-exe/build.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const Builder = @import("std").build.Builder;6const Builder = @import("std").build.Builder;
27
3pub fn build(b: *Builder) void {8pub fn build(b: *Builder) void {
lib/std/special/init-exe/src/main.zig+6-1
...@@ -1,5 +1,10 @@...@@ -1,5 +1,10 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std");6const std = @import("std");
27
3pub fn main() anyerror!void {8pub fn main() anyerror!void {
4 std.debug.warn("All your codebase are belong to us.\n", .{});9 std.log.info("All your codebase are belong to us.", .{});
5}10}
lib/std/special/init-lib/build.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const Builder = @import("std").build.Builder;6const Builder = @import("std").build.Builder;
27
3pub fn build(b: *Builder) void {8pub fn build(b: *Builder) void {
lib/std/special/init-lib/src/main.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std");6const std = @import("std");
2const testing = std.testing;7const testing = std.testing;
38
lib/std/special/test_runner.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std");6const std = @import("std");
2const io = std.io;7const io = std.io;
3const builtin = @import("builtin");8const builtin = @import("builtin");
lib/std/spinlock.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std.zig");6const std = @import("std.zig");
2const builtin = @import("builtin");7const builtin = @import("builtin");
38
lib/std/start.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1// This file is included in the compilation unit when exporting an executable.6// This file is included in the compilation unit when exporting an executable.
27
3const root = @import("root");8const root = @import("root");
lib/std/start_windows_tls.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std");6const std = @import("std");
2const builtin = std.builtin;7const builtin = std.builtin;
38
lib/std/std.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1pub const ArrayList = @import("array_list.zig").ArrayList;6pub const ArrayList = @import("array_list.zig").ArrayList;
2pub const ArrayListAligned = @import("array_list.zig").ArrayListAligned;7pub const ArrayListAligned = @import("array_list.zig").ArrayListAligned;
3pub const ArrayListAlignedUnmanaged = @import("array_list.zig").ArrayListAlignedUnmanaged;8pub const ArrayListAlignedUnmanaged = @import("array_list.zig").ArrayListAlignedUnmanaged;
lib/std/target.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std.zig");6const std = @import("std.zig");
2const mem = std.mem;7const mem = std.mem;
3const builtin = std.builtin;8const builtin = std.builtin;
lib/std/target/aarch64.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const CpuFeature = std.Target.Cpu.Feature;7const CpuFeature = std.Target.Cpu.Feature;
3const CpuModel = std.Target.Cpu.Model;8const CpuModel = std.Target.Cpu.Model;
lib/std/target/amdgpu.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const CpuFeature = std.Target.Cpu.Feature;7const CpuFeature = std.Target.Cpu.Feature;
3const CpuModel = std.Target.Cpu.Model;8const CpuModel = std.Target.Cpu.Model;
lib/std/target/arm.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const CpuFeature = std.Target.Cpu.Feature;7const CpuFeature = std.Target.Cpu.Feature;
3const CpuModel = std.Target.Cpu.Model;8const CpuModel = std.Target.Cpu.Model;
lib/std/target/avr.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const CpuFeature = std.Target.Cpu.Feature;7const CpuFeature = std.Target.Cpu.Feature;
3const CpuModel = std.Target.Cpu.Model;8const CpuModel = std.Target.Cpu.Model;
lib/std/target/bpf.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const CpuFeature = std.Target.Cpu.Feature;7const CpuFeature = std.Target.Cpu.Feature;
3const CpuModel = std.Target.Cpu.Model;8const CpuModel = std.Target.Cpu.Model;
lib/std/target/hexagon.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const CpuFeature = std.Target.Cpu.Feature;7const CpuFeature = std.Target.Cpu.Feature;
3const CpuModel = std.Target.Cpu.Model;8const CpuModel = std.Target.Cpu.Model;
lib/std/target/mips.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const CpuFeature = std.Target.Cpu.Feature;7const CpuFeature = std.Target.Cpu.Feature;
3const CpuModel = std.Target.Cpu.Model;8const CpuModel = std.Target.Cpu.Model;
lib/std/target/msp430.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const CpuFeature = std.Target.Cpu.Feature;7const CpuFeature = std.Target.Cpu.Feature;
3const CpuModel = std.Target.Cpu.Model;8const CpuModel = std.Target.Cpu.Model;
lib/std/target/nvptx.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const CpuFeature = std.Target.Cpu.Feature;7const CpuFeature = std.Target.Cpu.Feature;
3const CpuModel = std.Target.Cpu.Model;8const CpuModel = std.Target.Cpu.Model;
lib/std/target/powerpc.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const CpuFeature = std.Target.Cpu.Feature;7const CpuFeature = std.Target.Cpu.Feature;
3const CpuModel = std.Target.Cpu.Model;8const CpuModel = std.Target.Cpu.Model;
lib/std/target/riscv.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const CpuFeature = std.Target.Cpu.Feature;7const CpuFeature = std.Target.Cpu.Feature;
3const CpuModel = std.Target.Cpu.Model;8const CpuModel = std.Target.Cpu.Model;
lib/std/target/sparc.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const CpuFeature = std.Target.Cpu.Feature;7const CpuFeature = std.Target.Cpu.Feature;
3const CpuModel = std.Target.Cpu.Model;8const CpuModel = std.Target.Cpu.Model;
lib/std/target/systemz.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const CpuFeature = std.Target.Cpu.Feature;7const CpuFeature = std.Target.Cpu.Feature;
3const CpuModel = std.Target.Cpu.Model;8const CpuModel = std.Target.Cpu.Model;
lib/std/target/wasm.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const CpuFeature = std.Target.Cpu.Feature;7const CpuFeature = std.Target.Cpu.Feature;
3const CpuModel = std.Target.Cpu.Model;8const CpuModel = std.Target.Cpu.Model;
lib/std/target/x86.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const CpuFeature = std.Target.Cpu.Feature;7const CpuFeature = std.Target.Cpu.Feature;
3const CpuModel = std.Target.Cpu.Model;8const CpuModel = std.Target.Cpu.Model;
lib/std/testing.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std.zig");6const std = @import("std.zig");
2const print = std.debug.print;7const print = std.debug.print;
38
lib/std/testing/failing_allocator.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const mem = std.mem;7const mem = std.mem;
38
lib/std/thread.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std.zig");6const std = @import("std.zig");
2const builtin = std.builtin;7const builtin = std.builtin;
3const os = std.os;8const os = std.os;
lib/std/time.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std.zig");6const std = @import("std.zig");
2const builtin = std.builtin;7const builtin = std.builtin;
3const assert = std.debug.assert;8const assert = std.debug.assert;
lib/std/time/epoch.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1//! Epoch reference times in terms of their difference from6//! Epoch reference times in terms of their difference from
2//! UTC 1970-01-01 in seconds.7//! UTC 1970-01-01 in seconds.
38
lib/std/unicode.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("./std.zig");6const std = @import("./std.zig");
2const builtin = @import("builtin");7const builtin = @import("builtin");
3const assert = std.debug.assert;8const assert = std.debug.assert;
lib/std/unicode/throughput_test.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const builtin = @import("builtin");6const builtin = @import("builtin");
2const std = @import("std");7const std = @import("std");
38
lib/std/valgrind.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const builtin = @import("builtin");6const builtin = @import("builtin");
2const std = @import("std.zig");7const std = @import("std.zig");
3const math = std.math;8const math = std.math;
lib/std/valgrind/callgrind.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const valgrind = std.valgrind;7const valgrind = std.valgrind;
38
lib/std/valgrind/memcheck.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const testing = std.testing;7const testing = std.testing;
3const valgrind = std.valgrind;8const valgrind = std.valgrind;
lib/std/zig.zig+115-1
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std.zig");6const std = @import("std.zig");
2const tokenizer = @import("zig/tokenizer.zig");7const tokenizer = @import("zig/tokenizer.zig");
38
...@@ -21,7 +26,7 @@ pub fn hashSrc(src: []const u8) SrcHash {...@@ -21,7 +26,7 @@ pub fn hashSrc(src: []const u8) SrcHash {
21 std.mem.copy(u8, &out, src);26 std.mem.copy(u8, &out, src);
22 std.mem.set(u8, out[src.len..], 0);27 std.mem.set(u8, out[src.len..], 0);
23 } else {28 } else {
24 std.crypto.Blake3.hash(src, &out);29 std.crypto.hash.Blake3.hash(src, &out, .{});
25 }30 }
26 return out;31 return out;
27}32}
...@@ -80,6 +85,115 @@ pub fn binNameAlloc(...@@ -80,6 +85,115 @@ pub fn binNameAlloc(
80 }85 }
81}86}
8287
88/// Only validates escape sequence characters.
89/// Slice must be valid utf8 starting and ending with "'" and exactly one codepoint in between.
90pub fn parseCharLiteral(
91 slice: []const u8,
92 bad_index: *usize, // populated if error.InvalidCharacter is returned
93) error{InvalidCharacter}!u32 {
94 std.debug.assert(slice.len >= 3 and slice[0] == '\'' and slice[slice.len - 1] == '\'');
95
96 if (slice[1] == '\\') {
97 switch (slice[2]) {
98 'n' => return '\n',
99 'r' => return '\r',
100 '\\' => return '\\',
101 't' => return '\t',
102 '\'' => return '\'',
103 '"' => return '"',
104 'x' => {
105 if (slice.len != 6) {
106 bad_index.* = slice.len - 2;
107 return error.InvalidCharacter;
108 }
109 var value: u32 = 0;
110 for (slice[3..5]) |c, i| {
111 switch (c) {
112 '0'...'9' => {
113 value *= 16;
114 value += c - '0';
115 },
116 'a'...'f' => {
117 value *= 16;
118 value += c - 'a' + 10;
119 },
120 'A'...'F' => {
121 value *= 16;
122 value += c - 'A' + 10;
123 },
124 else => {
125 bad_index.* = 3 + i;
126 return error.InvalidCharacter;
127 },
128 }
129 }
130 return value;
131 },
132 'u' => {
133 if (slice.len < "'\\u{0}'".len or slice[3] != '{' or slice[slice.len - 2] != '}') {
134 bad_index.* = 2;
135 return error.InvalidCharacter;
136 }
137 var value: u32 = 0;
138 for (slice[4 .. slice.len - 2]) |c, i| {
139 switch (c) {
140 '0'...'9' => {
141 value *= 16;
142 value += c - '0';
143 },
144 'a'...'f' => {
145 value *= 16;
146 value += c - 'a' + 10;
147 },
148 'A'...'F' => {
149 value *= 16;
150 value += c - 'A' + 10;
151 },
152 else => {
153 bad_index.* = 4 + i;
154 return error.InvalidCharacter;
155 },
156 }
157 if (value > 0x10ffff) {
158 bad_index.* = 4 + i;
159 return error.InvalidCharacter;
160 }
161 }
162 return value;
163 },
164 else => {
165 bad_index.* = 2;
166 return error.InvalidCharacter;
167 },
168 }
169 }
170 return std.unicode.utf8Decode(slice[1 .. slice.len - 1]) catch unreachable;
171}
172
173test "parseCharLiteral" {
174 var bad_index: usize = undefined;
175 std.testing.expectEqual(try parseCharLiteral("'a'", &bad_index), 'a');
176 std.testing.expectEqual(try parseCharLiteral("'ä'", &bad_index), 'ä');
177 std.testing.expectEqual(try parseCharLiteral("'\\x00'", &bad_index), 0);
178 std.testing.expectEqual(try parseCharLiteral("'\\x4f'", &bad_index), 0x4f);
179 std.testing.expectEqual(try parseCharLiteral("'\\x4F'", &bad_index), 0x4f);
180 std.testing.expectEqual(try parseCharLiteral("'ぁ'", &bad_index), 0x3041);
181 std.testing.expectEqual(try parseCharLiteral("'\\u{0}'", &bad_index), 0);
182 std.testing.expectEqual(try parseCharLiteral("'\\u{3041}'", &bad_index), 0x3041);
183 std.testing.expectEqual(try parseCharLiteral("'\\u{7f}'", &bad_index), 0x7f);
184 std.testing.expectEqual(try parseCharLiteral("'\\u{7FFF}'", &bad_index), 0x7FFF);
185
186 std.testing.expectError(error.InvalidCharacter, parseCharLiteral("'\\x0'", &bad_index));
187 std.testing.expectError(error.InvalidCharacter, parseCharLiteral("'\\x000'", &bad_index));
188 std.testing.expectError(error.InvalidCharacter, parseCharLiteral("'\\y'", &bad_index));
189 std.testing.expectError(error.InvalidCharacter, parseCharLiteral("'\\u'", &bad_index));
190 std.testing.expectError(error.InvalidCharacter, parseCharLiteral("'\\uFFFF'", &bad_index));
191 std.testing.expectError(error.InvalidCharacter, parseCharLiteral("'\\u{}'", &bad_index));
192 std.testing.expectError(error.InvalidCharacter, parseCharLiteral("'\\u{FFFFFF}'", &bad_index));
193 std.testing.expectError(error.InvalidCharacter, parseCharLiteral("'\\u{FFFF'", &bad_index));
194 std.testing.expectError(error.InvalidCharacter, parseCharLiteral("'\\u{FFFF}x'", &bad_index));
195}
196
83test "" {197test "" {
84 @import("std").meta.refAllDecls(@This());198 @import("std").meta.refAllDecls(@This());
85}199}
lib/std/zig/ast.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const assert = std.debug.assert;7const assert = std.debug.assert;
3const testing = std.testing;8const testing = std.testing;
lib/std/zig/cross_target.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const assert = std.debug.assert;7const assert = std.debug.assert;
3const Target = std.Target;8const Target = std.Target;
lib/std/zig/parse.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const assert = std.debug.assert;7const assert = std.debug.assert;
3const Allocator = std.mem.Allocator;8const Allocator = std.mem.Allocator;
lib/std/zig/parser_test.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1test "zig fmt: convert var to anytype" {6test "zig fmt: convert var to anytype" {
2 // TODO remove in next release cycle7 // TODO remove in next release cycle
3 try testTransform(8 try testTransform(
lib/std/zig/perf_test.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std");6const std = @import("std");
2const mem = std.mem;7const mem = std.mem;
3const warn = std.debug.warn;8const warn = std.debug.warn;
lib/std/zig/render.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const assert = std.debug.assert;7const assert = std.debug.assert;
3const mem = std.mem;8const mem = std.mem;
lib/std/zig/string_literal.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const assert = std.debug.assert;7const assert = std.debug.assert;
38
lib/std/zig/system.zig+6
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const elf = std.elf;7const elf = std.elf;
3const mem = std.mem;8const mem = std.mem;
...@@ -857,6 +862,7 @@ pub const NativeTargetInfo = struct {...@@ -857,6 +862,7 @@ pub const NativeTargetInfo = struct {
857 const len = file.pread(buf[i .. buf.len - i], offset + i) catch |err| switch (err) {862 const len = file.pread(buf[i .. buf.len - i], offset + i) catch |err| switch (err) {
858 error.OperationAborted => unreachable, // Windows-only863 error.OperationAborted => unreachable, // Windows-only
859 error.WouldBlock => unreachable, // Did not request blocking mode864 error.WouldBlock => unreachable, // Did not request blocking mode
865 error.NotOpenForReading => unreachable,
860 error.SystemResources => return error.SystemResources,866 error.SystemResources => return error.SystemResources,
861 error.IsDir => return error.UnableToReadElfFile,867 error.IsDir => return error.UnableToReadElfFile,
862 error.BrokenPipe => return error.UnableToReadElfFile,868 error.BrokenPipe => return error.UnableToReadElfFile,
lib/std/zig/system/macos.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std");6const std = @import("std");
27
3pub fn version_from_build(build: []const u8) !std.builtin.Version {8pub fn version_from_build(build: []const u8) !std.builtin.Version {
lib/std/zig/system/x86.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("std");6const std = @import("std");
2const Target = std.Target;7const Target = std.Target;
3const CrossTarget = std.zig.CrossTarget;8const CrossTarget = std.zig.CrossTarget;
lib/std/zig/tokenizer.zig+5
...@@ -1,3 +1,8 @@...@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
1const std = @import("../std.zig");6const std = @import("../std.zig");
2const mem = std.mem;7const mem = std.mem;
38
src-self-hosted/Module.zig+412-14
...@@ -170,6 +170,9 @@ pub const Decl = struct {...@@ -170,6 +170,9 @@ pub const Decl = struct {
170 /// This flag is set when this Decl is added to a check_for_deletion set, and cleared170 /// This flag is set when this Decl is added to a check_for_deletion set, and cleared
171 /// when removed.171 /// when removed.
172 deletion_flag: bool,172 deletion_flag: bool,
173 /// Whether the corresponding AST decl has a `pub` keyword.
174 is_pub: bool,
175
173 /// An integer that can be checked against the corresponding incrementing176 /// An integer that can be checked against the corresponding incrementing
174 /// generation field of Module. This is used to determine whether `complete` status177 /// generation field of Module. This is used to determine whether `complete` status
175 /// represents pre- or post- re-analysis.178 /// represents pre- or post- re-analysis.
...@@ -320,6 +323,16 @@ pub const Fn = struct {...@@ -320,6 +323,16 @@ pub const Fn = struct {
320 }323 }
321};324};
322325
326pub const Var = struct {
327 /// if is_extern == true this is undefined
328 init: Value,
329 owner_decl: *Decl,
330
331 is_extern: bool,
332 is_mutable: bool,
333 is_threadlocal: bool,
334};
335
323pub const Scope = struct {336pub const Scope = struct {
324 tag: Tag,337 tag: Tag,
325338
...@@ -1235,6 +1248,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {...@@ -1235,6 +1248,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
1235 };1248 };
1236 defer fn_type_scope.instructions.deinit(self.gpa);1249 defer fn_type_scope.instructions.deinit(self.gpa);
12371250
1251 decl.is_pub = fn_proto.getTrailer("visib_token") != null;
1238 const body_node = fn_proto.getTrailer("body_node") orelse1252 const body_node = fn_proto.getTrailer("body_node") orelse
1239 return self.failTok(&fn_type_scope.base, fn_proto.fn_token, "TODO implement extern functions", .{});1253 return self.failTok(&fn_type_scope.base, fn_proto.fn_token, "TODO implement extern functions", .{});
12401254
...@@ -1419,8 +1433,213 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {...@@ -1419,8 +1433,213 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
1419 }1433 }
1420 return type_changed;1434 return type_changed;
1421 },1435 },
1422 .VarDecl => @panic("TODO var decl"),1436 .VarDecl => {
1423 .Comptime => @panic("TODO comptime decl"),1437 const var_decl = @fieldParentPtr(ast.Node.VarDecl, "base", ast_node);
1438
1439 decl.analysis = .in_progress;
1440
1441 // We need the memory for the Type to go into the arena for the Decl
1442 var decl_arena = std.heap.ArenaAllocator.init(self.gpa);
1443 errdefer decl_arena.deinit();
1444 const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State);
1445
1446 var block_scope: Scope.Block = .{
1447 .parent = null,
1448 .func = null,
1449 .decl = decl,
1450 .instructions = .{},
1451 .arena = &decl_arena.allocator,
1452 };
1453 defer block_scope.instructions.deinit(self.gpa);
1454
1455 decl.is_pub = var_decl.getTrailer("visib_token") != null;
1456 const is_extern = blk: {
1457 const maybe_extern_token = var_decl.getTrailer("extern_export_token") orelse
1458 break :blk false;
1459 if (tree.token_ids[maybe_extern_token] != .Keyword_extern) break :blk false;
1460 if (var_decl.getTrailer("init_node")) |some| {
1461 return self.failNode(&block_scope.base, some, "extern variables have no initializers", .{});
1462 }
1463 break :blk true;
1464 };
1465 if (var_decl.getTrailer("lib_name")) |lib_name| {
1466 assert(is_extern);
1467 return self.failNode(&block_scope.base, lib_name, "TODO implement function library name", .{});
1468 }
1469 const is_mutable = tree.token_ids[var_decl.mut_token] == .Keyword_var;
1470 const is_threadlocal = if (var_decl.getTrailer("thread_local_token")) |some| blk: {
1471 if (!is_mutable) {
1472 return self.failTok(&block_scope.base, some, "threadlocal variable cannot be constant", .{});
1473 }
1474 break :blk true;
1475 } else false;
1476 assert(var_decl.getTrailer("comptime_token") == null);
1477 if (var_decl.getTrailer("align_node")) |align_expr| {
1478 return self.failNode(&block_scope.base, align_expr, "TODO implement function align expression", .{});
1479 }
1480 if (var_decl.getTrailer("section_node")) |sect_expr| {
1481 return self.failNode(&block_scope.base, sect_expr, "TODO implement function section expression", .{});
1482 }
1483
1484 const explicit_type = blk: {
1485 const type_node = var_decl.getTrailer("type_node") orelse
1486 break :blk null;
1487
1488 // Temporary arena for the zir instructions.
1489 var type_scope_arena = std.heap.ArenaAllocator.init(self.gpa);
1490 defer type_scope_arena.deinit();
1491 var type_scope: Scope.GenZIR = .{
1492 .decl = decl,
1493 .arena = &type_scope_arena.allocator,
1494 .parent = decl.scope,
1495 };
1496 defer type_scope.instructions.deinit(self.gpa);
1497
1498 const src = tree.token_locs[type_node.firstToken()].start;
1499 const type_type = try astgen.addZIRInstConst(self, &type_scope.base, src, .{
1500 .ty = Type.initTag(.type),
1501 .val = Value.initTag(.type_type),
1502 });
1503 const var_type = try astgen.expr(self, &type_scope.base, .{ .ty = type_type }, type_node);
1504 _ = try astgen.addZIRUnOp(self, &type_scope.base, src, .@"return", var_type);
1505
1506 break :blk try zir_sema.analyzeBodyValueAsType(self, &block_scope, .{
1507 .instructions = type_scope.instructions.items,
1508 });
1509 };
1510
1511 var var_type: Type = undefined;
1512 const value: ?Value = if (var_decl.getTrailer("init_node")) |init_node| blk: {
1513 var gen_scope_arena = std.heap.ArenaAllocator.init(self.gpa);
1514 defer gen_scope_arena.deinit();
1515 var gen_scope: Scope.GenZIR = .{
1516 .decl = decl,
1517 .arena = &gen_scope_arena.allocator,
1518 .parent = decl.scope,
1519 };
1520 defer gen_scope.instructions.deinit(self.gpa);
1521 const src = tree.token_locs[init_node.firstToken()].start;
1522
1523 // TODO comptime scope here
1524 const init_inst = try astgen.expr(self, &gen_scope.base, .none, init_node);
1525 _ = try astgen.addZIRUnOp(self, &gen_scope.base, src, .@"return", init_inst);
1526
1527 var inner_block: Scope.Block = .{
1528 .parent = null,
1529 .func = null,
1530 .decl = decl,
1531 .instructions = .{},
1532 .arena = &gen_scope_arena.allocator,
1533 };
1534 defer inner_block.instructions.deinit(self.gpa);
1535 try zir_sema.analyzeBody(self, &inner_block.base, .{ .instructions = gen_scope.instructions.items });
1536
1537 for (inner_block.instructions.items) |inst| {
1538 if (inst.castTag(.ret)) |ret| {
1539 const coerced = if (explicit_type) |some|
1540 try self.coerce(&inner_block.base, some, ret.operand)
1541 else
1542 ret.operand;
1543 const val = coerced.value() orelse
1544 return self.fail(&block_scope.base, inst.src, "unable to resolve comptime value", .{});
1545
1546 var_type = explicit_type orelse try ret.operand.ty.copy(block_scope.arena);
1547 break :blk try val.copy(block_scope.arena);
1548 } else {
1549 return self.fail(&block_scope.base, inst.src, "unable to resolve comptime value", .{});
1550 }
1551 }
1552 unreachable;
1553 } else if (!is_extern) {
1554 return self.failTok(&block_scope.base, var_decl.firstToken(), "variables must be initialized", .{});
1555 } else if (explicit_type) |some| blk: {
1556 var_type = some;
1557 break :blk null;
1558 } else {
1559 return self.failTok(&block_scope.base, var_decl.firstToken(), "unable to infer variable type", .{});
1560 };
1561
1562 if (is_mutable and !var_type.isValidVarType(is_extern)) {
1563 return self.failTok(&block_scope.base, var_decl.firstToken(), "variable of type '{}' must be const", .{var_type});
1564 }
1565
1566 var type_changed = true;
1567 if (decl.typedValueManaged()) |tvm| {
1568 type_changed = !tvm.typed_value.ty.eql(var_type);
1569
1570 tvm.deinit(self.gpa);
1571 }
1572
1573 const new_variable = try decl_arena.allocator.create(Var);
1574 const var_payload = try decl_arena.allocator.create(Value.Payload.Variable);
1575 new_variable.* = .{
1576 .owner_decl = decl,
1577 .init = value orelse undefined,
1578 .is_extern = is_extern,
1579 .is_mutable = is_mutable,
1580 .is_threadlocal = is_threadlocal,
1581 };
1582 var_payload.* = .{ .variable = new_variable };
1583
1584 decl_arena_state.* = decl_arena.state;
1585 decl.typed_value = .{
1586 .most_recent = .{
1587 .typed_value = .{
1588 .ty = var_type,
1589 .val = Value.initPayload(&var_payload.base),
1590 },
1591 .arena = decl_arena_state,
1592 },
1593 };
1594 decl.analysis = .complete;
1595 decl.generation = self.generation;
1596
1597 if (var_decl.getTrailer("extern_export_token")) |maybe_export_token| {
1598 if (tree.token_ids[maybe_export_token] == .Keyword_export) {
1599 const export_src = tree.token_locs[maybe_export_token].start;
1600 const name_loc = tree.token_locs[var_decl.name_token];
1601 const name = tree.tokenSliceLoc(name_loc);
1602 // The scope needs to have the decl in it.
1603 try self.analyzeExport(&block_scope.base, export_src, name, decl);
1604 }
1605 }
1606 return type_changed;
1607 },
1608 .Comptime => {
1609 const comptime_decl = @fieldParentPtr(ast.Node.Comptime, "base", ast_node);
1610
1611 decl.analysis = .in_progress;
1612
1613 // A comptime decl does not store any value so we can just deinit this arena after analysis is done.
1614 var analysis_arena = std.heap.ArenaAllocator.init(self.gpa);
1615 defer analysis_arena.deinit();
1616 var gen_scope: Scope.GenZIR = .{
1617 .decl = decl,
1618 .arena = &analysis_arena.allocator,
1619 .parent = decl.scope,
1620 };
1621 defer gen_scope.instructions.deinit(self.gpa);
1622
1623 // TODO comptime scope here
1624 _ = try astgen.expr(self, &gen_scope.base, .none, comptime_decl.expr);
1625
1626 var block_scope: Scope.Block = .{
1627 .parent = null,
1628 .func = null,
1629 .decl = decl,
1630 .instructions = .{},
1631 .arena = &analysis_arena.allocator,
1632 };
1633 defer block_scope.instructions.deinit(self.gpa);
1634
1635 _ = try zir_sema.analyzeBody(self, &block_scope.base, .{
1636 .instructions = gen_scope.instructions.items,
1637 });
1638
1639 decl.analysis = .complete;
1640 decl.generation = self.generation;
1641 return true;
1642 },
1424 .Use => @panic("TODO usingnamespace decl"),1643 .Use => @panic("TODO usingnamespace decl"),
1425 else => unreachable,1644 else => unreachable,
1426 }1645 }
...@@ -1583,11 +1802,53 @@ fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void {...@@ -1583,11 +1802,53 @@ fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void {
1583 }1802 }
1584 }1803 }
1585 }1804 }
1805 } else if (src_decl.castTag(.VarDecl)) |var_decl| {
1806 const name_loc = tree.token_locs[var_decl.name_token];
1807 const name = tree.tokenSliceLoc(name_loc);
1808 const name_hash = root_scope.fullyQualifiedNameHash(name);
1809 const contents_hash = std.zig.hashSrc(tree.getNodeSource(src_decl));
1810 if (self.decl_table.get(name_hash)) |decl| {
1811 // Update the AST Node index of the decl, even if its contents are unchanged, it may
1812 // have been re-ordered.
1813 decl.src_index = decl_i;
1814 if (deleted_decls.remove(decl) == null) {
1815 decl.analysis = .sema_failure;
1816 const err_msg = try ErrorMsg.create(self.gpa, name_loc.start, "redefinition of '{}'", .{decl.name});
1817 errdefer err_msg.destroy(self.gpa);
1818 try self.failed_decls.putNoClobber(self.gpa, decl, err_msg);
1819 } else if (!srcHashEql(decl.contents_hash, contents_hash)) {
1820 try self.markOutdatedDecl(decl);
1821 decl.contents_hash = contents_hash;
1822 }
1823 } else {
1824 const new_decl = try self.createNewDecl(&root_scope.base, name, decl_i, name_hash, contents_hash);
1825 root_scope.decls.appendAssumeCapacity(new_decl);
1826 if (var_decl.getTrailer("extern_export_token")) |maybe_export_token| {
1827 if (tree.token_ids[maybe_export_token] == .Keyword_export) {
1828 self.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl });
1829 }
1830 }
1831 }
1832 } else if (src_decl.castTag(.Comptime)) |comptime_node| {
1833 const name_index = self.getNextAnonNameIndex();
1834 const name = try std.fmt.allocPrint(self.gpa, "__comptime_{}", .{name_index});
1835 defer self.gpa.free(name);
1836
1837 const name_hash = root_scope.fullyQualifiedNameHash(name);
1838 const contents_hash = std.zig.hashSrc(tree.getNodeSource(src_decl));
1839
1840 const new_decl = try self.createNewDecl(&root_scope.base, name, decl_i, name_hash, contents_hash);
1841 root_scope.decls.appendAssumeCapacity(new_decl);
1842 self.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl });
1843 } else if (src_decl.castTag(.ContainerField)) |container_field| {
1844 log.err("TODO: analyze container field", .{});
1845 } else if (src_decl.castTag(.TestDecl)) |test_decl| {
1846 log.err("TODO: analyze test decl", .{});
1847 } else if (src_decl.castTag(.Use)) |use_decl| {
1848 log.err("TODO: analyze usingnamespace decl", .{});
1586 } else {1849 } else {
1587 std.debug.panic("TODO: analyzeRootSrcFile {}", .{src_decl.tag});1850 unreachable;
1588 }1851 }
1589 // TODO also look for global variable declarations
1590 // TODO also look for comptime blocks and exported globals
1591 }1852 }
1592 // Handle explicitly deleted decls from the source code. Not to be confused1853 // Handle explicitly deleted decls from the source code. Not to be confused
1593 // with when we delete decls because they are no longer referenced.1854 // with when we delete decls because they are no longer referenced.
...@@ -1790,6 +2051,7 @@ fn allocateNewDecl(...@@ -1790,6 +2051,7 @@ fn allocateNewDecl(
1790 .wasm => .{ .wasm = null },2051 .wasm => .{ .wasm = null },
1791 },2052 },
1792 .generation = 0,2053 .generation = 0,
2054 .is_pub = false,
1793 };2055 };
1794 return new_decl;2056 return new_decl;
1795}2057}
...@@ -2209,20 +2471,46 @@ pub fn analyzeDeclRef(self: *Module, scope: *Scope, src: usize, decl: *Decl) Inn...@@ -2209,20 +2471,46 @@ pub fn analyzeDeclRef(self: *Module, scope: *Scope, src: usize, decl: *Decl) Inn
2209 };2471 };
22102472
2211 const decl_tv = try decl.typedValue();2473 const decl_tv = try decl.typedValue();
2212 const ty_payload = try scope.arena().create(Type.Payload.Pointer);2474 if (decl_tv.val.tag() == .variable) {
2213 ty_payload.* = .{2475 return self.analyzeVarRef(scope, src, decl_tv);
2214 .base = .{ .tag = .single_const_pointer },2476 }
2215 .pointee_type = decl_tv.ty,2477 const ty = try self.simplePtrType(scope, src, decl_tv.ty, false, .One);
2216 };
2217 const val_payload = try scope.arena().create(Value.Payload.DeclRef);2478 const val_payload = try scope.arena().create(Value.Payload.DeclRef);
2218 val_payload.* = .{ .decl = decl };2479 val_payload.* = .{ .decl = decl };
22192480
2220 return self.constInst(scope, src, .{2481 return self.constInst(scope, src, .{
2221 .ty = Type.initPayload(&ty_payload.base),2482 .ty = ty,
2222 .val = Value.initPayload(&val_payload.base),2483 .val = Value.initPayload(&val_payload.base),
2223 });2484 });
2224}2485}
22252486
2487fn analyzeVarRef(self: *Module, scope: *Scope, src: usize, tv: TypedValue) InnerError!*Inst {
2488 const variable = tv.val.cast(Value.Payload.Variable).?.variable;
2489
2490 const ty = try self.simplePtrType(scope, src, tv.ty, variable.is_mutable, .One);
2491 if (!variable.is_mutable and !variable.is_extern) {
2492 const val_payload = try scope.arena().create(Value.Payload.RefVal);
2493 val_payload.* = .{ .val = variable.init };
2494 return self.constInst(scope, src, .{
2495 .ty = ty,
2496 .val = Value.initPayload(&val_payload.base),
2497 });
2498 }
2499
2500 const b = try self.requireRuntimeBlock(scope, src);
2501 const inst = try b.arena.create(Inst.VarPtr);
2502 inst.* = .{
2503 .base = .{
2504 .tag = .varptr,
2505 .ty = ty,
2506 .src = src,
2507 },
2508 .variable = variable,
2509 };
2510 try b.instructions.append(self.gpa, &inst.base);
2511 return &inst.base;
2512}
2513
2226pub fn analyzeDeref(self: *Module, scope: *Scope, src: usize, ptr: *Inst, ptr_src: usize) InnerError!*Inst {2514pub fn analyzeDeref(self: *Module, scope: *Scope, src: usize, ptr: *Inst, ptr_src: usize) InnerError!*Inst {
2227 const elem_ty = switch (ptr.ty.zigTypeTag()) {2515 const elem_ty = switch (ptr.ty.zigTypeTag()) {
2228 .Pointer => ptr.ty.elemType(),2516 .Pointer => ptr.ty.elemType(),
...@@ -2523,7 +2811,7 @@ pub fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst...@@ -2523,7 +2811,7 @@ pub fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst
25232811
2524 // T to ?T2812 // T to ?T
2525 if (dest_type.zigTypeTag() == .Optional) {2813 if (dest_type.zigTypeTag() == .Optional) {
2526 var buf: Type.Payload.Pointer = undefined;2814 var buf: Type.Payload.PointerSimple = undefined;
2527 const child_type = dest_type.optionalChild(&buf);2815 const child_type = dest_type.optionalChild(&buf);
2528 if (child_type.eql(inst.ty)) {2816 if (child_type.eql(inst.ty)) {
2529 return self.wrapOptional(scope, dest_type, inst);2817 return self.wrapOptional(scope, dest_type, inst);
...@@ -2902,15 +3190,125 @@ pub fn floatSub(self: *Module, scope: *Scope, float_type: Type, src: usize, lhs:...@@ -2902,15 +3190,125 @@ pub fn floatSub(self: *Module, scope: *Scope, float_type: Type, src: usize, lhs:
2902 return Value.initPayload(val_payload);3190 return Value.initPayload(val_payload);
2903}3191}
29043192
2905pub fn singlePtrType(self: *Module, scope: *Scope, src: usize, mutable: bool, elem_ty: Type) error{OutOfMemory}!Type {3193pub fn simplePtrType(self: *Module, scope: *Scope, src: usize, elem_ty: Type, mutable: bool, size: std.builtin.TypeInfo.Pointer.Size) Allocator.Error!Type {
3194 if (!mutable and size == .Slice and elem_ty.eql(Type.initTag(.u8))) {
3195 return Type.initTag(.const_slice_u8);
3196 }
3197 // TODO stage1 type inference bug
3198 const T = Type.Tag;
3199
3200 const type_payload = try scope.arena().create(Type.Payload.PointerSimple);
3201 type_payload.* = .{
3202 .base = .{
3203 .tag = switch (size) {
3204 .One => if (mutable) T.single_mut_pointer else T.single_const_pointer,
3205 .Many => if (mutable) T.many_mut_pointer else T.many_const_pointer,
3206 .C => if (mutable) T.c_mut_pointer else T.c_const_pointer,
3207 .Slice => if (mutable) T.mut_slice else T.const_slice,
3208 },
3209 },
3210 .pointee_type = elem_ty,
3211 };
3212 return Type.initPayload(&type_payload.base);
3213}
3214
3215pub fn ptrType(
3216 self: *Module,
3217 scope: *Scope,
3218 src: usize,
3219 elem_ty: Type,
3220 sentinel: ?Value,
3221 @"align": u32,
3222 bit_offset: u16,
3223 host_size: u16,
3224 mutable: bool,
3225 @"allowzero": bool,
3226 @"volatile": bool,
3227 size: std.builtin.TypeInfo.Pointer.Size,
3228) Allocator.Error!Type {
3229 assert(host_size == 0 or bit_offset < host_size * 8);
3230
3231 // TODO check if type can be represented by simplePtrType
2906 const type_payload = try scope.arena().create(Type.Payload.Pointer);3232 const type_payload = try scope.arena().create(Type.Payload.Pointer);
2907 type_payload.* = .{3233 type_payload.* = .{
2908 .base = .{ .tag = if (mutable) .single_mut_pointer else .single_const_pointer },
2909 .pointee_type = elem_ty,3234 .pointee_type = elem_ty,
3235 .sentinel = sentinel,
3236 .@"align" = @"align",
3237 .bit_offset = bit_offset,
3238 .host_size = host_size,
3239 .@"allowzero" = @"allowzero",
3240 .mutable = mutable,
3241 .@"volatile" = @"volatile",
3242 .size = size,
2910 };3243 };
2911 return Type.initPayload(&type_payload.base);3244 return Type.initPayload(&type_payload.base);
2912}3245}
29133246
3247pub fn optionalType(self: *Module, scope: *Scope, child_type: Type) Allocator.Error!Type {
3248 return Type.initPayload(switch (child_type.tag()) {
3249 .single_const_pointer => blk: {
3250 const payload = try scope.arena().create(Type.Payload.PointerSimple);
3251 payload.* = .{
3252 .base = .{ .tag = .optional_single_const_pointer },
3253 .pointee_type = child_type.elemType(),
3254 };
3255 break :blk &payload.base;
3256 },
3257 .single_mut_pointer => blk: {
3258 const payload = try scope.arena().create(Type.Payload.PointerSimple);
3259 payload.* = .{
3260 .base = .{ .tag = .optional_single_mut_pointer },
3261 .pointee_type = child_type.elemType(),
3262 };
3263 break :blk &payload.base;
3264 },
3265 else => blk: {
3266 const payload = try scope.arena().create(Type.Payload.Optional);
3267 payload.* = .{
3268 .child_type = child_type,
3269 };
3270 break :blk &payload.base;
3271 },
3272 });
3273}
3274
3275pub fn arrayType(self: *Module, scope: *Scope, len: u64, sentinel: ?Value, elem_type: Type) Allocator.Error!Type {
3276 if (elem_type.eql(Type.initTag(.u8))) {
3277 if (sentinel) |some| {
3278 if (some.eql(Value.initTag(.zero))) {
3279 const payload = try scope.arena().create(Type.Payload.Array_u8_Sentinel0);
3280 payload.* = .{
3281 .len = len,
3282 };
3283 return Type.initPayload(&payload.base);
3284 }
3285 } else {
3286 const payload = try scope.arena().create(Type.Payload.Array_u8);
3287 payload.* = .{
3288 .len = len,
3289 };
3290 return Type.initPayload(&payload.base);
3291 }
3292 }
3293
3294 if (sentinel) |some| {
3295 const payload = try scope.arena().create(Type.Payload.ArraySentinel);
3296 payload.* = .{
3297 .len = len,
3298 .sentinel = some,
3299 .elem_type = elem_type,
3300 };
3301 return Type.initPayload(&payload.base);
3302 }
3303
3304 const payload = try scope.arena().create(Type.Payload.Array);
3305 payload.* = .{
3306 .len = len,
3307 .elem_type = elem_type,
3308 };
3309 return Type.initPayload(&payload.base);
3310}
3311
2914pub fn dumpInst(self: *Module, scope: *Scope, inst: *Inst) void {3312pub fn dumpInst(self: *Module, scope: *Scope, inst: *Inst) void {
2915 const zir_module = scope.namespace();3313 const zir_module = scope.namespace();
2916 const source = zir_module.getSource(self) catch @panic("dumpInst failed to get source");3314 const source = zir_module.getSource(self) catch @panic("dumpInst failed to get source");
src-self-hosted/astgen.zig+384-42
...@@ -20,6 +20,8 @@ pub const ResultLoc = union(enum) {...@@ -20,6 +20,8 @@ pub const ResultLoc = union(enum) {
20 /// The expression must generate a pointer rather than a value. For example, the left hand side20 /// The expression must generate a pointer rather than a value. For example, the left hand side
21 /// of an assignment uses an "LValue" result location.21 /// of an assignment uses an "LValue" result location.
22 lvalue,22 lvalue,
23 /// The expression must generate a pointer
24 ref,
23 /// The expression will be type coerced into this type, but it will be evaluated as an rvalue.25 /// The expression will be type coerced into this type, but it will be evaluated as an rvalue.
24 ty: *zir.Inst,26 ty: *zir.Inst,
25 /// The expression must store its result into this typed pointer.27 /// The expression must store its result into this typed pointer.
...@@ -46,6 +48,132 @@ pub fn typeExpr(mod: *Module, scope: *Scope, type_node: *ast.Node) InnerError!*z...@@ -46,6 +48,132 @@ pub fn typeExpr(mod: *Module, scope: *Scope, type_node: *ast.Node) InnerError!*z
4648
47/// Turn Zig AST into untyped ZIR istructions.49/// Turn Zig AST into untyped ZIR istructions.
48pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerError!*zir.Inst {50pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerError!*zir.Inst {
51 if (rl == .lvalue) {
52 switch (node.tag) {
53 .Root => unreachable,
54 .Use => unreachable,
55 .TestDecl => unreachable,
56 .DocComment => unreachable,
57 .VarDecl => unreachable,
58 .SwitchCase => unreachable,
59 .SwitchElse => unreachable,
60 .Else => unreachable,
61 .Payload => unreachable,
62 .PointerPayload => unreachable,
63 .PointerIndexPayload => unreachable,
64 .ErrorTag => unreachable,
65 .FieldInitializer => unreachable,
66 .ContainerField => unreachable,
67
68 .Assign,
69 .AssignBitAnd,
70 .AssignBitOr,
71 .AssignBitShiftLeft,
72 .AssignBitShiftRight,
73 .AssignBitXor,
74 .AssignDiv,
75 .AssignSub,
76 .AssignSubWrap,
77 .AssignMod,
78 .AssignAdd,
79 .AssignAddWrap,
80 .AssignMul,
81 .AssignMulWrap,
82 .Add,
83 .AddWrap,
84 .Sub,
85 .SubWrap,
86 .Mul,
87 .MulWrap,
88 .Div,
89 .Mod,
90 .BitAnd,
91 .BitOr,
92 .BitShiftLeft,
93 .BitShiftRight,
94 .BitXor,
95 .BangEqual,
96 .EqualEqual,
97 .GreaterThan,
98 .GreaterOrEqual,
99 .LessThan,
100 .LessOrEqual,
101 .ArrayCat,
102 .ArrayMult,
103 .BoolAnd,
104 .BoolOr,
105 .Asm,
106 .StringLiteral,
107 .IntegerLiteral,
108 .Call,
109 .Unreachable,
110 .Return,
111 .If,
112 .While,
113 .BoolNot,
114 .AddressOf,
115 .FloatLiteral,
116 .UndefinedLiteral,
117 .BoolLiteral,
118 .NullLiteral,
119 .OptionalType,
120 .Block,
121 .LabeledBlock,
122 .Break,
123 .PtrType,
124 .GroupedExpression,
125 .ArrayType,
126 .ArrayTypeSentinel,
127 .EnumLiteral,
128 .MultilineStringLiteral,
129 .CharLiteral,
130 .Defer,
131 .Catch,
132 .ErrorUnion,
133 .MergeErrorSets,
134 .Range,
135 .OrElse,
136 .Await,
137 .BitNot,
138 .Negation,
139 .NegationWrap,
140 .Resume,
141 .Try,
142 .SliceType,
143 .Slice,
144 .ArrayInitializer,
145 .ArrayInitializerDot,
146 .StructInitializer,
147 .StructInitializerDot,
148 .Switch,
149 .For,
150 .Suspend,
151 .Continue,
152 .AnyType,
153 .ErrorType,
154 .FnProto,
155 .AnyFrameType,
156 .ErrorSetDecl,
157 .ContainerDecl,
158 .Comptime,
159 .Nosuspend,
160 => return mod.failNode(scope, node, "invalid left-hand side to assignment", .{}),
161
162 // @field can be assigned to
163 .BuiltinCall => {
164 const call = node.castTag(.BuiltinCall).?;
165 const tree = scope.tree();
166 const builtin_name = tree.tokenSlice(call.builtin_token);
167
168 if (!mem.eql(u8, builtin_name, "@field")) {
169 return mod.failNode(scope, node, "invalid left-hand side to assignment", .{});
170 }
171 },
172
173 // can be assigned to
174 .UnwrapOptional, .Deref, .Period, .ArrayAccess, .Identifier => {},
175 }
176 }
49 switch (node.tag) {177 switch (node.tag) {
50 .Root => unreachable, // Top-level declaration.178 .Root => unreachable, // Top-level declaration.
51 .Use => unreachable, // Top-level declaration.179 .Use => unreachable, // Top-level declaration.
...@@ -60,6 +188,7 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr...@@ -60,6 +188,7 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr
60 .PointerIndexPayload => unreachable, // Handled explicitly.188 .PointerIndexPayload => unreachable, // Handled explicitly.
61 .ErrorTag => unreachable, // Handled explicitly.189 .ErrorTag => unreachable, // Handled explicitly.
62 .FieldInitializer => unreachable, // Handled explicitly.190 .FieldInitializer => unreachable, // Handled explicitly.
191 .ContainerField => unreachable, // Handled explicitly.
63192
64 .Assign => return rlWrapVoid(mod, scope, rl, node, try assign(mod, scope, node.castTag(.Assign).?)),193 .Assign => return rlWrapVoid(mod, scope, rl, node, try assign(mod, scope, node.castTag(.Assign).?)),
65 .AssignBitAnd => return rlWrapVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignBitAnd).?, .bitand)),194 .AssignBitAnd => return rlWrapVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignBitAnd).?, .bitand)),
...@@ -100,6 +229,9 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr...@@ -100,6 +229,9 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr
100 .ArrayCat => return simpleBinOp(mod, scope, rl, node.castTag(.ArrayCat).?, .array_cat),229 .ArrayCat => return simpleBinOp(mod, scope, rl, node.castTag(.ArrayCat).?, .array_cat),
101 .ArrayMult => return simpleBinOp(mod, scope, rl, node.castTag(.ArrayMult).?, .array_mul),230 .ArrayMult => return simpleBinOp(mod, scope, rl, node.castTag(.ArrayMult).?, .array_mul),
102231
232 .BoolAnd => return boolBinOp(mod, scope, rl, node.castTag(.BoolAnd).?),
233 .BoolOr => return boolBinOp(mod, scope, rl, node.castTag(.BoolOr).?),
234
103 .Identifier => return try identifier(mod, scope, rl, node.castTag(.Identifier).?),235 .Identifier => return try identifier(mod, scope, rl, node.castTag(.Identifier).?),
104 .Asm => return rlWrap(mod, scope, rl, try assembly(mod, scope, node.castTag(.Asm).?)),236 .Asm => return rlWrap(mod, scope, rl, try assembly(mod, scope, node.castTag(.Asm).?)),
105 .StringLiteral => return rlWrap(mod, scope, rl, try stringLiteral(mod, scope, node.castTag(.StringLiteral).?)),237 .StringLiteral => return rlWrap(mod, scope, rl, try stringLiteral(mod, scope, node.castTag(.StringLiteral).?)),
...@@ -124,11 +256,16 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr...@@ -124,11 +256,16 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr
124 .LabeledBlock => return labeledBlockExpr(mod, scope, rl, node.castTag(.LabeledBlock).?),256 .LabeledBlock => return labeledBlockExpr(mod, scope, rl, node.castTag(.LabeledBlock).?),
125 .Break => return rlWrap(mod, scope, rl, try breakExpr(mod, scope, node.castTag(.Break).?)),257 .Break => return rlWrap(mod, scope, rl, try breakExpr(mod, scope, node.castTag(.Break).?)),
126 .PtrType => return rlWrap(mod, scope, rl, try ptrType(mod, scope, node.castTag(.PtrType).?)),258 .PtrType => return rlWrap(mod, scope, rl, try ptrType(mod, scope, node.castTag(.PtrType).?)),
259 .GroupedExpression => return expr(mod, scope, rl, node.castTag(.GroupedExpression).?.expr),
260 .ArrayType => return rlWrap(mod, scope, rl, try arrayType(mod, scope, node.castTag(.ArrayType).?)),
261 .ArrayTypeSentinel => return rlWrap(mod, scope, rl, try arrayTypeSentinel(mod, scope, node.castTag(.ArrayTypeSentinel).?)),
262 .EnumLiteral => return rlWrap(mod, scope, rl, try enumLiteral(mod, scope, node.castTag(.EnumLiteral).?)),
263 .MultilineStringLiteral => return rlWrap(mod, scope, rl, try multilineStrLiteral(mod, scope, node.castTag(.MultilineStringLiteral).?)),
264 .CharLiteral => return rlWrap(mod, scope, rl, try charLiteral(mod, scope, node.castTag(.CharLiteral).?)),
265 .SliceType => return rlWrap(mod, scope, rl, try sliceType(mod, scope, node.castTag(.SliceType).?)),
127266
128 .Defer => return mod.failNode(scope, node, "TODO implement astgen.expr for .Defer", .{}),267 .Defer => return mod.failNode(scope, node, "TODO implement astgen.expr for .Defer", .{}),
129 .Catch => return mod.failNode(scope, node, "TODO implement astgen.expr for .Catch", .{}),268 .Catch => return mod.failNode(scope, node, "TODO implement astgen.expr for .Catch", .{}),
130 .BoolAnd => return mod.failNode(scope, node, "TODO implement astgen.expr for .BoolAnd", .{}),
131 .BoolOr => return mod.failNode(scope, node, "TODO implement astgen.expr for .BoolOr", .{}),
132 .ErrorUnion => return mod.failNode(scope, node, "TODO implement astgen.expr for .ErrorUnion", .{}),269 .ErrorUnion => return mod.failNode(scope, node, "TODO implement astgen.expr for .ErrorUnion", .{}),
133 .MergeErrorSets => return mod.failNode(scope, node, "TODO implement astgen.expr for .MergeErrorSets", .{}),270 .MergeErrorSets => return mod.failNode(scope, node, "TODO implement astgen.expr for .MergeErrorSets", .{}),
134 .Range => return mod.failNode(scope, node, "TODO implement astgen.expr for .Range", .{}),271 .Range => return mod.failNode(scope, node, "TODO implement astgen.expr for .Range", .{}),
...@@ -139,9 +276,6 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr...@@ -139,9 +276,6 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr
139 .NegationWrap => return mod.failNode(scope, node, "TODO implement astgen.expr for .NegationWrap", .{}),276 .NegationWrap => return mod.failNode(scope, node, "TODO implement astgen.expr for .NegationWrap", .{}),
140 .Resume => return mod.failNode(scope, node, "TODO implement astgen.expr for .Resume", .{}),277 .Resume => return mod.failNode(scope, node, "TODO implement astgen.expr for .Resume", .{}),
141 .Try => return mod.failNode(scope, node, "TODO implement astgen.expr for .Try", .{}),278 .Try => return mod.failNode(scope, node, "TODO implement astgen.expr for .Try", .{}),
142 .ArrayType => return mod.failNode(scope, node, "TODO implement astgen.expr for .ArrayType", .{}),
143 .ArrayTypeSentinel => return mod.failNode(scope, node, "TODO implement astgen.expr for .ArrayTypeSentinel", .{}),
144 .SliceType => return mod.failNode(scope, node, "TODO implement astgen.expr for .SliceType", .{}),
145 .Slice => return mod.failNode(scope, node, "TODO implement astgen.expr for .Slice", .{}),279 .Slice => return mod.failNode(scope, node, "TODO implement astgen.expr for .Slice", .{}),
146 .ArrayAccess => return mod.failNode(scope, node, "TODO implement astgen.expr for .ArrayAccess", .{}),280 .ArrayAccess => return mod.failNode(scope, node, "TODO implement astgen.expr for .ArrayAccess", .{}),
147 .ArrayInitializer => return mod.failNode(scope, node, "TODO implement astgen.expr for .ArrayInitializer", .{}),281 .ArrayInitializer => return mod.failNode(scope, node, "TODO implement astgen.expr for .ArrayInitializer", .{}),
...@@ -156,15 +290,10 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr...@@ -156,15 +290,10 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr
156 .ErrorType => return mod.failNode(scope, node, "TODO implement astgen.expr for .ErrorType", .{}),290 .ErrorType => return mod.failNode(scope, node, "TODO implement astgen.expr for .ErrorType", .{}),
157 .FnProto => return mod.failNode(scope, node, "TODO implement astgen.expr for .FnProto", .{}),291 .FnProto => return mod.failNode(scope, node, "TODO implement astgen.expr for .FnProto", .{}),
158 .AnyFrameType => return mod.failNode(scope, node, "TODO implement astgen.expr for .AnyFrameType", .{}),292 .AnyFrameType => return mod.failNode(scope, node, "TODO implement astgen.expr for .AnyFrameType", .{}),
159 .EnumLiteral => return mod.failNode(scope, node, "TODO implement astgen.expr for .EnumLiteral", .{}),
160 .MultilineStringLiteral => return mod.failNode(scope, node, "TODO implement astgen.expr for .MultilineStringLiteral", .{}),
161 .CharLiteral => return mod.failNode(scope, node, "TODO implement astgen.expr for .CharLiteral", .{}),
162 .GroupedExpression => return mod.failNode(scope, node, "TODO implement astgen.expr for .GroupedExpression", .{}),
163 .ErrorSetDecl => return mod.failNode(scope, node, "TODO implement astgen.expr for .ErrorSetDecl", .{}),293 .ErrorSetDecl => return mod.failNode(scope, node, "TODO implement astgen.expr for .ErrorSetDecl", .{}),
164 .ContainerDecl => return mod.failNode(scope, node, "TODO implement astgen.expr for .ContainerDecl", .{}),294 .ContainerDecl => return mod.failNode(scope, node, "TODO implement astgen.expr for .ContainerDecl", .{}),
165 .Comptime => return mod.failNode(scope, node, "TODO implement astgen.expr for .Comptime", .{}),295 .Comptime => return mod.failNode(scope, node, "TODO implement astgen.expr for .Comptime", .{}),
166 .Nosuspend => return mod.failNode(scope, node, "TODO implement astgen.expr for .Nosuspend", .{}),296 .Nosuspend => return mod.failNode(scope, node, "TODO implement astgen.expr for .Nosuspend", .{}),
167 .ContainerField => return mod.failNode(scope, node, "TODO implement astgen.expr for .ContainerField", .{}),
168 }297 }
169}298}
170299
...@@ -187,7 +316,7 @@ fn breakExpr(mod: *Module, parent_scope: *Scope, node: *ast.Node.ControlFlowExpr...@@ -187,7 +316,7 @@ fn breakExpr(mod: *Module, parent_scope: *Scope, node: *ast.Node.ControlFlowExpr
187 // proper type inference requires peer type resolution on the block's316 // proper type inference requires peer type resolution on the block's
188 // break operand expressions.317 // break operand expressions.
189 const branch_rl: ResultLoc = switch (label.result_loc) {318 const branch_rl: ResultLoc = switch (label.result_loc) {
190 .discard, .none, .ty, .ptr, .lvalue => label.result_loc,319 .discard, .none, .ty, .ptr, .lvalue, .ref => label.result_loc,
191 .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = label.block_inst },320 .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = label.block_inst },
192 };321 };
193 const operand = try expr(mod, parent_scope, branch_rl, rhs);322 const operand = try expr(mod, parent_scope, branch_rl, rhs);
...@@ -426,7 +555,7 @@ fn boolNot(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerErr...@@ -426,7 +555,7 @@ fn boolNot(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerErr
426}555}
427556
428fn addressOf(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerError!*zir.Inst {557fn addressOf(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerError!*zir.Inst {
429 return expr(mod, scope, .lvalue, node.rhs);558 return expr(mod, scope, .ref, node.rhs);
430}559}
431560
432fn optionalType(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerError!*zir.Inst {561fn optionalType(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerError!*zir.Inst {
...@@ -440,43 +569,67 @@ fn optionalType(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) Inn...@@ -440,43 +569,67 @@ fn optionalType(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) Inn
440 return addZIRUnOp(mod, scope, src, .optional_type, operand);569 return addZIRUnOp(mod, scope, src, .optional_type, operand);
441}570}
442571
572fn sliceType(mod: *Module, scope: *Scope, node: *ast.Node.SliceType) InnerError!*zir.Inst {
573 const tree = scope.tree();
574 const src = tree.token_locs[node.op_token].start;
575 return ptrSliceType(mod, scope, src, &node.ptr_info, node.rhs, .Slice);
576}
577
443fn ptrType(mod: *Module, scope: *Scope, node: *ast.Node.PtrType) InnerError!*zir.Inst {578fn ptrType(mod: *Module, scope: *Scope, node: *ast.Node.PtrType) InnerError!*zir.Inst {
444 const tree = scope.tree();579 const tree = scope.tree();
445 const src = tree.token_locs[node.op_token].start;580 const src = tree.token_locs[node.op_token].start;
581 return ptrSliceType(mod, scope, src, &node.ptr_info, node.rhs, switch (tree.token_ids[node.op_token]) {
582 .Asterisk, .AsteriskAsterisk => .One,
583 // TODO stage1 type inference bug
584 .LBracket => @as(std.builtin.TypeInfo.Pointer.Size, switch (tree.token_ids[node.op_token + 2]) {
585 .Identifier => .C,
586 else => .Many,
587 }),
588 else => unreachable,
589 });
590}
591
592fn ptrSliceType(mod: *Module, scope: *Scope, src: usize, ptr_info: *ast.PtrInfo, rhs: *ast.Node, size: std.builtin.TypeInfo.Pointer.Size) InnerError!*zir.Inst {
446 const meta_type = try addZIRInstConst(mod, scope, src, .{593 const meta_type = try addZIRInstConst(mod, scope, src, .{
447 .ty = Type.initTag(.type),594 .ty = Type.initTag(.type),
448 .val = Value.initTag(.type_type),595 .val = Value.initTag(.type_type),
449 });596 });
450597
451 const simple = node.ptr_info.allowzero_token == null and598 const simple = ptr_info.allowzero_token == null and
452 node.ptr_info.align_info == null and599 ptr_info.align_info == null and
453 node.ptr_info.volatile_token == null and600 ptr_info.volatile_token == null and
454 node.ptr_info.sentinel == null;601 ptr_info.sentinel == null;
455602
456 if (simple) {603 if (simple) {
457 const child_type = try expr(mod, scope, .{ .ty = meta_type }, node.rhs);604 const child_type = try expr(mod, scope, .{ .ty = meta_type }, rhs);
458 return addZIRUnOp(mod, scope, src, if (node.ptr_info.const_token == null)605 const mutable = ptr_info.const_token == null;
459 .single_mut_ptr_type606 // TODO stage1 type inference bug
460 else607 const T = zir.Inst.Tag;
461 .single_const_ptr_type, child_type);608 return addZIRUnOp(mod, scope, src, switch (size) {
609 .One => if (mutable) T.single_mut_ptr_type else T.single_const_ptr_type,
610 .Many => if (mutable) T.many_mut_ptr_type else T.many_const_ptr_type,
611 .C => if (mutable) T.c_mut_ptr_type else T.c_const_ptr_type,
612 .Slice => if (mutable) T.mut_slice_type else T.mut_slice_type,
613 }, child_type);
462 }614 }
463615
464 var kw_args: std.meta.fieldInfo(zir.Inst.PtrType, "kw_args").field_type = .{};616 var kw_args: std.meta.fieldInfo(zir.Inst.PtrType, "kw_args").field_type = .{};
465 kw_args.@"allowzero" = node.ptr_info.allowzero_token != null;617 kw_args.size = size;
466 if (node.ptr_info.align_info) |some| {618 kw_args.@"allowzero" = ptr_info.allowzero_token != null;
619 if (ptr_info.align_info) |some| {
467 kw_args.@"align" = try expr(mod, scope, .none, some.node);620 kw_args.@"align" = try expr(mod, scope, .none, some.node);
468 if (some.bit_range) |bit_range| {621 if (some.bit_range) |bit_range| {
469 kw_args.align_bit_start = try expr(mod, scope, .none, bit_range.start);622 kw_args.align_bit_start = try expr(mod, scope, .none, bit_range.start);
470 kw_args.align_bit_end = try expr(mod, scope, .none, bit_range.end);623 kw_args.align_bit_end = try expr(mod, scope, .none, bit_range.end);
471 }624 }
472 }625 }
473 kw_args.@"const" = node.ptr_info.const_token != null;626 kw_args.mutable = ptr_info.const_token == null;
474 kw_args.@"volatile" = node.ptr_info.volatile_token != null;627 kw_args.@"volatile" = ptr_info.volatile_token != null;
475 if (node.ptr_info.sentinel) |some| {628 if (ptr_info.sentinel) |some| {
476 kw_args.sentinel = try expr(mod, scope, .none, some);629 kw_args.sentinel = try expr(mod, scope, .none, some);
477 }630 }
478631
479 const child_type = try expr(mod, scope, .{ .ty = meta_type }, node.rhs);632 const child_type = try expr(mod, scope, .{ .ty = meta_type }, rhs);
480 if (kw_args.sentinel) |some| {633 if (kw_args.sentinel) |some| {
481 kw_args.sentinel = try addZIRBinOp(mod, scope, some.src, .as, child_type, some);634 kw_args.sentinel = try addZIRBinOp(mod, scope, some.src, .as, child_type, some);
482 }635 }
...@@ -484,13 +637,65 @@ fn ptrType(mod: *Module, scope: *Scope, node: *ast.Node.PtrType) InnerError!*zir...@@ -484,13 +637,65 @@ fn ptrType(mod: *Module, scope: *Scope, node: *ast.Node.PtrType) InnerError!*zir
484 return addZIRInst(mod, scope, src, zir.Inst.PtrType, .{ .child_type = child_type }, kw_args);637 return addZIRInst(mod, scope, src, zir.Inst.PtrType, .{ .child_type = child_type }, kw_args);
485}638}
486639
640fn arrayType(mod: *Module, scope: *Scope, node: *ast.Node.ArrayType) !*zir.Inst {
641 const tree = scope.tree();
642 const src = tree.token_locs[node.op_token].start;
643 const meta_type = try addZIRInstConst(mod, scope, src, .{
644 .ty = Type.initTag(.type),
645 .val = Value.initTag(.type_type),
646 });
647 const usize_type = try addZIRInstConst(mod, scope, src, .{
648 .ty = Type.initTag(.type),
649 .val = Value.initTag(.usize_type),
650 });
651
652 // TODO check for [_]T
653 const len = try expr(mod, scope, .{ .ty = usize_type }, node.len_expr);
654 const child_type = try expr(mod, scope, .{ .ty = meta_type }, node.rhs);
655
656 return addZIRBinOp(mod, scope, src, .array_type, len, child_type);
657}
658
659fn arrayTypeSentinel(mod: *Module, scope: *Scope, node: *ast.Node.ArrayTypeSentinel) !*zir.Inst {
660 const tree = scope.tree();
661 const src = tree.token_locs[node.op_token].start;
662 const meta_type = try addZIRInstConst(mod, scope, src, .{
663 .ty = Type.initTag(.type),
664 .val = Value.initTag(.type_type),
665 });
666 const usize_type = try addZIRInstConst(mod, scope, src, .{
667 .ty = Type.initTag(.type),
668 .val = Value.initTag(.usize_type),
669 });
670
671 // TODO check for [_]T
672 const len = try expr(mod, scope, .{ .ty = usize_type }, node.len_expr);
673 const sentinel_uncasted = try expr(mod, scope, .none, node.sentinel);
674 const elem_type = try expr(mod, scope, .{ .ty = meta_type }, node.rhs);
675 const sentinel = try addZIRBinOp(mod, scope, src, .as, elem_type, sentinel_uncasted);
676
677 return addZIRInst(mod, scope, src, zir.Inst.ArrayTypeSentinel, .{
678 .len = len,
679 .sentinel = sentinel,
680 .elem_type = elem_type,
681 }, .{});
682}
683
684fn enumLiteral(mod: *Module, scope: *Scope, node: *ast.Node.EnumLiteral) !*zir.Inst {
685 const tree = scope.tree();
686 const src = tree.token_locs[node.name].start;
687 const name = try identifierTokenString(mod, scope, node.name);
688
689 return addZIRInst(mod, scope, src, zir.Inst.EnumLiteral, .{ .name = name }, .{});
690}
691
487fn unwrapOptional(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.SimpleSuffixOp) InnerError!*zir.Inst {692fn unwrapOptional(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.SimpleSuffixOp) InnerError!*zir.Inst {
488 const tree = scope.tree();693 const tree = scope.tree();
489 const src = tree.token_locs[node.rtoken].start;694 const src = tree.token_locs[node.rtoken].start;
490695
491 const operand = try expr(mod, scope, .lvalue, node.lhs);696 const operand = try expr(mod, scope, .ref, node.lhs);
492 const unwrapped_ptr = try addZIRUnOp(mod, scope, src, .unwrap_optional_safe, operand);697 const unwrapped_ptr = try addZIRUnOp(mod, scope, src, .unwrap_optional_safe, operand);
493 if (rl == .lvalue) return unwrapped_ptr;698 if (rl == .lvalue or rl == .ref) return unwrapped_ptr;
494699
495 return rlWrap(mod, scope, rl, try addZIRUnOp(mod, scope, src, .deref, unwrapped_ptr));700 return rlWrap(mod, scope, rl, try addZIRUnOp(mod, scope, src, .deref, unwrapped_ptr));
496}701}
...@@ -568,6 +773,88 @@ fn simpleBinOp(...@@ -568,6 +773,88 @@ fn simpleBinOp(
568 return rlWrap(mod, scope, rl, result);773 return rlWrap(mod, scope, rl, result);
569}774}
570775
776fn boolBinOp(
777 mod: *Module,
778 scope: *Scope,
779 rl: ResultLoc,
780 infix_node: *ast.Node.SimpleInfixOp,
781) InnerError!*zir.Inst {
782 const tree = scope.tree();
783 const src = tree.token_locs[infix_node.op_token].start;
784 const bool_type = try addZIRInstConst(mod, scope, src, .{
785 .ty = Type.initTag(.type),
786 .val = Value.initTag(.bool_type),
787 });
788
789 var block_scope: Scope.GenZIR = .{
790 .parent = scope,
791 .decl = scope.decl().?,
792 .arena = scope.arena(),
793 .instructions = .{},
794 };
795 defer block_scope.instructions.deinit(mod.gpa);
796
797 const lhs = try expr(mod, scope, .{ .ty = bool_type }, infix_node.lhs);
798 const condbr = try addZIRInstSpecial(mod, &block_scope.base, src, zir.Inst.CondBr, .{
799 .condition = lhs,
800 .then_body = undefined, // populated below
801 .else_body = undefined, // populated below
802 }, .{});
803
804 const block = try addZIRInstBlock(mod, scope, src, .{
805 .instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items),
806 });
807
808 var rhs_scope: Scope.GenZIR = .{
809 .parent = scope,
810 .decl = block_scope.decl,
811 .arena = block_scope.arena,
812 .instructions = .{},
813 };
814 defer rhs_scope.instructions.deinit(mod.gpa);
815
816 const rhs = try expr(mod, &rhs_scope.base, .{ .ty = bool_type }, infix_node.rhs);
817 _ = try addZIRInst(mod, &rhs_scope.base, src, zir.Inst.Break, .{
818 .block = block,
819 .operand = rhs,
820 }, .{});
821
822 var const_scope: Scope.GenZIR = .{
823 .parent = scope,
824 .decl = block_scope.decl,
825 .arena = block_scope.arena,
826 .instructions = .{},
827 };
828 defer const_scope.instructions.deinit(mod.gpa);
829
830 const is_bool_and = infix_node.base.tag == .BoolAnd;
831 _ = try addZIRInst(mod, &const_scope.base, src, zir.Inst.Break, .{
832 .block = block,
833 .operand = try addZIRInstConst(mod, &const_scope.base, src, .{
834 .ty = Type.initTag(.bool),
835 .val = if (is_bool_and) Value.initTag(.bool_false) else Value.initTag(.bool_true),
836 }),
837 }, .{});
838
839 if (is_bool_and) {
840 // if lhs // AND
841 // break rhs
842 // else
843 // break false
844 condbr.positionals.then_body = .{ .instructions = try rhs_scope.arena.dupe(*zir.Inst, rhs_scope.instructions.items) };
845 condbr.positionals.else_body = .{ .instructions = try const_scope.arena.dupe(*zir.Inst, const_scope.instructions.items) };
846 } else {
847 // if lhs // OR
848 // break true
849 // else
850 // break rhs
851 condbr.positionals.then_body = .{ .instructions = try const_scope.arena.dupe(*zir.Inst, const_scope.instructions.items) };
852 condbr.positionals.else_body = .{ .instructions = try rhs_scope.arena.dupe(*zir.Inst, rhs_scope.instructions.items) };
853 }
854
855 return rlWrap(mod, scope, rl, &block.base);
856}
857
571const CondKind = union(enum) {858const CondKind = union(enum) {
572 bool,859 bool,
573 optional: ?*zir.Inst,860 optional: ?*zir.Inst,
...@@ -583,13 +870,13 @@ const CondKind = union(enum) {...@@ -583,13 +870,13 @@ const CondKind = union(enum) {
583 return try expr(mod, &block_scope.base, .{ .ty = bool_type }, cond_node);870 return try expr(mod, &block_scope.base, .{ .ty = bool_type }, cond_node);
584 },871 },
585 .optional => {872 .optional => {
586 const cond_ptr = try expr(mod, &block_scope.base, .lvalue, cond_node);873 const cond_ptr = try expr(mod, &block_scope.base, .ref, cond_node);
587 self.* = .{ .optional = cond_ptr };874 self.* = .{ .optional = cond_ptr };
588 const result = try addZIRUnOp(mod, &block_scope.base, src, .deref, cond_ptr);875 const result = try addZIRUnOp(mod, &block_scope.base, src, .deref, cond_ptr);
589 return try addZIRUnOp(mod, &block_scope.base, src, .isnonnull, result);876 return try addZIRUnOp(mod, &block_scope.base, src, .isnonnull, result);
590 },877 },
591 .err_union => {878 .err_union => {
592 const err_ptr = try expr(mod, &block_scope.base, .lvalue, cond_node);879 const err_ptr = try expr(mod, &block_scope.base, .ref, cond_node);
593 self.* = .{ .err_union = err_ptr };880 self.* = .{ .err_union = err_ptr };
594 const result = try addZIRUnOp(mod, &block_scope.base, src, .deref, err_ptr);881 const result = try addZIRUnOp(mod, &block_scope.base, src, .deref, err_ptr);
595 return try addZIRUnOp(mod, &block_scope.base, src, .iserr, result);882 return try addZIRUnOp(mod, &block_scope.base, src, .iserr, result);
...@@ -600,7 +887,11 @@ const CondKind = union(enum) {...@@ -600,7 +887,11 @@ const CondKind = union(enum) {
600 fn thenSubScope(self: CondKind, mod: *Module, then_scope: *Scope.GenZIR, src: usize, payload_node: ?*ast.Node) !*Scope {887 fn thenSubScope(self: CondKind, mod: *Module, then_scope: *Scope.GenZIR, src: usize, payload_node: ?*ast.Node) !*Scope {
601 if (self == .bool) return &then_scope.base;888 if (self == .bool) return &then_scope.base;
602889
603 const payload = payload_node.?.castTag(.PointerPayload).?;890 const payload = payload_node.?.castTag(.PointerPayload) orelse {
891 // condition is error union and payload is not explicitly ignored
892 _ = try addZIRUnOp(mod, &then_scope.base, src, .ensure_err_payload_void, self.err_union.?);
893 return &then_scope.base;
894 };
604 const is_ptr = payload.ptr_token != null;895 const is_ptr = payload.ptr_token != null;
605 const ident_node = payload.value_symbol.castTag(.Identifier).?;896 const ident_node = payload.value_symbol.castTag(.Identifier).?;
606897
...@@ -680,7 +971,7 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn...@@ -680,7 +971,7 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn
680 // proper type inference requires peer type resolution on the if's971 // proper type inference requires peer type resolution on the if's
681 // branches.972 // branches.
682 const branch_rl: ResultLoc = switch (rl) {973 const branch_rl: ResultLoc = switch (rl) {
683 .discard, .none, .ty, .ptr, .lvalue => rl,974 .discard, .none, .ty, .ptr, .lvalue, .ref => rl,
684 .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = block },975 .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = block },
685 };976 };
686977
...@@ -810,7 +1101,7 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W...@@ -810,7 +1101,7 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W
810 // proper type inference requires peer type resolution on the while's1101 // proper type inference requires peer type resolution on the while's
811 // branches.1102 // branches.
812 const branch_rl: ResultLoc = switch (rl) {1103 const branch_rl: ResultLoc = switch (rl) {
813 .discard, .none, .ty, .ptr, .lvalue => rl,1104 .discard, .none, .ty, .ptr, .lvalue, .ref => rl,
814 .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = while_block },1105 .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = while_block },
815 };1106 };
8161107
...@@ -941,7 +1232,7 @@ fn identifier(mod: *Module, scope: *Scope, rl: ResultLoc, ident: *ast.Node.OneTo...@@ -941,7 +1232,7 @@ fn identifier(mod: *Module, scope: *Scope, rl: ResultLoc, ident: *ast.Node.OneTo
941 .local_ptr => {1232 .local_ptr => {
942 const local_ptr = s.cast(Scope.LocalPtr).?;1233 const local_ptr = s.cast(Scope.LocalPtr).?;
943 if (mem.eql(u8, local_ptr.name, ident_name)) {1234 if (mem.eql(u8, local_ptr.name, ident_name)) {
944 if (rl == .lvalue) {1235 if (rl == .lvalue or rl == .ref) {
945 return local_ptr.ptr;1236 return local_ptr.ptr;
946 } else {1237 } else {
947 const result = try addZIRUnOp(mod, scope, src, .deref, local_ptr.ptr);1238 const result = try addZIRUnOp(mod, scope, src, .deref, local_ptr.ptr);
...@@ -956,9 +1247,10 @@ fn identifier(mod: *Module, scope: *Scope, rl: ResultLoc, ident: *ast.Node.OneTo...@@ -956,9 +1247,10 @@ fn identifier(mod: *Module, scope: *Scope, rl: ResultLoc, ident: *ast.Node.OneTo
956 }1247 }
9571248
958 if (mod.lookupDeclName(scope, ident_name)) |decl| {1249 if (mod.lookupDeclName(scope, ident_name)) |decl| {
959 // TODO handle lvalues
960 const result = try addZIRInst(mod, scope, src, zir.Inst.DeclValInModule, .{ .decl = decl }, .{});1250 const result = try addZIRInst(mod, scope, src, zir.Inst.DeclValInModule, .{ .decl = decl }, .{});
961 return rlWrap(mod, scope, rl, result);1251 if (rl == .lvalue or rl == .ref)
1252 return result;
1253 return rlWrap(mod, scope, rl, try addZIRUnOp(mod, scope, src, .deref, result));
962 }1254 }
9631255
964 return mod.failNode(scope, &ident.base, "use of undeclared identifier '{}'", .{ident_name});1256 return mod.failNode(scope, &ident.base, "use of undeclared identifier '{}'", .{ident_name});
...@@ -983,6 +1275,54 @@ fn stringLiteral(mod: *Module, scope: *Scope, str_lit: *ast.Node.OneToken) Inner...@@ -983,6 +1275,54 @@ fn stringLiteral(mod: *Module, scope: *Scope, str_lit: *ast.Node.OneToken) Inner
983 return addZIRInst(mod, scope, src, zir.Inst.Str, .{ .bytes = bytes }, .{});1275 return addZIRInst(mod, scope, src, zir.Inst.Str, .{ .bytes = bytes }, .{});
984}1276}
9851277
1278fn multilineStrLiteral(mod: *Module, scope: *Scope, node: *ast.Node.MultilineStringLiteral) !*zir.Inst {
1279 const tree = scope.tree();
1280 const lines = node.linesConst();
1281 const src = tree.token_locs[lines[0]].start;
1282
1283 // line lengths and new lines
1284 var len = lines.len - 1;
1285 for (lines) |line| {
1286 // 2 for the '//' + 1 for '\n'
1287 len += tree.tokenSlice(line).len - 3;
1288 }
1289
1290 const bytes = try scope.arena().alloc(u8, len);
1291 var i: usize = 0;
1292 for (lines) |line, line_i| {
1293 if (line_i != 0) {
1294 bytes[i] = '\n';
1295 i += 1;
1296 }
1297 const slice = tree.tokenSlice(line);
1298 mem.copy(u8, bytes[i..], slice[2 .. slice.len - 1]);
1299 i += slice.len - 3;
1300 }
1301
1302 return addZIRInst(mod, scope, src, zir.Inst.Str, .{ .bytes = bytes }, .{});
1303}
1304
1305fn charLiteral(mod: *Module, scope: *Scope, node: *ast.Node.OneToken) !*zir.Inst {
1306 const tree = scope.tree();
1307 const src = tree.token_locs[node.token].start;
1308 const slice = tree.tokenSlice(node.token);
1309
1310 var bad_index: usize = undefined;
1311 const value = std.zig.parseCharLiteral(slice, &bad_index) catch |err| switch (err) {
1312 error.InvalidCharacter => {
1313 const bad_byte = slice[bad_index];
1314 return mod.fail(scope, src + bad_index, "invalid character: '{c}'\n", .{bad_byte});
1315 },
1316 };
1317
1318 const int_payload = try scope.arena().create(Value.Payload.Int_u64);
1319 int_payload.* = .{ .int = value };
1320 return addZIRInstConst(mod, scope, src, .{
1321 .ty = Type.initTag(.comptime_int),
1322 .val = Value.initPayload(&int_payload.base),
1323 });
1324}
1325
986fn integerLiteral(mod: *Module, scope: *Scope, int_lit: *ast.Node.OneToken) InnerError!*zir.Inst {1326fn integerLiteral(mod: *Module, scope: *Scope, int_lit: *ast.Node.OneToken) InnerError!*zir.Inst {
987 const arena = scope.arena();1327 const arena = scope.arena();
988 const tree = scope.tree();1328 const tree = scope.tree();
...@@ -1158,7 +1498,8 @@ fn as(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.BuiltinCall) I...@@ -1158,7 +1498,8 @@ fn as(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.BuiltinCall) I
1158 _ = try addZIRUnOp(mod, scope, result.src, .ensure_result_non_error, result);1498 _ = try addZIRUnOp(mod, scope, result.src, .ensure_result_non_error, result);
1159 return result;1499 return result;
1160 },1500 },
1161 .lvalue => {1501 .lvalue => unreachable,
1502 .ref => {
1162 const result = try expr(mod, scope, .{ .ty = dest_type }, params[1]);1503 const result = try expr(mod, scope, .{ .ty = dest_type }, params[1]);
1163 return addZIRUnOp(mod, scope, result.src, .ref, result);1504 return addZIRUnOp(mod, scope, result.src, .ref, result);
1164 },1505 },
...@@ -1209,9 +1550,10 @@ fn bitCast(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.BuiltinCa...@@ -1209,9 +1550,10 @@ fn bitCast(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.BuiltinCa
1209 _ = try addZIRUnOp(mod, scope, result.src, .ensure_result_non_error, result);1550 _ = try addZIRUnOp(mod, scope, result.src, .ensure_result_non_error, result);
1210 return result;1551 return result;
1211 },1552 },
1212 .lvalue => {1553 .lvalue => unreachable,
1213 const operand = try expr(mod, scope, .lvalue, params[1]);1554 .ref => {
1214 const result = try addZIRBinOp(mod, scope, src, .bitcast_lvalue, dest_type, operand);1555 const operand = try expr(mod, scope, .ref, params[1]);
1556 const result = try addZIRBinOp(mod, scope, src, .bitcast_ref, dest_type, operand);
1215 return result;1557 return result;
1216 },1558 },
1217 .ty => |result_ty| {1559 .ty => |result_ty| {
...@@ -1476,7 +1818,7 @@ fn rlWrap(mod: *Module, scope: *Scope, rl: ResultLoc, result: *zir.Inst) InnerEr...@@ -1476,7 +1818,7 @@ fn rlWrap(mod: *Module, scope: *Scope, rl: ResultLoc, result: *zir.Inst) InnerEr
1476 _ = try addZIRUnOp(mod, scope, result.src, .ensure_result_non_error, result);1818 _ = try addZIRUnOp(mod, scope, result.src, .ensure_result_non_error, result);
1477 return result;1819 return result;
1478 },1820 },
1479 .lvalue => {1821 .lvalue, .ref => {
1480 // We need a pointer but we have a value.1822 // We need a pointer but we have a value.
1481 return addZIRUnOp(mod, scope, result.src, .ref, result);1823 return addZIRUnOp(mod, scope, result.src, .ref, result);
1482 },1824 },
src-self-hosted/cbe.h deleted-15
...@@ -1,15 +0,0 @@
1#if __STDC_VERSION__ >= 201112L
2#define zig_noreturn _Noreturn
3#elif __GNUC__
4#define zig_noreturn __attribute__ ((noreturn))
5#elif _MSC_VER
6#define zig_noreturn __declspec(noreturn)
7#else
8#define zig_noreturn
9#endif
10
11#if __GNUC__
12#define zig_unreachable() __builtin_unreachable()
13#else
14#define zig_unreachable()
15#endif
src-self-hosted/codegen.zig+131-100
...@@ -59,20 +59,20 @@ pub const GenerateSymbolError = error{...@@ -59,20 +59,20 @@ pub const GenerateSymbolError = error{
59};59};
6060
61pub fn generateSymbol(61pub fn generateSymbol(
62 bin_file: *link.File.Elf,62 bin_file: *link.File,
63 src: usize,63 src: usize,
64 typed_value: TypedValue,64 typed_value: TypedValue,
65 code: *std.ArrayList(u8),65 code: *std.ArrayList(u8),
66 dbg_line: *std.ArrayList(u8),66 dbg_line: *std.ArrayList(u8),
67 dbg_info: *std.ArrayList(u8),67 dbg_info: *std.ArrayList(u8),
68 dbg_info_type_relocs: *link.File.Elf.DbgInfoTypeRelocsTable,68 dbg_info_type_relocs: *link.File.DbgInfoTypeRelocsTable,
69) GenerateSymbolError!Result {69) GenerateSymbolError!Result {
70 const tracy = trace(@src());70 const tracy = trace(@src());
71 defer tracy.end();71 defer tracy.end();
7272
73 switch (typed_value.ty.zigTypeTag()) {73 switch (typed_value.ty.zigTypeTag()) {
74 .Fn => {74 .Fn => {
75 switch (bin_file.base.options.target.cpu.arch) {75 switch (bin_file.options.target.cpu.arch) {
76 .wasm32 => unreachable, // has its own code path76 .wasm32 => unreachable, // has its own code path
77 .wasm64 => unreachable, // has its own code path77 .wasm64 => unreachable, // has its own code path
78 //.arm => return Function(.arm).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs),78 //.arm => return Function(.arm).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs),
...@@ -151,7 +151,7 @@ pub fn generateSymbol(...@@ -151,7 +151,7 @@ pub fn generateSymbol(
151 }151 }
152 return Result{152 return Result{
153 .fail = try ErrorMsg.create(153 .fail = try ErrorMsg.create(
154 bin_file.base.allocator,154 bin_file.allocator,
155 src,155 src,
156 "TODO implement generateSymbol for more kinds of arrays",156 "TODO implement generateSymbol for more kinds of arrays",
157 .{},157 .{},
...@@ -164,12 +164,11 @@ pub fn generateSymbol(...@@ -164,12 +164,11 @@ pub fn generateSymbol(
164 if (typed_value.val.cast(Value.Payload.DeclRef)) |payload| {164 if (typed_value.val.cast(Value.Payload.DeclRef)) |payload| {
165 const decl = payload.decl;165 const decl = payload.decl;
166 if (decl.analysis != .complete) return error.AnalysisFail;166 if (decl.analysis != .complete) return error.AnalysisFail;
167 assert(decl.link.elf.local_sym_index != 0);
168 // TODO handle the dependency of this symbol on the decl's vaddr.167 // TODO handle the dependency of this symbol on the decl's vaddr.
169 // If the decl changes vaddr, then this symbol needs to get regenerated.168 // If the decl changes vaddr, then this symbol needs to get regenerated.
170 const vaddr = bin_file.local_symbols.items[decl.link.elf.local_sym_index].st_value;169 const vaddr = bin_file.getDeclVAddr(decl);
171 const endian = bin_file.base.options.target.cpu.arch.endian();170 const endian = bin_file.options.target.cpu.arch.endian();
172 switch (bin_file.base.options.target.cpu.arch.ptrBitWidth()) {171 switch (bin_file.options.target.cpu.arch.ptrBitWidth()) {
173 16 => {172 16 => {
174 try code.resize(2);173 try code.resize(2);
175 mem.writeInt(u16, code.items[0..2], @intCast(u16, vaddr), endian);174 mem.writeInt(u16, code.items[0..2], @intCast(u16, vaddr), endian);
...@@ -188,7 +187,7 @@ pub fn generateSymbol(...@@ -188,7 +187,7 @@ pub fn generateSymbol(
188 }187 }
189 return Result{188 return Result{
190 .fail = try ErrorMsg.create(189 .fail = try ErrorMsg.create(
191 bin_file.base.allocator,190 bin_file.allocator,
192 src,191 src,
193 "TODO implement generateSymbol for pointer {}",192 "TODO implement generateSymbol for pointer {}",
194 .{typed_value.val},193 .{typed_value.val},
...@@ -198,7 +197,7 @@ pub fn generateSymbol(...@@ -198,7 +197,7 @@ pub fn generateSymbol(
198 .Int => {197 .Int => {
199 // TODO populate .debug_info for the integer198 // TODO populate .debug_info for the integer
200199
201 const info = typed_value.ty.intInfo(bin_file.base.options.target);200 const info = typed_value.ty.intInfo(bin_file.options.target);
202 if (info.bits == 8 and !info.signed) {201 if (info.bits == 8 and !info.signed) {
203 const x = typed_value.val.toUnsignedInt();202 const x = typed_value.val.toUnsignedInt();
204 try code.append(@intCast(u8, x));203 try code.append(@intCast(u8, x));
...@@ -206,7 +205,7 @@ pub fn generateSymbol(...@@ -206,7 +205,7 @@ pub fn generateSymbol(
206 }205 }
207 return Result{206 return Result{
208 .fail = try ErrorMsg.create(207 .fail = try ErrorMsg.create(
209 bin_file.base.allocator,208 bin_file.allocator,
210 src,209 src,
211 "TODO implement generateSymbol for int type '{}'",210 "TODO implement generateSymbol for int type '{}'",
212 .{typed_value.ty},211 .{typed_value.ty},
...@@ -216,7 +215,7 @@ pub fn generateSymbol(...@@ -216,7 +215,7 @@ pub fn generateSymbol(
216 else => |t| {215 else => |t| {
217 return Result{216 return Result{
218 .fail = try ErrorMsg.create(217 .fail = try ErrorMsg.create(
219 bin_file.base.allocator,218 bin_file.allocator,
220 src,219 src,
221 "TODO implement generateSymbol for type '{}'",220 "TODO implement generateSymbol for type '{}'",
222 .{@tagName(t)},221 .{@tagName(t)},
...@@ -234,13 +233,13 @@ const InnerError = error{...@@ -234,13 +233,13 @@ const InnerError = error{
234fn Function(comptime arch: std.Target.Cpu.Arch) type {233fn Function(comptime arch: std.Target.Cpu.Arch) type {
235 return struct {234 return struct {
236 gpa: *Allocator,235 gpa: *Allocator,
237 bin_file: *link.File.Elf,236 bin_file: *link.File,
238 target: *const std.Target,237 target: *const std.Target,
239 mod_fn: *const Module.Fn,238 mod_fn: *const Module.Fn,
240 code: *std.ArrayList(u8),239 code: *std.ArrayList(u8),
241 dbg_line: *std.ArrayList(u8),240 dbg_line: *std.ArrayList(u8),
242 dbg_info: *std.ArrayList(u8),241 dbg_info: *std.ArrayList(u8),
243 dbg_info_type_relocs: *link.File.Elf.DbgInfoTypeRelocsTable,242 dbg_info_type_relocs: *link.File.DbgInfoTypeRelocsTable,
244 err_msg: ?*ErrorMsg,243 err_msg: ?*ErrorMsg,
245 args: []MCValue,244 args: []MCValue,
246 ret_mcv: MCValue,245 ret_mcv: MCValue,
...@@ -405,22 +404,22 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -405,22 +404,22 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
405 const Self = @This();404 const Self = @This();
406405
407 fn generateSymbol(406 fn generateSymbol(
408 bin_file: *link.File.Elf,407 bin_file: *link.File,
409 src: usize,408 src: usize,
410 typed_value: TypedValue,409 typed_value: TypedValue,
411 code: *std.ArrayList(u8),410 code: *std.ArrayList(u8),
412 dbg_line: *std.ArrayList(u8),411 dbg_line: *std.ArrayList(u8),
413 dbg_info: *std.ArrayList(u8),412 dbg_info: *std.ArrayList(u8),
414 dbg_info_type_relocs: *link.File.Elf.DbgInfoTypeRelocsTable,413 dbg_info_type_relocs: *link.File.DbgInfoTypeRelocsTable,
415 ) GenerateSymbolError!Result {414 ) GenerateSymbolError!Result {
416 const module_fn = typed_value.val.cast(Value.Payload.Function).?.func;415 const module_fn = typed_value.val.cast(Value.Payload.Function).?.func;
417416
418 const fn_type = module_fn.owner_decl.typed_value.most_recent.typed_value.ty;417 const fn_type = module_fn.owner_decl.typed_value.most_recent.typed_value.ty;
419418
420 var branch_stack = std.ArrayList(Branch).init(bin_file.base.allocator);419 var branch_stack = std.ArrayList(Branch).init(bin_file.allocator);
421 defer {420 defer {
422 assert(branch_stack.items.len == 1);421 assert(branch_stack.items.len == 1);
423 branch_stack.items[0].deinit(bin_file.base.allocator);422 branch_stack.items[0].deinit(bin_file.allocator);
424 branch_stack.deinit();423 branch_stack.deinit();
425 }424 }
426 const branch = try branch_stack.addOne();425 const branch = try branch_stack.addOne();
...@@ -443,8 +442,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -443,8 +442,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
443 };442 };
444443
445 var function = Self{444 var function = Self{
446 .gpa = bin_file.base.allocator,445 .gpa = bin_file.allocator,
447 .target = &bin_file.base.options.target,446 .target = &bin_file.options.target,
448 .bin_file = bin_file,447 .bin_file = bin_file,
449 .mod_fn = module_fn,448 .mod_fn = module_fn,
450 .code = code,449 .code = code,
...@@ -464,7 +463,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -464,7 +463,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
464 .rbrace_src = src_data.rbrace_src,463 .rbrace_src = src_data.rbrace_src,
465 .source = src_data.source,464 .source = src_data.source,
466 };465 };
467 defer function.exitlude_jump_relocs.deinit(bin_file.base.allocator);466 defer function.exitlude_jump_relocs.deinit(bin_file.allocator);
468467
469 var call_info = function.resolveCallingConventionValues(src, fn_type) catch |err| switch (err) {468 var call_info = function.resolveCallingConventionValues(src, fn_type) catch |err| switch (err) {
470 error.CodegenFail => return Result{ .fail = function.err_msg.? },469 error.CodegenFail => return Result{ .fail = function.err_msg.? },
...@@ -684,6 +683,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -684,6 +683,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
684 .unreach => return MCValue{ .unreach = {} },683 .unreach => return MCValue{ .unreach = {} },
685 .unwrap_optional => return self.genUnwrapOptional(inst.castTag(.unwrap_optional).?),684 .unwrap_optional => return self.genUnwrapOptional(inst.castTag(.unwrap_optional).?),
686 .wrap_optional => return self.genWrapOptional(inst.castTag(.wrap_optional).?),685 .wrap_optional => return self.genWrapOptional(inst.castTag(.wrap_optional).?),
686 .varptr => return self.genVarPtr(inst.castTag(.varptr).?),
687 }687 }
688 }688 }
689689
...@@ -858,6 +858,26 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -858,6 +858,26 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
858 }858 }
859 }859 }
860860
861 fn genVarPtr(self: *Self, inst: *ir.Inst.VarPtr) !MCValue {
862 // No side effects, so if it's unreferenced, do nothing.
863 if (inst.base.isUnused())
864 return MCValue.dead;
865
866 switch (arch) {
867 else => return self.fail(inst.base.src, "TODO implement varptr for {}", .{self.target.cpu.arch}),
868 }
869 }
870
871 fn reuseOperand(inst: *ir.Inst, op_index: ir.Inst.DeathsBitIndex, mcv: MCValue) bool {
872 if (!inst.operandDies(op_index) or !mcv.isMutable())
873 return false;
874
875 // OK we're going to do it, but we need to clear the operand death bit so that
876 // it stays allocated.
877 inst.clearOperandDeath(op_index);
878 return true;
879 }
880
861 fn genLoad(self: *Self, inst: *ir.Inst.UnOp) !MCValue {881 fn genLoad(self: *Self, inst: *ir.Inst.UnOp) !MCValue {
862 const elem_ty = inst.base.ty;882 const elem_ty = inst.base.ty;
863 if (!elem_ty.hasCodeGenBits())883 if (!elem_ty.hasCodeGenBits())
...@@ -867,9 +887,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -867,9 +887,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
867 if (inst.base.isUnused() and !is_volatile)887 if (inst.base.isUnused() and !is_volatile)
868 return MCValue.dead;888 return MCValue.dead;
869 const dst_mcv: MCValue = blk: {889 const dst_mcv: MCValue = blk: {
870 if (inst.base.operandDies(0) and ptr.isMutable()) {890 if (reuseOperand(&inst.base, 0, ptr)) {
871 // The MCValue that holds the pointer can be re-used as the value.891 // The MCValue that holds the pointer can be re-used as the value.
872 // TODO track this in the register/stack allocation metadata.
873 break :blk ptr;892 break :blk ptr;
874 } else {893 } else {
875 break :blk try self.allocRegOrMem(&inst.base);894 break :blk try self.allocRegOrMem(&inst.base);
...@@ -966,7 +985,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -966,7 +985,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
966 var dst_mcv: MCValue = undefined;985 var dst_mcv: MCValue = undefined;
967 var src_mcv: MCValue = undefined;986 var src_mcv: MCValue = undefined;
968 var src_inst: *ir.Inst = undefined;987 var src_inst: *ir.Inst = undefined;
969 if (inst.operandDies(0) and lhs.isMutable()) {988 if (reuseOperand(inst, 0, lhs)) {
970 // LHS dies; use it as the destination.989 // LHS dies; use it as the destination.
971 // Both operands cannot be memory.990 // Both operands cannot be memory.
972 src_inst = op_rhs;991 src_inst = op_rhs;
...@@ -977,7 +996,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -977,7 +996,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
977 dst_mcv = lhs;996 dst_mcv = lhs;
978 src_mcv = rhs;997 src_mcv = rhs;
979 }998 }
980 } else if (inst.operandDies(1) and rhs.isMutable()) {999 } else if (reuseOperand(inst, 1, rhs)) {
981 // RHS dies; use it as the destination.1000 // RHS dies; use it as the destination.
982 // Both operands cannot be memory.1001 // Both operands cannot be memory.
983 src_inst = op_lhs;1002 src_inst = op_lhs;
...@@ -1124,80 +1143,88 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1124,80 +1143,88 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1124 var info = try self.resolveCallingConventionValues(inst.base.src, inst.func.ty);1143 var info = try self.resolveCallingConventionValues(inst.base.src, inst.func.ty);
1125 defer info.deinit(self);1144 defer info.deinit(self);
11261145
1127 switch (arch) {1146 // Due to incremental compilation, how function calls are generated depends
1128 .x86_64 => {1147 // on linking.
1129 for (info.args) |mc_arg, arg_i| {1148 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
1130 const arg = inst.args[arg_i];1149 switch (arch) {
1131 const arg_mcv = try self.resolveInst(inst.args[arg_i]);1150 .x86_64 => {
1132 // Here we do not use setRegOrMem even though the logic is similar, because1151 for (info.args) |mc_arg, arg_i| {
1133 // the function call will move the stack pointer, so the offsets are different.1152 const arg = inst.args[arg_i];
1134 switch (mc_arg) {1153 const arg_mcv = try self.resolveInst(inst.args[arg_i]);
1135 .none => continue,1154 // Here we do not use setRegOrMem even though the logic is similar, because
1136 .register => |reg| {1155 // the function call will move the stack pointer, so the offsets are different.
1137 try self.genSetReg(arg.src, reg, arg_mcv);1156 switch (mc_arg) {
1138 // TODO interact with the register allocator to mark the instruction as moved.1157 .none => continue,
1139 },1158 .register => |reg| {
1140 .stack_offset => {1159 try self.genSetReg(arg.src, reg, arg_mcv);
1141 // Here we need to emit instructions like this:1160 // TODO interact with the register allocator to mark the instruction as moved.
1142 // mov qword ptr [rsp + stack_offset], x1161 },
1143 return self.fail(inst.base.src, "TODO implement calling with parameters in memory", .{});1162 .stack_offset => {
1144 },1163 // Here we need to emit instructions like this:
1145 .ptr_stack_offset => {1164 // mov qword ptr [rsp + stack_offset], x
1146 return self.fail(inst.base.src, "TODO implement calling with MCValue.ptr_stack_offset arg", .{});1165 return self.fail(inst.base.src, "TODO implement calling with parameters in memory", .{});
1147 },1166 },
1148 .ptr_embedded_in_code => {1167 .ptr_stack_offset => {
1149 return self.fail(inst.base.src, "TODO implement calling with MCValue.ptr_embedded_in_code arg", .{});1168 return self.fail(inst.base.src, "TODO implement calling with MCValue.ptr_stack_offset arg", .{});
1150 },1169 },
1151 .undef => unreachable,1170 .ptr_embedded_in_code => {
1152 .immediate => unreachable,1171 return self.fail(inst.base.src, "TODO implement calling with MCValue.ptr_embedded_in_code arg", .{});
1153 .unreach => unreachable,1172 },
1154 .dead => unreachable,1173 .undef => unreachable,
1155 .embedded_in_code => unreachable,1174 .immediate => unreachable,
1156 .memory => unreachable,1175 .unreach => unreachable,
1157 .compare_flags_signed => unreachable,1176 .dead => unreachable,
1158 .compare_flags_unsigned => unreachable,1177 .embedded_in_code => unreachable,
1178 .memory => unreachable,
1179 .compare_flags_signed => unreachable,
1180 .compare_flags_unsigned => unreachable,
1181 }
1159 }1182 }
1160 }
11611183
1162 if (inst.func.cast(ir.Inst.Constant)) |func_inst| {1184 if (inst.func.cast(ir.Inst.Constant)) |func_inst| {
1163 if (func_inst.val.cast(Value.Payload.Function)) |func_val| {1185 if (func_inst.val.cast(Value.Payload.Function)) |func_val| {
1164 const func = func_val.func;1186 const func = func_val.func;
1165 const got = &self.bin_file.program_headers.items[self.bin_file.phdr_got_index.?];1187 const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];
1166 const ptr_bits = self.target.cpu.arch.ptrBitWidth();1188 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
1167 const ptr_bytes: u64 = @divExact(ptr_bits, 8);1189 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
1168 const got_addr = @intCast(u32, got.p_vaddr + func.owner_decl.link.elf.offset_table_index * ptr_bytes);1190 const got_addr = @intCast(u32, got.p_vaddr + func.owner_decl.link.elf.offset_table_index * ptr_bytes);
1169 // ff 14 25 xx xx xx xx call [addr]1191 // ff 14 25 xx xx xx xx call [addr]
1170 try self.code.ensureCapacity(self.code.items.len + 7);1192 try self.code.ensureCapacity(self.code.items.len + 7);
1171 self.code.appendSliceAssumeCapacity(&[3]u8{ 0xff, 0x14, 0x25 });1193 self.code.appendSliceAssumeCapacity(&[3]u8{ 0xff, 0x14, 0x25 });
1172 mem.writeIntLittle(u32, self.code.addManyAsArrayAssumeCapacity(4), got_addr);1194 mem.writeIntLittle(u32, self.code.addManyAsArrayAssumeCapacity(4), got_addr);
1195 } else {
1196 return self.fail(inst.base.src, "TODO implement calling bitcasted functions", .{});
1197 }
1173 } else {1198 } else {
1174 return self.fail(inst.base.src, "TODO implement calling bitcasted functions", .{});1199 return self.fail(inst.base.src, "TODO implement calling runtime known function pointer", .{});
1175 }1200 }
1176 } else {1201 },
1177 return self.fail(inst.base.src, "TODO implement calling runtime known function pointer", .{});1202 .riscv64 => {
1178 }1203 if (info.args.len > 0) return self.fail(inst.base.src, "TODO implement fn args for {}", .{self.target.cpu.arch});
1179 },1204
1180 .riscv64 => {1205 if (inst.func.cast(ir.Inst.Constant)) |func_inst| {
1181 if (info.args.len > 0) return self.fail(inst.base.src, "TODO implement fn args for {}", .{self.target.cpu.arch});1206 if (func_inst.val.cast(Value.Payload.Function)) |func_val| {
11821207 const func = func_val.func;
1183 if (inst.func.cast(ir.Inst.Constant)) |func_inst| {1208 const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];
1184 if (func_inst.val.cast(Value.Payload.Function)) |func_val| {1209 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
1185 const func = func_val.func;1210 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
1186 const got = &self.bin_file.program_headers.items[self.bin_file.phdr_got_index.?];1211 const got_addr = @intCast(u32, got.p_vaddr + func.owner_decl.link.elf.offset_table_index * ptr_bytes);
1187 const ptr_bits = self.target.cpu.arch.ptrBitWidth();1212
1188 const ptr_bytes: u64 = @divExact(ptr_bits, 8);1213 try self.genSetReg(inst.base.src, .ra, .{ .memory = got_addr });
1189 const got_addr = @intCast(u32, got.p_vaddr + func.owner_decl.link.elf.offset_table_index * ptr_bytes);1214 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.jalr(.ra, 0, .ra).toU32());
11901215 } else {
1191 try self.genSetReg(inst.base.src, .ra, .{ .memory = got_addr });1216 return self.fail(inst.base.src, "TODO implement calling bitcasted functions", .{});
1192 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.jalr(.ra, 0, .ra).toU32());1217 }
1193 } else {1218 } else {
1194 return self.fail(inst.base.src, "TODO implement calling bitcasted functions", .{});1219 return self.fail(inst.base.src, "TODO implement calling runtime known function pointer", .{});
1195 }1220 }
1196 } else {1221 },
1197 return self.fail(inst.base.src, "TODO implement calling runtime known function pointer", .{});1222 else => return self.fail(inst.base.src, "TODO implement call for {}", .{self.target.cpu.arch}),
1198 }1223 }
1199 },1224 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
1200 else => return self.fail(inst.base.src, "TODO implement call for {}", .{self.target.cpu.arch}),1225 return self.fail(inst.base.src, "TODO implement codegen for call when linking with MachO", .{});
1226 } else {
1227 unreachable;
1201 }1228 }
12021229
1203 return info.return_value;1230 return info.return_value;
...@@ -2016,10 +2043,14 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -2016,10 +2043,14 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2016 switch (typed_value.ty.zigTypeTag()) {2043 switch (typed_value.ty.zigTypeTag()) {
2017 .Pointer => {2044 .Pointer => {
2018 if (typed_value.val.cast(Value.Payload.DeclRef)) |payload| {2045 if (typed_value.val.cast(Value.Payload.DeclRef)) |payload| {
2019 const got = &self.bin_file.program_headers.items[self.bin_file.phdr_got_index.?];2046 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
2020 const decl = payload.decl;2047 const decl = payload.decl;
2021 const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes;2048 const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];
2022 return MCValue{ .memory = got_addr };2049 const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes;
2050 return MCValue{ .memory = got_addr };
2051 } else {
2052 return self.fail(src, "TODO codegen non-ELF const Decl pointer", .{});
2053 }
2023 }2054 }
2024 return self.fail(src, "TODO codegen more kinds of const pointers", .{});2055 return self.fail(src, "TODO codegen more kinds of const pointers", .{});
2025 },2056 },
...@@ -2040,7 +2071,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -2040,7 +2071,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2040 if (typed_value.val.isNull())2071 if (typed_value.val.isNull())
2041 return MCValue{ .immediate = 0 };2072 return MCValue{ .immediate = 0 };
20422073
2043 var buf: Type.Payload.Pointer = undefined;2074 var buf: Type.Payload.PointerSimple = undefined;
2044 return self.genTypedValue(src, .{2075 return self.genTypedValue(src, .{
2045 .ty = typed_value.ty.optionalChild(&buf),2076 .ty = typed_value.ty.optionalChild(&buf),
2046 .val = typed_value.val,2077 .val = typed_value.val,
...@@ -2147,7 +2178,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -2147,7 +2178,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
21472178
2148 /// TODO support scope overrides. Also note this logic is duplicated with `Module.wantSafety`.2179 /// TODO support scope overrides. Also note this logic is duplicated with `Module.wantSafety`.
2149 fn wantSafety(self: *Self) bool {2180 fn wantSafety(self: *Self) bool {
2150 return switch (self.bin_file.base.options.optimize_mode) {2181 return switch (self.bin_file.options.optimize_mode) {
2151 .Debug => true,2182 .Debug => true,
2152 .ReleaseSafe => true,2183 .ReleaseSafe => true,
2153 .ReleaseFast => false,2184 .ReleaseFast => false,
...@@ -2158,7 +2189,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -2158,7 +2189,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2158 fn fail(self: *Self, src: usize, comptime format: []const u8, args: anytype) InnerError {2189 fn fail(self: *Self, src: usize, comptime format: []const u8, args: anytype) InnerError {
2159 @setCold(true);2190 @setCold(true);
2160 assert(self.err_msg == null);2191 assert(self.err_msg == null);
2161 self.err_msg = try ErrorMsg.create(self.bin_file.base.allocator, src, format, args);2192 self.err_msg = try ErrorMsg.create(self.bin_file.allocator, src, format, args);
2162 return error.CodegenFail;2193 return error.CodegenFail;
2163 }2194 }
21642195
src-self-hosted/codegen/wasm.zig+59-37
...@@ -62,58 +62,80 @@ pub fn genCode(buf: *ArrayList(u8), decl: *Decl) !void {...@@ -62,58 +62,80 @@ pub fn genCode(buf: *ArrayList(u8), decl: *Decl) !void {
62 // TODO: check for and handle death of instructions62 // TODO: check for and handle death of instructions
63 const tv = decl.typed_value.most_recent.typed_value;63 const tv = decl.typed_value.most_recent.typed_value;
64 const mod_fn = tv.val.cast(Value.Payload.Function).?.func;64 const mod_fn = tv.val.cast(Value.Payload.Function).?.func;
65 for (mod_fn.analysis.success.instructions) |inst| try genInst(writer, inst);65 for (mod_fn.analysis.success.instructions) |inst| try genInst(buf, decl, inst);
6666
67 // Write 'end' opcode67 // Write 'end' opcode
68 try writer.writeByte(0x0B);68 try writer.writeByte(0x0B);
6969
70 // Fill in the size of the generated code to the reserved space at the70 // Fill in the size of the generated code to the reserved space at the
71 // beginning of the buffer.71 // beginning of the buffer.
72 leb.writeUnsignedFixed(5, buf.items[0..5], @intCast(u32, buf.items.len - 5));72 const size = buf.items.len - 5 + decl.fn_link.wasm.?.idx_refs.items.len * 5;
73 leb.writeUnsignedFixed(5, buf.items[0..5], @intCast(u32, size));
73}74}
7475
75fn genInst(writer: ArrayList(u8).Writer, inst: *Inst) !void {76fn genInst(buf: *ArrayList(u8), decl: *Decl, inst: *Inst) !void {
76 return switch (inst.tag) {77 return switch (inst.tag) {
78 .call => genCall(buf, decl, inst.castTag(.call).?),
79 .constant => genConstant(buf, decl, inst.castTag(.constant).?),
77 .dbg_stmt => {},80 .dbg_stmt => {},
78 .ret => genRet(writer, inst.castTag(.ret).?),81 .ret => genRet(buf, decl, inst.castTag(.ret).?),
82 .retvoid => {},
79 else => error.TODOImplementMoreWasmCodegen,83 else => error.TODOImplementMoreWasmCodegen,
80 };84 };
81}85}
8286
83fn genRet(writer: ArrayList(u8).Writer, inst: *Inst.UnOp) !void {87fn genConstant(buf: *ArrayList(u8), decl: *Decl, inst: *Inst.Constant) !void {
84 switch (inst.operand.tag) {88 const writer = buf.writer();
85 .constant => {89 switch (inst.base.ty.tag()) {
86 const constant = inst.operand.castTag(.constant).?;90 .u32 => {
87 switch (inst.operand.ty.tag()) {91 try writer.writeByte(0x41); // i32.const
88 .u32 => {92 try leb.writeILEB128(writer, inst.val.toUnsignedInt());
89 try writer.writeByte(0x41); // i32.const93 },
90 try leb.writeILEB128(writer, constant.val.toUnsignedInt());94 .i32 => {
91 },95 try writer.writeByte(0x41); // i32.const
92 .i32 => {96 try leb.writeILEB128(writer, inst.val.toSignedInt());
93 try writer.writeByte(0x41); // i32.const97 },
94 try leb.writeILEB128(writer, constant.val.toSignedInt());98 .u64 => {
95 },99 try writer.writeByte(0x42); // i64.const
96 .u64 => {100 try leb.writeILEB128(writer, inst.val.toUnsignedInt());
97 try writer.writeByte(0x42); // i64.const101 },
98 try leb.writeILEB128(writer, constant.val.toUnsignedInt());102 .i64 => {
99 },103 try writer.writeByte(0x42); // i64.const
100 .i64 => {104 try leb.writeILEB128(writer, inst.val.toSignedInt());
101 try writer.writeByte(0x42); // i64.const
102 try leb.writeILEB128(writer, constant.val.toSignedInt());
103 },
104 .f32 => {
105 try writer.writeByte(0x43); // f32.const
106 // TODO: enforce LE byte order
107 try writer.writeAll(mem.asBytes(&constant.val.toFloat(f32)));
108 },
109 .f64 => {
110 try writer.writeByte(0x44); // f64.const
111 // TODO: enforce LE byte order
112 try writer.writeAll(mem.asBytes(&constant.val.toFloat(f64)));
113 },
114 else => return error.TODOImplementMoreWasmCodegen,
115 }
116 },105 },
106 .f32 => {
107 try writer.writeByte(0x43); // f32.const
108 // TODO: enforce LE byte order
109 try writer.writeAll(mem.asBytes(&inst.val.toFloat(f32)));
110 },
111 .f64 => {
112 try writer.writeByte(0x44); // f64.const
113 // TODO: enforce LE byte order
114 try writer.writeAll(mem.asBytes(&inst.val.toFloat(f64)));
115 },
116 .void => {},
117 else => return error.TODOImplementMoreWasmCodegen,117 else => return error.TODOImplementMoreWasmCodegen,
118 }118 }
119}119}
120
121fn genRet(buf: *ArrayList(u8), decl: *Decl, inst: *Inst.UnOp) !void {
122 try genInst(buf, decl, inst.operand);
123}
124
125fn genCall(buf: *ArrayList(u8), decl: *Decl, inst: *Inst.Call) !void {
126 const func_inst = inst.func.castTag(.constant).?;
127 const func_val = func_inst.val.cast(Value.Payload.Function).?;
128 const target = func_val.func.owner_decl;
129 const target_ty = target.typed_value.most_recent.typed_value.ty;
130
131 if (inst.args.len != 0) return error.TODOImplementMoreWasmCodegen;
132
133 try buf.append(0x10); // call
134
135 // The function index immediate argument will be filled in using this data
136 // in link.Wasm.flush().
137 try decl.fn_link.wasm.?.idx_refs.append(buf.allocator, .{
138 .offset = @intCast(u32, buf.items.len),
139 .decl = target,
140 });
141}
src-self-hosted/introspect.zig+8-5
...@@ -87,6 +87,13 @@ pub fn resolveGlobalCacheDir(allocator: *mem.Allocator) ![]u8 {...@@ -87,6 +87,13 @@ pub fn resolveGlobalCacheDir(allocator: *mem.Allocator) ![]u8 {
87 return fs.getAppDataDir(allocator, appname);87 return fs.getAppDataDir(allocator, appname);
88}88}
8989
90pub fn openGlobalCacheDir() !fs.Dir {
91 var buf: [fs.MAX_PATH_BYTES]u8 = undefined;
92 var fba = std.heap.FixedBufferAllocator.init(&buf);
93 const path_name = try resolveGlobalCacheDir(&fba.allocator);
94 return fs.cwd().makeOpenPath(path_name, .{});
95}
96
90var compiler_id_mutex = std.Mutex{};97var compiler_id_mutex = std.Mutex{};
91var compiler_id: [16]u8 = undefined;98var compiler_id: [16]u8 = undefined;
92var compiler_id_computed = false;99var compiler_id_computed = false;
...@@ -99,11 +106,7 @@ pub fn resolveCompilerId(gpa: *mem.Allocator) ![16]u8 {...@@ -99,11 +106,7 @@ pub fn resolveCompilerId(gpa: *mem.Allocator) ![16]u8 {
99 return compiler_id;106 return compiler_id;
100 compiler_id_computed = true;107 compiler_id_computed = true;
101108
102 const global_cache_dir = try resolveGlobalCacheDir(gpa);109 var cache_dir = try openGlobalCacheDir();
103 defer gpa.free(global_cache_dir);
104
105 // TODO Introduce openGlobalCacheDir which returns a dir handle rather than a string.
106 var cache_dir = try fs.cwd().openDir(global_cache_dir, .{});
107 defer cache_dir.close();110 defer cache_dir.close();
108111
109 var ch = try CacheHash.init(gpa, cache_dir, "exe");112 var ch = try CacheHash.init(gpa, cache_dir, "exe");
src-self-hosted/ir.zig+21
...@@ -42,6 +42,11 @@ pub const Inst = struct {...@@ -42,6 +42,11 @@ pub const Inst = struct {
42 return @truncate(u1, self.deaths >> index) != 0;42 return @truncate(u1, self.deaths >> index) != 0;
43 }43 }
4444
45 pub fn clearOperandDeath(self: *Inst, index: DeathsBitIndex) void {
46 assert(index < deaths_bits);
47 self.deaths &= ~(@as(DeathsInt, 1) << index);
48 }
49
45 pub fn specialOperandDeaths(self: Inst) bool {50 pub fn specialOperandDeaths(self: Inst) bool {
46 return (self.deaths & (1 << deaths_bits)) != 0;51 return (self.deaths & (1 << deaths_bits)) != 0;
47 }52 }
...@@ -76,6 +81,7 @@ pub const Inst = struct {...@@ -76,6 +81,7 @@ pub const Inst = struct {
76 ref,81 ref,
77 ret,82 ret,
78 retvoid,83 retvoid,
84 varptr,
79 /// Write a value to a pointer. LHS is pointer, RHS is value.85 /// Write a value to a pointer. LHS is pointer, RHS is value.
80 store,86 store,
81 sub,87 sub,
...@@ -130,6 +136,7 @@ pub const Inst = struct {...@@ -130,6 +136,7 @@ pub const Inst = struct {
130 .condbr => CondBr,136 .condbr => CondBr,
131 .constant => Constant,137 .constant => Constant,
132 .loop => Loop,138 .loop => Loop,
139 .varptr => VarPtr,
133 };140 };
134 }141 }
135142
...@@ -429,6 +436,20 @@ pub const Inst = struct {...@@ -429,6 +436,20 @@ pub const Inst = struct {
429 return null;436 return null;
430 }437 }
431 };438 };
439
440 pub const VarPtr = struct {
441 pub const base_tag = Tag.varptr;
442
443 base: Inst,
444 variable: *Module.Var,
445
446 pub fn operandCount(self: *const VarPtr) usize {
447 return 0;
448 }
449 pub fn getOperand(self: *const VarPtr, index: usize) ?*Inst {
450 return null;
451 }
452 };
432};453};
433454
434pub const Body = struct {455pub const Body = struct {
src-self-hosted/link.zig+36-2686
...@@ -1,28 +1,10 @@...@@ -1,28 +1,10 @@
1const std = @import("std");1const std = @import("std");
2const mem = std.mem;
3const assert = std.debug.assert;
4const Allocator = std.mem.Allocator;2const Allocator = std.mem.Allocator;
5const ir = @import("ir.zig");
6const Module = @import("Module.zig");3const Module = @import("Module.zig");
7const fs = std.fs;4const fs = std.fs;
8const elf = std.elf;
9const codegen = @import("codegen.zig");
10const c_codegen = @import("codegen/c.zig");
11const log = std.log.scoped(.link);
12const DW = std.dwarf;
13const trace = @import("tracy.zig").trace;5const trace = @import("tracy.zig").trace;
14const leb128 = std.debug.leb;
15const Package = @import("Package.zig");6const Package = @import("Package.zig");
16const Value = @import("value.zig").Value;
17const Type = @import("type.zig").Type;7const Type = @import("type.zig").Type;
18const build_options = @import("build_options");
19
20const producer_string = if (std.builtin.is_test) "zig test" else "zig " ++ build_options.version;
21
22// TODO Turn back on zig fmt when https://github.com/ziglang/zig/issues/5948 is implemented.
23// zig fmt: off
24
25const default_entry_addr = 0x8000000;
268
27pub const Options = struct {9pub const Options = struct {
28 target: std.Target,10 target: std.Target,
...@@ -40,8 +22,12 @@ pub const Options = struct {...@@ -40,8 +22,12 @@ pub const Options = struct {
40 program_code_size_hint: u64 = 256 * 1024,22 program_code_size_hint: u64 = 256 * 1024,
41};23};
4224
43
44pub const File = struct {25pub const File = struct {
26 tag: Tag,
27 options: Options,
28 file: ?fs.File,
29 allocator: *Allocator,
30
45 pub const LinkBlock = union {31 pub const LinkBlock = union {
46 elf: Elf.TextBlock,32 elf: Elf.TextBlock,
47 macho: MachO.TextBlock,33 macho: MachO.TextBlock,
...@@ -56,16 +42,24 @@ pub const File = struct {...@@ -56,16 +42,24 @@ pub const File = struct {
56 wasm: ?Wasm.FnData,42 wasm: ?Wasm.FnData,
57 };43 };
5844
59 tag: Tag,45 /// For DWARF .debug_info.
60 options: Options,46 pub const DbgInfoTypeRelocsTable = std.HashMapUnmanaged(Type, DbgInfoTypeReloc, Type.hash, Type.eql, true);
61 file: ?fs.File,47
62 allocator: *Allocator,48 /// For DWARF .debug_info.
49 pub const DbgInfoTypeReloc = struct {
50 /// Offset from `TextBlock.dbg_info_off` (the buffer that is local to a Decl).
51 /// This is where the .debug_info tag for the type is.
52 off: u32,
53 /// Offset from `TextBlock.dbg_info_off` (the buffer that is local to a Decl).
54 /// List of DW.AT_type / DW.FORM_ref4 that points to the type.
55 relocs: std.ArrayListUnmanaged(u32),
56 };
6357
64 /// Attempts incremental linking, if the file already exists. If58 /// Attempts incremental linking, if the file already exists. If
65 /// incremental linking fails, falls back to truncating the file and59 /// incremental linking fails, falls back to truncating the file and
66 /// rewriting it. A malicious file is detected as incremental link failure60 /// rewriting it. A malicious file is detected as incremental link failure
67 /// and does not cause Illegal Behavior. This operation is not atomic.61 /// and does not cause Illegal Behavior. This operation is not atomic.
68 pub fn openPath(allocator: *Allocator, dir: fs.Dir, sub_path: []const u8, options: Options) !*File {62 pub fn openPath(allocator: *Allocator, dir: fs.Dir, sub_path: []const u8, options: Options) !*File {
69 switch (options.object_format) {63 switch (options.object_format) {
70 .unknown => unreachable,64 .unknown => unreachable,
71 .coff => return error.TODOImplementCoff,65 .coff => return error.TODOImplementCoff,
...@@ -110,6 +104,8 @@ pub const File = struct {...@@ -110,6 +104,8 @@ pub const File = struct {
110 }104 }
111 }105 }
112106
107 /// May be called before or after updateDeclExports but must be called
108 /// after allocateDeclIndexes for any given Decl.
113 pub fn updateDecl(base: *File, module: *Module, decl: *Module.Decl) !void {109 pub fn updateDecl(base: *File, module: *Module, decl: *Module.Decl) !void {
114 switch (base.tag) {110 switch (base.tag) {
115 .elf => return @fieldParentPtr(Elf, "base", base).updateDecl(module, decl),111 .elf => return @fieldParentPtr(Elf, "base", base).updateDecl(module, decl),
...@@ -127,6 +123,8 @@ pub const File = struct {...@@ -127,6 +123,8 @@ pub const File = struct {
127 }123 }
128 }124 }
129125
126 /// Must be called before any call to updateDecl or updateDeclExports for
127 /// any given Decl.
130 pub fn allocateDeclIndexes(base: *File, decl: *Module.Decl) !void {128 pub fn allocateDeclIndexes(base: *File, decl: *Module.Decl) !void {
131 switch (base.tag) {129 switch (base.tag) {
132 .elf => return @fieldParentPtr(Elf, "base", base).allocateDeclIndexes(decl),130 .elf => return @fieldParentPtr(Elf, "base", base).allocateDeclIndexes(decl),
...@@ -200,7 +198,8 @@ pub const File = struct {...@@ -200,7 +198,8 @@ pub const File = struct {
200 };198 };
201 }199 }
202200
203 /// Must be called only after a successful call to `updateDecl`.201 /// May be called before or after updateDecl, but must be called after
202 /// allocateDeclIndexes for any given Decl.
204 pub fn updateDeclExports(203 pub fn updateDeclExports(
205 base: *File,204 base: *File,
206 module: *Module,205 module: *Module,
...@@ -215,6 +214,15 @@ pub const File = struct {...@@ -215,6 +214,15 @@ pub const File = struct {
215 }214 }
216 }215 }
217216
217 pub fn getDeclVAddr(base: *File, decl: *const Module.Decl) u64 {
218 switch (base.tag) {
219 .elf => return @fieldParentPtr(Elf, "base", base).getDeclVAddr(decl),
220 .macho => return @fieldParentPtr(MachO, "base", base).getDeclVAddr(decl),
221 .c => unreachable,
222 .wasm => unreachable,
223 }
224 }
225
218 pub const Tag = enum {226 pub const Tag = enum {
219 elf,227 elf,
220 macho,228 macho,
...@@ -226,2670 +234,12 @@ pub const File = struct {...@@ -226,2670 +234,12 @@ pub const File = struct {
226 no_entry_point_found: bool = false,234 no_entry_point_found: bool = false,
227 };235 };
228236
229 pub const C = struct {237 pub const C = @import("link/C.zig");
230 pub const base_tag: Tag = .c;238 pub const Elf = @import("link/Elf.zig");
231
232 base: File,
233
234 header: std.ArrayList(u8),
235 constants: std.ArrayList(u8),
236 main: std.ArrayList(u8),
237
238 called: std.StringHashMap(void),
239 need_stddef: bool = false,
240 need_stdint: bool = false,
241 error_msg: *Module.ErrorMsg = undefined,
242
243 pub fn openPath(allocator: *Allocator, dir: fs.Dir, sub_path: []const u8, options: Options) !*File {
244 assert(options.object_format == .c);
245
246 const file = try dir.createFile(sub_path, .{ .truncate = true, .read = true, .mode = determineMode(options) });
247 errdefer file.close();
248
249 var c_file = try allocator.create(C);
250 errdefer allocator.destroy(c_file);
251
252 c_file.* = File.C{
253 .base = .{
254 .tag = .c,
255 .options = options,
256 .file = file,
257 .allocator = allocator,
258 },
259 .main = std.ArrayList(u8).init(allocator),
260 .header = std.ArrayList(u8).init(allocator),
261 .constants = std.ArrayList(u8).init(allocator),
262 .called = std.StringHashMap(void).init(allocator),
263 };
264
265 return &c_file.base;
266 }
267
268 pub fn fail(self: *C, src: usize, comptime format: []const u8, args: anytype) error{AnalysisFail, OutOfMemory} {
269 self.error_msg = try Module.ErrorMsg.create(self.base.allocator, src, format, args);
270 return error.AnalysisFail;
271 }
272
273 pub fn deinit(self: *File.C) void {
274 self.main.deinit();
275 self.header.deinit();
276 self.constants.deinit();
277 self.called.deinit();
278 }
279
280 pub fn updateDecl(self: *File.C, module: *Module, decl: *Module.Decl) !void {
281 c_codegen.generate(self, decl) catch |err| {
282 if (err == error.AnalysisFail) {
283 try module.failed_decls.put(module.gpa, decl, self.error_msg);
284 }
285 return err;
286 };
287 }
288
289 pub fn flush(self: *File.C, module: *Module) !void {
290 const writer = self.base.file.?.writer();
291 try writer.writeAll(@embedFile("cbe.h"));
292 var includes = false;
293 if (self.need_stddef) {
294 try writer.writeAll("#include <stddef.h>\n");
295 includes = true;
296 }
297 if (self.need_stdint) {
298 try writer.writeAll("#include <stdint.h>\n");
299 includes = true;
300 }
301 if (includes) {
302 try writer.writeByte('\n');
303 }
304 if (self.header.items.len > 0) {
305 try writer.print("{}\n", .{self.header.items});
306 }
307 if (self.constants.items.len > 0) {
308 try writer.print("{}\n", .{self.constants.items});
309 }
310 if (self.main.items.len > 1) {
311 const last_two = self.main.items[self.main.items.len - 2 ..];
312 if (std.mem.eql(u8, last_two, "\n\n")) {
313 self.main.items.len -= 1;
314 }
315 }
316 try writer.writeAll(self.main.items);
317 self.base.file.?.close();
318 self.base.file = null;
319 }
320 };
321
322 pub const Elf = struct {
323 pub const base_tag: Tag = .elf;
324
325 base: File,
326
327 ptr_width: enum { p32, p64 },
328
329 /// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write.
330 /// Same order as in the file.
331 sections: std.ArrayListUnmanaged(elf.Elf64_Shdr) = std.ArrayListUnmanaged(elf.Elf64_Shdr){},
332 shdr_table_offset: ?u64 = null,
333
334 /// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write.
335 /// Same order as in the file.
336 program_headers: std.ArrayListUnmanaged(elf.Elf64_Phdr) = std.ArrayListUnmanaged(elf.Elf64_Phdr){},
337 phdr_table_offset: ?u64 = null,
338 /// The index into the program headers of a PT_LOAD program header with Read and Execute flags
339 phdr_load_re_index: ?u16 = null,
340 /// The index into the program headers of the global offset table.
341 /// It needs PT_LOAD and Read flags.
342 phdr_got_index: ?u16 = null,
343 entry_addr: ?u64 = null,
344
345 debug_strtab: std.ArrayListUnmanaged(u8) = std.ArrayListUnmanaged(u8){},
346 shstrtab: std.ArrayListUnmanaged(u8) = std.ArrayListUnmanaged(u8){},
347 shstrtab_index: ?u16 = null,
348
349 text_section_index: ?u16 = null,
350 symtab_section_index: ?u16 = null,
351 got_section_index: ?u16 = null,
352 debug_info_section_index: ?u16 = null,
353 debug_abbrev_section_index: ?u16 = null,
354 debug_str_section_index: ?u16 = null,
355 debug_aranges_section_index: ?u16 = null,
356 debug_line_section_index: ?u16 = null,
357
358 debug_abbrev_table_offset: ?u64 = null,
359
360 /// The same order as in the file. ELF requires global symbols to all be after the
361 /// local symbols, they cannot be mixed. So we must buffer all the global symbols and
362 /// write them at the end. These are only the local symbols. The length of this array
363 /// is the value used for sh_info in the .symtab section.
364 local_symbols: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{},
365 global_symbols: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{},
366
367 local_symbol_free_list: std.ArrayListUnmanaged(u32) = .{},
368 global_symbol_free_list: std.ArrayListUnmanaged(u32) = .{},
369 offset_table_free_list: std.ArrayListUnmanaged(u32) = .{},
370
371 /// Same order as in the file. The value is the absolute vaddr value.
372 /// If the vaddr of the executable program header changes, the entire
373 /// offset table needs to be rewritten.
374 offset_table: std.ArrayListUnmanaged(u64) = .{},
375
376 phdr_table_dirty: bool = false,
377 shdr_table_dirty: bool = false,
378 shstrtab_dirty: bool = false,
379 debug_strtab_dirty: bool = false,
380 offset_table_count_dirty: bool = false,
381 debug_abbrev_section_dirty: bool = false,
382 debug_aranges_section_dirty: bool = false,
383
384 debug_info_header_dirty: bool = false,
385 debug_line_header_dirty: bool = false,
386
387 error_flags: ErrorFlags = ErrorFlags{},
388
389 /// A list of text blocks that have surplus capacity. This list can have false
390 /// positives, as functions grow and shrink over time, only sometimes being added
391 /// or removed from the freelist.
392 ///
393 /// A text block has surplus capacity when its overcapacity value is greater than
394 /// minimum_text_block_size * alloc_num / alloc_den. That is, when it has so
395 /// much extra capacity, that we could fit a small new symbol in it, itself with
396 /// ideal_capacity or more.
397 ///
398 /// Ideal capacity is defined by size * alloc_num / alloc_den.
399 ///
400 /// Overcapacity is measured by actual_capacity - ideal_capacity. Note that
401 /// overcapacity can be negative. A simple way to have negative overcapacity is to
402 /// allocate a fresh text block, which will have ideal capacity, and then grow it
403 /// by 1 byte. It will then have -1 overcapacity.
404 text_block_free_list: std.ArrayListUnmanaged(*TextBlock) = .{},
405 last_text_block: ?*TextBlock = null,
406
407 /// A list of `SrcFn` whose Line Number Programs have surplus capacity.
408 /// This is the same concept as `text_block_free_list`; see those doc comments.
409 dbg_line_fn_free_list: std.AutoHashMapUnmanaged(*SrcFn, void) = .{},
410 dbg_line_fn_first: ?*SrcFn = null,
411 dbg_line_fn_last: ?*SrcFn = null,
412
413 /// A list of `TextBlock` whose corresponding .debug_info tags have surplus capacity.
414 /// This is the same concept as `text_block_free_list`; see those doc comments.
415 dbg_info_decl_free_list: std.AutoHashMapUnmanaged(*TextBlock, void) = .{},
416 dbg_info_decl_first: ?*TextBlock = null,
417 dbg_info_decl_last: ?*TextBlock = null,
418
419 /// `alloc_num / alloc_den` is the factor of padding when allocating.
420 const alloc_num = 4;
421 const alloc_den = 3;
422
423 /// In order for a slice of bytes to be considered eligible to keep metadata pointing at
424 /// it as a possible place to put new symbols, it must have enough room for this many bytes
425 /// (plus extra for reserved capacity).
426 const minimum_text_block_size = 64;
427 const min_text_capacity = minimum_text_block_size * alloc_num / alloc_den;
428
429 pub const DbgInfoTypeRelocsTable = std.HashMapUnmanaged(Type, DbgInfoTypeReloc, Type.hash, Type.eql, true);
430
431 const DbgInfoTypeReloc = struct {
432 /// Offset from `TextBlock.dbg_info_off` (the buffer that is local to a Decl).
433 /// This is where the .debug_info tag for the type is.
434 off: u32,
435 /// Offset from `TextBlock.dbg_info_off` (the buffer that is local to a Decl).
436 /// List of DW.AT_type / DW.FORM_ref4 that points to the type.
437 relocs: std.ArrayListUnmanaged(u32),
438 };
439
440 pub const TextBlock = struct {
441 /// Each decl always gets a local symbol with the fully qualified name.
442 /// The vaddr and size are found here directly.
443 /// The file offset is found by computing the vaddr offset from the section vaddr
444 /// the symbol references, and adding that to the file offset of the section.
445 /// If this field is 0, it means the codegen size = 0 and there is no symbol or
446 /// offset table entry.
447 local_sym_index: u32,
448 /// This field is undefined for symbols with size = 0.
449 offset_table_index: u32,
450 /// Points to the previous and next neighbors, based on the `text_offset`.
451 /// This can be used to find, for example, the capacity of this `TextBlock`.
452 prev: ?*TextBlock,
453 next: ?*TextBlock,
454
455 /// Previous/next linked list pointers. This value is `next ^ prev`.
456 /// This is the linked list node for this Decl's corresponding .debug_info tag.
457 dbg_info_prev: ?*TextBlock,
458 dbg_info_next: ?*TextBlock,
459 /// Offset into .debug_info pointing to the tag for this Decl.
460 dbg_info_off: u32,
461 /// Size of the .debug_info tag for this Decl, not including padding.
462 dbg_info_len: u32,
463
464 pub const empty = TextBlock{
465 .local_sym_index = 0,
466 .offset_table_index = undefined,
467 .prev = null,
468 .next = null,
469 .dbg_info_prev = null,
470 .dbg_info_next = null,
471 .dbg_info_off = undefined,
472 .dbg_info_len = undefined,
473 };
474
475 /// Returns how much room there is to grow in virtual address space.
476 /// File offset relocation happens transparently, so it is not included in
477 /// this calculation.
478 fn capacity(self: TextBlock, elf_file: Elf) u64 {
479 const self_sym = elf_file.local_symbols.items[self.local_sym_index];
480 if (self.next) |next| {
481 const next_sym = elf_file.local_symbols.items[next.local_sym_index];
482 return next_sym.st_value - self_sym.st_value;
483 } else {
484 // We are the last block. The capacity is limited only by virtual address space.
485 return std.math.maxInt(u32) - self_sym.st_value;
486 }
487 }
488
489 fn freeListEligible(self: TextBlock, elf_file: Elf) bool {
490 // No need to keep a free list node for the last block.
491 const next = self.next orelse return false;
492 const self_sym = elf_file.local_symbols.items[self.local_sym_index];
493 const next_sym = elf_file.local_symbols.items[next.local_sym_index];
494 const cap = next_sym.st_value - self_sym.st_value;
495 const ideal_cap = self_sym.st_size * alloc_num / alloc_den;
496 if (cap <= ideal_cap) return false;
497 const surplus = cap - ideal_cap;
498 return surplus >= min_text_capacity;
499 }
500 };
501
502 pub const Export = struct {
503 sym_index: ?u32 = null,
504 };
505
506 pub const SrcFn = struct {
507 /// Offset from the beginning of the Debug Line Program header that contains this function.
508 off: u32,
509 /// Size of the line number program component belonging to this function, not
510 /// including padding.
511 len: u32,
512
513 /// Points to the previous and next neighbors, based on the offset from .debug_line.
514 /// This can be used to find, for example, the capacity of this `SrcFn`.
515 prev: ?*SrcFn,
516 next: ?*SrcFn,
517
518 pub const empty: SrcFn = .{
519 .off = 0,
520 .len = 0,
521 .prev = null,
522 .next = null,
523 };
524 };
525
526 pub fn openPath(allocator: *Allocator, dir: fs.Dir, sub_path: []const u8, options: Options) !*File {
527 assert(options.object_format == .elf);
528
529 const file = try dir.createFile(sub_path, .{ .truncate = false, .read = true, .mode = determineMode(options) });
530 errdefer file.close();
531
532 var elf_file = try allocator.create(Elf);
533 errdefer allocator.destroy(elf_file);
534
535 elf_file.* = openFile(allocator, file, options) catch |err| switch (err) {
536 error.IncrFailed => try createFile(allocator, file, options),
537 else => |e| return e,
538 };
539
540 return &elf_file.base;
541 }
542
543 /// Returns error.IncrFailed if incremental update could not be performed.
544 fn openFile(allocator: *Allocator, file: fs.File, options: Options) !Elf {
545 switch (options.output_mode) {
546 .Exe => {},
547 .Obj => {},
548 .Lib => return error.IncrFailed,
549 }
550 var self: Elf = .{
551 .base = .{
552 .file = file,
553 .tag = .elf,
554 .options = options,
555 .allocator = allocator,
556 },
557 .ptr_width = switch (options.target.cpu.arch.ptrBitWidth()) {
558 32 => .p32,
559 64 => .p64,
560 else => return error.UnsupportedELFArchitecture,
561 },
562 };
563 errdefer self.deinit();
564
565 // TODO implement reading the elf file
566 return error.IncrFailed;
567 //try self.populateMissingMetadata();
568 //return self;
569 }
570
571 /// Truncates the existing file contents and overwrites the contents.
572 /// Returns an error if `file` is not already open with +read +write +seek abilities.
573 fn createFile(allocator: *Allocator, file: fs.File, options: Options) !Elf {
574 switch (options.output_mode) {
575 .Exe => {},
576 .Obj => {},
577 .Lib => return error.TODOImplementWritingLibFiles,
578 }
579 var self: Elf = .{
580 .base = .{
581 .tag = .elf,
582 .options = options,
583 .allocator = allocator,
584 .file = file,
585 },
586 .ptr_width = switch (options.target.cpu.arch.ptrBitWidth()) {
587 32 => .p32,
588 64 => .p64,
589 else => return error.UnsupportedELFArchitecture,
590 },
591 .shdr_table_dirty = true,
592 };
593 errdefer self.deinit();
594
595 // Index 0 is always a null symbol.
596 try self.local_symbols.append(allocator, .{
597 .st_name = 0,
598 .st_info = 0,
599 .st_other = 0,
600 .st_shndx = 0,
601 .st_value = 0,
602 .st_size = 0,
603 });
604
605 // There must always be a null section in index 0
606 try self.sections.append(allocator, .{
607 .sh_name = 0,
608 .sh_type = elf.SHT_NULL,
609 .sh_flags = 0,
610 .sh_addr = 0,
611 .sh_offset = 0,
612 .sh_size = 0,
613 .sh_link = 0,
614 .sh_info = 0,
615 .sh_addralign = 0,
616 .sh_entsize = 0,
617 });
618
619 try self.populateMissingMetadata();
620
621 return self;
622 }
623
624 pub fn deinit(self: *Elf) void {
625 self.sections.deinit(self.base.allocator);
626 self.program_headers.deinit(self.base.allocator);
627 self.shstrtab.deinit(self.base.allocator);
628 self.debug_strtab.deinit(self.base.allocator);
629 self.local_symbols.deinit(self.base.allocator);
630 self.global_symbols.deinit(self.base.allocator);
631 self.global_symbol_free_list.deinit(self.base.allocator);
632 self.local_symbol_free_list.deinit(self.base.allocator);
633 self.offset_table_free_list.deinit(self.base.allocator);
634 self.text_block_free_list.deinit(self.base.allocator);
635 self.dbg_line_fn_free_list.deinit(self.base.allocator);
636 self.dbg_info_decl_free_list.deinit(self.base.allocator);
637 self.offset_table.deinit(self.base.allocator);
638 }
639
640 fn getDebugLineProgramOff(self: Elf) u32 {
641 return self.dbg_line_fn_first.?.off;
642 }
643
644 fn getDebugLineProgramEnd(self: Elf) u32 {
645 return self.dbg_line_fn_last.?.off + self.dbg_line_fn_last.?.len;
646 }
647
648 /// Returns end pos of collision, if any.
649 fn detectAllocCollision(self: *Elf, start: u64, size: u64) ?u64 {
650 const small_ptr = self.base.options.target.cpu.arch.ptrBitWidth() == 32;
651 const ehdr_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Ehdr) else @sizeOf(elf.Elf64_Ehdr);
652 if (start < ehdr_size)
653 return ehdr_size;
654
655 const end = start + satMul(size, alloc_num) / alloc_den;
656
657 if (self.shdr_table_offset) |off| {
658 const shdr_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Shdr) else @sizeOf(elf.Elf64_Shdr);
659 const tight_size = self.sections.items.len * shdr_size;
660 const increased_size = satMul(tight_size, alloc_num) / alloc_den;
661 const test_end = off + increased_size;
662 if (end > off and start < test_end) {
663 return test_end;
664 }
665 }
666
667 if (self.phdr_table_offset) |off| {
668 const phdr_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Phdr) else @sizeOf(elf.Elf64_Phdr);
669 const tight_size = self.sections.items.len * phdr_size;
670 const increased_size = satMul(tight_size, alloc_num) / alloc_den;
671 const test_end = off + increased_size;
672 if (end > off and start < test_end) {
673 return test_end;
674 }
675 }
676
677 for (self.sections.items) |section| {
678 const increased_size = satMul(section.sh_size, alloc_num) / alloc_den;
679 const test_end = section.sh_offset + increased_size;
680 if (end > section.sh_offset and start < test_end) {
681 return test_end;
682 }
683 }
684 for (self.program_headers.items) |program_header| {
685 const increased_size = satMul(program_header.p_filesz, alloc_num) / alloc_den;
686 const test_end = program_header.p_offset + increased_size;
687 if (end > program_header.p_offset and start < test_end) {
688 return test_end;
689 }
690 }
691 return null;
692 }
693
694 fn allocatedSize(self: *Elf, start: u64) u64 {
695 if (start == 0)
696 return 0;
697 var min_pos: u64 = std.math.maxInt(u64);
698 if (self.shdr_table_offset) |off| {
699 if (off > start and off < min_pos) min_pos = off;
700 }
701 if (self.phdr_table_offset) |off| {
702 if (off > start and off < min_pos) min_pos = off;
703 }
704 for (self.sections.items) |section| {
705 if (section.sh_offset <= start) continue;
706 if (section.sh_offset < min_pos) min_pos = section.sh_offset;
707 }
708 for (self.program_headers.items) |program_header| {
709 if (program_header.p_offset <= start) continue;
710 if (program_header.p_offset < min_pos) min_pos = program_header.p_offset;
711 }
712 return min_pos - start;
713 }
714
715 fn findFreeSpace(self: *Elf, object_size: u64, min_alignment: u16) u64 {
716 var start: u64 = 0;
717 while (self.detectAllocCollision(start, object_size)) |item_end| {
718 start = mem.alignForwardGeneric(u64, item_end, min_alignment);
719 }
720 return start;
721 }
722
723 /// TODO Improve this to use a table.
724 fn makeString(self: *Elf, bytes: []const u8) !u32 {
725 try self.shstrtab.ensureCapacity(self.base.allocator, self.shstrtab.items.len + bytes.len + 1);
726 const result = self.shstrtab.items.len;
727 self.shstrtab.appendSliceAssumeCapacity(bytes);
728 self.shstrtab.appendAssumeCapacity(0);
729 return @intCast(u32, result);
730 }
731
732 /// TODO Improve this to use a table.
733 fn makeDebugString(self: *Elf, bytes: []const u8) !u32 {
734 try self.debug_strtab.ensureCapacity(self.base.allocator, self.debug_strtab.items.len + bytes.len + 1);
735 const result = self.debug_strtab.items.len;
736 self.debug_strtab.appendSliceAssumeCapacity(bytes);
737 self.debug_strtab.appendAssumeCapacity(0);
738 return @intCast(u32, result);
739 }
740
741 fn getString(self: *Elf, str_off: u32) []const u8 {
742 assert(str_off < self.shstrtab.items.len);
743 return mem.spanZ(@ptrCast([*:0]const u8, self.shstrtab.items.ptr + str_off));
744 }
745
746 fn updateString(self: *Elf, old_str_off: u32, new_name: []const u8) !u32 {
747 const existing_name = self.getString(old_str_off);
748 if (mem.eql(u8, existing_name, new_name)) {
749 return old_str_off;
750 }
751 return self.makeString(new_name);
752 }
753
754 pub fn populateMissingMetadata(self: *Elf) !void {
755 const small_ptr = switch (self.ptr_width) {
756 .p32 => true,
757 .p64 => false,
758 };
759 const ptr_size: u8 = self.ptrWidthBytes();
760 if (self.phdr_load_re_index == null) {
761 self.phdr_load_re_index = @intCast(u16, self.program_headers.items.len);
762 const file_size = self.base.options.program_code_size_hint;
763 const p_align = 0x1000;
764 const off = self.findFreeSpace(file_size, p_align);
765 log.debug("found PT_LOAD free space 0x{x} to 0x{x}\n", .{ off, off + file_size });
766 try self.program_headers.append(self.base.allocator, .{
767 .p_type = elf.PT_LOAD,
768 .p_offset = off,
769 .p_filesz = file_size,
770 .p_vaddr = default_entry_addr,
771 .p_paddr = default_entry_addr,
772 .p_memsz = file_size,
773 .p_align = p_align,
774 .p_flags = elf.PF_X | elf.PF_R,
775 });
776 self.entry_addr = null;
777 self.phdr_table_dirty = true;
778 }
779 if (self.phdr_got_index == null) {
780 self.phdr_got_index = @intCast(u16, self.program_headers.items.len);
781 const file_size = @as(u64, ptr_size) * self.base.options.symbol_count_hint;
782 // We really only need ptr alignment but since we are using PROGBITS, linux requires
783 // page align.
784 const p_align = if (self.base.options.target.os.tag == .linux) 0x1000 else @as(u16, ptr_size);
785 const off = self.findFreeSpace(file_size, p_align);
786 log.debug("found PT_LOAD free space 0x{x} to 0x{x}\n", .{ off, off + file_size });
787 // TODO instead of hard coding the vaddr, make a function to find a vaddr to put things at.
788 // we'll need to re-use that function anyway, in case the GOT grows and overlaps something
789 // else in virtual memory.
790 const default_got_addr = if (ptr_size == 2) @as(u32, 0x8000) else 0x4000000;
791 try self.program_headers.append(self.base.allocator, .{
792 .p_type = elf.PT_LOAD,
793 .p_offset = off,
794 .p_filesz = file_size,
795 .p_vaddr = default_got_addr,
796 .p_paddr = default_got_addr,
797 .p_memsz = file_size,
798 .p_align = p_align,
799 .p_flags = elf.PF_R,
800 });
801 self.phdr_table_dirty = true;
802 }
803 if (self.shstrtab_index == null) {
804 self.shstrtab_index = @intCast(u16, self.sections.items.len);
805 assert(self.shstrtab.items.len == 0);
806 try self.shstrtab.append(self.base.allocator, 0); // need a 0 at position 0
807 const off = self.findFreeSpace(self.shstrtab.items.len, 1);
808 log.debug("found shstrtab free space 0x{x} to 0x{x}\n", .{ off, off + self.shstrtab.items.len });
809 try self.sections.append(self.base.allocator, .{
810 .sh_name = try self.makeString(".shstrtab"),
811 .sh_type = elf.SHT_STRTAB,
812 .sh_flags = 0,
813 .sh_addr = 0,
814 .sh_offset = off,
815 .sh_size = self.shstrtab.items.len,
816 .sh_link = 0,
817 .sh_info = 0,
818 .sh_addralign = 1,
819 .sh_entsize = 0,
820 });
821 self.shstrtab_dirty = true;
822 self.shdr_table_dirty = true;
823 }
824 if (self.text_section_index == null) {
825 self.text_section_index = @intCast(u16, self.sections.items.len);
826 const phdr = &self.program_headers.items[self.phdr_load_re_index.?];
827
828 try self.sections.append(self.base.allocator, .{
829 .sh_name = try self.makeString(".text"),
830 .sh_type = elf.SHT_PROGBITS,
831 .sh_flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR,
832 .sh_addr = phdr.p_vaddr,
833 .sh_offset = phdr.p_offset,
834 .sh_size = phdr.p_filesz,
835 .sh_link = 0,
836 .sh_info = 0,
837 .sh_addralign = phdr.p_align,
838 .sh_entsize = 0,
839 });
840 self.shdr_table_dirty = true;
841 }
842 if (self.got_section_index == null) {
843 self.got_section_index = @intCast(u16, self.sections.items.len);
844 const phdr = &self.program_headers.items[self.phdr_got_index.?];
845
846 try self.sections.append(self.base.allocator, .{
847 .sh_name = try self.makeString(".got"),
848 .sh_type = elf.SHT_PROGBITS,
849 .sh_flags = elf.SHF_ALLOC,
850 .sh_addr = phdr.p_vaddr,
851 .sh_offset = phdr.p_offset,
852 .sh_size = phdr.p_filesz,
853 .sh_link = 0,
854 .sh_info = 0,
855 .sh_addralign = phdr.p_align,
856 .sh_entsize = 0,
857 });
858 self.shdr_table_dirty = true;
859 }
860 if (self.symtab_section_index == null) {
861 self.symtab_section_index = @intCast(u16, self.sections.items.len);
862 const min_align: u16 = if (small_ptr) @alignOf(elf.Elf32_Sym) else @alignOf(elf.Elf64_Sym);
863 const each_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Sym) else @sizeOf(elf.Elf64_Sym);
864 const file_size = self.base.options.symbol_count_hint * each_size;
865 const off = self.findFreeSpace(file_size, min_align);
866 log.debug("found symtab free space 0x{x} to 0x{x}\n", .{ off, off + file_size });
867
868 try self.sections.append(self.base.allocator, .{
869 .sh_name = try self.makeString(".symtab"),
870 .sh_type = elf.SHT_SYMTAB,
871 .sh_flags = 0,
872 .sh_addr = 0,
873 .sh_offset = off,
874 .sh_size = file_size,
875 // The section header index of the associated string table.
876 .sh_link = self.shstrtab_index.?,
877 .sh_info = @intCast(u32, self.local_symbols.items.len),
878 .sh_addralign = min_align,
879 .sh_entsize = each_size,
880 });
881 self.shdr_table_dirty = true;
882 try self.writeSymbol(0);
883 }
884 if (self.debug_str_section_index == null) {
885 self.debug_str_section_index = @intCast(u16, self.sections.items.len);
886 assert(self.debug_strtab.items.len == 0);
887 try self.sections.append(self.base.allocator, .{
888 .sh_name = try self.makeString(".debug_str"),
889 .sh_type = elf.SHT_PROGBITS,
890 .sh_flags = elf.SHF_MERGE | elf.SHF_STRINGS,
891 .sh_addr = 0,
892 .sh_offset = 0,
893 .sh_size = self.debug_strtab.items.len,
894 .sh_link = 0,
895 .sh_info = 0,
896 .sh_addralign = 1,
897 .sh_entsize = 1,
898 });
899 self.debug_strtab_dirty = true;
900 self.shdr_table_dirty = true;
901 }
902 if (self.debug_info_section_index == null) {
903 self.debug_info_section_index = @intCast(u16, self.sections.items.len);
904
905 const file_size_hint = 200;
906 const p_align = 1;
907 const off = self.findFreeSpace(file_size_hint, p_align);
908 log.debug("found .debug_info free space 0x{x} to 0x{x}\n", .{
909 off,
910 off + file_size_hint,
911 });
912 try self.sections.append(self.base.allocator, .{
913 .sh_name = try self.makeString(".debug_info"),
914 .sh_type = elf.SHT_PROGBITS,
915 .sh_flags = 0,
916 .sh_addr = 0,
917 .sh_offset = off,
918 .sh_size = file_size_hint,
919 .sh_link = 0,
920 .sh_info = 0,
921 .sh_addralign = p_align,
922 .sh_entsize = 0,
923 });
924 self.shdr_table_dirty = true;
925 self.debug_info_header_dirty = true;
926 }
927 if (self.debug_abbrev_section_index == null) {
928 self.debug_abbrev_section_index = @intCast(u16, self.sections.items.len);
929
930 const file_size_hint = 128;
931 const p_align = 1;
932 const off = self.findFreeSpace(file_size_hint, p_align);
933 log.debug("found .debug_abbrev free space 0x{x} to 0x{x}\n", .{
934 off,
935 off + file_size_hint,
936 });
937 try self.sections.append(self.base.allocator, .{
938 .sh_name = try self.makeString(".debug_abbrev"),
939 .sh_type = elf.SHT_PROGBITS,
940 .sh_flags = 0,
941 .sh_addr = 0,
942 .sh_offset = off,
943 .sh_size = file_size_hint,
944 .sh_link = 0,
945 .sh_info = 0,
946 .sh_addralign = p_align,
947 .sh_entsize = 0,
948 });
949 self.shdr_table_dirty = true;
950 self.debug_abbrev_section_dirty = true;
951 }
952 if (self.debug_aranges_section_index == null) {
953 self.debug_aranges_section_index = @intCast(u16, self.sections.items.len);
954
955 const file_size_hint = 160;
956 const p_align = 16;
957 const off = self.findFreeSpace(file_size_hint, p_align);
958 log.debug("found .debug_aranges free space 0x{x} to 0x{x}\n", .{
959 off,
960 off + file_size_hint,
961 });
962 try self.sections.append(self.base.allocator, .{
963 .sh_name = try self.makeString(".debug_aranges"),
964 .sh_type = elf.SHT_PROGBITS,
965 .sh_flags = 0,
966 .sh_addr = 0,
967 .sh_offset = off,
968 .sh_size = file_size_hint,
969 .sh_link = 0,
970 .sh_info = 0,
971 .sh_addralign = p_align,
972 .sh_entsize = 0,
973 });
974 self.shdr_table_dirty = true;
975 self.debug_aranges_section_dirty = true;
976 }
977 if (self.debug_line_section_index == null) {
978 self.debug_line_section_index = @intCast(u16, self.sections.items.len);
979
980 const file_size_hint = 250;
981 const p_align = 1;
982 const off = self.findFreeSpace(file_size_hint, p_align);
983 log.debug("found .debug_line free space 0x{x} to 0x{x}\n", .{
984 off,
985 off + file_size_hint,
986 });
987 try self.sections.append(self.base.allocator, .{
988 .sh_name = try self.makeString(".debug_line"),
989 .sh_type = elf.SHT_PROGBITS,
990 .sh_flags = 0,
991 .sh_addr = 0,
992 .sh_offset = off,
993 .sh_size = file_size_hint,
994 .sh_link = 0,
995 .sh_info = 0,
996 .sh_addralign = p_align,
997 .sh_entsize = 0,
998 });
999 self.shdr_table_dirty = true;
1000 self.debug_line_header_dirty = true;
1001 }
1002 const shsize: u64 = switch (self.ptr_width) {
1003 .p32 => @sizeOf(elf.Elf32_Shdr),
1004 .p64 => @sizeOf(elf.Elf64_Shdr),
1005 };
1006 const shalign: u16 = switch (self.ptr_width) {
1007 .p32 => @alignOf(elf.Elf32_Shdr),
1008 .p64 => @alignOf(elf.Elf64_Shdr),
1009 };
1010 if (self.shdr_table_offset == null) {
1011 self.shdr_table_offset = self.findFreeSpace(self.sections.items.len * shsize, shalign);
1012 self.shdr_table_dirty = true;
1013 }
1014 const phsize: u64 = switch (self.ptr_width) {
1015 .p32 => @sizeOf(elf.Elf32_Phdr),
1016 .p64 => @sizeOf(elf.Elf64_Phdr),
1017 };
1018 const phalign: u16 = switch (self.ptr_width) {
1019 .p32 => @alignOf(elf.Elf32_Phdr),
1020 .p64 => @alignOf(elf.Elf64_Phdr),
1021 };
1022 if (self.phdr_table_offset == null) {
1023 self.phdr_table_offset = self.findFreeSpace(self.program_headers.items.len * phsize, phalign);
1024 self.phdr_table_dirty = true;
1025 }
1026 {
1027 // Iterate over symbols, populating free_list and last_text_block.
1028 if (self.local_symbols.items.len != 1) {
1029 @panic("TODO implement setting up free_list and last_text_block from existing ELF file");
1030 }
1031 // We are starting with an empty file. The default values are correct, null and empty list.
1032 }
1033 }
1034
1035 pub const abbrev_compile_unit = 1;
1036 pub const abbrev_subprogram = 2;
1037 pub const abbrev_subprogram_retvoid = 3;
1038 pub const abbrev_base_type = 4;
1039 pub const abbrev_pad1 = 5;
1040 pub const abbrev_parameter = 6;
1041
1042 /// Commit pending changes and write headers.
1043 pub fn flush(self: *Elf, module: *Module) !void {
1044 const target_endian = self.base.options.target.cpu.arch.endian();
1045 const foreign_endian = target_endian != std.Target.current.cpu.arch.endian();
1046 const ptr_width_bytes: u8 = self.ptrWidthBytes();
1047 const init_len_size: usize = switch (self.ptr_width) {
1048 .p32 => 4,
1049 .p64 => 12,
1050 };
1051
1052 // Unfortunately these have to be buffered and done at the end because ELF does not allow
1053 // mixing local and global symbols within a symbol table.
1054 try self.writeAllGlobalSymbols();
1055
1056 if (self.debug_abbrev_section_dirty) {
1057 const debug_abbrev_sect = &self.sections.items[self.debug_abbrev_section_index.?];
1058
1059 // These are LEB encoded but since the values are all less than 127
1060 // we can simply append these bytes.
1061 const abbrev_buf = [_]u8{
1062 abbrev_compile_unit, DW.TAG_compile_unit, DW.CHILDREN_yes, // header
1063 DW.AT_stmt_list, DW.FORM_sec_offset,
1064 DW.AT_low_pc , DW.FORM_addr,
1065 DW.AT_high_pc , DW.FORM_addr,
1066 DW.AT_name , DW.FORM_strp,
1067 DW.AT_comp_dir , DW.FORM_strp,
1068 DW.AT_producer , DW.FORM_strp,
1069 DW.AT_language , DW.FORM_data2,
1070 0, 0, // table sentinel
1071
1072 abbrev_subprogram, DW.TAG_subprogram, DW.CHILDREN_yes, // header
1073 DW.AT_low_pc , DW.FORM_addr,
1074 DW.AT_high_pc , DW.FORM_data4,
1075 DW.AT_type , DW.FORM_ref4,
1076 DW.AT_name , DW.FORM_string,
1077 0, 0, // table sentinel
1078
1079 abbrev_subprogram_retvoid, DW.TAG_subprogram, DW.CHILDREN_yes, // header
1080 DW.AT_low_pc , DW.FORM_addr,
1081 DW.AT_high_pc , DW.FORM_data4,
1082 DW.AT_name , DW.FORM_string,
1083 0, 0, // table sentinel
1084
1085 abbrev_base_type, DW.TAG_base_type, DW.CHILDREN_no, // header
1086 DW.AT_encoding , DW.FORM_data1,
1087 DW.AT_byte_size, DW.FORM_data1,
1088 DW.AT_name , DW.FORM_string,
1089 0, 0, // table sentinel
1090
1091 abbrev_pad1, DW.TAG_unspecified_type, DW.CHILDREN_no, // header
1092 0, 0, // table sentinel
1093
1094 abbrev_parameter, DW.TAG_formal_parameter, DW.CHILDREN_no, // header
1095 DW.AT_location , DW.FORM_exprloc,
1096 DW.AT_type , DW.FORM_ref4,
1097 DW.AT_name , DW.FORM_string,
1098 0, 0, // table sentinel
1099
1100 0, 0, 0, // section sentinel
1101 };
1102
1103 const needed_size = abbrev_buf.len;
1104 const allocated_size = self.allocatedSize(debug_abbrev_sect.sh_offset);
1105 if (needed_size > allocated_size) {
1106 debug_abbrev_sect.sh_size = 0; // free the space
1107 debug_abbrev_sect.sh_offset = self.findFreeSpace(needed_size, 1);
1108 }
1109 debug_abbrev_sect.sh_size = needed_size;
1110 log.debug(".debug_abbrev start=0x{x} end=0x{x}\n", .{
1111 debug_abbrev_sect.sh_offset,
1112 debug_abbrev_sect.sh_offset + needed_size,
1113 });
1114
1115 const abbrev_offset = 0;
1116 self.debug_abbrev_table_offset = abbrev_offset;
1117 try self.base.file.?.pwriteAll(&abbrev_buf, debug_abbrev_sect.sh_offset + abbrev_offset);
1118 if (!self.shdr_table_dirty) {
1119 // Then it won't get written with the others and we need to do it.
1120 try self.writeSectHeader(self.debug_abbrev_section_index.?);
1121 }
1122
1123 self.debug_abbrev_section_dirty = false;
1124 }
1125
1126 if (self.debug_info_header_dirty) debug_info: {
1127 // If this value is null it means there is an error in the module;
1128 // leave debug_info_header_dirty=true.
1129 const first_dbg_info_decl = self.dbg_info_decl_first orelse break :debug_info;
1130 const last_dbg_info_decl = self.dbg_info_decl_last.?;
1131 const debug_info_sect = &self.sections.items[self.debug_info_section_index.?];
1132
1133 var di_buf = std.ArrayList(u8).init(self.base.allocator);
1134 defer di_buf.deinit();
1135
1136 // We have a function to compute the upper bound size, because it's needed
1137 // for determining where to put the offset of the first `LinkBlock`.
1138 try di_buf.ensureCapacity(self.dbgInfoNeededHeaderBytes());
1139
1140 // initial length - length of the .debug_info contribution for this compilation unit,
1141 // not including the initial length itself.
1142 // We have to come back and write it later after we know the size.
1143 const after_init_len = di_buf.items.len + init_len_size;
1144 // +1 for the final 0 that ends the compilation unit children.
1145 const dbg_info_end = last_dbg_info_decl.dbg_info_off + last_dbg_info_decl.dbg_info_len + 1;
1146 const init_len = dbg_info_end - after_init_len;
1147 switch (self.ptr_width) {
1148 .p32 => {
1149 mem.writeInt(u32, di_buf.addManyAsArrayAssumeCapacity(4), @intCast(u32, init_len), target_endian);
1150 },
1151 .p64 => {
1152 di_buf.appendNTimesAssumeCapacity(0xff, 4);
1153 mem.writeInt(u64, di_buf.addManyAsArrayAssumeCapacity(8), init_len, target_endian);
1154 },
1155 }
1156 mem.writeInt(u16, di_buf.addManyAsArrayAssumeCapacity(2), 4, target_endian); // DWARF version
1157 const abbrev_offset = self.debug_abbrev_table_offset.?;
1158 switch (self.ptr_width) {
1159 .p32 => {
1160 mem.writeInt(u32, di_buf.addManyAsArrayAssumeCapacity(4), @intCast(u32, abbrev_offset), target_endian);
1161 di_buf.appendAssumeCapacity(4); // address size
1162 },
1163 .p64 => {
1164 mem.writeInt(u64, di_buf.addManyAsArrayAssumeCapacity(8), abbrev_offset, target_endian);
1165 di_buf.appendAssumeCapacity(8); // address size
1166 },
1167 }
1168 // Write the form for the compile unit, which must match the abbrev table above.
1169 const name_strp = try self.makeDebugString(self.base.options.root_pkg.root_src_path);
1170 const comp_dir_strp = try self.makeDebugString(self.base.options.root_pkg.root_src_dir_path);
1171 const producer_strp = try self.makeDebugString(producer_string);
1172 // Currently only one compilation unit is supported, so the address range is simply
1173 // identical to the main program header virtual address and memory size.
1174 const text_phdr = &self.program_headers.items[self.phdr_load_re_index.?];
1175 const low_pc = text_phdr.p_vaddr;
1176 const high_pc = text_phdr.p_vaddr + text_phdr.p_memsz;
1177
1178 di_buf.appendAssumeCapacity(abbrev_compile_unit);
1179 self.writeDwarfAddrAssumeCapacity(&di_buf, 0); // DW.AT_stmt_list, DW.FORM_sec_offset
1180 self.writeDwarfAddrAssumeCapacity(&di_buf, low_pc);
1181 self.writeDwarfAddrAssumeCapacity(&di_buf, high_pc);
1182 self.writeDwarfAddrAssumeCapacity(&di_buf, name_strp);
1183 self.writeDwarfAddrAssumeCapacity(&di_buf, comp_dir_strp);
1184 self.writeDwarfAddrAssumeCapacity(&di_buf, producer_strp);
1185 // We are still waiting on dwarf-std.org to assign DW_LANG_Zig a number:
1186 // http://dwarfstd.org/ShowIssue.php?issue=171115.1
1187 // Until then we say it is C99.
1188 mem.writeInt(u16, di_buf.addManyAsArrayAssumeCapacity(2), DW.LANG_C99, target_endian);
1189
1190 if (di_buf.items.len > first_dbg_info_decl.dbg_info_off) {
1191 // Move the first N decls to the end to make more padding for the header.
1192 @panic("TODO: handle .debug_info header exceeding its padding");
1193 }
1194 const jmp_amt = first_dbg_info_decl.dbg_info_off - di_buf.items.len;
1195 try self.pwriteDbgInfoNops(0, di_buf.items, jmp_amt, false, debug_info_sect.sh_offset);
1196 self.debug_info_header_dirty = false;
1197 }
1198
1199 if (self.debug_aranges_section_dirty) {
1200 const debug_aranges_sect = &self.sections.items[self.debug_aranges_section_index.?];
1201
1202 var di_buf = std.ArrayList(u8).init(self.base.allocator);
1203 defer di_buf.deinit();
1204
1205 // Enough for all the data without resizing. When support for more compilation units
1206 // is added, the size of this section will become more variable.
1207 try di_buf.ensureCapacity(100);
1208
1209 // initial length - length of the .debug_aranges contribution for this compilation unit,
1210 // not including the initial length itself.
1211 // We have to come back and write it later after we know the size.
1212 const init_len_index = di_buf.items.len;
1213 di_buf.items.len += init_len_size;
1214 const after_init_len = di_buf.items.len;
1215 mem.writeInt(u16, di_buf.addManyAsArrayAssumeCapacity(2), 2, target_endian); // version
1216 // When more than one compilation unit is supported, this will be the offset to it.
1217 // For now it is always at offset 0 in .debug_info.
1218 self.writeDwarfAddrAssumeCapacity(&di_buf, 0); // .debug_info offset
1219 di_buf.appendAssumeCapacity(ptr_width_bytes); // address_size
1220 di_buf.appendAssumeCapacity(0); // segment_selector_size
1221
1222 const end_header_offset = di_buf.items.len;
1223 const begin_entries_offset = mem.alignForward(end_header_offset, ptr_width_bytes * 2);
1224 di_buf.appendNTimesAssumeCapacity(0, begin_entries_offset - end_header_offset);
1225
1226 // Currently only one compilation unit is supported, so the address range is simply
1227 // identical to the main program header virtual address and memory size.
1228 const text_phdr = &self.program_headers.items[self.phdr_load_re_index.?];
1229 self.writeDwarfAddrAssumeCapacity(&di_buf, text_phdr.p_vaddr);
1230 self.writeDwarfAddrAssumeCapacity(&di_buf, text_phdr.p_memsz);
1231
1232 // Sentinel.
1233 self.writeDwarfAddrAssumeCapacity(&di_buf, 0);
1234 self.writeDwarfAddrAssumeCapacity(&di_buf, 0);
1235
1236 // Go back and populate the initial length.
1237 const init_len = di_buf.items.len - after_init_len;
1238 switch (self.ptr_width) {
1239 .p32 => {
1240 mem.writeInt(u32, di_buf.items[init_len_index..][0..4], @intCast(u32, init_len), target_endian);
1241 },
1242 .p64 => {
1243 // initial length - length of the .debug_aranges contribution for this compilation unit,
1244 // not including the initial length itself.
1245 di_buf.items[init_len_index..][0..4].* = [_]u8{ 0xff, 0xff, 0xff, 0xff };
1246 mem.writeInt(u64, di_buf.items[init_len_index + 4..][0..8], init_len, target_endian);
1247 },
1248 }
1249
1250 const needed_size = di_buf.items.len;
1251 const allocated_size = self.allocatedSize(debug_aranges_sect.sh_offset);
1252 if (needed_size > allocated_size) {
1253 debug_aranges_sect.sh_size = 0; // free the space
1254 debug_aranges_sect.sh_offset = self.findFreeSpace(needed_size, 16);
1255 }
1256 debug_aranges_sect.sh_size = needed_size;
1257 log.debug(".debug_aranges start=0x{x} end=0x{x}\n", .{
1258 debug_aranges_sect.sh_offset,
1259 debug_aranges_sect.sh_offset + needed_size,
1260 });
1261
1262 try self.base.file.?.pwriteAll(di_buf.items, debug_aranges_sect.sh_offset);
1263 if (!self.shdr_table_dirty) {
1264 // Then it won't get written with the others and we need to do it.
1265 try self.writeSectHeader(self.debug_aranges_section_index.?);
1266 }
1267
1268 self.debug_aranges_section_dirty = false;
1269 }
1270 if (self.debug_line_header_dirty) debug_line: {
1271 if (self.dbg_line_fn_first == null) {
1272 break :debug_line; // Error in module; leave debug_line_header_dirty=true.
1273 }
1274 const dbg_line_prg_off = self.getDebugLineProgramOff();
1275 const dbg_line_prg_end = self.getDebugLineProgramEnd();
1276 assert(dbg_line_prg_end != 0);
1277
1278 const debug_line_sect = &self.sections.items[self.debug_line_section_index.?];
1279
1280 var di_buf = std.ArrayList(u8).init(self.base.allocator);
1281 defer di_buf.deinit();
1282
1283 // The size of this header is variable, depending on the number of directories,
1284 // files, and padding. We have a function to compute the upper bound size, however,
1285 // because it's needed for determining where to put the offset of the first `SrcFn`.
1286 try di_buf.ensureCapacity(self.dbgLineNeededHeaderBytes());
1287
1288 // initial length - length of the .debug_line contribution for this compilation unit,
1289 // not including the initial length itself.
1290 const after_init_len = di_buf.items.len + init_len_size;
1291 const init_len = dbg_line_prg_end - after_init_len;
1292 switch (self.ptr_width) {
1293 .p32 => {
1294 mem.writeInt(u32, di_buf.addManyAsArrayAssumeCapacity(4), @intCast(u32, init_len), target_endian);
1295 },
1296 .p64 => {
1297 di_buf.appendNTimesAssumeCapacity(0xff, 4);
1298 mem.writeInt(u64, di_buf.addManyAsArrayAssumeCapacity(8), init_len, target_endian);
1299 },
1300 }
1301
1302 mem.writeInt(u16, di_buf.addManyAsArrayAssumeCapacity(2), 4, target_endian); // version
1303
1304 // Empirically, debug info consumers do not respect this field, or otherwise
1305 // consider it to be an error when it does not point exactly to the end of the header.
1306 // Therefore we rely on the NOP jump at the beginning of the Line Number Program for
1307 // padding rather than this field.
1308 const before_header_len = di_buf.items.len;
1309 di_buf.items.len += ptr_width_bytes; // We will come back and write this.
1310 const after_header_len = di_buf.items.len;
1311
1312 const opcode_base = DW.LNS_set_isa + 1;
1313 di_buf.appendSliceAssumeCapacity(&[_]u8{
1314 1, // minimum_instruction_length
1315 1, // maximum_operations_per_instruction
1316 1, // default_is_stmt
1317 1, // line_base (signed)
1318 1, // line_range
1319 opcode_base,
1320
1321 // Standard opcode lengths. The number of items here is based on `opcode_base`.
1322 // The value is the number of LEB128 operands the instruction takes.
1323 0, // `DW.LNS_copy`
1324 1, // `DW.LNS_advance_pc`
1325 1, // `DW.LNS_advance_line`
1326 1, // `DW.LNS_set_file`
1327 1, // `DW.LNS_set_column`
1328 0, // `DW.LNS_negate_stmt`
1329 0, // `DW.LNS_set_basic_block`
1330 0, // `DW.LNS_const_add_pc`
1331 1, // `DW.LNS_fixed_advance_pc`
1332 0, // `DW.LNS_set_prologue_end`
1333 0, // `DW.LNS_set_epilogue_begin`
1334 1, // `DW.LNS_set_isa`
1335
1336 0, // include_directories (none except the compilation unit cwd)
1337 });
1338 // file_names[0]
1339 di_buf.appendSliceAssumeCapacity(self.base.options.root_pkg.root_src_path); // relative path name
1340 di_buf.appendSliceAssumeCapacity(&[_]u8{
1341 0, // null byte for the relative path name
1342 0, // directory_index
1343 0, // mtime (TODO supply this)
1344 0, // file size bytes (TODO supply this)
1345 0, // file_names sentinel
1346 });
1347
1348 const header_len = di_buf.items.len - after_header_len;
1349 switch (self.ptr_width) {
1350 .p32 => {
1351 mem.writeInt(u32, di_buf.items[before_header_len..][0..4], @intCast(u32, header_len), target_endian);
1352 },
1353 .p64 => {
1354 mem.writeInt(u64, di_buf.items[before_header_len..][0..8], header_len, target_endian);
1355 },
1356 }
1357
1358 // We use NOPs because consumers empirically do not respect the header length field.
1359 if (di_buf.items.len > dbg_line_prg_off) {
1360 // Move the first N files to the end to make more padding for the header.
1361 @panic("TODO: handle .debug_line header exceeding its padding");
1362 }
1363 const jmp_amt = dbg_line_prg_off - di_buf.items.len;
1364 try self.pwriteDbgLineNops(0, di_buf.items, jmp_amt, debug_line_sect.sh_offset);
1365 self.debug_line_header_dirty = false;
1366 }
1367
1368 if (self.phdr_table_dirty) {
1369 const phsize: u64 = switch (self.ptr_width) {
1370 .p32 => @sizeOf(elf.Elf32_Phdr),
1371 .p64 => @sizeOf(elf.Elf64_Phdr),
1372 };
1373 const phalign: u16 = switch (self.ptr_width) {
1374 .p32 => @alignOf(elf.Elf32_Phdr),
1375 .p64 => @alignOf(elf.Elf64_Phdr),
1376 };
1377 const allocated_size = self.allocatedSize(self.phdr_table_offset.?);
1378 const needed_size = self.program_headers.items.len * phsize;
1379
1380 if (needed_size > allocated_size) {
1381 self.phdr_table_offset = null; // free the space
1382 self.phdr_table_offset = self.findFreeSpace(needed_size, phalign);
1383 }
1384
1385 switch (self.ptr_width) {
1386 .p32 => {
1387 const buf = try self.base.allocator.alloc(elf.Elf32_Phdr, self.program_headers.items.len);
1388 defer self.base.allocator.free(buf);
1389
1390 for (buf) |*phdr, i| {
1391 phdr.* = progHeaderTo32(self.program_headers.items[i]);
1392 if (foreign_endian) {
1393 bswapAllFields(elf.Elf32_Phdr, phdr);
1394 }
1395 }
1396 try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), self.phdr_table_offset.?);
1397 },
1398 .p64 => {
1399 const buf = try self.base.allocator.alloc(elf.Elf64_Phdr, self.program_headers.items.len);
1400 defer self.base.allocator.free(buf);
1401
1402 for (buf) |*phdr, i| {
1403 phdr.* = self.program_headers.items[i];
1404 if (foreign_endian) {
1405 bswapAllFields(elf.Elf64_Phdr, phdr);
1406 }
1407 }
1408 try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), self.phdr_table_offset.?);
1409 },
1410 }
1411 self.phdr_table_dirty = false;
1412 }
1413
1414 {
1415 const shstrtab_sect = &self.sections.items[self.shstrtab_index.?];
1416 if (self.shstrtab_dirty or self.shstrtab.items.len != shstrtab_sect.sh_size) {
1417 const allocated_size = self.allocatedSize(shstrtab_sect.sh_offset);
1418 const needed_size = self.shstrtab.items.len;
1419
1420 if (needed_size > allocated_size) {
1421 shstrtab_sect.sh_size = 0; // free the space
1422 shstrtab_sect.sh_offset = self.findFreeSpace(needed_size, 1);
1423 }
1424 shstrtab_sect.sh_size = needed_size;
1425 log.debug("writing shstrtab start=0x{x} end=0x{x}\n", .{ shstrtab_sect.sh_offset, shstrtab_sect.sh_offset + needed_size });
1426
1427 try self.base.file.?.pwriteAll(self.shstrtab.items, shstrtab_sect.sh_offset);
1428 if (!self.shdr_table_dirty) {
1429 // Then it won't get written with the others and we need to do it.
1430 try self.writeSectHeader(self.shstrtab_index.?);
1431 }
1432 self.shstrtab_dirty = false;
1433 }
1434 }
1435 {
1436 const debug_strtab_sect = &self.sections.items[self.debug_str_section_index.?];
1437 if (self.debug_strtab_dirty or self.debug_strtab.items.len != debug_strtab_sect.sh_size) {
1438 const allocated_size = self.allocatedSize(debug_strtab_sect.sh_offset);
1439 const needed_size = self.debug_strtab.items.len;
1440
1441 if (needed_size > allocated_size) {
1442 debug_strtab_sect.sh_size = 0; // free the space
1443 debug_strtab_sect.sh_offset = self.findFreeSpace(needed_size, 1);
1444 }
1445 debug_strtab_sect.sh_size = needed_size;
1446 log.debug("debug_strtab start=0x{x} end=0x{x}\n", .{ debug_strtab_sect.sh_offset, debug_strtab_sect.sh_offset + needed_size });
1447
1448 try self.base.file.?.pwriteAll(self.debug_strtab.items, debug_strtab_sect.sh_offset);
1449 if (!self.shdr_table_dirty) {
1450 // Then it won't get written with the others and we need to do it.
1451 try self.writeSectHeader(self.debug_str_section_index.?);
1452 }
1453 self.debug_strtab_dirty = false;
1454 }
1455 }
1456 if (self.shdr_table_dirty) {
1457 const shsize: u64 = switch (self.ptr_width) {
1458 .p32 => @sizeOf(elf.Elf32_Shdr),
1459 .p64 => @sizeOf(elf.Elf64_Shdr),
1460 };
1461 const shalign: u16 = switch (self.ptr_width) {
1462 .p32 => @alignOf(elf.Elf32_Shdr),
1463 .p64 => @alignOf(elf.Elf64_Shdr),
1464 };
1465 const allocated_size = self.allocatedSize(self.shdr_table_offset.?);
1466 const needed_size = self.sections.items.len * shsize;
1467
1468 if (needed_size > allocated_size) {
1469 self.shdr_table_offset = null; // free the space
1470 self.shdr_table_offset = self.findFreeSpace(needed_size, shalign);
1471 }
1472
1473 switch (self.ptr_width) {
1474 .p32 => {
1475 const buf = try self.base.allocator.alloc(elf.Elf32_Shdr, self.sections.items.len);
1476 defer self.base.allocator.free(buf);
1477
1478 for (buf) |*shdr, i| {
1479 shdr.* = sectHeaderTo32(self.sections.items[i]);
1480 log.debug("writing section {}\n", .{shdr.*});
1481 if (foreign_endian) {
1482 bswapAllFields(elf.Elf32_Shdr, shdr);
1483 }
1484 }
1485 try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), self.shdr_table_offset.?);
1486 },
1487 .p64 => {
1488 const buf = try self.base.allocator.alloc(elf.Elf64_Shdr, self.sections.items.len);
1489 defer self.base.allocator.free(buf);
1490
1491 for (buf) |*shdr, i| {
1492 shdr.* = self.sections.items[i];
1493 log.debug("writing section {}\n", .{shdr.*});
1494 if (foreign_endian) {
1495 bswapAllFields(elf.Elf64_Shdr, shdr);
1496 }
1497 }
1498 try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), self.shdr_table_offset.?);
1499 },
1500 }
1501 self.shdr_table_dirty = false;
1502 }
1503 if (self.entry_addr == null and self.base.options.output_mode == .Exe) {
1504 log.debug("flushing. no_entry_point_found = true\n", .{});
1505 self.error_flags.no_entry_point_found = true;
1506 } else {
1507 log.debug("flushing. no_entry_point_found = false\n", .{});
1508 self.error_flags.no_entry_point_found = false;
1509 try self.writeElfHeader();
1510 }
1511
1512 // The point of flush() is to commit changes, so in theory, nothing should
1513 // be dirty after this. However, it is possible for some things to remain
1514 // dirty because they fail to be written in the event of compile errors,
1515 // such as debug_line_header_dirty and debug_info_header_dirty.
1516 assert(!self.debug_abbrev_section_dirty);
1517 assert(!self.debug_aranges_section_dirty);
1518 assert(!self.phdr_table_dirty);
1519 assert(!self.shdr_table_dirty);
1520 assert(!self.shstrtab_dirty);
1521 assert(!self.debug_strtab_dirty);
1522 }
1523
1524 fn writeDwarfAddrAssumeCapacity(self: *Elf, buf: *std.ArrayList(u8), addr: u64) void {
1525 const target_endian = self.base.options.target.cpu.arch.endian();
1526 switch (self.ptr_width) {
1527 .p32 => mem.writeInt(u32, buf.addManyAsArrayAssumeCapacity(4), @intCast(u32, addr), target_endian),
1528 .p64 => mem.writeInt(u64, buf.addManyAsArrayAssumeCapacity(8), addr, target_endian),
1529 }
1530 }
1531
1532 fn writeElfHeader(self: *Elf) !void {
1533 var hdr_buf: [@sizeOf(elf.Elf64_Ehdr)]u8 = undefined;
1534
1535 var index: usize = 0;
1536 hdr_buf[0..4].* = "\x7fELF".*;
1537 index += 4;
1538
1539 hdr_buf[index] = switch (self.ptr_width) {
1540 .p32 => elf.ELFCLASS32,
1541 .p64 => elf.ELFCLASS64,
1542 };
1543 index += 1;
1544
1545 const endian = self.base.options.target.cpu.arch.endian();
1546 hdr_buf[index] = switch (endian) {
1547 .Little => elf.ELFDATA2LSB,
1548 .Big => elf.ELFDATA2MSB,
1549 };
1550 index += 1;
1551
1552 hdr_buf[index] = 1; // ELF version
1553 index += 1;
1554
1555 // OS ABI, often set to 0 regardless of target platform
1556 // ABI Version, possibly used by glibc but not by static executables
1557 // padding
1558 mem.set(u8, hdr_buf[index..][0..9], 0);
1559 index += 9;
1560
1561 assert(index == 16);
1562
1563 const elf_type = switch (self.base.options.output_mode) {
1564 .Exe => elf.ET.EXEC,
1565 .Obj => elf.ET.REL,
1566 .Lib => switch (self.base.options.link_mode) {
1567 .Static => elf.ET.REL,
1568 .Dynamic => elf.ET.DYN,
1569 },
1570 };
1571 mem.writeInt(u16, hdr_buf[index..][0..2], @enumToInt(elf_type), endian);
1572 index += 2;
1573
1574 const machine = self.base.options.target.cpu.arch.toElfMachine();
1575 mem.writeInt(u16, hdr_buf[index..][0..2], @enumToInt(machine), endian);
1576 index += 2;
1577
1578 // ELF Version, again
1579 mem.writeInt(u32, hdr_buf[index..][0..4], 1, endian);
1580 index += 4;
1581
1582 const e_entry = if (elf_type == .REL) 0 else self.entry_addr.?;
1583
1584 switch (self.ptr_width) {
1585 .p32 => {
1586 mem.writeInt(u32, hdr_buf[index..][0..4], @intCast(u32, e_entry), endian);
1587 index += 4;
1588
1589 // e_phoff
1590 mem.writeInt(u32, hdr_buf[index..][0..4], @intCast(u32, self.phdr_table_offset.?), endian);
1591 index += 4;
1592
1593 // e_shoff
1594 mem.writeInt(u32, hdr_buf[index..][0..4], @intCast(u32, self.shdr_table_offset.?), endian);
1595 index += 4;
1596 },
1597 .p64 => {
1598 // e_entry
1599 mem.writeInt(u64, hdr_buf[index..][0..8], e_entry, endian);
1600 index += 8;
1601
1602 // e_phoff
1603 mem.writeInt(u64, hdr_buf[index..][0..8], self.phdr_table_offset.?, endian);
1604 index += 8;
1605
1606 // e_shoff
1607 mem.writeInt(u64, hdr_buf[index..][0..8], self.shdr_table_offset.?, endian);
1608 index += 8;
1609 },
1610 }
1611
1612 const e_flags = 0;
1613 mem.writeInt(u32, hdr_buf[index..][0..4], e_flags, endian);
1614 index += 4;
1615
1616 const e_ehsize: u16 = switch (self.ptr_width) {
1617 .p32 => @sizeOf(elf.Elf32_Ehdr),
1618 .p64 => @sizeOf(elf.Elf64_Ehdr),
1619 };
1620 mem.writeInt(u16, hdr_buf[index..][0..2], e_ehsize, endian);
1621 index += 2;
1622
1623 const e_phentsize: u16 = switch (self.ptr_width) {
1624 .p32 => @sizeOf(elf.Elf32_Phdr),
1625 .p64 => @sizeOf(elf.Elf64_Phdr),
1626 };
1627 mem.writeInt(u16, hdr_buf[index..][0..2], e_phentsize, endian);
1628 index += 2;
1629
1630 const e_phnum = @intCast(u16, self.program_headers.items.len);
1631 mem.writeInt(u16, hdr_buf[index..][0..2], e_phnum, endian);
1632 index += 2;
1633
1634 const e_shentsize: u16 = switch (self.ptr_width) {
1635 .p32 => @sizeOf(elf.Elf32_Shdr),
1636 .p64 => @sizeOf(elf.Elf64_Shdr),
1637 };
1638 mem.writeInt(u16, hdr_buf[index..][0..2], e_shentsize, endian);
1639 index += 2;
1640
1641 const e_shnum = @intCast(u16, self.sections.items.len);
1642 mem.writeInt(u16, hdr_buf[index..][0..2], e_shnum, endian);
1643 index += 2;
1644
1645 mem.writeInt(u16, hdr_buf[index..][0..2], self.shstrtab_index.?, endian);
1646 index += 2;
1647
1648 assert(index == e_ehsize);
1649
1650 try self.base.file.?.pwriteAll(hdr_buf[0..index], 0);
1651 }
1652
1653 fn freeTextBlock(self: *Elf, text_block: *TextBlock) void {
1654 var already_have_free_list_node = false;
1655 {
1656 var i: usize = 0;
1657 while (i < self.text_block_free_list.items.len) {
1658 if (self.text_block_free_list.items[i] == text_block) {
1659 _ = self.text_block_free_list.swapRemove(i);
1660 continue;
1661 }
1662 if (self.text_block_free_list.items[i] == text_block.prev) {
1663 already_have_free_list_node = true;
1664 }
1665 i += 1;
1666 }
1667 }
1668
1669 if (self.last_text_block == text_block) {
1670 // TODO shrink the .text section size here
1671 self.last_text_block = text_block.prev;
1672 }
1673
1674 if (text_block.prev) |prev| {
1675 prev.next = text_block.next;
1676
1677 if (!already_have_free_list_node and prev.freeListEligible(self.*)) {
1678 // The free list is heuristics, it doesn't have to be perfect, so we can
1679 // ignore the OOM here.
1680 self.text_block_free_list.append(self.base.allocator, prev) catch {};
1681 }
1682 } else {
1683 text_block.prev = null;
1684 }
1685
1686 if (text_block.next) |next| {
1687 next.prev = text_block.prev;
1688 } else {
1689 text_block.next = null;
1690 }
1691 }
1692
1693 fn shrinkTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64) void {
1694 // TODO check the new capacity, and if it crosses the size threshold into a big enough
1695 // capacity, insert a free list node for it.
1696 }
1697
1698 fn growTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, alignment: u64) !u64 {
1699 const sym = self.local_symbols.items[text_block.local_sym_index];
1700 const align_ok = mem.alignBackwardGeneric(u64, sym.st_value, alignment) == sym.st_value;
1701 const need_realloc = !align_ok or new_block_size > text_block.capacity(self.*);
1702 if (!need_realloc) return sym.st_value;
1703 return self.allocateTextBlock(text_block, new_block_size, alignment);
1704 }
1705
1706 fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, alignment: u64) !u64 {
1707 const phdr = &self.program_headers.items[self.phdr_load_re_index.?];
1708 const shdr = &self.sections.items[self.text_section_index.?];
1709 const new_block_ideal_capacity = new_block_size * alloc_num / alloc_den;
1710
1711 // We use these to indicate our intention to update metadata, placing the new block,
1712 // and possibly removing a free list node.
1713 // It would be simpler to do it inside the for loop below, but that would cause a
1714 // problem if an error was returned later in the function. So this action
1715 // is actually carried out at the end of the function, when errors are no longer possible.
1716 var block_placement: ?*TextBlock = null;
1717 var free_list_removal: ?usize = null;
1718
1719 // First we look for an appropriately sized free list node.
1720 // The list is unordered. We'll just take the first thing that works.
1721 const vaddr = blk: {
1722 var i: usize = 0;
1723 while (i < self.text_block_free_list.items.len) {
1724 const big_block = self.text_block_free_list.items[i];
1725 // We now have a pointer to a live text block that has too much capacity.
1726 // Is it enough that we could fit this new text block?
1727 const sym = self.local_symbols.items[big_block.local_sym_index];
1728 const capacity = big_block.capacity(self.*);
1729 const ideal_capacity = capacity * alloc_num / alloc_den;
1730 const ideal_capacity_end_vaddr = sym.st_value + ideal_capacity;
1731 const capacity_end_vaddr = sym.st_value + capacity;
1732 const new_start_vaddr_unaligned = capacity_end_vaddr - new_block_ideal_capacity;
1733 const new_start_vaddr = mem.alignBackwardGeneric(u64, new_start_vaddr_unaligned, alignment);
1734 if (new_start_vaddr < ideal_capacity_end_vaddr) {
1735 // Additional bookkeeping here to notice if this free list node
1736 // should be deleted because the block that it points to has grown to take up
1737 // more of the extra capacity.
1738 if (!big_block.freeListEligible(self.*)) {
1739 _ = self.text_block_free_list.swapRemove(i);
1740 } else {
1741 i += 1;
1742 }
1743 continue;
1744 }
1745 // At this point we know that we will place the new block here. But the
1746 // remaining question is whether there is still yet enough capacity left
1747 // over for there to still be a free list node.
1748 const remaining_capacity = new_start_vaddr - ideal_capacity_end_vaddr;
1749 const keep_free_list_node = remaining_capacity >= min_text_capacity;
1750
1751 // Set up the metadata to be updated, after errors are no longer possible.
1752 block_placement = big_block;
1753 if (!keep_free_list_node) {
1754 free_list_removal = i;
1755 }
1756 break :blk new_start_vaddr;
1757 } else if (self.last_text_block) |last| {
1758 const sym = self.local_symbols.items[last.local_sym_index];
1759 const ideal_capacity = sym.st_size * alloc_num / alloc_den;
1760 const ideal_capacity_end_vaddr = sym.st_value + ideal_capacity;
1761 const new_start_vaddr = mem.alignForwardGeneric(u64, ideal_capacity_end_vaddr, alignment);
1762 // Set up the metadata to be updated, after errors are no longer possible.
1763 block_placement = last;
1764 break :blk new_start_vaddr;
1765 } else {
1766 break :blk phdr.p_vaddr;
1767 }
1768 };
1769
1770 const expand_text_section = block_placement == null or block_placement.?.next == null;
1771 if (expand_text_section) {
1772 const text_capacity = self.allocatedSize(shdr.sh_offset);
1773 const needed_size = (vaddr + new_block_size) - phdr.p_vaddr;
1774 if (needed_size > text_capacity) {
1775 // Must move the entire text section.
1776 const new_offset = self.findFreeSpace(needed_size, 0x1000);
1777 const text_size = if (self.last_text_block) |last| blk: {
1778 const sym = self.local_symbols.items[last.local_sym_index];
1779 break :blk (sym.st_value + sym.st_size) - phdr.p_vaddr;
1780 } else 0;
1781 const amt = try self.base.file.?.copyRangeAll(shdr.sh_offset, self.base.file.?, new_offset, text_size);
1782 if (amt != text_size) return error.InputOutput;
1783 shdr.sh_offset = new_offset;
1784 phdr.p_offset = new_offset;
1785 }
1786 self.last_text_block = text_block;
1787
1788 shdr.sh_size = needed_size;
1789 phdr.p_memsz = needed_size;
1790 phdr.p_filesz = needed_size;
1791
1792 // The .debug_info section has `low_pc` and `high_pc` values which is the virtual address
1793 // range of the compilation unit. When we expand the text section, this range changes,
1794 // so the DW_TAG_compile_unit tag of the .debug_info section becomes dirty.
1795 self.debug_info_header_dirty = true;
1796 // This becomes dirty for the same reason. We could potentially make this more
1797 // fine-grained with the addition of support for more compilation units. It is planned to
1798 // model each package as a different compilation unit.
1799 self.debug_aranges_section_dirty = true;
1800
1801 self.phdr_table_dirty = true; // TODO look into making only the one program header dirty
1802 self.shdr_table_dirty = true; // TODO look into making only the one section dirty
1803 }
1804
1805 // This function can also reallocate a text block.
1806 // In this case we need to "unplug" it from its previous location before
1807 // plugging it in to its new location.
1808 if (text_block.prev) |prev| {
1809 prev.next = text_block.next;
1810 }
1811 if (text_block.next) |next| {
1812 next.prev = text_block.prev;
1813 }
1814
1815 if (block_placement) |big_block| {
1816 text_block.prev = big_block;
1817 text_block.next = big_block.next;
1818 big_block.next = text_block;
1819 } else {
1820 text_block.prev = null;
1821 text_block.next = null;
1822 }
1823 if (free_list_removal) |i| {
1824 _ = self.text_block_free_list.swapRemove(i);
1825 }
1826 return vaddr;
1827 }
1828
1829 pub fn allocateDeclIndexes(self: *Elf, decl: *Module.Decl) !void {
1830 if (decl.link.elf.local_sym_index != 0) return;
1831
1832 try self.local_symbols.ensureCapacity(self.base.allocator, self.local_symbols.items.len + 1);
1833 try self.offset_table.ensureCapacity(self.base.allocator, self.offset_table.items.len + 1);
1834
1835 if (self.local_symbol_free_list.popOrNull()) |i| {
1836 log.debug("reusing symbol index {} for {}\n", .{ i, decl.name });
1837 decl.link.elf.local_sym_index = i;
1838 } else {
1839 log.debug("allocating symbol index {} for {}\n", .{ self.local_symbols.items.len, decl.name });
1840 decl.link.elf.local_sym_index = @intCast(u32, self.local_symbols.items.len);
1841 _ = self.local_symbols.addOneAssumeCapacity();
1842 }
1843
1844 if (self.offset_table_free_list.popOrNull()) |i| {
1845 decl.link.elf.offset_table_index = i;
1846 } else {
1847 decl.link.elf.offset_table_index = @intCast(u32, self.offset_table.items.len);
1848 _ = self.offset_table.addOneAssumeCapacity();
1849 self.offset_table_count_dirty = true;
1850 }
1851
1852 const phdr = &self.program_headers.items[self.phdr_load_re_index.?];
1853
1854 self.local_symbols.items[decl.link.elf.local_sym_index] = .{
1855 .st_name = 0,
1856 .st_info = 0,
1857 .st_other = 0,
1858 .st_shndx = 0,
1859 .st_value = phdr.p_vaddr,
1860 .st_size = 0,
1861 };
1862 self.offset_table.items[decl.link.elf.offset_table_index] = 0;
1863 }
1864
1865 pub fn freeDecl(self: *Elf, decl: *Module.Decl) void {
1866 // Appending to free lists is allowed to fail because the free lists are heuristics based anyway.
1867 self.freeTextBlock(&decl.link.elf);
1868 if (decl.link.elf.local_sym_index != 0) {
1869 self.local_symbol_free_list.append(self.base.allocator, decl.link.elf.local_sym_index) catch {};
1870 self.offset_table_free_list.append(self.base.allocator, decl.link.elf.offset_table_index) catch {};
1871
1872 self.local_symbols.items[decl.link.elf.local_sym_index].st_info = 0;
1873
1874 decl.link.elf.local_sym_index = 0;
1875 }
1876 // TODO make this logic match freeTextBlock. Maybe abstract the logic out since the same thing
1877 // is desired for both.
1878 _ = self.dbg_line_fn_free_list.remove(&decl.fn_link.elf);
1879 if (decl.fn_link.elf.prev) |prev| {
1880 _ = self.dbg_line_fn_free_list.put(self.base.allocator, prev, {}) catch {};
1881 prev.next = decl.fn_link.elf.next;
1882 if (decl.fn_link.elf.next) |next| {
1883 next.prev = prev;
1884 } else {
1885 self.dbg_line_fn_last = prev;
1886 }
1887 } else if (decl.fn_link.elf.next) |next| {
1888 self.dbg_line_fn_first = next;
1889 next.prev = null;
1890 }
1891 if (self.dbg_line_fn_first == &decl.fn_link.elf) {
1892 self.dbg_line_fn_first = null;
1893 }
1894 if (self.dbg_line_fn_last == &decl.fn_link.elf) {
1895 self.dbg_line_fn_last = null;
1896 }
1897 }
1898
1899 pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void {
1900 const tracy = trace(@src());
1901 defer tracy.end();
1902
1903 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
1904 defer code_buffer.deinit();
1905
1906 var dbg_line_buffer = std.ArrayList(u8).init(self.base.allocator);
1907 defer dbg_line_buffer.deinit();
1908
1909 var dbg_info_buffer = std.ArrayList(u8).init(self.base.allocator);
1910 defer dbg_info_buffer.deinit();
1911
1912 var dbg_info_type_relocs: DbgInfoTypeRelocsTable = .{};
1913 defer {
1914 for (dbg_info_type_relocs.items()) |*entry| {
1915 entry.value.relocs.deinit(self.base.allocator);
1916 }
1917 dbg_info_type_relocs.deinit(self.base.allocator);
1918 }
1919
1920 const typed_value = decl.typed_value.most_recent.typed_value;
1921 const is_fn: bool = switch (typed_value.ty.zigTypeTag()) {
1922 .Fn => true,
1923 else => false,
1924 };
1925 if (is_fn) {
1926 //if (mem.eql(u8, mem.spanZ(decl.name), "add")) {
1927 // typed_value.val.cast(Value.Payload.Function).?.func.dump(module.*);
1928 //}
1929
1930 // For functions we need to add a prologue to the debug line program.
1931 try dbg_line_buffer.ensureCapacity(26);
1932
1933 const line_off: u28 = blk: {
1934 if (decl.scope.cast(Module.Scope.File)) |scope_file| {
1935 const tree = scope_file.contents.tree;
1936 const file_ast_decls = tree.root_node.decls();
1937 // TODO Look into improving the performance here by adding a token-index-to-line
1938 // lookup table. Currently this involves scanning over the source code for newlines.
1939 const fn_proto = file_ast_decls[decl.src_index].castTag(.FnProto).?;
1940 const block = fn_proto.body().?.castTag(.Block).?;
1941 const line_delta = std.zig.lineDelta(tree.source, 0, tree.token_locs[block.lbrace].start);
1942 break :blk @intCast(u28, line_delta);
1943 } else if (decl.scope.cast(Module.Scope.ZIRModule)) |zir_module| {
1944 const byte_off = zir_module.contents.module.decls[decl.src_index].inst.src;
1945 const line_delta = std.zig.lineDelta(zir_module.source.bytes, 0, byte_off);
1946 break :blk @intCast(u28, line_delta);
1947 } else {
1948 unreachable;
1949 }
1950 };
1951
1952 const ptr_width_bytes = self.ptrWidthBytes();
1953 dbg_line_buffer.appendSliceAssumeCapacity(&[_]u8{
1954 DW.LNS_extended_op,
1955 ptr_width_bytes + 1,
1956 DW.LNE_set_address,
1957 });
1958 // This is the "relocatable" vaddr, corresponding to `code_buffer` index `0`.
1959 assert(dbg_line_vaddr_reloc_index == dbg_line_buffer.items.len);
1960 dbg_line_buffer.items.len += ptr_width_bytes;
1961
1962 dbg_line_buffer.appendAssumeCapacity(DW.LNS_advance_line);
1963 // This is the "relocatable" relative line offset from the previous function's end curly
1964 // to this function's begin curly.
1965 assert(self.getRelocDbgLineOff() == dbg_line_buffer.items.len);
1966 // Here we use a ULEB128-fixed-4 to make sure this field can be overwritten later.
1967 leb128.writeUnsignedFixed(4, dbg_line_buffer.addManyAsArrayAssumeCapacity(4), line_off);
1968
1969 dbg_line_buffer.appendAssumeCapacity(DW.LNS_set_file);
1970 assert(self.getRelocDbgFileIndex() == dbg_line_buffer.items.len);
1971 // Once we support more than one source file, this will have the ability to be more
1972 // than one possible value.
1973 const file_index = 1;
1974 leb128.writeUnsignedFixed(4, dbg_line_buffer.addManyAsArrayAssumeCapacity(4), file_index);
1975
1976 // Emit a line for the begin curly with prologue_end=false. The codegen will
1977 // do the work of setting prologue_end=true and epilogue_begin=true.
1978 dbg_line_buffer.appendAssumeCapacity(DW.LNS_copy);
1979
1980 // .debug_info subprogram
1981 const decl_name_with_null = decl.name[0..mem.lenZ(decl.name) + 1];
1982 try dbg_info_buffer.ensureCapacity(dbg_info_buffer.items.len + 25 + decl_name_with_null.len);
1983
1984 const fn_ret_type = typed_value.ty.fnReturnType();
1985 const fn_ret_has_bits = fn_ret_type.hasCodeGenBits();
1986 if (fn_ret_has_bits) {
1987 dbg_info_buffer.appendAssumeCapacity(abbrev_subprogram);
1988 } else {
1989 dbg_info_buffer.appendAssumeCapacity(abbrev_subprogram_retvoid);
1990 }
1991 // These get overwritten after generating the machine code. These values are
1992 // "relocations" and have to be in this fixed place so that functions can be
1993 // moved in virtual address space.
1994 assert(dbg_info_low_pc_reloc_index == dbg_info_buffer.items.len);
1995 dbg_info_buffer.items.len += ptr_width_bytes; // DW.AT_low_pc, DW.FORM_addr
1996 assert(self.getRelocDbgInfoSubprogramHighPC() == dbg_info_buffer.items.len);
1997 dbg_info_buffer.items.len += 4; // DW.AT_high_pc, DW.FORM_data4
1998 if (fn_ret_has_bits) {
1999 const gop = try dbg_info_type_relocs.getOrPut(self.base.allocator, fn_ret_type);
2000 if (!gop.found_existing) {
2001 gop.entry.value = .{
2002 .off = undefined,
2003 .relocs = .{},
2004 };
2005 }
2006 try gop.entry.value.relocs.append(self.base.allocator, @intCast(u32, dbg_info_buffer.items.len));
2007 dbg_info_buffer.items.len += 4; // DW.AT_type, DW.FORM_ref4
2008 }
2009 dbg_info_buffer.appendSliceAssumeCapacity(decl_name_with_null); // DW.AT_name, DW.FORM_string
2010 } else {
2011 // TODO implement .debug_info for global variables
2012 }
2013 const res = try codegen.generateSymbol(self, decl.src(), typed_value, &code_buffer, &dbg_line_buffer, &dbg_info_buffer, &dbg_info_type_relocs);
2014 const code = switch (res) {
2015 .externally_managed => |x| x,
2016 .appended => code_buffer.items,
2017 .fail => |em| {
2018 decl.analysis = .codegen_failure;
2019 try module.failed_decls.put(module.gpa, decl, em);
2020 return;
2021 },
2022 };
2023
2024 const required_alignment = typed_value.ty.abiAlignment(self.base.options.target);
2025
2026 const stt_bits: u8 = if (is_fn) elf.STT_FUNC else elf.STT_OBJECT;
2027
2028 assert(decl.link.elf.local_sym_index != 0); // Caller forgot to allocateDeclIndexes()
2029 const local_sym = &self.local_symbols.items[decl.link.elf.local_sym_index];
2030 if (local_sym.st_size != 0) {
2031 const capacity = decl.link.elf.capacity(self.*);
2032 const need_realloc = code.len > capacity or
2033 !mem.isAlignedGeneric(u64, local_sym.st_value, required_alignment);
2034 if (need_realloc) {
2035 const vaddr = try self.growTextBlock(&decl.link.elf, code.len, required_alignment);
2036 log.debug("growing {} from 0x{x} to 0x{x}\n", .{ decl.name, local_sym.st_value, vaddr });
2037 if (vaddr != local_sym.st_value) {
2038 local_sym.st_value = vaddr;
2039
2040 log.debug(" (writing new offset table entry)\n", .{});
2041 self.offset_table.items[decl.link.elf.offset_table_index] = vaddr;
2042 try self.writeOffsetTableEntry(decl.link.elf.offset_table_index);
2043 }
2044 } else if (code.len < local_sym.st_size) {
2045 self.shrinkTextBlock(&decl.link.elf, code.len);
2046 }
2047 local_sym.st_size = code.len;
2048 local_sym.st_name = try self.updateString(local_sym.st_name, mem.spanZ(decl.name));
2049 local_sym.st_info = (elf.STB_LOCAL << 4) | stt_bits;
2050 local_sym.st_other = 0;
2051 local_sym.st_shndx = self.text_section_index.?;
2052 // TODO this write could be avoided if no fields of the symbol were changed.
2053 try self.writeSymbol(decl.link.elf.local_sym_index);
2054 } else {
2055 const decl_name = mem.spanZ(decl.name);
2056 const name_str_index = try self.makeString(decl_name);
2057 const vaddr = try self.allocateTextBlock(&decl.link.elf, code.len, required_alignment);
2058 log.debug("allocated text block for {} at 0x{x}\n", .{ decl_name, vaddr });
2059 errdefer self.freeTextBlock(&decl.link.elf);
2060
2061 local_sym.* = .{
2062 .st_name = name_str_index,
2063 .st_info = (elf.STB_LOCAL << 4) | stt_bits,
2064 .st_other = 0,
2065 .st_shndx = self.text_section_index.?,
2066 .st_value = vaddr,
2067 .st_size = code.len,
2068 };
2069 self.offset_table.items[decl.link.elf.offset_table_index] = vaddr;
2070
2071 try self.writeSymbol(decl.link.elf.local_sym_index);
2072 try self.writeOffsetTableEntry(decl.link.elf.offset_table_index);
2073 }
2074
2075 const section_offset = local_sym.st_value - self.program_headers.items[self.phdr_load_re_index.?].p_vaddr;
2076 const file_offset = self.sections.items[self.text_section_index.?].sh_offset + section_offset;
2077 try self.base.file.?.pwriteAll(code, file_offset);
2078
2079 const target_endian = self.base.options.target.cpu.arch.endian();
2080
2081 const text_block = &decl.link.elf;
2082
2083 // If the Decl is a function, we need to update the .debug_line program.
2084 if (is_fn) {
2085 // Perform the relocations based on vaddr.
2086 switch (self.ptr_width) {
2087 .p32 => {
2088 {
2089 const ptr = dbg_line_buffer.items[dbg_line_vaddr_reloc_index..][0..4];
2090 mem.writeInt(u32, ptr, @intCast(u32, local_sym.st_value), target_endian);
2091 }
2092 {
2093 const ptr = dbg_info_buffer.items[dbg_info_low_pc_reloc_index..][0..4];
2094 mem.writeInt(u32, ptr, @intCast(u32, local_sym.st_value), target_endian);
2095 }
2096 },
2097 .p64 => {
2098 {
2099 const ptr = dbg_line_buffer.items[dbg_line_vaddr_reloc_index..][0..8];
2100 mem.writeInt(u64, ptr, local_sym.st_value, target_endian);
2101 }
2102 {
2103 const ptr = dbg_info_buffer.items[dbg_info_low_pc_reloc_index..][0..8];
2104 mem.writeInt(u64, ptr, local_sym.st_value, target_endian);
2105 }
2106 },
2107 }
2108 {
2109 const ptr = dbg_info_buffer.items[self.getRelocDbgInfoSubprogramHighPC()..][0..4];
2110 mem.writeInt(u32, ptr, @intCast(u32, local_sym.st_size), target_endian);
2111 }
2112
2113 try dbg_line_buffer.appendSlice(&[_]u8{ DW.LNS_extended_op, 1, DW.LNE_end_sequence });
2114
2115 // Now we have the full contents and may allocate a region to store it.
2116
2117 // This logic is nearly identical to the logic below in `updateDeclDebugInfo` for
2118 // `TextBlock` and the .debug_info. If you are editing this logic, you
2119 // probably need to edit that logic too.
2120
2121 const debug_line_sect = &self.sections.items[self.debug_line_section_index.?];
2122 const src_fn = &decl.fn_link.elf;
2123 src_fn.len = @intCast(u32, dbg_line_buffer.items.len);
2124 if (self.dbg_line_fn_last) |last| {
2125 if (src_fn.next) |next| {
2126 // Update existing function - non-last item.
2127 if (src_fn.off + src_fn.len + min_nop_size > next.off) {
2128 // It grew too big, so we move it to a new location.
2129 if (src_fn.prev) |prev| {
2130 _ = self.dbg_line_fn_free_list.put(self.base.allocator, prev, {}) catch {};
2131 prev.next = src_fn.next;
2132 }
2133 next.prev = src_fn.prev;
2134 src_fn.next = null;
2135 // Populate where it used to be with NOPs.
2136 const file_pos = debug_line_sect.sh_offset + src_fn.off;
2137 try self.pwriteDbgLineNops(0, &[0]u8{}, src_fn.len, file_pos);
2138 // TODO Look at the free list before appending at the end.
2139 src_fn.prev = last;
2140 last.next = src_fn;
2141 self.dbg_line_fn_last = src_fn;
2142
2143 src_fn.off = last.off + (last.len * alloc_num / alloc_den);
2144 }
2145 } else if (src_fn.prev == null) {
2146 // Append new function.
2147 // TODO Look at the free list before appending at the end.
2148 src_fn.prev = last;
2149 last.next = src_fn;
2150 self.dbg_line_fn_last = src_fn;
2151
2152 src_fn.off = last.off + (last.len * alloc_num / alloc_den);
2153 }
2154 } else {
2155 // This is the first function of the Line Number Program.
2156 self.dbg_line_fn_first = src_fn;
2157 self.dbg_line_fn_last = src_fn;
2158
2159 src_fn.off = self.dbgLineNeededHeaderBytes() * alloc_num / alloc_den;
2160 }
2161
2162 const last_src_fn = self.dbg_line_fn_last.?;
2163 const needed_size = last_src_fn.off + last_src_fn.len;
2164 if (needed_size != debug_line_sect.sh_size) {
2165 if (needed_size > self.allocatedSize(debug_line_sect.sh_offset)) {
2166 const new_offset = self.findFreeSpace(needed_size, 1);
2167 const existing_size = last_src_fn.off;
2168 log.debug("moving .debug_line section: {} bytes from 0x{x} to 0x{x}\n", .{
2169 existing_size,
2170 debug_line_sect.sh_offset,
2171 new_offset,
2172 });
2173 const amt = try self.base.file.?.copyRangeAll(debug_line_sect.sh_offset, self.base.file.?, new_offset, existing_size);
2174 if (amt != existing_size) return error.InputOutput;
2175 debug_line_sect.sh_offset = new_offset;
2176 }
2177 debug_line_sect.sh_size = needed_size;
2178 self.shdr_table_dirty = true; // TODO look into making only the one section dirty
2179 self.debug_line_header_dirty = true;
2180 }
2181 const prev_padding_size: u32 = if (src_fn.prev) |prev| src_fn.off - (prev.off + prev.len) else 0;
2182 const next_padding_size: u32 = if (src_fn.next) |next| next.off - (src_fn.off + src_fn.len) else 0;
2183
2184 // We only have support for one compilation unit so far, so the offsets are directly
2185 // from the .debug_line section.
2186 const file_pos = debug_line_sect.sh_offset + src_fn.off;
2187 try self.pwriteDbgLineNops(prev_padding_size, dbg_line_buffer.items, next_padding_size, file_pos);
2188
2189 // .debug_info - End the TAG_subprogram children.
2190 try dbg_info_buffer.append(0);
2191 }
2192
2193 // Now we emit the .debug_info types of the Decl. These will count towards the size of
2194 // the buffer, so we have to do it before computing the offset, and we can't perform the actual
2195 // relocations yet.
2196 for (dbg_info_type_relocs.items()) |*entry| {
2197 entry.value.off = @intCast(u32, dbg_info_buffer.items.len);
2198 try self.addDbgInfoType(entry.key, &dbg_info_buffer);
2199 }
2200
2201 try self.updateDeclDebugInfoAllocation(text_block, @intCast(u32, dbg_info_buffer.items.len));
2202
2203 // Now that we have the offset assigned we can finally perform type relocations.
2204 for (dbg_info_type_relocs.items()) |entry| {
2205 for (entry.value.relocs.items) |off| {
2206 mem.writeInt(
2207 u32,
2208 dbg_info_buffer.items[off..][0..4],
2209 text_block.dbg_info_off + entry.value.off,
2210 target_endian,
2211 );
2212 }
2213 }
2214
2215 try self.writeDeclDebugInfo(text_block, dbg_info_buffer.items);
2216
2217 // Since we updated the vaddr and the size, each corresponding export symbol also needs to be updated.
2218 const decl_exports = module.decl_exports.get(decl) orelse &[0]*Module.Export{};
2219 return self.updateDeclExports(module, decl, decl_exports);
2220 }
2221
2222 /// Asserts the type has codegen bits.
2223 fn addDbgInfoType(self: *Elf, ty: Type, dbg_info_buffer: *std.ArrayList(u8)) !void {
2224 switch (ty.zigTypeTag()) {
2225 .Void => unreachable,
2226 .NoReturn => unreachable,
2227 .Bool => {
2228 try dbg_info_buffer.appendSlice(&[_]u8{
2229 abbrev_base_type,
2230 DW.ATE_boolean, // DW.AT_encoding , DW.FORM_data1
2231 1, // DW.AT_byte_size, DW.FORM_data1
2232 'b', 'o', 'o', 'l', 0, // DW.AT_name, DW.FORM_string
2233 });
2234 },
2235 .Int => {
2236 const info = ty.intInfo(self.base.options.target);
2237 try dbg_info_buffer.ensureCapacity(dbg_info_buffer.items.len + 12);
2238 dbg_info_buffer.appendAssumeCapacity(abbrev_base_type);
2239 // DW.AT_encoding, DW.FORM_data1
2240 dbg_info_buffer.appendAssumeCapacity(if (info.signed) DW.ATE_signed else DW.ATE_unsigned);
2241 // DW.AT_byte_size, DW.FORM_data1
2242 dbg_info_buffer.appendAssumeCapacity(@intCast(u8, ty.abiSize(self.base.options.target)));
2243 // DW.AT_name, DW.FORM_string
2244 try dbg_info_buffer.writer().print("{}\x00", .{ty});
2245 },
2246 else => {
2247 std.log.scoped(.compiler).err("TODO implement .debug_info for type '{}'", .{ty});
2248 try dbg_info_buffer.append(abbrev_pad1);
2249 },
2250 }
2251 }
2252
2253 fn updateDeclDebugInfoAllocation(self: *Elf, text_block: *TextBlock, len: u32) !void {
2254 const tracy = trace(@src());
2255 defer tracy.end();
2256
2257 // This logic is nearly identical to the logic above in `updateDecl` for
2258 // `SrcFn` and the line number programs. If you are editing this logic, you
2259 // probably need to edit that logic too.
2260
2261 const debug_info_sect = &self.sections.items[self.debug_info_section_index.?];
2262 text_block.dbg_info_len = len;
2263 if (self.dbg_info_decl_last) |last| {
2264 if (text_block.dbg_info_next) |next| {
2265 // Update existing Decl - non-last item.
2266 if (text_block.dbg_info_off + text_block.dbg_info_len + min_nop_size > next.dbg_info_off) {
2267 // It grew too big, so we move it to a new location.
2268 if (text_block.dbg_info_prev) |prev| {
2269 _ = self.dbg_info_decl_free_list.put(self.base.allocator, prev, {}) catch {};
2270 prev.dbg_info_next = text_block.dbg_info_next;
2271 }
2272 next.dbg_info_prev = text_block.dbg_info_prev;
2273 text_block.dbg_info_next = null;
2274 // Populate where it used to be with NOPs.
2275 const file_pos = debug_info_sect.sh_offset + text_block.dbg_info_off;
2276 try self.pwriteDbgInfoNops(0, &[0]u8{}, text_block.dbg_info_len, false, file_pos);
2277 // TODO Look at the free list before appending at the end.
2278 text_block.dbg_info_prev = last;
2279 last.dbg_info_next = text_block;
2280 self.dbg_info_decl_last = text_block;
2281
2282 text_block.dbg_info_off = last.dbg_info_off + (last.dbg_info_len * alloc_num / alloc_den);
2283 }
2284 } else if (text_block.dbg_info_prev == null) {
2285 // Append new Decl.
2286 // TODO Look at the free list before appending at the end.
2287 text_block.dbg_info_prev = last;
2288 last.dbg_info_next = text_block;
2289 self.dbg_info_decl_last = text_block;
2290
2291 text_block.dbg_info_off = last.dbg_info_off + (last.dbg_info_len * alloc_num / alloc_den);
2292 }
2293 } else {
2294 // This is the first Decl of the .debug_info
2295 self.dbg_info_decl_first = text_block;
2296 self.dbg_info_decl_last = text_block;
2297
2298 text_block.dbg_info_off = self.dbgInfoNeededHeaderBytes() * alloc_num / alloc_den;
2299 }
2300 }
2301
2302 fn writeDeclDebugInfo(self: *Elf, text_block: *TextBlock, dbg_info_buf: []const u8) !void {
2303 const tracy = trace(@src());
2304 defer tracy.end();
2305
2306 // This logic is nearly identical to the logic above in `updateDecl` for
2307 // `SrcFn` and the line number programs. If you are editing this logic, you
2308 // probably need to edit that logic too.
2309
2310 const debug_info_sect = &self.sections.items[self.debug_info_section_index.?];
2311
2312 const last_decl = self.dbg_info_decl_last.?;
2313 // +1 for a trailing zero to end the children of the decl tag.
2314 const needed_size = last_decl.dbg_info_off + last_decl.dbg_info_len + 1;
2315 if (needed_size != debug_info_sect.sh_size) {
2316 if (needed_size > self.allocatedSize(debug_info_sect.sh_offset)) {
2317 const new_offset = self.findFreeSpace(needed_size, 1);
2318 const existing_size = last_decl.dbg_info_off;
2319 log.debug("moving .debug_info section: {} bytes from 0x{x} to 0x{x}\n", .{
2320 existing_size,
2321 debug_info_sect.sh_offset,
2322 new_offset,
2323 });
2324 const amt = try self.base.file.?.copyRangeAll(debug_info_sect.sh_offset, self.base.file.?, new_offset, existing_size);
2325 if (amt != existing_size) return error.InputOutput;
2326 debug_info_sect.sh_offset = new_offset;
2327 }
2328 debug_info_sect.sh_size = needed_size;
2329 self.shdr_table_dirty = true; // TODO look into making only the one section dirty
2330 self.debug_info_header_dirty = true;
2331 }
2332 const prev_padding_size: u32 = if (text_block.dbg_info_prev) |prev|
2333 text_block.dbg_info_off - (prev.dbg_info_off + prev.dbg_info_len)
2334 else
2335 0;
2336 const next_padding_size: u32 = if (text_block.dbg_info_next) |next|
2337 next.dbg_info_off - (text_block.dbg_info_off + text_block.dbg_info_len)
2338 else
2339 0;
2340
2341 // To end the children of the decl tag.
2342 const trailing_zero = text_block.dbg_info_next == null;
2343
2344 // We only have support for one compilation unit so far, so the offsets are directly
2345 // from the .debug_info section.
2346 const file_pos = debug_info_sect.sh_offset + text_block.dbg_info_off;
2347 try self.pwriteDbgInfoNops(prev_padding_size, dbg_info_buf, next_padding_size, trailing_zero, file_pos);
2348 }
2349
2350 pub fn updateDeclExports(
2351 self: *Elf,
2352 module: *Module,
2353 decl: *const Module.Decl,
2354 exports: []const *Module.Export,
2355 ) !void {
2356 const tracy = trace(@src());
2357 defer tracy.end();
2358
2359 try self.global_symbols.ensureCapacity(self.base.allocator, self.global_symbols.items.len + exports.len);
2360 const typed_value = decl.typed_value.most_recent.typed_value;
2361 if (decl.link.elf.local_sym_index == 0) return;
2362 const decl_sym = self.local_symbols.items[decl.link.elf.local_sym_index];
2363
2364 for (exports) |exp| {
2365 if (exp.options.section) |section_name| {
2366 if (!mem.eql(u8, section_name, ".text")) {
2367 try module.failed_exports.ensureCapacity(module.gpa, module.failed_exports.items().len + 1);
2368 module.failed_exports.putAssumeCapacityNoClobber(
2369 exp,
2370 try Module.ErrorMsg.create(self.base.allocator, 0, "Unimplemented: ExportOptions.section", .{}),
2371 );
2372 continue;
2373 }
2374 }
2375 const stb_bits: u8 = switch (exp.options.linkage) {
2376 .Internal => elf.STB_LOCAL,
2377 .Strong => blk: {
2378 if (mem.eql(u8, exp.options.name, "_start")) {
2379 self.entry_addr = decl_sym.st_value;
2380 }
2381 break :blk elf.STB_GLOBAL;
2382 },
2383 .Weak => elf.STB_WEAK,
2384 .LinkOnce => {
2385 try module.failed_exports.ensureCapacity(module.gpa, module.failed_exports.items().len + 1);
2386 module.failed_exports.putAssumeCapacityNoClobber(
2387 exp,
2388 try Module.ErrorMsg.create(self.base.allocator, 0, "Unimplemented: GlobalLinkage.LinkOnce", .{}),
2389 );
2390 continue;
2391 },
2392 };
2393 const stt_bits: u8 = @truncate(u4, decl_sym.st_info);
2394 if (exp.link.sym_index) |i| {
2395 const sym = &self.global_symbols.items[i];
2396 sym.* = .{
2397 .st_name = try self.updateString(sym.st_name, exp.options.name),
2398 .st_info = (stb_bits << 4) | stt_bits,
2399 .st_other = 0,
2400 .st_shndx = self.text_section_index.?,
2401 .st_value = decl_sym.st_value,
2402 .st_size = decl_sym.st_size,
2403 };
2404 } else {
2405 const name = try self.makeString(exp.options.name);
2406 const i = if (self.global_symbol_free_list.popOrNull()) |i| i else blk: {
2407 _ = self.global_symbols.addOneAssumeCapacity();
2408 break :blk self.global_symbols.items.len - 1;
2409 };
2410 self.global_symbols.items[i] = .{
2411 .st_name = name,
2412 .st_info = (stb_bits << 4) | stt_bits,
2413 .st_other = 0,
2414 .st_shndx = self.text_section_index.?,
2415 .st_value = decl_sym.st_value,
2416 .st_size = decl_sym.st_size,
2417 };
2418
2419 exp.link.sym_index = @intCast(u32, i);
2420 }
2421 }
2422 }
2423
2424 /// Must be called only after a successful call to `updateDecl`.
2425 pub fn updateDeclLineNumber(self: *Elf, module: *Module, decl: *const Module.Decl) !void {
2426 const tracy = trace(@src());
2427 defer tracy.end();
2428
2429 const scope_file = decl.scope.cast(Module.Scope.File).?;
2430 const tree = scope_file.contents.tree;
2431 const file_ast_decls = tree.root_node.decls();
2432 // TODO Look into improving the performance here by adding a token-index-to-line
2433 // lookup table. Currently this involves scanning over the source code for newlines.
2434 const fn_proto = file_ast_decls[decl.src_index].castTag(.FnProto).?;
2435 const block = fn_proto.body().?.castTag(.Block).?;
2436 const line_delta = std.zig.lineDelta(tree.source, 0, tree.token_locs[block.lbrace].start);
2437 const casted_line_off = @intCast(u28, line_delta);
2438
2439 const shdr = &self.sections.items[self.debug_line_section_index.?];
2440 const file_pos = shdr.sh_offset + decl.fn_link.elf.off + self.getRelocDbgLineOff();
2441 var data: [4]u8 = undefined;
2442 leb128.writeUnsignedFixed(4, &data, casted_line_off);
2443 try self.base.file.?.pwriteAll(&data, file_pos);
2444 }
2445
2446 pub fn deleteExport(self: *Elf, exp: Export) void {
2447 const sym_index = exp.sym_index orelse return;
2448 self.global_symbol_free_list.append(self.base.allocator, sym_index) catch {};
2449 self.global_symbols.items[sym_index].st_info = 0;
2450 }
2451
2452 fn writeProgHeader(self: *Elf, index: usize) !void {
2453 const foreign_endian = self.base.options.target.cpu.arch.endian() != std.Target.current.cpu.arch.endian();
2454 const offset = self.program_headers.items[index].p_offset;
2455 switch (self.base.options.target.cpu.arch.ptrBitWidth()) {
2456 32 => {
2457 var phdr = [1]elf.Elf32_Phdr{progHeaderTo32(self.program_headers.items[index])};
2458 if (foreign_endian) {
2459 bswapAllFields(elf.Elf32_Phdr, &phdr[0]);
2460 }
2461 return self.base.file.?.pwriteAll(mem.sliceAsBytes(&phdr), offset);
2462 },
2463 64 => {
2464 var phdr = [1]elf.Elf64_Phdr{self.program_headers.items[index]};
2465 if (foreign_endian) {
2466 bswapAllFields(elf.Elf64_Phdr, &phdr[0]);
2467 }
2468 return self.base.file.?.pwriteAll(mem.sliceAsBytes(&phdr), offset);
2469 },
2470 else => return error.UnsupportedArchitecture,
2471 }
2472 }
2473
2474 fn writeSectHeader(self: *Elf, index: usize) !void {
2475 const foreign_endian = self.base.options.target.cpu.arch.endian() != std.Target.current.cpu.arch.endian();
2476 switch (self.base.options.target.cpu.arch.ptrBitWidth()) {
2477 32 => {
2478 var shdr: [1]elf.Elf32_Shdr = undefined;
2479 shdr[0] = sectHeaderTo32(self.sections.items[index]);
2480 if (foreign_endian) {
2481 bswapAllFields(elf.Elf32_Shdr, &shdr[0]);
2482 }
2483 const offset = self.shdr_table_offset.? + index * @sizeOf(elf.Elf32_Shdr);
2484 return self.base.file.?.pwriteAll(mem.sliceAsBytes(&shdr), offset);
2485 },
2486 64 => {
2487 var shdr = [1]elf.Elf64_Shdr{self.sections.items[index]};
2488 if (foreign_endian) {
2489 bswapAllFields(elf.Elf64_Shdr, &shdr[0]);
2490 }
2491 const offset = self.shdr_table_offset.? + index * @sizeOf(elf.Elf64_Shdr);
2492 return self.base.file.?.pwriteAll(mem.sliceAsBytes(&shdr), offset);
2493 },
2494 else => return error.UnsupportedArchitecture,
2495 }
2496 }
2497
2498 fn writeOffsetTableEntry(self: *Elf, index: usize) !void {
2499 const shdr = &self.sections.items[self.got_section_index.?];
2500 const phdr = &self.program_headers.items[self.phdr_got_index.?];
2501 const entry_size: u16 = self.ptrWidthBytes();
2502 if (self.offset_table_count_dirty) {
2503 // TODO Also detect virtual address collisions.
2504 const allocated_size = self.allocatedSize(shdr.sh_offset);
2505 const needed_size = self.local_symbols.items.len * entry_size;
2506 if (needed_size > allocated_size) {
2507 // Must move the entire got section.
2508 const new_offset = self.findFreeSpace(needed_size, entry_size);
2509 const amt = try self.base.file.?.copyRangeAll(shdr.sh_offset, self.base.file.?, new_offset, shdr.sh_size);
2510 if (amt != shdr.sh_size) return error.InputOutput;
2511 shdr.sh_offset = new_offset;
2512 phdr.p_offset = new_offset;
2513 }
2514 shdr.sh_size = needed_size;
2515 phdr.p_memsz = needed_size;
2516 phdr.p_filesz = needed_size;
2517
2518 self.shdr_table_dirty = true; // TODO look into making only the one section dirty
2519 self.phdr_table_dirty = true; // TODO look into making only the one program header dirty
2520
2521 self.offset_table_count_dirty = false;
2522 }
2523 const endian = self.base.options.target.cpu.arch.endian();
2524 const off = shdr.sh_offset + @as(u64, entry_size) * index;
2525 switch (self.ptr_width) {
2526 .p32 => {
2527 var buf: [4]u8 = undefined;
2528 mem.writeInt(u32, &buf, @intCast(u32, self.offset_table.items[index]), endian);
2529 try self.base.file.?.pwriteAll(&buf, off);
2530 },
2531 .p64 => {
2532 var buf: [8]u8 = undefined;
2533 mem.writeInt(u64, &buf, self.offset_table.items[index], endian);
2534 try self.base.file.?.pwriteAll(&buf, off);
2535 },
2536 }
2537 }
2538
2539 fn writeSymbol(self: *Elf, index: usize) !void {
2540 const tracy = trace(@src());
2541 defer tracy.end();
2542
2543 const syms_sect = &self.sections.items[self.symtab_section_index.?];
2544 // Make sure we are not pointlessly writing symbol data that will have to get relocated
2545 // due to running out of space.
2546 if (self.local_symbols.items.len != syms_sect.sh_info) {
2547 const sym_size: u64 = switch (self.ptr_width) {
2548 .p32 => @sizeOf(elf.Elf32_Sym),
2549 .p64 => @sizeOf(elf.Elf64_Sym),
2550 };
2551 const sym_align: u16 = switch (self.ptr_width) {
2552 .p32 => @alignOf(elf.Elf32_Sym),
2553 .p64 => @alignOf(elf.Elf64_Sym),
2554 };
2555 const needed_size = (self.local_symbols.items.len + self.global_symbols.items.len) * sym_size;
2556 if (needed_size > self.allocatedSize(syms_sect.sh_offset)) {
2557 // Move all the symbols to a new file location.
2558 const new_offset = self.findFreeSpace(needed_size, sym_align);
2559 const existing_size = @as(u64, syms_sect.sh_info) * sym_size;
2560 const amt = try self.base.file.?.copyRangeAll(syms_sect.sh_offset, self.base.file.?, new_offset, existing_size);
2561 if (amt != existing_size) return error.InputOutput;
2562 syms_sect.sh_offset = new_offset;
2563 }
2564 syms_sect.sh_info = @intCast(u32, self.local_symbols.items.len);
2565 syms_sect.sh_size = needed_size; // anticipating adding the global symbols later
2566 self.shdr_table_dirty = true; // TODO look into only writing one section
2567 }
2568 const foreign_endian = self.base.options.target.cpu.arch.endian() != std.Target.current.cpu.arch.endian();
2569 switch (self.ptr_width) {
2570 .p32 => {
2571 var sym = [1]elf.Elf32_Sym{
2572 .{
2573 .st_name = self.local_symbols.items[index].st_name,
2574 .st_value = @intCast(u32, self.local_symbols.items[index].st_value),
2575 .st_size = @intCast(u32, self.local_symbols.items[index].st_size),
2576 .st_info = self.local_symbols.items[index].st_info,
2577 .st_other = self.local_symbols.items[index].st_other,
2578 .st_shndx = self.local_symbols.items[index].st_shndx,
2579 },
2580 };
2581 if (foreign_endian) {
2582 bswapAllFields(elf.Elf32_Sym, &sym[0]);
2583 }
2584 const off = syms_sect.sh_offset + @sizeOf(elf.Elf32_Sym) * index;
2585 try self.base.file.?.pwriteAll(mem.sliceAsBytes(sym[0..1]), off);
2586 },
2587 .p64 => {
2588 var sym = [1]elf.Elf64_Sym{self.local_symbols.items[index]};
2589 if (foreign_endian) {
2590 bswapAllFields(elf.Elf64_Sym, &sym[0]);
2591 }
2592 const off = syms_sect.sh_offset + @sizeOf(elf.Elf64_Sym) * index;
2593 try self.base.file.?.pwriteAll(mem.sliceAsBytes(sym[0..1]), off);
2594 },
2595 }
2596 }
2597
2598 fn writeAllGlobalSymbols(self: *Elf) !void {
2599 const syms_sect = &self.sections.items[self.symtab_section_index.?];
2600 const sym_size: u64 = switch (self.ptr_width) {
2601 .p32 => @sizeOf(elf.Elf32_Sym),
2602 .p64 => @sizeOf(elf.Elf64_Sym),
2603 };
2604 const foreign_endian = self.base.options.target.cpu.arch.endian() != std.Target.current.cpu.arch.endian();
2605 const global_syms_off = syms_sect.sh_offset + self.local_symbols.items.len * sym_size;
2606 switch (self.ptr_width) {
2607 .p32 => {
2608 const buf = try self.base.allocator.alloc(elf.Elf32_Sym, self.global_symbols.items.len);
2609 defer self.base.allocator.free(buf);
2610
2611 for (buf) |*sym, i| {
2612 sym.* = .{
2613 .st_name = self.global_symbols.items[i].st_name,
2614 .st_value = @intCast(u32, self.global_symbols.items[i].st_value),
2615 .st_size = @intCast(u32, self.global_symbols.items[i].st_size),
2616 .st_info = self.global_symbols.items[i].st_info,
2617 .st_other = self.global_symbols.items[i].st_other,
2618 .st_shndx = self.global_symbols.items[i].st_shndx,
2619 };
2620 if (foreign_endian) {
2621 bswapAllFields(elf.Elf32_Sym, sym);
2622 }
2623 }
2624 try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), global_syms_off);
2625 },
2626 .p64 => {
2627 const buf = try self.base.allocator.alloc(elf.Elf64_Sym, self.global_symbols.items.len);
2628 defer self.base.allocator.free(buf);
2629
2630 for (buf) |*sym, i| {
2631 sym.* = .{
2632 .st_name = self.global_symbols.items[i].st_name,
2633 .st_value = self.global_symbols.items[i].st_value,
2634 .st_size = self.global_symbols.items[i].st_size,
2635 .st_info = self.global_symbols.items[i].st_info,
2636 .st_other = self.global_symbols.items[i].st_other,
2637 .st_shndx = self.global_symbols.items[i].st_shndx,
2638 };
2639 if (foreign_endian) {
2640 bswapAllFields(elf.Elf64_Sym, sym);
2641 }
2642 }
2643 try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), global_syms_off);
2644 },
2645 }
2646 }
2647
2648 fn ptrWidthBytes(self: Elf) u8 {
2649 return switch (self.ptr_width) {
2650 .p32 => 4,
2651 .p64 => 8,
2652 };
2653 }
2654
2655 /// The reloc offset for the virtual address of a function in its Line Number Program.
2656 /// Size is a virtual address integer.
2657 const dbg_line_vaddr_reloc_index = 3;
2658 /// The reloc offset for the virtual address of a function in its .debug_info TAG_subprogram.
2659 /// Size is a virtual address integer.
2660 const dbg_info_low_pc_reloc_index = 1;
2661
2662 /// The reloc offset for the line offset of a function from the previous function's line.
2663 /// It's a fixed-size 4-byte ULEB128.
2664 fn getRelocDbgLineOff(self: Elf) usize {
2665 return dbg_line_vaddr_reloc_index + self.ptrWidthBytes() + 1;
2666 }
2667
2668 fn getRelocDbgFileIndex(self: Elf) usize {
2669 return self.getRelocDbgLineOff() + 5;
2670 }
2671
2672 fn getRelocDbgInfoSubprogramHighPC(self: Elf) u32 {
2673 return dbg_info_low_pc_reloc_index + self.ptrWidthBytes();
2674 }
2675
2676 fn dbgLineNeededHeaderBytes(self: Elf) u32 {
2677 const directory_entry_format_count = 1;
2678 const file_name_entry_format_count = 1;
2679 const directory_count = 1;
2680 const file_name_count = 1;
2681 return @intCast(u32, 53 + directory_entry_format_count * 2 + file_name_entry_format_count * 2 +
2682 directory_count * 8 + file_name_count * 8 +
2683 // These are encoded as DW.FORM_string rather than DW.FORM_strp as we would like
2684 // because of a workaround for readelf and gdb failing to understand DWARFv5 correctly.
2685 self.base.options.root_pkg.root_src_dir_path.len +
2686 self.base.options.root_pkg.root_src_path.len);
2687
2688 }
2689
2690 fn dbgInfoNeededHeaderBytes(self: Elf) u32 {
2691 return 120;
2692 }
2693
2694 const min_nop_size = 2;
2695
2696 /// Writes to the file a buffer, prefixed and suffixed by the specified number of
2697 /// bytes of NOPs. Asserts each padding size is at least `min_nop_size` and total padding bytes
2698 /// are less than 126,976 bytes (if this limit is ever reached, this function can be
2699 /// improved to make more than one pwritev call, or the limit can be raised by a fixed
2700 /// amount by increasing the length of `vecs`).
2701 fn pwriteDbgLineNops(
2702 self: *Elf,
2703 prev_padding_size: usize,
2704 buf: []const u8,
2705 next_padding_size: usize,
2706 offset: usize,
2707 ) !void {
2708 const tracy = trace(@src());
2709 defer tracy.end();
2710
2711 const page_of_nops = [1]u8{DW.LNS_negate_stmt} ** 4096;
2712 const three_byte_nop = [3]u8{DW.LNS_advance_pc, 0b1000_0000, 0};
2713 var vecs: [32]std.os.iovec_const = undefined;
2714 var vec_index: usize = 0;
2715 {
2716 var padding_left = prev_padding_size;
2717 if (padding_left % 2 != 0) {
2718 vecs[vec_index] = .{
2719 .iov_base = &three_byte_nop,
2720 .iov_len = three_byte_nop.len,
2721 };
2722 vec_index += 1;
2723 padding_left -= three_byte_nop.len;
2724 }
2725 while (padding_left > page_of_nops.len) {
2726 vecs[vec_index] = .{
2727 .iov_base = &page_of_nops,
2728 .iov_len = page_of_nops.len,
2729 };
2730 vec_index += 1;
2731 padding_left -= page_of_nops.len;
2732 }
2733 if (padding_left > 0) {
2734 vecs[vec_index] = .{
2735 .iov_base = &page_of_nops,
2736 .iov_len = padding_left,
2737 };
2738 vec_index += 1;
2739 }
2740 }
2741
2742 vecs[vec_index] = .{
2743 .iov_base = buf.ptr,
2744 .iov_len = buf.len,
2745 };
2746 vec_index += 1;
2747
2748 {
2749 var padding_left = next_padding_size;
2750 if (padding_left % 2 != 0) {
2751 vecs[vec_index] = .{
2752 .iov_base = &three_byte_nop,
2753 .iov_len = three_byte_nop.len,
2754 };
2755 vec_index += 1;
2756 padding_left -= three_byte_nop.len;
2757 }
2758 while (padding_left > page_of_nops.len) {
2759 vecs[vec_index] = .{
2760 .iov_base = &page_of_nops,
2761 .iov_len = page_of_nops.len,
2762 };
2763 vec_index += 1;
2764 padding_left -= page_of_nops.len;
2765 }
2766 if (padding_left > 0) {
2767 vecs[vec_index] = .{
2768 .iov_base = &page_of_nops,
2769 .iov_len = padding_left,
2770 };
2771 vec_index += 1;
2772 }
2773 }
2774 try self.base.file.?.pwritevAll(vecs[0..vec_index], offset - prev_padding_size);
2775 }
2776
2777 /// Writes to the file a buffer, prefixed and suffixed by the specified number of
2778 /// bytes of padding.
2779 fn pwriteDbgInfoNops(
2780 self: *Elf,
2781 prev_padding_size: usize,
2782 buf: []const u8,
2783 next_padding_size: usize,
2784 trailing_zero: bool,
2785 offset: usize,
2786 ) !void {
2787 const tracy = trace(@src());
2788 defer tracy.end();
2789
2790 const page_of_nops = [1]u8{abbrev_pad1} ** 4096;
2791 var vecs: [32]std.os.iovec_const = undefined;
2792 var vec_index: usize = 0;
2793 {
2794 var padding_left = prev_padding_size;
2795 while (padding_left > page_of_nops.len) {
2796 vecs[vec_index] = .{
2797 .iov_base = &page_of_nops,
2798 .iov_len = page_of_nops.len,
2799 };
2800 vec_index += 1;
2801 padding_left -= page_of_nops.len;
2802 }
2803 if (padding_left > 0) {
2804 vecs[vec_index] = .{
2805 .iov_base = &page_of_nops,
2806 .iov_len = padding_left,
2807 };
2808 vec_index += 1;
2809 }
2810 }
2811
2812 vecs[vec_index] = .{
2813 .iov_base = buf.ptr,
2814 .iov_len = buf.len,
2815 };
2816 vec_index += 1;
2817
2818 {
2819 var padding_left = next_padding_size;
2820 while (padding_left > page_of_nops.len) {
2821 vecs[vec_index] = .{
2822 .iov_base = &page_of_nops,
2823 .iov_len = page_of_nops.len,
2824 };
2825 vec_index += 1;
2826 padding_left -= page_of_nops.len;
2827 }
2828 if (padding_left > 0) {
2829 vecs[vec_index] = .{
2830 .iov_base = &page_of_nops,
2831 .iov_len = padding_left,
2832 };
2833 vec_index += 1;
2834 }
2835 }
2836
2837 if (trailing_zero) {
2838 var zbuf = [1]u8{0};
2839 vecs[vec_index] = .{
2840 .iov_base = &zbuf,
2841 .iov_len = zbuf.len,
2842 };
2843 vec_index += 1;
2844 }
2845
2846 try self.base.file.?.pwritevAll(vecs[0..vec_index], offset - prev_padding_size);
2847 }
2848
2849 };
2850
2851 pub const MachO = @import("link/MachO.zig");239 pub const MachO = @import("link/MachO.zig");
2852 const Wasm = @import("link/Wasm.zig");240 pub const Wasm = @import("link/Wasm.zig");
2853};241};
2854242
2855/// Saturating multiplication
2856fn satMul(a: anytype, b: anytype) @TypeOf(a, b) {
2857 const T = @TypeOf(a, b);
2858 return std.math.mul(T, a, b) catch std.math.maxInt(T);
2859}
2860
2861fn bswapAllFields(comptime S: type, ptr: *S) void {
2862 @panic("TODO implement bswapAllFields");
2863}
2864
2865fn progHeaderTo32(phdr: elf.Elf64_Phdr) elf.Elf32_Phdr {
2866 return .{
2867 .p_type = phdr.p_type,
2868 .p_flags = phdr.p_flags,
2869 .p_offset = @intCast(u32, phdr.p_offset),
2870 .p_vaddr = @intCast(u32, phdr.p_vaddr),
2871 .p_paddr = @intCast(u32, phdr.p_paddr),
2872 .p_filesz = @intCast(u32, phdr.p_filesz),
2873 .p_memsz = @intCast(u32, phdr.p_memsz),
2874 .p_align = @intCast(u32, phdr.p_align),
2875 };
2876}
2877
2878fn sectHeaderTo32(shdr: elf.Elf64_Shdr) elf.Elf32_Shdr {
2879 return .{
2880 .sh_name = shdr.sh_name,
2881 .sh_type = shdr.sh_type,
2882 .sh_flags = @intCast(u32, shdr.sh_flags),
2883 .sh_addr = @intCast(u32, shdr.sh_addr),
2884 .sh_offset = @intCast(u32, shdr.sh_offset),
2885 .sh_size = @intCast(u32, shdr.sh_size),
2886 .sh_link = shdr.sh_link,
2887 .sh_info = shdr.sh_info,
2888 .sh_addralign = @intCast(u32, shdr.sh_addralign),
2889 .sh_entsize = @intCast(u32, shdr.sh_entsize),
2890 };
2891}
2892
2893pub fn determineMode(options: Options) fs.File.Mode {243pub fn determineMode(options: Options) fs.File.Mode {
2894 // On common systems with a 0o022 umask, 0o777 will still result in a file created244 // On common systems with a 0o022 umask, 0o777 will still result in a file created
2895 // with 0o755 permissions, but it works appropriately if the system is configured245 // with 0o755 permissions, but it works appropriately if the system is configured
src-self-hosted/link/C.zig created+101
...@@ -0,0 +1,101 @@
1const std = @import("std");
2const mem = std.mem;
3const assert = std.debug.assert;
4const Allocator = std.mem.Allocator;
5const Module = @import("../Module.zig");
6const fs = std.fs;
7const codegen = @import("../codegen/c.zig");
8const link = @import("../link.zig");
9const File = link.File;
10const C = @This();
11
12pub const base_tag: File.Tag = .c;
13
14base: File,
15
16header: std.ArrayList(u8),
17constants: std.ArrayList(u8),
18main: std.ArrayList(u8),
19
20called: std.StringHashMap(void),
21need_stddef: bool = false,
22need_stdint: bool = false,
23error_msg: *Module.ErrorMsg = undefined,
24
25pub fn openPath(allocator: *Allocator, dir: fs.Dir, sub_path: []const u8, options: link.Options) !*File {
26 assert(options.object_format == .c);
27
28 const file = try dir.createFile(sub_path, .{ .truncate = true, .read = true, .mode = link.determineMode(options) });
29 errdefer file.close();
30
31 var c_file = try allocator.create(C);
32 errdefer allocator.destroy(c_file);
33
34 c_file.* = C{
35 .base = .{
36 .tag = .c,
37 .options = options,
38 .file = file,
39 .allocator = allocator,
40 },
41 .main = std.ArrayList(u8).init(allocator),
42 .header = std.ArrayList(u8).init(allocator),
43 .constants = std.ArrayList(u8).init(allocator),
44 .called = std.StringHashMap(void).init(allocator),
45 };
46
47 return &c_file.base;
48}
49
50pub fn fail(self: *C, src: usize, comptime format: []const u8, args: anytype) error{ AnalysisFail, OutOfMemory } {
51 self.error_msg = try Module.ErrorMsg.create(self.base.allocator, src, format, args);
52 return error.AnalysisFail;
53}
54
55pub fn deinit(self: *C) void {
56 self.main.deinit();
57 self.header.deinit();
58 self.constants.deinit();
59 self.called.deinit();
60}
61
62pub fn updateDecl(self: *C, module: *Module, decl: *Module.Decl) !void {
63 codegen.generate(self, decl) catch |err| {
64 if (err == error.AnalysisFail) {
65 try module.failed_decls.put(module.gpa, decl, self.error_msg);
66 }
67 return err;
68 };
69}
70
71pub fn flush(self: *C, module: *Module) !void {
72 const writer = self.base.file.?.writer();
73 try writer.writeAll(@embedFile("cbe.h"));
74 var includes = false;
75 if (self.need_stddef) {
76 try writer.writeAll("#include <stddef.h>\n");
77 includes = true;
78 }
79 if (self.need_stdint) {
80 try writer.writeAll("#include <stdint.h>\n");
81 includes = true;
82 }
83 if (includes) {
84 try writer.writeByte('\n');
85 }
86 if (self.header.items.len > 0) {
87 try writer.print("{}\n", .{self.header.items});
88 }
89 if (self.constants.items.len > 0) {
90 try writer.print("{}\n", .{self.constants.items});
91 }
92 if (self.main.items.len > 1) {
93 const last_two = self.main.items[self.main.items.len - 2 ..];
94 if (std.mem.eql(u8, last_two, "\n\n")) {
95 self.main.items.len -= 1;
96 }
97 }
98 try writer.writeAll(self.main.items);
99 self.base.file.?.close();
100 self.base.file = null;
101}
src-self-hosted/link/Elf.zig created+2583
...@@ -0,0 +1,2583 @@
1const std = @import("std");
2const mem = std.mem;
3const assert = std.debug.assert;
4const Allocator = std.mem.Allocator;
5const ir = @import("../ir.zig");
6const Module = @import("../Module.zig");
7const fs = std.fs;
8const elf = std.elf;
9const codegen = @import("../codegen.zig");
10const log = std.log.scoped(.link);
11const DW = std.dwarf;
12const trace = @import("../tracy.zig").trace;
13const leb128 = std.debug.leb;
14const Package = @import("../Package.zig");
15const Value = @import("../value.zig").Value;
16const Type = @import("../type.zig").Type;
17const build_options = @import("build_options");
18const link = @import("../link.zig");
19const File = link.File;
20const Elf = @This();
21
22const producer_string = if (std.builtin.is_test) "zig test" else "zig " ++ build_options.version;
23const default_entry_addr = 0x8000000;
24
25// TODO Turn back on zig fmt when https://github.com/ziglang/zig/issues/5948 is implemented.
26// zig fmt: off
27
28pub const base_tag: File.Tag = .elf;
29
30base: File,
31
32ptr_width: enum { p32, p64 },
33
34/// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write.
35/// Same order as in the file.
36sections: std.ArrayListUnmanaged(elf.Elf64_Shdr) = std.ArrayListUnmanaged(elf.Elf64_Shdr){},
37shdr_table_offset: ?u64 = null,
38
39/// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write.
40/// Same order as in the file.
41program_headers: std.ArrayListUnmanaged(elf.Elf64_Phdr) = std.ArrayListUnmanaged(elf.Elf64_Phdr){},
42phdr_table_offset: ?u64 = null,
43/// The index into the program headers of a PT_LOAD program header with Read and Execute flags
44phdr_load_re_index: ?u16 = null,
45/// The index into the program headers of the global offset table.
46/// It needs PT_LOAD and Read flags.
47phdr_got_index: ?u16 = null,
48entry_addr: ?u64 = null,
49
50debug_strtab: std.ArrayListUnmanaged(u8) = std.ArrayListUnmanaged(u8){},
51shstrtab: std.ArrayListUnmanaged(u8) = std.ArrayListUnmanaged(u8){},
52shstrtab_index: ?u16 = null,
53
54text_section_index: ?u16 = null,
55symtab_section_index: ?u16 = null,
56got_section_index: ?u16 = null,
57debug_info_section_index: ?u16 = null,
58debug_abbrev_section_index: ?u16 = null,
59debug_str_section_index: ?u16 = null,
60debug_aranges_section_index: ?u16 = null,
61debug_line_section_index: ?u16 = null,
62
63debug_abbrev_table_offset: ?u64 = null,
64
65/// The same order as in the file. ELF requires global symbols to all be after the
66/// local symbols, they cannot be mixed. So we must buffer all the global symbols and
67/// write them at the end. These are only the local symbols. The length of this array
68/// is the value used for sh_info in the .symtab section.
69local_symbols: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{},
70global_symbols: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{},
71
72local_symbol_free_list: std.ArrayListUnmanaged(u32) = .{},
73global_symbol_free_list: std.ArrayListUnmanaged(u32) = .{},
74offset_table_free_list: std.ArrayListUnmanaged(u32) = .{},
75
76/// Same order as in the file. The value is the absolute vaddr value.
77/// If the vaddr of the executable program header changes, the entire
78/// offset table needs to be rewritten.
79offset_table: std.ArrayListUnmanaged(u64) = .{},
80
81phdr_table_dirty: bool = false,
82shdr_table_dirty: bool = false,
83shstrtab_dirty: bool = false,
84debug_strtab_dirty: bool = false,
85offset_table_count_dirty: bool = false,
86debug_abbrev_section_dirty: bool = false,
87debug_aranges_section_dirty: bool = false,
88
89debug_info_header_dirty: bool = false,
90debug_line_header_dirty: bool = false,
91
92error_flags: File.ErrorFlags = File.ErrorFlags{},
93
94/// A list of text blocks that have surplus capacity. This list can have false
95/// positives, as functions grow and shrink over time, only sometimes being added
96/// or removed from the freelist.
97///
98/// A text block has surplus capacity when its overcapacity value is greater than
99/// minimum_text_block_size * alloc_num / alloc_den. That is, when it has so
100/// much extra capacity, that we could fit a small new symbol in it, itself with
101/// ideal_capacity or more.
102///
103/// Ideal capacity is defined by size * alloc_num / alloc_den.
104///
105/// Overcapacity is measured by actual_capacity - ideal_capacity. Note that
106/// overcapacity can be negative. A simple way to have negative overcapacity is to
107/// allocate a fresh text block, which will have ideal capacity, and then grow it
108/// by 1 byte. It will then have -1 overcapacity.
109text_block_free_list: std.ArrayListUnmanaged(*TextBlock) = .{},
110last_text_block: ?*TextBlock = null,
111
112/// A list of `SrcFn` whose Line Number Programs have surplus capacity.
113/// This is the same concept as `text_block_free_list`; see those doc comments.
114dbg_line_fn_free_list: std.AutoHashMapUnmanaged(*SrcFn, void) = .{},
115dbg_line_fn_first: ?*SrcFn = null,
116dbg_line_fn_last: ?*SrcFn = null,
117
118/// A list of `TextBlock` whose corresponding .debug_info tags have surplus capacity.
119/// This is the same concept as `text_block_free_list`; see those doc comments.
120dbg_info_decl_free_list: std.AutoHashMapUnmanaged(*TextBlock, void) = .{},
121dbg_info_decl_first: ?*TextBlock = null,
122dbg_info_decl_last: ?*TextBlock = null,
123
124/// `alloc_num / alloc_den` is the factor of padding when allocating.
125const alloc_num = 4;
126const alloc_den = 3;
127
128/// In order for a slice of bytes to be considered eligible to keep metadata pointing at
129/// it as a possible place to put new symbols, it must have enough room for this many bytes
130/// (plus extra for reserved capacity).
131const minimum_text_block_size = 64;
132const min_text_capacity = minimum_text_block_size * alloc_num / alloc_den;
133
134pub const TextBlock = struct {
135 /// Each decl always gets a local symbol with the fully qualified name.
136 /// The vaddr and size are found here directly.
137 /// The file offset is found by computing the vaddr offset from the section vaddr
138 /// the symbol references, and adding that to the file offset of the section.
139 /// If this field is 0, it means the codegen size = 0 and there is no symbol or
140 /// offset table entry.
141 local_sym_index: u32,
142 /// This field is undefined for symbols with size = 0.
143 offset_table_index: u32,
144 /// Points to the previous and next neighbors, based on the `text_offset`.
145 /// This can be used to find, for example, the capacity of this `TextBlock`.
146 prev: ?*TextBlock,
147 next: ?*TextBlock,
148
149 /// Previous/next linked list pointers. This value is `next ^ prev`.
150 /// This is the linked list node for this Decl's corresponding .debug_info tag.
151 dbg_info_prev: ?*TextBlock,
152 dbg_info_next: ?*TextBlock,
153 /// Offset into .debug_info pointing to the tag for this Decl.
154 dbg_info_off: u32,
155 /// Size of the .debug_info tag for this Decl, not including padding.
156 dbg_info_len: u32,
157
158 pub const empty = TextBlock{
159 .local_sym_index = 0,
160 .offset_table_index = undefined,
161 .prev = null,
162 .next = null,
163 .dbg_info_prev = null,
164 .dbg_info_next = null,
165 .dbg_info_off = undefined,
166 .dbg_info_len = undefined,
167 };
168
169 /// Returns how much room there is to grow in virtual address space.
170 /// File offset relocation happens transparently, so it is not included in
171 /// this calculation.
172 fn capacity(self: TextBlock, elf_file: Elf) u64 {
173 const self_sym = elf_file.local_symbols.items[self.local_sym_index];
174 if (self.next) |next| {
175 const next_sym = elf_file.local_symbols.items[next.local_sym_index];
176 return next_sym.st_value - self_sym.st_value;
177 } else {
178 // We are the last block. The capacity is limited only by virtual address space.
179 return std.math.maxInt(u32) - self_sym.st_value;
180 }
181 }
182
183 fn freeListEligible(self: TextBlock, elf_file: Elf) bool {
184 // No need to keep a free list node for the last block.
185 const next = self.next orelse return false;
186 const self_sym = elf_file.local_symbols.items[self.local_sym_index];
187 const next_sym = elf_file.local_symbols.items[next.local_sym_index];
188 const cap = next_sym.st_value - self_sym.st_value;
189 const ideal_cap = self_sym.st_size * alloc_num / alloc_den;
190 if (cap <= ideal_cap) return false;
191 const surplus = cap - ideal_cap;
192 return surplus >= min_text_capacity;
193 }
194};
195
196pub const Export = struct {
197 sym_index: ?u32 = null,
198};
199
200pub const SrcFn = struct {
201 /// Offset from the beginning of the Debug Line Program header that contains this function.
202 off: u32,
203 /// Size of the line number program component belonging to this function, not
204 /// including padding.
205 len: u32,
206
207 /// Points to the previous and next neighbors, based on the offset from .debug_line.
208 /// This can be used to find, for example, the capacity of this `SrcFn`.
209 prev: ?*SrcFn,
210 next: ?*SrcFn,
211
212 pub const empty: SrcFn = .{
213 .off = 0,
214 .len = 0,
215 .prev = null,
216 .next = null,
217 };
218};
219
220pub fn openPath(allocator: *Allocator, dir: fs.Dir, sub_path: []const u8, options: link.Options) !*File {
221 assert(options.object_format == .elf);
222
223 const file = try dir.createFile(sub_path, .{ .truncate = false, .read = true, .mode = link.determineMode(options) });
224 errdefer file.close();
225
226 var elf_file = try allocator.create(Elf);
227 errdefer allocator.destroy(elf_file);
228
229 elf_file.* = openFile(allocator, file, options) catch |err| switch (err) {
230 error.IncrFailed => try createFile(allocator, file, options),
231 else => |e| return e,
232 };
233
234 return &elf_file.base;
235}
236
237/// Returns error.IncrFailed if incremental update could not be performed.
238fn openFile(allocator: *Allocator, file: fs.File, options: link.Options) !Elf {
239 switch (options.output_mode) {
240 .Exe => {},
241 .Obj => {},
242 .Lib => return error.IncrFailed,
243 }
244 var self: Elf = .{
245 .base = .{
246 .file = file,
247 .tag = .elf,
248 .options = options,
249 .allocator = allocator,
250 },
251 .ptr_width = switch (options.target.cpu.arch.ptrBitWidth()) {
252 32 => .p32,
253 64 => .p64,
254 else => return error.UnsupportedELFArchitecture,
255 },
256 };
257 errdefer self.deinit();
258
259 // TODO implement reading the elf file
260 return error.IncrFailed;
261 //try self.populateMissingMetadata();
262 //return self;
263}
264
265/// Truncates the existing file contents and overwrites the contents.
266/// Returns an error if `file` is not already open with +read +write +seek abilities.
267fn createFile(allocator: *Allocator, file: fs.File, options: link.Options) !Elf {
268 switch (options.output_mode) {
269 .Exe => {},
270 .Obj => {},
271 .Lib => return error.TODOImplementWritingLibFiles,
272 }
273 var self: Elf = .{
274 .base = .{
275 .tag = .elf,
276 .options = options,
277 .allocator = allocator,
278 .file = file,
279 },
280 .ptr_width = switch (options.target.cpu.arch.ptrBitWidth()) {
281 32 => .p32,
282 64 => .p64,
283 else => return error.UnsupportedELFArchitecture,
284 },
285 .shdr_table_dirty = true,
286 };
287 errdefer self.deinit();
288
289 // Index 0 is always a null symbol.
290 try self.local_symbols.append(allocator, .{
291 .st_name = 0,
292 .st_info = 0,
293 .st_other = 0,
294 .st_shndx = 0,
295 .st_value = 0,
296 .st_size = 0,
297 });
298
299 // There must always be a null section in index 0
300 try self.sections.append(allocator, .{
301 .sh_name = 0,
302 .sh_type = elf.SHT_NULL,
303 .sh_flags = 0,
304 .sh_addr = 0,
305 .sh_offset = 0,
306 .sh_size = 0,
307 .sh_link = 0,
308 .sh_info = 0,
309 .sh_addralign = 0,
310 .sh_entsize = 0,
311 });
312
313 try self.populateMissingMetadata();
314
315 return self;
316}
317
318pub fn deinit(self: *Elf) void {
319 self.sections.deinit(self.base.allocator);
320 self.program_headers.deinit(self.base.allocator);
321 self.shstrtab.deinit(self.base.allocator);
322 self.debug_strtab.deinit(self.base.allocator);
323 self.local_symbols.deinit(self.base.allocator);
324 self.global_symbols.deinit(self.base.allocator);
325 self.global_symbol_free_list.deinit(self.base.allocator);
326 self.local_symbol_free_list.deinit(self.base.allocator);
327 self.offset_table_free_list.deinit(self.base.allocator);
328 self.text_block_free_list.deinit(self.base.allocator);
329 self.dbg_line_fn_free_list.deinit(self.base.allocator);
330 self.dbg_info_decl_free_list.deinit(self.base.allocator);
331 self.offset_table.deinit(self.base.allocator);
332}
333
334pub fn getDeclVAddr(self: *Elf, decl: *const Module.Decl) u64 {
335 assert(decl.link.elf.local_sym_index != 0);
336 return self.local_symbols.items[decl.link.elf.local_sym_index].st_value;
337}
338
339fn getDebugLineProgramOff(self: Elf) u32 {
340 return self.dbg_line_fn_first.?.off;
341}
342
343fn getDebugLineProgramEnd(self: Elf) u32 {
344 return self.dbg_line_fn_last.?.off + self.dbg_line_fn_last.?.len;
345}
346
347/// Returns end pos of collision, if any.
348fn detectAllocCollision(self: *Elf, start: u64, size: u64) ?u64 {
349 const small_ptr = self.base.options.target.cpu.arch.ptrBitWidth() == 32;
350 const ehdr_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Ehdr) else @sizeOf(elf.Elf64_Ehdr);
351 if (start < ehdr_size)
352 return ehdr_size;
353
354 const end = start + satMul(size, alloc_num) / alloc_den;
355
356 if (self.shdr_table_offset) |off| {
357 const shdr_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Shdr) else @sizeOf(elf.Elf64_Shdr);
358 const tight_size = self.sections.items.len * shdr_size;
359 const increased_size = satMul(tight_size, alloc_num) / alloc_den;
360 const test_end = off + increased_size;
361 if (end > off and start < test_end) {
362 return test_end;
363 }
364 }
365
366 if (self.phdr_table_offset) |off| {
367 const phdr_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Phdr) else @sizeOf(elf.Elf64_Phdr);
368 const tight_size = self.sections.items.len * phdr_size;
369 const increased_size = satMul(tight_size, alloc_num) / alloc_den;
370 const test_end = off + increased_size;
371 if (end > off and start < test_end) {
372 return test_end;
373 }
374 }
375
376 for (self.sections.items) |section| {
377 const increased_size = satMul(section.sh_size, alloc_num) / alloc_den;
378 const test_end = section.sh_offset + increased_size;
379 if (end > section.sh_offset and start < test_end) {
380 return test_end;
381 }
382 }
383 for (self.program_headers.items) |program_header| {
384 const increased_size = satMul(program_header.p_filesz, alloc_num) / alloc_den;
385 const test_end = program_header.p_offset + increased_size;
386 if (end > program_header.p_offset and start < test_end) {
387 return test_end;
388 }
389 }
390 return null;
391}
392
393fn allocatedSize(self: *Elf, start: u64) u64 {
394 if (start == 0)
395 return 0;
396 var min_pos: u64 = std.math.maxInt(u64);
397 if (self.shdr_table_offset) |off| {
398 if (off > start and off < min_pos) min_pos = off;
399 }
400 if (self.phdr_table_offset) |off| {
401 if (off > start and off < min_pos) min_pos = off;
402 }
403 for (self.sections.items) |section| {
404 if (section.sh_offset <= start) continue;
405 if (section.sh_offset < min_pos) min_pos = section.sh_offset;
406 }
407 for (self.program_headers.items) |program_header| {
408 if (program_header.p_offset <= start) continue;
409 if (program_header.p_offset < min_pos) min_pos = program_header.p_offset;
410 }
411 return min_pos - start;
412}
413
414fn findFreeSpace(self: *Elf, object_size: u64, min_alignment: u16) u64 {
415 var start: u64 = 0;
416 while (self.detectAllocCollision(start, object_size)) |item_end| {
417 start = mem.alignForwardGeneric(u64, item_end, min_alignment);
418 }
419 return start;
420}
421
422/// TODO Improve this to use a table.
423fn makeString(self: *Elf, bytes: []const u8) !u32 {
424 try self.shstrtab.ensureCapacity(self.base.allocator, self.shstrtab.items.len + bytes.len + 1);
425 const result = self.shstrtab.items.len;
426 self.shstrtab.appendSliceAssumeCapacity(bytes);
427 self.shstrtab.appendAssumeCapacity(0);
428 return @intCast(u32, result);
429}
430
431/// TODO Improve this to use a table.
432fn makeDebugString(self: *Elf, bytes: []const u8) !u32 {
433 try self.debug_strtab.ensureCapacity(self.base.allocator, self.debug_strtab.items.len + bytes.len + 1);
434 const result = self.debug_strtab.items.len;
435 self.debug_strtab.appendSliceAssumeCapacity(bytes);
436 self.debug_strtab.appendAssumeCapacity(0);
437 return @intCast(u32, result);
438}
439
440fn getString(self: *Elf, str_off: u32) []const u8 {
441 assert(str_off < self.shstrtab.items.len);
442 return mem.spanZ(@ptrCast([*:0]const u8, self.shstrtab.items.ptr + str_off));
443}
444
445fn updateString(self: *Elf, old_str_off: u32, new_name: []const u8) !u32 {
446 const existing_name = self.getString(old_str_off);
447 if (mem.eql(u8, existing_name, new_name)) {
448 return old_str_off;
449 }
450 return self.makeString(new_name);
451}
452
453pub fn populateMissingMetadata(self: *Elf) !void {
454 const small_ptr = switch (self.ptr_width) {
455 .p32 => true,
456 .p64 => false,
457 };
458 const ptr_size: u8 = self.ptrWidthBytes();
459 if (self.phdr_load_re_index == null) {
460 self.phdr_load_re_index = @intCast(u16, self.program_headers.items.len);
461 const file_size = self.base.options.program_code_size_hint;
462 const p_align = 0x1000;
463 const off = self.findFreeSpace(file_size, p_align);
464 log.debug("found PT_LOAD free space 0x{x} to 0x{x}\n", .{ off, off + file_size });
465 try self.program_headers.append(self.base.allocator, .{
466 .p_type = elf.PT_LOAD,
467 .p_offset = off,
468 .p_filesz = file_size,
469 .p_vaddr = default_entry_addr,
470 .p_paddr = default_entry_addr,
471 .p_memsz = file_size,
472 .p_align = p_align,
473 .p_flags = elf.PF_X | elf.PF_R,
474 });
475 self.entry_addr = null;
476 self.phdr_table_dirty = true;
477 }
478 if (self.phdr_got_index == null) {
479 self.phdr_got_index = @intCast(u16, self.program_headers.items.len);
480 const file_size = @as(u64, ptr_size) * self.base.options.symbol_count_hint;
481 // We really only need ptr alignment but since we are using PROGBITS, linux requires
482 // page align.
483 const p_align = if (self.base.options.target.os.tag == .linux) 0x1000 else @as(u16, ptr_size);
484 const off = self.findFreeSpace(file_size, p_align);
485 log.debug("found PT_LOAD free space 0x{x} to 0x{x}\n", .{ off, off + file_size });
486 // TODO instead of hard coding the vaddr, make a function to find a vaddr to put things at.
487 // we'll need to re-use that function anyway, in case the GOT grows and overlaps something
488 // else in virtual memory.
489 const default_got_addr = if (ptr_size == 2) @as(u32, 0x8000) else 0x4000000;
490 try self.program_headers.append(self.base.allocator, .{
491 .p_type = elf.PT_LOAD,
492 .p_offset = off,
493 .p_filesz = file_size,
494 .p_vaddr = default_got_addr,
495 .p_paddr = default_got_addr,
496 .p_memsz = file_size,
497 .p_align = p_align,
498 .p_flags = elf.PF_R,
499 });
500 self.phdr_table_dirty = true;
501 }
502 if (self.shstrtab_index == null) {
503 self.shstrtab_index = @intCast(u16, self.sections.items.len);
504 assert(self.shstrtab.items.len == 0);
505 try self.shstrtab.append(self.base.allocator, 0); // need a 0 at position 0
506 const off = self.findFreeSpace(self.shstrtab.items.len, 1);
507 log.debug("found shstrtab free space 0x{x} to 0x{x}\n", .{ off, off + self.shstrtab.items.len });
508 try self.sections.append(self.base.allocator, .{
509 .sh_name = try self.makeString(".shstrtab"),
510 .sh_type = elf.SHT_STRTAB,
511 .sh_flags = 0,
512 .sh_addr = 0,
513 .sh_offset = off,
514 .sh_size = self.shstrtab.items.len,
515 .sh_link = 0,
516 .sh_info = 0,
517 .sh_addralign = 1,
518 .sh_entsize = 0,
519 });
520 self.shstrtab_dirty = true;
521 self.shdr_table_dirty = true;
522 }
523 if (self.text_section_index == null) {
524 self.text_section_index = @intCast(u16, self.sections.items.len);
525 const phdr = &self.program_headers.items[self.phdr_load_re_index.?];
526
527 try self.sections.append(self.base.allocator, .{
528 .sh_name = try self.makeString(".text"),
529 .sh_type = elf.SHT_PROGBITS,
530 .sh_flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR,
531 .sh_addr = phdr.p_vaddr,
532 .sh_offset = phdr.p_offset,
533 .sh_size = phdr.p_filesz,
534 .sh_link = 0,
535 .sh_info = 0,
536 .sh_addralign = phdr.p_align,
537 .sh_entsize = 0,
538 });
539 self.shdr_table_dirty = true;
540 }
541 if (self.got_section_index == null) {
542 self.got_section_index = @intCast(u16, self.sections.items.len);
543 const phdr = &self.program_headers.items[self.phdr_got_index.?];
544
545 try self.sections.append(self.base.allocator, .{
546 .sh_name = try self.makeString(".got"),
547 .sh_type = elf.SHT_PROGBITS,
548 .sh_flags = elf.SHF_ALLOC,
549 .sh_addr = phdr.p_vaddr,
550 .sh_offset = phdr.p_offset,
551 .sh_size = phdr.p_filesz,
552 .sh_link = 0,
553 .sh_info = 0,
554 .sh_addralign = phdr.p_align,
555 .sh_entsize = 0,
556 });
557 self.shdr_table_dirty = true;
558 }
559 if (self.symtab_section_index == null) {
560 self.symtab_section_index = @intCast(u16, self.sections.items.len);
561 const min_align: u16 = if (small_ptr) @alignOf(elf.Elf32_Sym) else @alignOf(elf.Elf64_Sym);
562 const each_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Sym) else @sizeOf(elf.Elf64_Sym);
563 const file_size = self.base.options.symbol_count_hint * each_size;
564 const off = self.findFreeSpace(file_size, min_align);
565 log.debug("found symtab free space 0x{x} to 0x{x}\n", .{ off, off + file_size });
566
567 try self.sections.append(self.base.allocator, .{
568 .sh_name = try self.makeString(".symtab"),
569 .sh_type = elf.SHT_SYMTAB,
570 .sh_flags = 0,
571 .sh_addr = 0,
572 .sh_offset = off,
573 .sh_size = file_size,
574 // The section header index of the associated string table.
575 .sh_link = self.shstrtab_index.?,
576 .sh_info = @intCast(u32, self.local_symbols.items.len),
577 .sh_addralign = min_align,
578 .sh_entsize = each_size,
579 });
580 self.shdr_table_dirty = true;
581 try self.writeSymbol(0);
582 }
583 if (self.debug_str_section_index == null) {
584 self.debug_str_section_index = @intCast(u16, self.sections.items.len);
585 assert(self.debug_strtab.items.len == 0);
586 try self.sections.append(self.base.allocator, .{
587 .sh_name = try self.makeString(".debug_str"),
588 .sh_type = elf.SHT_PROGBITS,
589 .sh_flags = elf.SHF_MERGE | elf.SHF_STRINGS,
590 .sh_addr = 0,
591 .sh_offset = 0,
592 .sh_size = self.debug_strtab.items.len,
593 .sh_link = 0,
594 .sh_info = 0,
595 .sh_addralign = 1,
596 .sh_entsize = 1,
597 });
598 self.debug_strtab_dirty = true;
599 self.shdr_table_dirty = true;
600 }
601 if (self.debug_info_section_index == null) {
602 self.debug_info_section_index = @intCast(u16, self.sections.items.len);
603
604 const file_size_hint = 200;
605 const p_align = 1;
606 const off = self.findFreeSpace(file_size_hint, p_align);
607 log.debug("found .debug_info free space 0x{x} to 0x{x}\n", .{
608 off,
609 off + file_size_hint,
610 });
611 try self.sections.append(self.base.allocator, .{
612 .sh_name = try self.makeString(".debug_info"),
613 .sh_type = elf.SHT_PROGBITS,
614 .sh_flags = 0,
615 .sh_addr = 0,
616 .sh_offset = off,
617 .sh_size = file_size_hint,
618 .sh_link = 0,
619 .sh_info = 0,
620 .sh_addralign = p_align,
621 .sh_entsize = 0,
622 });
623 self.shdr_table_dirty = true;
624 self.debug_info_header_dirty = true;
625 }
626 if (self.debug_abbrev_section_index == null) {
627 self.debug_abbrev_section_index = @intCast(u16, self.sections.items.len);
628
629 const file_size_hint = 128;
630 const p_align = 1;
631 const off = self.findFreeSpace(file_size_hint, p_align);
632 log.debug("found .debug_abbrev free space 0x{x} to 0x{x}\n", .{
633 off,
634 off + file_size_hint,
635 });
636 try self.sections.append(self.base.allocator, .{
637 .sh_name = try self.makeString(".debug_abbrev"),
638 .sh_type = elf.SHT_PROGBITS,
639 .sh_flags = 0,
640 .sh_addr = 0,
641 .sh_offset = off,
642 .sh_size = file_size_hint,
643 .sh_link = 0,
644 .sh_info = 0,
645 .sh_addralign = p_align,
646 .sh_entsize = 0,
647 });
648 self.shdr_table_dirty = true;
649 self.debug_abbrev_section_dirty = true;
650 }
651 if (self.debug_aranges_section_index == null) {
652 self.debug_aranges_section_index = @intCast(u16, self.sections.items.len);
653
654 const file_size_hint = 160;
655 const p_align = 16;
656 const off = self.findFreeSpace(file_size_hint, p_align);
657 log.debug("found .debug_aranges free space 0x{x} to 0x{x}\n", .{
658 off,
659 off + file_size_hint,
660 });
661 try self.sections.append(self.base.allocator, .{
662 .sh_name = try self.makeString(".debug_aranges"),
663 .sh_type = elf.SHT_PROGBITS,
664 .sh_flags = 0,
665 .sh_addr = 0,
666 .sh_offset = off,
667 .sh_size = file_size_hint,
668 .sh_link = 0,
669 .sh_info = 0,
670 .sh_addralign = p_align,
671 .sh_entsize = 0,
672 });
673 self.shdr_table_dirty = true;
674 self.debug_aranges_section_dirty = true;
675 }
676 if (self.debug_line_section_index == null) {
677 self.debug_line_section_index = @intCast(u16, self.sections.items.len);
678
679 const file_size_hint = 250;
680 const p_align = 1;
681 const off = self.findFreeSpace(file_size_hint, p_align);
682 log.debug("found .debug_line free space 0x{x} to 0x{x}\n", .{
683 off,
684 off + file_size_hint,
685 });
686 try self.sections.append(self.base.allocator, .{
687 .sh_name = try self.makeString(".debug_line"),
688 .sh_type = elf.SHT_PROGBITS,
689 .sh_flags = 0,
690 .sh_addr = 0,
691 .sh_offset = off,
692 .sh_size = file_size_hint,
693 .sh_link = 0,
694 .sh_info = 0,
695 .sh_addralign = p_align,
696 .sh_entsize = 0,
697 });
698 self.shdr_table_dirty = true;
699 self.debug_line_header_dirty = true;
700 }
701 const shsize: u64 = switch (self.ptr_width) {
702 .p32 => @sizeOf(elf.Elf32_Shdr),
703 .p64 => @sizeOf(elf.Elf64_Shdr),
704 };
705 const shalign: u16 = switch (self.ptr_width) {
706 .p32 => @alignOf(elf.Elf32_Shdr),
707 .p64 => @alignOf(elf.Elf64_Shdr),
708 };
709 if (self.shdr_table_offset == null) {
710 self.shdr_table_offset = self.findFreeSpace(self.sections.items.len * shsize, shalign);
711 self.shdr_table_dirty = true;
712 }
713 const phsize: u64 = switch (self.ptr_width) {
714 .p32 => @sizeOf(elf.Elf32_Phdr),
715 .p64 => @sizeOf(elf.Elf64_Phdr),
716 };
717 const phalign: u16 = switch (self.ptr_width) {
718 .p32 => @alignOf(elf.Elf32_Phdr),
719 .p64 => @alignOf(elf.Elf64_Phdr),
720 };
721 if (self.phdr_table_offset == null) {
722 self.phdr_table_offset = self.findFreeSpace(self.program_headers.items.len * phsize, phalign);
723 self.phdr_table_dirty = true;
724 }
725 {
726 // Iterate over symbols, populating free_list and last_text_block.
727 if (self.local_symbols.items.len != 1) {
728 @panic("TODO implement setting up free_list and last_text_block from existing ELF file");
729 }
730 // We are starting with an empty file. The default values are correct, null and empty list.
731 }
732}
733
734pub const abbrev_compile_unit = 1;
735pub const abbrev_subprogram = 2;
736pub const abbrev_subprogram_retvoid = 3;
737pub const abbrev_base_type = 4;
738pub const abbrev_pad1 = 5;
739pub const abbrev_parameter = 6;
740
741/// Commit pending changes and write headers.
742pub fn flush(self: *Elf, module: *Module) !void {
743 const target_endian = self.base.options.target.cpu.arch.endian();
744 const foreign_endian = target_endian != std.Target.current.cpu.arch.endian();
745 const ptr_width_bytes: u8 = self.ptrWidthBytes();
746 const init_len_size: usize = switch (self.ptr_width) {
747 .p32 => 4,
748 .p64 => 12,
749 };
750
751 // Unfortunately these have to be buffered and done at the end because ELF does not allow
752 // mixing local and global symbols within a symbol table.
753 try self.writeAllGlobalSymbols();
754
755 if (self.debug_abbrev_section_dirty) {
756 const debug_abbrev_sect = &self.sections.items[self.debug_abbrev_section_index.?];
757
758 // These are LEB encoded but since the values are all less than 127
759 // we can simply append these bytes.
760 const abbrev_buf = [_]u8{
761 abbrev_compile_unit, DW.TAG_compile_unit, DW.CHILDREN_yes, // header
762 DW.AT_stmt_list, DW.FORM_sec_offset, DW.AT_low_pc,
763 DW.FORM_addr, DW.AT_high_pc, DW.FORM_addr,
764 DW.AT_name, DW.FORM_strp, DW.AT_comp_dir,
765 DW.FORM_strp, DW.AT_producer, DW.FORM_strp,
766 DW.AT_language, DW.FORM_data2, 0,
767 0, // table sentinel
768 abbrev_subprogram, DW.TAG_subprogram,
769 DW.CHILDREN_yes, // header
770 DW.AT_low_pc, DW.FORM_addr,
771 DW.AT_high_pc, DW.FORM_data4, DW.AT_type,
772 DW.FORM_ref4, DW.AT_name, DW.FORM_string,
773 0, 0, // table sentinel
774 abbrev_subprogram_retvoid,
775 DW.TAG_subprogram, DW.CHILDREN_yes, // header
776 DW.AT_low_pc,
777 DW.FORM_addr, DW.AT_high_pc, DW.FORM_data4,
778 DW.AT_name, DW.FORM_string, 0,
779 0, // table sentinel
780 abbrev_base_type, DW.TAG_base_type,
781 DW.CHILDREN_no, // header
782 DW.AT_encoding, DW.FORM_data1,
783 DW.AT_byte_size, DW.FORM_data1, DW.AT_name,
784 DW.FORM_string, 0, 0, // table sentinel
785
786 abbrev_pad1, DW.TAG_unspecified_type, DW.CHILDREN_no, // header
787 0, 0, // table sentinel
788 abbrev_parameter,
789 DW.TAG_formal_parameter, DW.CHILDREN_no, // header
790 DW.AT_location,
791 DW.FORM_exprloc, DW.AT_type, DW.FORM_ref4,
792 DW.AT_name, DW.FORM_string, 0,
793 0, // table sentinel
794 0, 0,
795 0, // section sentinel
796 };
797
798 const needed_size = abbrev_buf.len;
799 const allocated_size = self.allocatedSize(debug_abbrev_sect.sh_offset);
800 if (needed_size > allocated_size) {
801 debug_abbrev_sect.sh_size = 0; // free the space
802 debug_abbrev_sect.sh_offset = self.findFreeSpace(needed_size, 1);
803 }
804 debug_abbrev_sect.sh_size = needed_size;
805 log.debug(".debug_abbrev start=0x{x} end=0x{x}\n", .{
806 debug_abbrev_sect.sh_offset,
807 debug_abbrev_sect.sh_offset + needed_size,
808 });
809
810 const abbrev_offset = 0;
811 self.debug_abbrev_table_offset = abbrev_offset;
812 try self.base.file.?.pwriteAll(&abbrev_buf, debug_abbrev_sect.sh_offset + abbrev_offset);
813 if (!self.shdr_table_dirty) {
814 // Then it won't get written with the others and we need to do it.
815 try self.writeSectHeader(self.debug_abbrev_section_index.?);
816 }
817
818 self.debug_abbrev_section_dirty = false;
819 }
820
821 if (self.debug_info_header_dirty) debug_info: {
822 // If this value is null it means there is an error in the module;
823 // leave debug_info_header_dirty=true.
824 const first_dbg_info_decl = self.dbg_info_decl_first orelse break :debug_info;
825 const last_dbg_info_decl = self.dbg_info_decl_last.?;
826 const debug_info_sect = &self.sections.items[self.debug_info_section_index.?];
827
828 var di_buf = std.ArrayList(u8).init(self.base.allocator);
829 defer di_buf.deinit();
830
831 // We have a function to compute the upper bound size, because it's needed
832 // for determining where to put the offset of the first `LinkBlock`.
833 try di_buf.ensureCapacity(self.dbgInfoNeededHeaderBytes());
834
835 // initial length - length of the .debug_info contribution for this compilation unit,
836 // not including the initial length itself.
837 // We have to come back and write it later after we know the size.
838 const after_init_len = di_buf.items.len + init_len_size;
839 // +1 for the final 0 that ends the compilation unit children.
840 const dbg_info_end = last_dbg_info_decl.dbg_info_off + last_dbg_info_decl.dbg_info_len + 1;
841 const init_len = dbg_info_end - after_init_len;
842 switch (self.ptr_width) {
843 .p32 => {
844 mem.writeInt(u32, di_buf.addManyAsArrayAssumeCapacity(4), @intCast(u32, init_len), target_endian);
845 },
846 .p64 => {
847 di_buf.appendNTimesAssumeCapacity(0xff, 4);
848 mem.writeInt(u64, di_buf.addManyAsArrayAssumeCapacity(8), init_len, target_endian);
849 },
850 }
851 mem.writeInt(u16, di_buf.addManyAsArrayAssumeCapacity(2), 4, target_endian); // DWARF version
852 const abbrev_offset = self.debug_abbrev_table_offset.?;
853 switch (self.ptr_width) {
854 .p32 => {
855 mem.writeInt(u32, di_buf.addManyAsArrayAssumeCapacity(4), @intCast(u32, abbrev_offset), target_endian);
856 di_buf.appendAssumeCapacity(4); // address size
857 },
858 .p64 => {
859 mem.writeInt(u64, di_buf.addManyAsArrayAssumeCapacity(8), abbrev_offset, target_endian);
860 di_buf.appendAssumeCapacity(8); // address size
861 },
862 }
863 // Write the form for the compile unit, which must match the abbrev table above.
864 const name_strp = try self.makeDebugString(self.base.options.root_pkg.root_src_path);
865 const comp_dir_strp = try self.makeDebugString(self.base.options.root_pkg.root_src_dir_path);
866 const producer_strp = try self.makeDebugString(producer_string);
867 // Currently only one compilation unit is supported, so the address range is simply
868 // identical to the main program header virtual address and memory size.
869 const text_phdr = &self.program_headers.items[self.phdr_load_re_index.?];
870 const low_pc = text_phdr.p_vaddr;
871 const high_pc = text_phdr.p_vaddr + text_phdr.p_memsz;
872
873 di_buf.appendAssumeCapacity(abbrev_compile_unit);
874 self.writeDwarfAddrAssumeCapacity(&di_buf, 0); // DW.AT_stmt_list, DW.FORM_sec_offset
875 self.writeDwarfAddrAssumeCapacity(&di_buf, low_pc);
876 self.writeDwarfAddrAssumeCapacity(&di_buf, high_pc);
877 self.writeDwarfAddrAssumeCapacity(&di_buf, name_strp);
878 self.writeDwarfAddrAssumeCapacity(&di_buf, comp_dir_strp);
879 self.writeDwarfAddrAssumeCapacity(&di_buf, producer_strp);
880 // We are still waiting on dwarf-std.org to assign DW_LANG_Zig a number:
881 // http://dwarfstd.org/ShowIssue.php?issue=171115.1
882 // Until then we say it is C99.
883 mem.writeInt(u16, di_buf.addManyAsArrayAssumeCapacity(2), DW.LANG_C99, target_endian);
884
885 if (di_buf.items.len > first_dbg_info_decl.dbg_info_off) {
886 // Move the first N decls to the end to make more padding for the header.
887 @panic("TODO: handle .debug_info header exceeding its padding");
888 }
889 const jmp_amt = first_dbg_info_decl.dbg_info_off - di_buf.items.len;
890 try self.pwriteDbgInfoNops(0, di_buf.items, jmp_amt, false, debug_info_sect.sh_offset);
891 self.debug_info_header_dirty = false;
892 }
893
894 if (self.debug_aranges_section_dirty) {
895 const debug_aranges_sect = &self.sections.items[self.debug_aranges_section_index.?];
896
897 var di_buf = std.ArrayList(u8).init(self.base.allocator);
898 defer di_buf.deinit();
899
900 // Enough for all the data without resizing. When support for more compilation units
901 // is added, the size of this section will become more variable.
902 try di_buf.ensureCapacity(100);
903
904 // initial length - length of the .debug_aranges contribution for this compilation unit,
905 // not including the initial length itself.
906 // We have to come back and write it later after we know the size.
907 const init_len_index = di_buf.items.len;
908 di_buf.items.len += init_len_size;
909 const after_init_len = di_buf.items.len;
910 mem.writeInt(u16, di_buf.addManyAsArrayAssumeCapacity(2), 2, target_endian); // version
911 // When more than one compilation unit is supported, this will be the offset to it.
912 // For now it is always at offset 0 in .debug_info.
913 self.writeDwarfAddrAssumeCapacity(&di_buf, 0); // .debug_info offset
914 di_buf.appendAssumeCapacity(ptr_width_bytes); // address_size
915 di_buf.appendAssumeCapacity(0); // segment_selector_size
916
917 const end_header_offset = di_buf.items.len;
918 const begin_entries_offset = mem.alignForward(end_header_offset, ptr_width_bytes * 2);
919 di_buf.appendNTimesAssumeCapacity(0, begin_entries_offset - end_header_offset);
920
921 // Currently only one compilation unit is supported, so the address range is simply
922 // identical to the main program header virtual address and memory size.
923 const text_phdr = &self.program_headers.items[self.phdr_load_re_index.?];
924 self.writeDwarfAddrAssumeCapacity(&di_buf, text_phdr.p_vaddr);
925 self.writeDwarfAddrAssumeCapacity(&di_buf, text_phdr.p_memsz);
926
927 // Sentinel.
928 self.writeDwarfAddrAssumeCapacity(&di_buf, 0);
929 self.writeDwarfAddrAssumeCapacity(&di_buf, 0);
930
931 // Go back and populate the initial length.
932 const init_len = di_buf.items.len - after_init_len;
933 switch (self.ptr_width) {
934 .p32 => {
935 mem.writeInt(u32, di_buf.items[init_len_index..][0..4], @intCast(u32, init_len), target_endian);
936 },
937 .p64 => {
938 // initial length - length of the .debug_aranges contribution for this compilation unit,
939 // not including the initial length itself.
940 di_buf.items[init_len_index..][0..4].* = [_]u8{ 0xff, 0xff, 0xff, 0xff };
941 mem.writeInt(u64, di_buf.items[init_len_index + 4 ..][0..8], init_len, target_endian);
942 },
943 }
944
945 const needed_size = di_buf.items.len;
946 const allocated_size = self.allocatedSize(debug_aranges_sect.sh_offset);
947 if (needed_size > allocated_size) {
948 debug_aranges_sect.sh_size = 0; // free the space
949 debug_aranges_sect.sh_offset = self.findFreeSpace(needed_size, 16);
950 }
951 debug_aranges_sect.sh_size = needed_size;
952 log.debug(".debug_aranges start=0x{x} end=0x{x}\n", .{
953 debug_aranges_sect.sh_offset,
954 debug_aranges_sect.sh_offset + needed_size,
955 });
956
957 try self.base.file.?.pwriteAll(di_buf.items, debug_aranges_sect.sh_offset);
958 if (!self.shdr_table_dirty) {
959 // Then it won't get written with the others and we need to do it.
960 try self.writeSectHeader(self.debug_aranges_section_index.?);
961 }
962
963 self.debug_aranges_section_dirty = false;
964 }
965 if (self.debug_line_header_dirty) debug_line: {
966 if (self.dbg_line_fn_first == null) {
967 break :debug_line; // Error in module; leave debug_line_header_dirty=true.
968 }
969 const dbg_line_prg_off = self.getDebugLineProgramOff();
970 const dbg_line_prg_end = self.getDebugLineProgramEnd();
971 assert(dbg_line_prg_end != 0);
972
973 const debug_line_sect = &self.sections.items[self.debug_line_section_index.?];
974
975 var di_buf = std.ArrayList(u8).init(self.base.allocator);
976 defer di_buf.deinit();
977
978 // The size of this header is variable, depending on the number of directories,
979 // files, and padding. We have a function to compute the upper bound size, however,
980 // because it's needed for determining where to put the offset of the first `SrcFn`.
981 try di_buf.ensureCapacity(self.dbgLineNeededHeaderBytes());
982
983 // initial length - length of the .debug_line contribution for this compilation unit,
984 // not including the initial length itself.
985 const after_init_len = di_buf.items.len + init_len_size;
986 const init_len = dbg_line_prg_end - after_init_len;
987 switch (self.ptr_width) {
988 .p32 => {
989 mem.writeInt(u32, di_buf.addManyAsArrayAssumeCapacity(4), @intCast(u32, init_len), target_endian);
990 },
991 .p64 => {
992 di_buf.appendNTimesAssumeCapacity(0xff, 4);
993 mem.writeInt(u64, di_buf.addManyAsArrayAssumeCapacity(8), init_len, target_endian);
994 },
995 }
996
997 mem.writeInt(u16, di_buf.addManyAsArrayAssumeCapacity(2), 4, target_endian); // version
998
999 // Empirically, debug info consumers do not respect this field, or otherwise
1000 // consider it to be an error when it does not point exactly to the end of the header.
1001 // Therefore we rely on the NOP jump at the beginning of the Line Number Program for
1002 // padding rather than this field.
1003 const before_header_len = di_buf.items.len;
1004 di_buf.items.len += ptr_width_bytes; // We will come back and write this.
1005 const after_header_len = di_buf.items.len;
1006
1007 const opcode_base = DW.LNS_set_isa + 1;
1008 di_buf.appendSliceAssumeCapacity(&[_]u8{
1009 1, // minimum_instruction_length
1010 1, // maximum_operations_per_instruction
1011 1, // default_is_stmt
1012 1, // line_base (signed)
1013 1, // line_range
1014 opcode_base,
1015
1016 // Standard opcode lengths. The number of items here is based on `opcode_base`.
1017 // The value is the number of LEB128 operands the instruction takes.
1018 0, // `DW.LNS_copy`
1019 1, // `DW.LNS_advance_pc`
1020 1, // `DW.LNS_advance_line`
1021 1, // `DW.LNS_set_file`
1022 1, // `DW.LNS_set_column`
1023 0, // `DW.LNS_negate_stmt`
1024 0, // `DW.LNS_set_basic_block`
1025 0, // `DW.LNS_const_add_pc`
1026 1, // `DW.LNS_fixed_advance_pc`
1027 0, // `DW.LNS_set_prologue_end`
1028 0, // `DW.LNS_set_epilogue_begin`
1029 1, // `DW.LNS_set_isa`
1030
1031 0, // include_directories (none except the compilation unit cwd)
1032 });
1033 // file_names[0]
1034 di_buf.appendSliceAssumeCapacity(self.base.options.root_pkg.root_src_path); // relative path name
1035 di_buf.appendSliceAssumeCapacity(&[_]u8{
1036 0, // null byte for the relative path name
1037 0, // directory_index
1038 0, // mtime (TODO supply this)
1039 0, // file size bytes (TODO supply this)
1040 0, // file_names sentinel
1041 });
1042
1043 const header_len = di_buf.items.len - after_header_len;
1044 switch (self.ptr_width) {
1045 .p32 => {
1046 mem.writeInt(u32, di_buf.items[before_header_len..][0..4], @intCast(u32, header_len), target_endian);
1047 },
1048 .p64 => {
1049 mem.writeInt(u64, di_buf.items[before_header_len..][0..8], header_len, target_endian);
1050 },
1051 }
1052
1053 // We use NOPs because consumers empirically do not respect the header length field.
1054 if (di_buf.items.len > dbg_line_prg_off) {
1055 // Move the first N files to the end to make more padding for the header.
1056 @panic("TODO: handle .debug_line header exceeding its padding");
1057 }
1058 const jmp_amt = dbg_line_prg_off - di_buf.items.len;
1059 try self.pwriteDbgLineNops(0, di_buf.items, jmp_amt, debug_line_sect.sh_offset);
1060 self.debug_line_header_dirty = false;
1061 }
1062
1063 if (self.phdr_table_dirty) {
1064 const phsize: u64 = switch (self.ptr_width) {
1065 .p32 => @sizeOf(elf.Elf32_Phdr),
1066 .p64 => @sizeOf(elf.Elf64_Phdr),
1067 };
1068 const phalign: u16 = switch (self.ptr_width) {
1069 .p32 => @alignOf(elf.Elf32_Phdr),
1070 .p64 => @alignOf(elf.Elf64_Phdr),
1071 };
1072 const allocated_size = self.allocatedSize(self.phdr_table_offset.?);
1073 const needed_size = self.program_headers.items.len * phsize;
1074
1075 if (needed_size > allocated_size) {
1076 self.phdr_table_offset = null; // free the space
1077 self.phdr_table_offset = self.findFreeSpace(needed_size, phalign);
1078 }
1079
1080 switch (self.ptr_width) {
1081 .p32 => {
1082 const buf = try self.base.allocator.alloc(elf.Elf32_Phdr, self.program_headers.items.len);
1083 defer self.base.allocator.free(buf);
1084
1085 for (buf) |*phdr, i| {
1086 phdr.* = progHeaderTo32(self.program_headers.items[i]);
1087 if (foreign_endian) {
1088 bswapAllFields(elf.Elf32_Phdr, phdr);
1089 }
1090 }
1091 try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), self.phdr_table_offset.?);
1092 },
1093 .p64 => {
1094 const buf = try self.base.allocator.alloc(elf.Elf64_Phdr, self.program_headers.items.len);
1095 defer self.base.allocator.free(buf);
1096
1097 for (buf) |*phdr, i| {
1098 phdr.* = self.program_headers.items[i];
1099 if (foreign_endian) {
1100 bswapAllFields(elf.Elf64_Phdr, phdr);
1101 }
1102 }
1103 try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), self.phdr_table_offset.?);
1104 },
1105 }
1106 self.phdr_table_dirty = false;
1107 }
1108
1109 {
1110 const shstrtab_sect = &self.sections.items[self.shstrtab_index.?];
1111 if (self.shstrtab_dirty or self.shstrtab.items.len != shstrtab_sect.sh_size) {
1112 const allocated_size = self.allocatedSize(shstrtab_sect.sh_offset);
1113 const needed_size = self.shstrtab.items.len;
1114
1115 if (needed_size > allocated_size) {
1116 shstrtab_sect.sh_size = 0; // free the space
1117 shstrtab_sect.sh_offset = self.findFreeSpace(needed_size, 1);
1118 }
1119 shstrtab_sect.sh_size = needed_size;
1120 log.debug("writing shstrtab start=0x{x} end=0x{x}\n", .{ shstrtab_sect.sh_offset, shstrtab_sect.sh_offset + needed_size });
1121
1122 try self.base.file.?.pwriteAll(self.shstrtab.items, shstrtab_sect.sh_offset);
1123 if (!self.shdr_table_dirty) {
1124 // Then it won't get written with the others and we need to do it.
1125 try self.writeSectHeader(self.shstrtab_index.?);
1126 }
1127 self.shstrtab_dirty = false;
1128 }
1129 }
1130 {
1131 const debug_strtab_sect = &self.sections.items[self.debug_str_section_index.?];
1132 if (self.debug_strtab_dirty or self.debug_strtab.items.len != debug_strtab_sect.sh_size) {
1133 const allocated_size = self.allocatedSize(debug_strtab_sect.sh_offset);
1134 const needed_size = self.debug_strtab.items.len;
1135
1136 if (needed_size > allocated_size) {
1137 debug_strtab_sect.sh_size = 0; // free the space
1138 debug_strtab_sect.sh_offset = self.findFreeSpace(needed_size, 1);
1139 }
1140 debug_strtab_sect.sh_size = needed_size;
1141 log.debug("debug_strtab start=0x{x} end=0x{x}\n", .{ debug_strtab_sect.sh_offset, debug_strtab_sect.sh_offset + needed_size });
1142
1143 try self.base.file.?.pwriteAll(self.debug_strtab.items, debug_strtab_sect.sh_offset);
1144 if (!self.shdr_table_dirty) {
1145 // Then it won't get written with the others and we need to do it.
1146 try self.writeSectHeader(self.debug_str_section_index.?);
1147 }
1148 self.debug_strtab_dirty = false;
1149 }
1150 }
1151 if (self.shdr_table_dirty) {
1152 const shsize: u64 = switch (self.ptr_width) {
1153 .p32 => @sizeOf(elf.Elf32_Shdr),
1154 .p64 => @sizeOf(elf.Elf64_Shdr),
1155 };
1156 const shalign: u16 = switch (self.ptr_width) {
1157 .p32 => @alignOf(elf.Elf32_Shdr),
1158 .p64 => @alignOf(elf.Elf64_Shdr),
1159 };
1160 const allocated_size = self.allocatedSize(self.shdr_table_offset.?);
1161 const needed_size = self.sections.items.len * shsize;
1162
1163 if (needed_size > allocated_size) {
1164 self.shdr_table_offset = null; // free the space
1165 self.shdr_table_offset = self.findFreeSpace(needed_size, shalign);
1166 }
1167
1168 switch (self.ptr_width) {
1169 .p32 => {
1170 const buf = try self.base.allocator.alloc(elf.Elf32_Shdr, self.sections.items.len);
1171 defer self.base.allocator.free(buf);
1172
1173 for (buf) |*shdr, i| {
1174 shdr.* = sectHeaderTo32(self.sections.items[i]);
1175 log.debug("writing section {}\n", .{shdr.*});
1176 if (foreign_endian) {
1177 bswapAllFields(elf.Elf32_Shdr, shdr);
1178 }
1179 }
1180 try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), self.shdr_table_offset.?);
1181 },
1182 .p64 => {
1183 const buf = try self.base.allocator.alloc(elf.Elf64_Shdr, self.sections.items.len);
1184 defer self.base.allocator.free(buf);
1185
1186 for (buf) |*shdr, i| {
1187 shdr.* = self.sections.items[i];
1188 log.debug("writing section {}\n", .{shdr.*});
1189 if (foreign_endian) {
1190 bswapAllFields(elf.Elf64_Shdr, shdr);
1191 }
1192 }
1193 try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), self.shdr_table_offset.?);
1194 },
1195 }
1196 self.shdr_table_dirty = false;
1197 }
1198 if (self.entry_addr == null and self.base.options.output_mode == .Exe) {
1199 log.debug("flushing. no_entry_point_found = true\n", .{});
1200 self.error_flags.no_entry_point_found = true;
1201 } else {
1202 log.debug("flushing. no_entry_point_found = false\n", .{});
1203 self.error_flags.no_entry_point_found = false;
1204 try self.writeElfHeader();
1205 }
1206
1207 // The point of flush() is to commit changes, so in theory, nothing should
1208 // be dirty after this. However, it is possible for some things to remain
1209 // dirty because they fail to be written in the event of compile errors,
1210 // such as debug_line_header_dirty and debug_info_header_dirty.
1211 assert(!self.debug_abbrev_section_dirty);
1212 assert(!self.debug_aranges_section_dirty);
1213 assert(!self.phdr_table_dirty);
1214 assert(!self.shdr_table_dirty);
1215 assert(!self.shstrtab_dirty);
1216 assert(!self.debug_strtab_dirty);
1217}
1218
1219fn writeDwarfAddrAssumeCapacity(self: *Elf, buf: *std.ArrayList(u8), addr: u64) void {
1220 const target_endian = self.base.options.target.cpu.arch.endian();
1221 switch (self.ptr_width) {
1222 .p32 => mem.writeInt(u32, buf.addManyAsArrayAssumeCapacity(4), @intCast(u32, addr), target_endian),
1223 .p64 => mem.writeInt(u64, buf.addManyAsArrayAssumeCapacity(8), addr, target_endian),
1224 }
1225}
1226
1227fn writeElfHeader(self: *Elf) !void {
1228 var hdr_buf: [@sizeOf(elf.Elf64_Ehdr)]u8 = undefined;
1229
1230 var index: usize = 0;
1231 hdr_buf[0..4].* = "\x7fELF".*;
1232 index += 4;
1233
1234 hdr_buf[index] = switch (self.ptr_width) {
1235 .p32 => elf.ELFCLASS32,
1236 .p64 => elf.ELFCLASS64,
1237 };
1238 index += 1;
1239
1240 const endian = self.base.options.target.cpu.arch.endian();
1241 hdr_buf[index] = switch (endian) {
1242 .Little => elf.ELFDATA2LSB,
1243 .Big => elf.ELFDATA2MSB,
1244 };
1245 index += 1;
1246
1247 hdr_buf[index] = 1; // ELF version
1248 index += 1;
1249
1250 // OS ABI, often set to 0 regardless of target platform
1251 // ABI Version, possibly used by glibc but not by static executables
1252 // padding
1253 mem.set(u8, hdr_buf[index..][0..9], 0);
1254 index += 9;
1255
1256 assert(index == 16);
1257
1258 const elf_type = switch (self.base.options.output_mode) {
1259 .Exe => elf.ET.EXEC,
1260 .Obj => elf.ET.REL,
1261 .Lib => switch (self.base.options.link_mode) {
1262 .Static => elf.ET.REL,
1263 .Dynamic => elf.ET.DYN,
1264 },
1265 };
1266 mem.writeInt(u16, hdr_buf[index..][0..2], @enumToInt(elf_type), endian);
1267 index += 2;
1268
1269 const machine = self.base.options.target.cpu.arch.toElfMachine();
1270 mem.writeInt(u16, hdr_buf[index..][0..2], @enumToInt(machine), endian);
1271 index += 2;
1272
1273 // ELF Version, again
1274 mem.writeInt(u32, hdr_buf[index..][0..4], 1, endian);
1275 index += 4;
1276
1277 const e_entry = if (elf_type == .REL) 0 else self.entry_addr.?;
1278
1279 switch (self.ptr_width) {
1280 .p32 => {
1281 mem.writeInt(u32, hdr_buf[index..][0..4], @intCast(u32, e_entry), endian);
1282 index += 4;
1283
1284 // e_phoff
1285 mem.writeInt(u32, hdr_buf[index..][0..4], @intCast(u32, self.phdr_table_offset.?), endian);
1286 index += 4;
1287
1288 // e_shoff
1289 mem.writeInt(u32, hdr_buf[index..][0..4], @intCast(u32, self.shdr_table_offset.?), endian);
1290 index += 4;
1291 },
1292 .p64 => {
1293 // e_entry
1294 mem.writeInt(u64, hdr_buf[index..][0..8], e_entry, endian);
1295 index += 8;
1296
1297 // e_phoff
1298 mem.writeInt(u64, hdr_buf[index..][0..8], self.phdr_table_offset.?, endian);
1299 index += 8;
1300
1301 // e_shoff
1302 mem.writeInt(u64, hdr_buf[index..][0..8], self.shdr_table_offset.?, endian);
1303 index += 8;
1304 },
1305 }
1306
1307 const e_flags = 0;
1308 mem.writeInt(u32, hdr_buf[index..][0..4], e_flags, endian);
1309 index += 4;
1310
1311 const e_ehsize: u16 = switch (self.ptr_width) {
1312 .p32 => @sizeOf(elf.Elf32_Ehdr),
1313 .p64 => @sizeOf(elf.Elf64_Ehdr),
1314 };
1315 mem.writeInt(u16, hdr_buf[index..][0..2], e_ehsize, endian);
1316 index += 2;
1317
1318 const e_phentsize: u16 = switch (self.ptr_width) {
1319 .p32 => @sizeOf(elf.Elf32_Phdr),
1320 .p64 => @sizeOf(elf.Elf64_Phdr),
1321 };
1322 mem.writeInt(u16, hdr_buf[index..][0..2], e_phentsize, endian);
1323 index += 2;
1324
1325 const e_phnum = @intCast(u16, self.program_headers.items.len);
1326 mem.writeInt(u16, hdr_buf[index..][0..2], e_phnum, endian);
1327 index += 2;
1328
1329 const e_shentsize: u16 = switch (self.ptr_width) {
1330 .p32 => @sizeOf(elf.Elf32_Shdr),
1331 .p64 => @sizeOf(elf.Elf64_Shdr),
1332 };
1333 mem.writeInt(u16, hdr_buf[index..][0..2], e_shentsize, endian);
1334 index += 2;
1335
1336 const e_shnum = @intCast(u16, self.sections.items.len);
1337 mem.writeInt(u16, hdr_buf[index..][0..2], e_shnum, endian);
1338 index += 2;
1339
1340 mem.writeInt(u16, hdr_buf[index..][0..2], self.shstrtab_index.?, endian);
1341 index += 2;
1342
1343 assert(index == e_ehsize);
1344
1345 try self.base.file.?.pwriteAll(hdr_buf[0..index], 0);
1346}
1347
1348fn freeTextBlock(self: *Elf, text_block: *TextBlock) void {
1349 var already_have_free_list_node = false;
1350 {
1351 var i: usize = 0;
1352 while (i < self.text_block_free_list.items.len) {
1353 if (self.text_block_free_list.items[i] == text_block) {
1354 _ = self.text_block_free_list.swapRemove(i);
1355 continue;
1356 }
1357 if (self.text_block_free_list.items[i] == text_block.prev) {
1358 already_have_free_list_node = true;
1359 }
1360 i += 1;
1361 }
1362 }
1363
1364 if (self.last_text_block == text_block) {
1365 // TODO shrink the .text section size here
1366 self.last_text_block = text_block.prev;
1367 }
1368
1369 if (text_block.prev) |prev| {
1370 prev.next = text_block.next;
1371
1372 if (!already_have_free_list_node and prev.freeListEligible(self.*)) {
1373 // The free list is heuristics, it doesn't have to be perfect, so we can
1374 // ignore the OOM here.
1375 self.text_block_free_list.append(self.base.allocator, prev) catch {};
1376 }
1377 } else {
1378 text_block.prev = null;
1379 }
1380
1381 if (text_block.next) |next| {
1382 next.prev = text_block.prev;
1383 } else {
1384 text_block.next = null;
1385 }
1386}
1387
1388fn shrinkTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64) void {
1389 // TODO check the new capacity, and if it crosses the size threshold into a big enough
1390 // capacity, insert a free list node for it.
1391}
1392
1393fn growTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, alignment: u64) !u64 {
1394 const sym = self.local_symbols.items[text_block.local_sym_index];
1395 const align_ok = mem.alignBackwardGeneric(u64, sym.st_value, alignment) == sym.st_value;
1396 const need_realloc = !align_ok or new_block_size > text_block.capacity(self.*);
1397 if (!need_realloc) return sym.st_value;
1398 return self.allocateTextBlock(text_block, new_block_size, alignment);
1399}
1400
1401fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, alignment: u64) !u64 {
1402 const phdr = &self.program_headers.items[self.phdr_load_re_index.?];
1403 const shdr = &self.sections.items[self.text_section_index.?];
1404 const new_block_ideal_capacity = new_block_size * alloc_num / alloc_den;
1405
1406 // We use these to indicate our intention to update metadata, placing the new block,
1407 // and possibly removing a free list node.
1408 // It would be simpler to do it inside the for loop below, but that would cause a
1409 // problem if an error was returned later in the function. So this action
1410 // is actually carried out at the end of the function, when errors are no longer possible.
1411 var block_placement: ?*TextBlock = null;
1412 var free_list_removal: ?usize = null;
1413
1414 // First we look for an appropriately sized free list node.
1415 // The list is unordered. We'll just take the first thing that works.
1416 const vaddr = blk: {
1417 var i: usize = 0;
1418 while (i < self.text_block_free_list.items.len) {
1419 const big_block = self.text_block_free_list.items[i];
1420 // We now have a pointer to a live text block that has too much capacity.
1421 // Is it enough that we could fit this new text block?
1422 const sym = self.local_symbols.items[big_block.local_sym_index];
1423 const capacity = big_block.capacity(self.*);
1424 const ideal_capacity = capacity * alloc_num / alloc_den;
1425 const ideal_capacity_end_vaddr = sym.st_value + ideal_capacity;
1426 const capacity_end_vaddr = sym.st_value + capacity;
1427 const new_start_vaddr_unaligned = capacity_end_vaddr - new_block_ideal_capacity;
1428 const new_start_vaddr = mem.alignBackwardGeneric(u64, new_start_vaddr_unaligned, alignment);
1429 if (new_start_vaddr < ideal_capacity_end_vaddr) {
1430 // Additional bookkeeping here to notice if this free list node
1431 // should be deleted because the block that it points to has grown to take up
1432 // more of the extra capacity.
1433 if (!big_block.freeListEligible(self.*)) {
1434 _ = self.text_block_free_list.swapRemove(i);
1435 } else {
1436 i += 1;
1437 }
1438 continue;
1439 }
1440 // At this point we know that we will place the new block here. But the
1441 // remaining question is whether there is still yet enough capacity left
1442 // over for there to still be a free list node.
1443 const remaining_capacity = new_start_vaddr - ideal_capacity_end_vaddr;
1444 const keep_free_list_node = remaining_capacity >= min_text_capacity;
1445
1446 // Set up the metadata to be updated, after errors are no longer possible.
1447 block_placement = big_block;
1448 if (!keep_free_list_node) {
1449 free_list_removal = i;
1450 }
1451 break :blk new_start_vaddr;
1452 } else if (self.last_text_block) |last| {
1453 const sym = self.local_symbols.items[last.local_sym_index];
1454 const ideal_capacity = sym.st_size * alloc_num / alloc_den;
1455 const ideal_capacity_end_vaddr = sym.st_value + ideal_capacity;
1456 const new_start_vaddr = mem.alignForwardGeneric(u64, ideal_capacity_end_vaddr, alignment);
1457 // Set up the metadata to be updated, after errors are no longer possible.
1458 block_placement = last;
1459 break :blk new_start_vaddr;
1460 } else {
1461 break :blk phdr.p_vaddr;
1462 }
1463 };
1464
1465 const expand_text_section = block_placement == null or block_placement.?.next == null;
1466 if (expand_text_section) {
1467 const text_capacity = self.allocatedSize(shdr.sh_offset);
1468 const needed_size = (vaddr + new_block_size) - phdr.p_vaddr;
1469 if (needed_size > text_capacity) {
1470 // Must move the entire text section.
1471 const new_offset = self.findFreeSpace(needed_size, 0x1000);
1472 const text_size = if (self.last_text_block) |last| blk: {
1473 const sym = self.local_symbols.items[last.local_sym_index];
1474 break :blk (sym.st_value + sym.st_size) - phdr.p_vaddr;
1475 } else 0;
1476 const amt = try self.base.file.?.copyRangeAll(shdr.sh_offset, self.base.file.?, new_offset, text_size);
1477 if (amt != text_size) return error.InputOutput;
1478 shdr.sh_offset = new_offset;
1479 phdr.p_offset = new_offset;
1480 }
1481 self.last_text_block = text_block;
1482
1483 shdr.sh_size = needed_size;
1484 phdr.p_memsz = needed_size;
1485 phdr.p_filesz = needed_size;
1486
1487 // The .debug_info section has `low_pc` and `high_pc` values which is the virtual address
1488 // range of the compilation unit. When we expand the text section, this range changes,
1489 // so the DW_TAG_compile_unit tag of the .debug_info section becomes dirty.
1490 self.debug_info_header_dirty = true;
1491 // This becomes dirty for the same reason. We could potentially make this more
1492 // fine-grained with the addition of support for more compilation units. It is planned to
1493 // model each package as a different compilation unit.
1494 self.debug_aranges_section_dirty = true;
1495
1496 self.phdr_table_dirty = true; // TODO look into making only the one program header dirty
1497 self.shdr_table_dirty = true; // TODO look into making only the one section dirty
1498 }
1499
1500 // This function can also reallocate a text block.
1501 // In this case we need to "unplug" it from its previous location before
1502 // plugging it in to its new location.
1503 if (text_block.prev) |prev| {
1504 prev.next = text_block.next;
1505 }
1506 if (text_block.next) |next| {
1507 next.prev = text_block.prev;
1508 }
1509
1510 if (block_placement) |big_block| {
1511 text_block.prev = big_block;
1512 text_block.next = big_block.next;
1513 big_block.next = text_block;
1514 } else {
1515 text_block.prev = null;
1516 text_block.next = null;
1517 }
1518 if (free_list_removal) |i| {
1519 _ = self.text_block_free_list.swapRemove(i);
1520 }
1521 return vaddr;
1522}
1523
1524pub fn allocateDeclIndexes(self: *Elf, decl: *Module.Decl) !void {
1525 if (decl.link.elf.local_sym_index != 0) return;
1526
1527 try self.local_symbols.ensureCapacity(self.base.allocator, self.local_symbols.items.len + 1);
1528 try self.offset_table.ensureCapacity(self.base.allocator, self.offset_table.items.len + 1);
1529
1530 if (self.local_symbol_free_list.popOrNull()) |i| {
1531 log.debug("reusing symbol index {} for {}\n", .{ i, decl.name });
1532 decl.link.elf.local_sym_index = i;
1533 } else {
1534 log.debug("allocating symbol index {} for {}\n", .{ self.local_symbols.items.len, decl.name });
1535 decl.link.elf.local_sym_index = @intCast(u32, self.local_symbols.items.len);
1536 _ = self.local_symbols.addOneAssumeCapacity();
1537 }
1538
1539 if (self.offset_table_free_list.popOrNull()) |i| {
1540 decl.link.elf.offset_table_index = i;
1541 } else {
1542 decl.link.elf.offset_table_index = @intCast(u32, self.offset_table.items.len);
1543 _ = self.offset_table.addOneAssumeCapacity();
1544 self.offset_table_count_dirty = true;
1545 }
1546
1547 const phdr = &self.program_headers.items[self.phdr_load_re_index.?];
1548
1549 self.local_symbols.items[decl.link.elf.local_sym_index] = .{
1550 .st_name = 0,
1551 .st_info = 0,
1552 .st_other = 0,
1553 .st_shndx = 0,
1554 .st_value = phdr.p_vaddr,
1555 .st_size = 0,
1556 };
1557 self.offset_table.items[decl.link.elf.offset_table_index] = 0;
1558}
1559
1560pub fn freeDecl(self: *Elf, decl: *Module.Decl) void {
1561 // Appending to free lists is allowed to fail because the free lists are heuristics based anyway.
1562 self.freeTextBlock(&decl.link.elf);
1563 if (decl.link.elf.local_sym_index != 0) {
1564 self.local_symbol_free_list.append(self.base.allocator, decl.link.elf.local_sym_index) catch {};
1565 self.offset_table_free_list.append(self.base.allocator, decl.link.elf.offset_table_index) catch {};
1566
1567 self.local_symbols.items[decl.link.elf.local_sym_index].st_info = 0;
1568
1569 decl.link.elf.local_sym_index = 0;
1570 }
1571 // TODO make this logic match freeTextBlock. Maybe abstract the logic out since the same thing
1572 // is desired for both.
1573 _ = self.dbg_line_fn_free_list.remove(&decl.fn_link.elf);
1574 if (decl.fn_link.elf.prev) |prev| {
1575 _ = self.dbg_line_fn_free_list.put(self.base.allocator, prev, {}) catch {};
1576 prev.next = decl.fn_link.elf.next;
1577 if (decl.fn_link.elf.next) |next| {
1578 next.prev = prev;
1579 } else {
1580 self.dbg_line_fn_last = prev;
1581 }
1582 } else if (decl.fn_link.elf.next) |next| {
1583 self.dbg_line_fn_first = next;
1584 next.prev = null;
1585 }
1586 if (self.dbg_line_fn_first == &decl.fn_link.elf) {
1587 self.dbg_line_fn_first = null;
1588 }
1589 if (self.dbg_line_fn_last == &decl.fn_link.elf) {
1590 self.dbg_line_fn_last = null;
1591 }
1592}
1593
1594pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void {
1595 const tracy = trace(@src());
1596 defer tracy.end();
1597
1598 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
1599 defer code_buffer.deinit();
1600
1601 var dbg_line_buffer = std.ArrayList(u8).init(self.base.allocator);
1602 defer dbg_line_buffer.deinit();
1603
1604 var dbg_info_buffer = std.ArrayList(u8).init(self.base.allocator);
1605 defer dbg_info_buffer.deinit();
1606
1607 var dbg_info_type_relocs: File.DbgInfoTypeRelocsTable = .{};
1608 defer {
1609 for (dbg_info_type_relocs.items()) |*entry| {
1610 entry.value.relocs.deinit(self.base.allocator);
1611 }
1612 dbg_info_type_relocs.deinit(self.base.allocator);
1613 }
1614
1615 const typed_value = decl.typed_value.most_recent.typed_value;
1616 const is_fn: bool = switch (typed_value.ty.zigTypeTag()) {
1617 .Fn => true,
1618 else => false,
1619 };
1620 if (is_fn) {
1621 //if (mem.eql(u8, mem.spanZ(decl.name), "add")) {
1622 // typed_value.val.cast(Value.Payload.Function).?.func.dump(module.*);
1623 //}
1624
1625 // For functions we need to add a prologue to the debug line program.
1626 try dbg_line_buffer.ensureCapacity(26);
1627
1628 const line_off: u28 = blk: {
1629 if (decl.scope.cast(Module.Scope.File)) |scope_file| {
1630 const tree = scope_file.contents.tree;
1631 const file_ast_decls = tree.root_node.decls();
1632 // TODO Look into improving the performance here by adding a token-index-to-line
1633 // lookup table. Currently this involves scanning over the source code for newlines.
1634 const fn_proto = file_ast_decls[decl.src_index].castTag(.FnProto).?;
1635 const block = fn_proto.body().?.castTag(.Block).?;
1636 const line_delta = std.zig.lineDelta(tree.source, 0, tree.token_locs[block.lbrace].start);
1637 break :blk @intCast(u28, line_delta);
1638 } else if (decl.scope.cast(Module.Scope.ZIRModule)) |zir_module| {
1639 const byte_off = zir_module.contents.module.decls[decl.src_index].inst.src;
1640 const line_delta = std.zig.lineDelta(zir_module.source.bytes, 0, byte_off);
1641 break :blk @intCast(u28, line_delta);
1642 } else {
1643 unreachable;
1644 }
1645 };
1646
1647 const ptr_width_bytes = self.ptrWidthBytes();
1648 dbg_line_buffer.appendSliceAssumeCapacity(&[_]u8{
1649 DW.LNS_extended_op,
1650 ptr_width_bytes + 1,
1651 DW.LNE_set_address,
1652 });
1653 // This is the "relocatable" vaddr, corresponding to `code_buffer` index `0`.
1654 assert(dbg_line_vaddr_reloc_index == dbg_line_buffer.items.len);
1655 dbg_line_buffer.items.len += ptr_width_bytes;
1656
1657 dbg_line_buffer.appendAssumeCapacity(DW.LNS_advance_line);
1658 // This is the "relocatable" relative line offset from the previous function's end curly
1659 // to this function's begin curly.
1660 assert(self.getRelocDbgLineOff() == dbg_line_buffer.items.len);
1661 // Here we use a ULEB128-fixed-4 to make sure this field can be overwritten later.
1662 leb128.writeUnsignedFixed(4, dbg_line_buffer.addManyAsArrayAssumeCapacity(4), line_off);
1663
1664 dbg_line_buffer.appendAssumeCapacity(DW.LNS_set_file);
1665 assert(self.getRelocDbgFileIndex() == dbg_line_buffer.items.len);
1666 // Once we support more than one source file, this will have the ability to be more
1667 // than one possible value.
1668 const file_index = 1;
1669 leb128.writeUnsignedFixed(4, dbg_line_buffer.addManyAsArrayAssumeCapacity(4), file_index);
1670
1671 // Emit a line for the begin curly with prologue_end=false. The codegen will
1672 // do the work of setting prologue_end=true and epilogue_begin=true.
1673 dbg_line_buffer.appendAssumeCapacity(DW.LNS_copy);
1674
1675 // .debug_info subprogram
1676 const decl_name_with_null = decl.name[0 .. mem.lenZ(decl.name) + 1];
1677 try dbg_info_buffer.ensureCapacity(dbg_info_buffer.items.len + 25 + decl_name_with_null.len);
1678
1679 const fn_ret_type = typed_value.ty.fnReturnType();
1680 const fn_ret_has_bits = fn_ret_type.hasCodeGenBits();
1681 if (fn_ret_has_bits) {
1682 dbg_info_buffer.appendAssumeCapacity(abbrev_subprogram);
1683 } else {
1684 dbg_info_buffer.appendAssumeCapacity(abbrev_subprogram_retvoid);
1685 }
1686 // These get overwritten after generating the machine code. These values are
1687 // "relocations" and have to be in this fixed place so that functions can be
1688 // moved in virtual address space.
1689 assert(dbg_info_low_pc_reloc_index == dbg_info_buffer.items.len);
1690 dbg_info_buffer.items.len += ptr_width_bytes; // DW.AT_low_pc, DW.FORM_addr
1691 assert(self.getRelocDbgInfoSubprogramHighPC() == dbg_info_buffer.items.len);
1692 dbg_info_buffer.items.len += 4; // DW.AT_high_pc, DW.FORM_data4
1693 if (fn_ret_has_bits) {
1694 const gop = try dbg_info_type_relocs.getOrPut(self.base.allocator, fn_ret_type);
1695 if (!gop.found_existing) {
1696 gop.entry.value = .{
1697 .off = undefined,
1698 .relocs = .{},
1699 };
1700 }
1701 try gop.entry.value.relocs.append(self.base.allocator, @intCast(u32, dbg_info_buffer.items.len));
1702 dbg_info_buffer.items.len += 4; // DW.AT_type, DW.FORM_ref4
1703 }
1704 dbg_info_buffer.appendSliceAssumeCapacity(decl_name_with_null); // DW.AT_name, DW.FORM_string
1705 } else {
1706 // TODO implement .debug_info for global variables
1707 }
1708 const res = try codegen.generateSymbol(&self.base, decl.src(), typed_value, &code_buffer, &dbg_line_buffer, &dbg_info_buffer, &dbg_info_type_relocs);
1709 const code = switch (res) {
1710 .externally_managed => |x| x,
1711 .appended => code_buffer.items,
1712 .fail => |em| {
1713 decl.analysis = .codegen_failure;
1714 try module.failed_decls.put(module.gpa, decl, em);
1715 return;
1716 },
1717 };
1718
1719 const required_alignment = typed_value.ty.abiAlignment(self.base.options.target);
1720
1721 const stt_bits: u8 = if (is_fn) elf.STT_FUNC else elf.STT_OBJECT;
1722
1723 assert(decl.link.elf.local_sym_index != 0); // Caller forgot to allocateDeclIndexes()
1724 const local_sym = &self.local_symbols.items[decl.link.elf.local_sym_index];
1725 if (local_sym.st_size != 0) {
1726 const capacity = decl.link.elf.capacity(self.*);
1727 const need_realloc = code.len > capacity or
1728 !mem.isAlignedGeneric(u64, local_sym.st_value, required_alignment);
1729 if (need_realloc) {
1730 const vaddr = try self.growTextBlock(&decl.link.elf, code.len, required_alignment);
1731 log.debug("growing {} from 0x{x} to 0x{x}\n", .{ decl.name, local_sym.st_value, vaddr });
1732 if (vaddr != local_sym.st_value) {
1733 local_sym.st_value = vaddr;
1734
1735 log.debug(" (writing new offset table entry)\n", .{});
1736 self.offset_table.items[decl.link.elf.offset_table_index] = vaddr;
1737 try self.writeOffsetTableEntry(decl.link.elf.offset_table_index);
1738 }
1739 } else if (code.len < local_sym.st_size) {
1740 self.shrinkTextBlock(&decl.link.elf, code.len);
1741 }
1742 local_sym.st_size = code.len;
1743 local_sym.st_name = try self.updateString(local_sym.st_name, mem.spanZ(decl.name));
1744 local_sym.st_info = (elf.STB_LOCAL << 4) | stt_bits;
1745 local_sym.st_other = 0;
1746 local_sym.st_shndx = self.text_section_index.?;
1747 // TODO this write could be avoided if no fields of the symbol were changed.
1748 try self.writeSymbol(decl.link.elf.local_sym_index);
1749 } else {
1750 const decl_name = mem.spanZ(decl.name);
1751 const name_str_index = try self.makeString(decl_name);
1752 const vaddr = try self.allocateTextBlock(&decl.link.elf, code.len, required_alignment);
1753 log.debug("allocated text block for {} at 0x{x}\n", .{ decl_name, vaddr });
1754 errdefer self.freeTextBlock(&decl.link.elf);
1755
1756 local_sym.* = .{
1757 .st_name = name_str_index,
1758 .st_info = (elf.STB_LOCAL << 4) | stt_bits,
1759 .st_other = 0,
1760 .st_shndx = self.text_section_index.?,
1761 .st_value = vaddr,
1762 .st_size = code.len,
1763 };
1764 self.offset_table.items[decl.link.elf.offset_table_index] = vaddr;
1765
1766 try self.writeSymbol(decl.link.elf.local_sym_index);
1767 try self.writeOffsetTableEntry(decl.link.elf.offset_table_index);
1768 }
1769
1770 const section_offset = local_sym.st_value - self.program_headers.items[self.phdr_load_re_index.?].p_vaddr;
1771 const file_offset = self.sections.items[self.text_section_index.?].sh_offset + section_offset;
1772 try self.base.file.?.pwriteAll(code, file_offset);
1773
1774 const target_endian = self.base.options.target.cpu.arch.endian();
1775
1776 const text_block = &decl.link.elf;
1777
1778 // If the Decl is a function, we need to update the .debug_line program.
1779 if (is_fn) {
1780 // Perform the relocations based on vaddr.
1781 switch (self.ptr_width) {
1782 .p32 => {
1783 {
1784 const ptr = dbg_line_buffer.items[dbg_line_vaddr_reloc_index..][0..4];
1785 mem.writeInt(u32, ptr, @intCast(u32, local_sym.st_value), target_endian);
1786 }
1787 {
1788 const ptr = dbg_info_buffer.items[dbg_info_low_pc_reloc_index..][0..4];
1789 mem.writeInt(u32, ptr, @intCast(u32, local_sym.st_value), target_endian);
1790 }
1791 },
1792 .p64 => {
1793 {
1794 const ptr = dbg_line_buffer.items[dbg_line_vaddr_reloc_index..][0..8];
1795 mem.writeInt(u64, ptr, local_sym.st_value, target_endian);
1796 }
1797 {
1798 const ptr = dbg_info_buffer.items[dbg_info_low_pc_reloc_index..][0..8];
1799 mem.writeInt(u64, ptr, local_sym.st_value, target_endian);
1800 }
1801 },
1802 }
1803 {
1804 const ptr = dbg_info_buffer.items[self.getRelocDbgInfoSubprogramHighPC()..][0..4];
1805 mem.writeInt(u32, ptr, @intCast(u32, local_sym.st_size), target_endian);
1806 }
1807
1808 try dbg_line_buffer.appendSlice(&[_]u8{ DW.LNS_extended_op, 1, DW.LNE_end_sequence });
1809
1810 // Now we have the full contents and may allocate a region to store it.
1811
1812 // This logic is nearly identical to the logic below in `updateDeclDebugInfo` for
1813 // `TextBlock` and the .debug_info. If you are editing this logic, you
1814 // probably need to edit that logic too.
1815
1816 const debug_line_sect = &self.sections.items[self.debug_line_section_index.?];
1817 const src_fn = &decl.fn_link.elf;
1818 src_fn.len = @intCast(u32, dbg_line_buffer.items.len);
1819 if (self.dbg_line_fn_last) |last| {
1820 if (src_fn.next) |next| {
1821 // Update existing function - non-last item.
1822 if (src_fn.off + src_fn.len + min_nop_size > next.off) {
1823 // It grew too big, so we move it to a new location.
1824 if (src_fn.prev) |prev| {
1825 _ = self.dbg_line_fn_free_list.put(self.base.allocator, prev, {}) catch {};
1826 prev.next = src_fn.next;
1827 }
1828 next.prev = src_fn.prev;
1829 src_fn.next = null;
1830 // Populate where it used to be with NOPs.
1831 const file_pos = debug_line_sect.sh_offset + src_fn.off;
1832 try self.pwriteDbgLineNops(0, &[0]u8{}, src_fn.len, file_pos);
1833 // TODO Look at the free list before appending at the end.
1834 src_fn.prev = last;
1835 last.next = src_fn;
1836 self.dbg_line_fn_last = src_fn;
1837
1838 src_fn.off = last.off + (last.len * alloc_num / alloc_den);
1839 }
1840 } else if (src_fn.prev == null) {
1841 // Append new function.
1842 // TODO Look at the free list before appending at the end.
1843 src_fn.prev = last;
1844 last.next = src_fn;
1845 self.dbg_line_fn_last = src_fn;
1846
1847 src_fn.off = last.off + (last.len * alloc_num / alloc_den);
1848 }
1849 } else {
1850 // This is the first function of the Line Number Program.
1851 self.dbg_line_fn_first = src_fn;
1852 self.dbg_line_fn_last = src_fn;
1853
1854 src_fn.off = self.dbgLineNeededHeaderBytes() * alloc_num / alloc_den;
1855 }
1856
1857 const last_src_fn = self.dbg_line_fn_last.?;
1858 const needed_size = last_src_fn.off + last_src_fn.len;
1859 if (needed_size != debug_line_sect.sh_size) {
1860 if (needed_size > self.allocatedSize(debug_line_sect.sh_offset)) {
1861 const new_offset = self.findFreeSpace(needed_size, 1);
1862 const existing_size = last_src_fn.off;
1863 log.debug("moving .debug_line section: {} bytes from 0x{x} to 0x{x}\n", .{
1864 existing_size,
1865 debug_line_sect.sh_offset,
1866 new_offset,
1867 });
1868 const amt = try self.base.file.?.copyRangeAll(debug_line_sect.sh_offset, self.base.file.?, new_offset, existing_size);
1869 if (amt != existing_size) return error.InputOutput;
1870 debug_line_sect.sh_offset = new_offset;
1871 }
1872 debug_line_sect.sh_size = needed_size;
1873 self.shdr_table_dirty = true; // TODO look into making only the one section dirty
1874 self.debug_line_header_dirty = true;
1875 }
1876 const prev_padding_size: u32 = if (src_fn.prev) |prev| src_fn.off - (prev.off + prev.len) else 0;
1877 const next_padding_size: u32 = if (src_fn.next) |next| next.off - (src_fn.off + src_fn.len) else 0;
1878
1879 // We only have support for one compilation unit so far, so the offsets are directly
1880 // from the .debug_line section.
1881 const file_pos = debug_line_sect.sh_offset + src_fn.off;
1882 try self.pwriteDbgLineNops(prev_padding_size, dbg_line_buffer.items, next_padding_size, file_pos);
1883
1884 // .debug_info - End the TAG_subprogram children.
1885 try dbg_info_buffer.append(0);
1886 }
1887
1888 // Now we emit the .debug_info types of the Decl. These will count towards the size of
1889 // the buffer, so we have to do it before computing the offset, and we can't perform the actual
1890 // relocations yet.
1891 for (dbg_info_type_relocs.items()) |*entry| {
1892 entry.value.off = @intCast(u32, dbg_info_buffer.items.len);
1893 try self.addDbgInfoType(entry.key, &dbg_info_buffer);
1894 }
1895
1896 try self.updateDeclDebugInfoAllocation(text_block, @intCast(u32, dbg_info_buffer.items.len));
1897
1898 // Now that we have the offset assigned we can finally perform type relocations.
1899 for (dbg_info_type_relocs.items()) |entry| {
1900 for (entry.value.relocs.items) |off| {
1901 mem.writeInt(
1902 u32,
1903 dbg_info_buffer.items[off..][0..4],
1904 text_block.dbg_info_off + entry.value.off,
1905 target_endian,
1906 );
1907 }
1908 }
1909
1910 try self.writeDeclDebugInfo(text_block, dbg_info_buffer.items);
1911
1912 // Since we updated the vaddr and the size, each corresponding export symbol also needs to be updated.
1913 const decl_exports = module.decl_exports.get(decl) orelse &[0]*Module.Export{};
1914 return self.updateDeclExports(module, decl, decl_exports);
1915}
1916
1917/// Asserts the type has codegen bits.
1918fn addDbgInfoType(self: *Elf, ty: Type, dbg_info_buffer: *std.ArrayList(u8)) !void {
1919 switch (ty.zigTypeTag()) {
1920 .Void => unreachable,
1921 .NoReturn => unreachable,
1922 .Bool => {
1923 try dbg_info_buffer.appendSlice(&[_]u8{
1924 abbrev_base_type,
1925 DW.ATE_boolean, // DW.AT_encoding , DW.FORM_data1
1926 1, // DW.AT_byte_size, DW.FORM_data1
1927 'b',
1928 'o',
1929 'o',
1930 'l',
1931 0, // DW.AT_name, DW.FORM_string
1932 });
1933 },
1934 .Int => {
1935 const info = ty.intInfo(self.base.options.target);
1936 try dbg_info_buffer.ensureCapacity(dbg_info_buffer.items.len + 12);
1937 dbg_info_buffer.appendAssumeCapacity(abbrev_base_type);
1938 // DW.AT_encoding, DW.FORM_data1
1939 dbg_info_buffer.appendAssumeCapacity(if (info.signed) DW.ATE_signed else DW.ATE_unsigned);
1940 // DW.AT_byte_size, DW.FORM_data1
1941 dbg_info_buffer.appendAssumeCapacity(@intCast(u8, ty.abiSize(self.base.options.target)));
1942 // DW.AT_name, DW.FORM_string
1943 try dbg_info_buffer.writer().print("{}\x00", .{ty});
1944 },
1945 else => {
1946 std.log.scoped(.compiler).err("TODO implement .debug_info for type '{}'", .{ty});
1947 try dbg_info_buffer.append(abbrev_pad1);
1948 },
1949 }
1950}
1951
1952fn updateDeclDebugInfoAllocation(self: *Elf, text_block: *TextBlock, len: u32) !void {
1953 const tracy = trace(@src());
1954 defer tracy.end();
1955
1956 // This logic is nearly identical to the logic above in `updateDecl` for
1957 // `SrcFn` and the line number programs. If you are editing this logic, you
1958 // probably need to edit that logic too.
1959
1960 const debug_info_sect = &self.sections.items[self.debug_info_section_index.?];
1961 text_block.dbg_info_len = len;
1962 if (self.dbg_info_decl_last) |last| {
1963 if (text_block.dbg_info_next) |next| {
1964 // Update existing Decl - non-last item.
1965 if (text_block.dbg_info_off + text_block.dbg_info_len + min_nop_size > next.dbg_info_off) {
1966 // It grew too big, so we move it to a new location.
1967 if (text_block.dbg_info_prev) |prev| {
1968 _ = self.dbg_info_decl_free_list.put(self.base.allocator, prev, {}) catch {};
1969 prev.dbg_info_next = text_block.dbg_info_next;
1970 }
1971 next.dbg_info_prev = text_block.dbg_info_prev;
1972 text_block.dbg_info_next = null;
1973 // Populate where it used to be with NOPs.
1974 const file_pos = debug_info_sect.sh_offset + text_block.dbg_info_off;
1975 try self.pwriteDbgInfoNops(0, &[0]u8{}, text_block.dbg_info_len, false, file_pos);
1976 // TODO Look at the free list before appending at the end.
1977 text_block.dbg_info_prev = last;
1978 last.dbg_info_next = text_block;
1979 self.dbg_info_decl_last = text_block;
1980
1981 text_block.dbg_info_off = last.dbg_info_off + (last.dbg_info_len * alloc_num / alloc_den);
1982 }
1983 } else if (text_block.dbg_info_prev == null) {
1984 // Append new Decl.
1985 // TODO Look at the free list before appending at the end.
1986 text_block.dbg_info_prev = last;
1987 last.dbg_info_next = text_block;
1988 self.dbg_info_decl_last = text_block;
1989
1990 text_block.dbg_info_off = last.dbg_info_off + (last.dbg_info_len * alloc_num / alloc_den);
1991 }
1992 } else {
1993 // This is the first Decl of the .debug_info
1994 self.dbg_info_decl_first = text_block;
1995 self.dbg_info_decl_last = text_block;
1996
1997 text_block.dbg_info_off = self.dbgInfoNeededHeaderBytes() * alloc_num / alloc_den;
1998 }
1999}
2000
2001fn writeDeclDebugInfo(self: *Elf, text_block: *TextBlock, dbg_info_buf: []const u8) !void {
2002 const tracy = trace(@src());
2003 defer tracy.end();
2004
2005 // This logic is nearly identical to the logic above in `updateDecl` for
2006 // `SrcFn` and the line number programs. If you are editing this logic, you
2007 // probably need to edit that logic too.
2008
2009 const debug_info_sect = &self.sections.items[self.debug_info_section_index.?];
2010
2011 const last_decl = self.dbg_info_decl_last.?;
2012 // +1 for a trailing zero to end the children of the decl tag.
2013 const needed_size = last_decl.dbg_info_off + last_decl.dbg_info_len + 1;
2014 if (needed_size != debug_info_sect.sh_size) {
2015 if (needed_size > self.allocatedSize(debug_info_sect.sh_offset)) {
2016 const new_offset = self.findFreeSpace(needed_size, 1);
2017 const existing_size = last_decl.dbg_info_off;
2018 log.debug("moving .debug_info section: {} bytes from 0x{x} to 0x{x}\n", .{
2019 existing_size,
2020 debug_info_sect.sh_offset,
2021 new_offset,
2022 });
2023 const amt = try self.base.file.?.copyRangeAll(debug_info_sect.sh_offset, self.base.file.?, new_offset, existing_size);
2024 if (amt != existing_size) return error.InputOutput;
2025 debug_info_sect.sh_offset = new_offset;
2026 }
2027 debug_info_sect.sh_size = needed_size;
2028 self.shdr_table_dirty = true; // TODO look into making only the one section dirty
2029 self.debug_info_header_dirty = true;
2030 }
2031 const prev_padding_size: u32 = if (text_block.dbg_info_prev) |prev|
2032 text_block.dbg_info_off - (prev.dbg_info_off + prev.dbg_info_len)
2033 else
2034 0;
2035 const next_padding_size: u32 = if (text_block.dbg_info_next) |next|
2036 next.dbg_info_off - (text_block.dbg_info_off + text_block.dbg_info_len)
2037 else
2038 0;
2039
2040 // To end the children of the decl tag.
2041 const trailing_zero = text_block.dbg_info_next == null;
2042
2043 // We only have support for one compilation unit so far, so the offsets are directly
2044 // from the .debug_info section.
2045 const file_pos = debug_info_sect.sh_offset + text_block.dbg_info_off;
2046 try self.pwriteDbgInfoNops(prev_padding_size, dbg_info_buf, next_padding_size, trailing_zero, file_pos);
2047}
2048
2049pub fn updateDeclExports(
2050 self: *Elf,
2051 module: *Module,
2052 decl: *const Module.Decl,
2053 exports: []const *Module.Export,
2054) !void {
2055 const tracy = trace(@src());
2056 defer tracy.end();
2057
2058 try self.global_symbols.ensureCapacity(self.base.allocator, self.global_symbols.items.len + exports.len);
2059 const typed_value = decl.typed_value.most_recent.typed_value;
2060 if (decl.link.elf.local_sym_index == 0) return;
2061 const decl_sym = self.local_symbols.items[decl.link.elf.local_sym_index];
2062
2063 for (exports) |exp| {
2064 if (exp.options.section) |section_name| {
2065 if (!mem.eql(u8, section_name, ".text")) {
2066 try module.failed_exports.ensureCapacity(module.gpa, module.failed_exports.items().len + 1);
2067 module.failed_exports.putAssumeCapacityNoClobber(
2068 exp,
2069 try Module.ErrorMsg.create(self.base.allocator, 0, "Unimplemented: ExportOptions.section", .{}),
2070 );
2071 continue;
2072 }
2073 }
2074 const stb_bits: u8 = switch (exp.options.linkage) {
2075 .Internal => elf.STB_LOCAL,
2076 .Strong => blk: {
2077 if (mem.eql(u8, exp.options.name, "_start")) {
2078 self.entry_addr = decl_sym.st_value;
2079 }
2080 break :blk elf.STB_GLOBAL;
2081 },
2082 .Weak => elf.STB_WEAK,
2083 .LinkOnce => {
2084 try module.failed_exports.ensureCapacity(module.gpa, module.failed_exports.items().len + 1);
2085 module.failed_exports.putAssumeCapacityNoClobber(
2086 exp,
2087 try Module.ErrorMsg.create(self.base.allocator, 0, "Unimplemented: GlobalLinkage.LinkOnce", .{}),
2088 );
2089 continue;
2090 },
2091 };
2092 const stt_bits: u8 = @truncate(u4, decl_sym.st_info);
2093 if (exp.link.sym_index) |i| {
2094 const sym = &self.global_symbols.items[i];
2095 sym.* = .{
2096 .st_name = try self.updateString(sym.st_name, exp.options.name),
2097 .st_info = (stb_bits << 4) | stt_bits,
2098 .st_other = 0,
2099 .st_shndx = self.text_section_index.?,
2100 .st_value = decl_sym.st_value,
2101 .st_size = decl_sym.st_size,
2102 };
2103 } else {
2104 const name = try self.makeString(exp.options.name);
2105 const i = if (self.global_symbol_free_list.popOrNull()) |i| i else blk: {
2106 _ = self.global_symbols.addOneAssumeCapacity();
2107 break :blk self.global_symbols.items.len - 1;
2108 };
2109 self.global_symbols.items[i] = .{
2110 .st_name = name,
2111 .st_info = (stb_bits << 4) | stt_bits,
2112 .st_other = 0,
2113 .st_shndx = self.text_section_index.?,
2114 .st_value = decl_sym.st_value,
2115 .st_size = decl_sym.st_size,
2116 };
2117
2118 exp.link.sym_index = @intCast(u32, i);
2119 }
2120 }
2121}
2122
2123/// Must be called only after a successful call to `updateDecl`.
2124pub fn updateDeclLineNumber(self: *Elf, module: *Module, decl: *const Module.Decl) !void {
2125 const tracy = trace(@src());
2126 defer tracy.end();
2127
2128 const scope_file = decl.scope.cast(Module.Scope.File).?;
2129 const tree = scope_file.contents.tree;
2130 const file_ast_decls = tree.root_node.decls();
2131 // TODO Look into improving the performance here by adding a token-index-to-line
2132 // lookup table. Currently this involves scanning over the source code for newlines.
2133 const fn_proto = file_ast_decls[decl.src_index].castTag(.FnProto).?;
2134 const block = fn_proto.body().?.castTag(.Block).?;
2135 const line_delta = std.zig.lineDelta(tree.source, 0, tree.token_locs[block.lbrace].start);
2136 const casted_line_off = @intCast(u28, line_delta);
2137
2138 const shdr = &self.sections.items[self.debug_line_section_index.?];
2139 const file_pos = shdr.sh_offset + decl.fn_link.elf.off + self.getRelocDbgLineOff();
2140 var data: [4]u8 = undefined;
2141 leb128.writeUnsignedFixed(4, &data, casted_line_off);
2142 try self.base.file.?.pwriteAll(&data, file_pos);
2143}
2144
2145pub fn deleteExport(self: *Elf, exp: Export) void {
2146 const sym_index = exp.sym_index orelse return;
2147 self.global_symbol_free_list.append(self.base.allocator, sym_index) catch {};
2148 self.global_symbols.items[sym_index].st_info = 0;
2149}
2150
2151fn writeProgHeader(self: *Elf, index: usize) !void {
2152 const foreign_endian = self.base.options.target.cpu.arch.endian() != std.Target.current.cpu.arch.endian();
2153 const offset = self.program_headers.items[index].p_offset;
2154 switch (self.base.options.target.cpu.arch.ptrBitWidth()) {
2155 32 => {
2156 var phdr = [1]elf.Elf32_Phdr{progHeaderTo32(self.program_headers.items[index])};
2157 if (foreign_endian) {
2158 bswapAllFields(elf.Elf32_Phdr, &phdr[0]);
2159 }
2160 return self.base.file.?.pwriteAll(mem.sliceAsBytes(&phdr), offset);
2161 },
2162 64 => {
2163 var phdr = [1]elf.Elf64_Phdr{self.program_headers.items[index]};
2164 if (foreign_endian) {
2165 bswapAllFields(elf.Elf64_Phdr, &phdr[0]);
2166 }
2167 return self.base.file.?.pwriteAll(mem.sliceAsBytes(&phdr), offset);
2168 },
2169 else => return error.UnsupportedArchitecture,
2170 }
2171}
2172
2173fn writeSectHeader(self: *Elf, index: usize) !void {
2174 const foreign_endian = self.base.options.target.cpu.arch.endian() != std.Target.current.cpu.arch.endian();
2175 switch (self.base.options.target.cpu.arch.ptrBitWidth()) {
2176 32 => {
2177 var shdr: [1]elf.Elf32_Shdr = undefined;
2178 shdr[0] = sectHeaderTo32(self.sections.items[index]);
2179 if (foreign_endian) {
2180 bswapAllFields(elf.Elf32_Shdr, &shdr[0]);
2181 }
2182 const offset = self.shdr_table_offset.? + index * @sizeOf(elf.Elf32_Shdr);
2183 return self.base.file.?.pwriteAll(mem.sliceAsBytes(&shdr), offset);
2184 },
2185 64 => {
2186 var shdr = [1]elf.Elf64_Shdr{self.sections.items[index]};
2187 if (foreign_endian) {
2188 bswapAllFields(elf.Elf64_Shdr, &shdr[0]);
2189 }
2190 const offset = self.shdr_table_offset.? + index * @sizeOf(elf.Elf64_Shdr);
2191 return self.base.file.?.pwriteAll(mem.sliceAsBytes(&shdr), offset);
2192 },
2193 else => return error.UnsupportedArchitecture,
2194 }
2195}
2196
2197fn writeOffsetTableEntry(self: *Elf, index: usize) !void {
2198 const shdr = &self.sections.items[self.got_section_index.?];
2199 const phdr = &self.program_headers.items[self.phdr_got_index.?];
2200 const entry_size: u16 = self.ptrWidthBytes();
2201 if (self.offset_table_count_dirty) {
2202 // TODO Also detect virtual address collisions.
2203 const allocated_size = self.allocatedSize(shdr.sh_offset);
2204 const needed_size = self.local_symbols.items.len * entry_size;
2205 if (needed_size > allocated_size) {
2206 // Must move the entire got section.
2207 const new_offset = self.findFreeSpace(needed_size, entry_size);
2208 const amt = try self.base.file.?.copyRangeAll(shdr.sh_offset, self.base.file.?, new_offset, shdr.sh_size);
2209 if (amt != shdr.sh_size) return error.InputOutput;
2210 shdr.sh_offset = new_offset;
2211 phdr.p_offset = new_offset;
2212 }
2213 shdr.sh_size = needed_size;
2214 phdr.p_memsz = needed_size;
2215 phdr.p_filesz = needed_size;
2216
2217 self.shdr_table_dirty = true; // TODO look into making only the one section dirty
2218 self.phdr_table_dirty = true; // TODO look into making only the one program header dirty
2219
2220 self.offset_table_count_dirty = false;
2221 }
2222 const endian = self.base.options.target.cpu.arch.endian();
2223 const off = shdr.sh_offset + @as(u64, entry_size) * index;
2224 switch (self.ptr_width) {
2225 .p32 => {
2226 var buf: [4]u8 = undefined;
2227 mem.writeInt(u32, &buf, @intCast(u32, self.offset_table.items[index]), endian);
2228 try self.base.file.?.pwriteAll(&buf, off);
2229 },
2230 .p64 => {
2231 var buf: [8]u8 = undefined;
2232 mem.writeInt(u64, &buf, self.offset_table.items[index], endian);
2233 try self.base.file.?.pwriteAll(&buf, off);
2234 },
2235 }
2236}
2237
2238fn writeSymbol(self: *Elf, index: usize) !void {
2239 const tracy = trace(@src());
2240 defer tracy.end();
2241
2242 const syms_sect = &self.sections.items[self.symtab_section_index.?];
2243 // Make sure we are not pointlessly writing symbol data that will have to get relocated
2244 // due to running out of space.
2245 if (self.local_symbols.items.len != syms_sect.sh_info) {
2246 const sym_size: u64 = switch (self.ptr_width) {
2247 .p32 => @sizeOf(elf.Elf32_Sym),
2248 .p64 => @sizeOf(elf.Elf64_Sym),
2249 };
2250 const sym_align: u16 = switch (self.ptr_width) {
2251 .p32 => @alignOf(elf.Elf32_Sym),
2252 .p64 => @alignOf(elf.Elf64_Sym),
2253 };
2254 const needed_size = (self.local_symbols.items.len + self.global_symbols.items.len) * sym_size;
2255 if (needed_size > self.allocatedSize(syms_sect.sh_offset)) {
2256 // Move all the symbols to a new file location.
2257 const new_offset = self.findFreeSpace(needed_size, sym_align);
2258 const existing_size = @as(u64, syms_sect.sh_info) * sym_size;
2259 const amt = try self.base.file.?.copyRangeAll(syms_sect.sh_offset, self.base.file.?, new_offset, existing_size);
2260 if (amt != existing_size) return error.InputOutput;
2261 syms_sect.sh_offset = new_offset;
2262 }
2263 syms_sect.sh_info = @intCast(u32, self.local_symbols.items.len);
2264 syms_sect.sh_size = needed_size; // anticipating adding the global symbols later
2265 self.shdr_table_dirty = true; // TODO look into only writing one section
2266 }
2267 const foreign_endian = self.base.options.target.cpu.arch.endian() != std.Target.current.cpu.arch.endian();
2268 switch (self.ptr_width) {
2269 .p32 => {
2270 var sym = [1]elf.Elf32_Sym{
2271 .{
2272 .st_name = self.local_symbols.items[index].st_name,
2273 .st_value = @intCast(u32, self.local_symbols.items[index].st_value),
2274 .st_size = @intCast(u32, self.local_symbols.items[index].st_size),
2275 .st_info = self.local_symbols.items[index].st_info,
2276 .st_other = self.local_symbols.items[index].st_other,
2277 .st_shndx = self.local_symbols.items[index].st_shndx,
2278 },
2279 };
2280 if (foreign_endian) {
2281 bswapAllFields(elf.Elf32_Sym, &sym[0]);
2282 }
2283 const off = syms_sect.sh_offset + @sizeOf(elf.Elf32_Sym) * index;
2284 try self.base.file.?.pwriteAll(mem.sliceAsBytes(sym[0..1]), off);
2285 },
2286 .p64 => {
2287 var sym = [1]elf.Elf64_Sym{self.local_symbols.items[index]};
2288 if (foreign_endian) {
2289 bswapAllFields(elf.Elf64_Sym, &sym[0]);
2290 }
2291 const off = syms_sect.sh_offset + @sizeOf(elf.Elf64_Sym) * index;
2292 try self.base.file.?.pwriteAll(mem.sliceAsBytes(sym[0..1]), off);
2293 },
2294 }
2295}
2296
2297fn writeAllGlobalSymbols(self: *Elf) !void {
2298 const syms_sect = &self.sections.items[self.symtab_section_index.?];
2299 const sym_size: u64 = switch (self.ptr_width) {
2300 .p32 => @sizeOf(elf.Elf32_Sym),
2301 .p64 => @sizeOf(elf.Elf64_Sym),
2302 };
2303 const foreign_endian = self.base.options.target.cpu.arch.endian() != std.Target.current.cpu.arch.endian();
2304 const global_syms_off = syms_sect.sh_offset + self.local_symbols.items.len * sym_size;
2305 switch (self.ptr_width) {
2306 .p32 => {
2307 const buf = try self.base.allocator.alloc(elf.Elf32_Sym, self.global_symbols.items.len);
2308 defer self.base.allocator.free(buf);
2309
2310 for (buf) |*sym, i| {
2311 sym.* = .{
2312 .st_name = self.global_symbols.items[i].st_name,
2313 .st_value = @intCast(u32, self.global_symbols.items[i].st_value),
2314 .st_size = @intCast(u32, self.global_symbols.items[i].st_size),
2315 .st_info = self.global_symbols.items[i].st_info,
2316 .st_other = self.global_symbols.items[i].st_other,
2317 .st_shndx = self.global_symbols.items[i].st_shndx,
2318 };
2319 if (foreign_endian) {
2320 bswapAllFields(elf.Elf32_Sym, sym);
2321 }
2322 }
2323 try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), global_syms_off);
2324 },
2325 .p64 => {
2326 const buf = try self.base.allocator.alloc(elf.Elf64_Sym, self.global_symbols.items.len);
2327 defer self.base.allocator.free(buf);
2328
2329 for (buf) |*sym, i| {
2330 sym.* = .{
2331 .st_name = self.global_symbols.items[i].st_name,
2332 .st_value = self.global_symbols.items[i].st_value,
2333 .st_size = self.global_symbols.items[i].st_size,
2334 .st_info = self.global_symbols.items[i].st_info,
2335 .st_other = self.global_symbols.items[i].st_other,
2336 .st_shndx = self.global_symbols.items[i].st_shndx,
2337 };
2338 if (foreign_endian) {
2339 bswapAllFields(elf.Elf64_Sym, sym);
2340 }
2341 }
2342 try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), global_syms_off);
2343 },
2344 }
2345}
2346
2347fn ptrWidthBytes(self: Elf) u8 {
2348 return switch (self.ptr_width) {
2349 .p32 => 4,
2350 .p64 => 8,
2351 };
2352}
2353
2354/// The reloc offset for the virtual address of a function in its Line Number Program.
2355/// Size is a virtual address integer.
2356const dbg_line_vaddr_reloc_index = 3;
2357/// The reloc offset for the virtual address of a function in its .debug_info TAG_subprogram.
2358/// Size is a virtual address integer.
2359const dbg_info_low_pc_reloc_index = 1;
2360
2361/// The reloc offset for the line offset of a function from the previous function's line.
2362/// It's a fixed-size 4-byte ULEB128.
2363fn getRelocDbgLineOff(self: Elf) usize {
2364 return dbg_line_vaddr_reloc_index + self.ptrWidthBytes() + 1;
2365}
2366
2367fn getRelocDbgFileIndex(self: Elf) usize {
2368 return self.getRelocDbgLineOff() + 5;
2369}
2370
2371fn getRelocDbgInfoSubprogramHighPC(self: Elf) u32 {
2372 return dbg_info_low_pc_reloc_index + self.ptrWidthBytes();
2373}
2374
2375fn dbgLineNeededHeaderBytes(self: Elf) u32 {
2376 const directory_entry_format_count = 1;
2377 const file_name_entry_format_count = 1;
2378 const directory_count = 1;
2379 const file_name_count = 1;
2380 return @intCast(u32, 53 + directory_entry_format_count * 2 + file_name_entry_format_count * 2 +
2381 directory_count * 8 + file_name_count * 8 +
2382 // These are encoded as DW.FORM_string rather than DW.FORM_strp as we would like
2383 // because of a workaround for readelf and gdb failing to understand DWARFv5 correctly.
2384 self.base.options.root_pkg.root_src_dir_path.len +
2385 self.base.options.root_pkg.root_src_path.len);
2386}
2387
2388fn dbgInfoNeededHeaderBytes(self: Elf) u32 {
2389 return 120;
2390}
2391
2392const min_nop_size = 2;
2393
2394/// Writes to the file a buffer, prefixed and suffixed by the specified number of
2395/// bytes of NOPs. Asserts each padding size is at least `min_nop_size` and total padding bytes
2396/// are less than 126,976 bytes (if this limit is ever reached, this function can be
2397/// improved to make more than one pwritev call, or the limit can be raised by a fixed
2398/// amount by increasing the length of `vecs`).
2399fn pwriteDbgLineNops(
2400 self: *Elf,
2401 prev_padding_size: usize,
2402 buf: []const u8,
2403 next_padding_size: usize,
2404 offset: usize,
2405) !void {
2406 const tracy = trace(@src());
2407 defer tracy.end();
2408
2409 const page_of_nops = [1]u8{DW.LNS_negate_stmt} ** 4096;
2410 const three_byte_nop = [3]u8{ DW.LNS_advance_pc, 0b1000_0000, 0 };
2411 var vecs: [32]std.os.iovec_const = undefined;
2412 var vec_index: usize = 0;
2413 {
2414 var padding_left = prev_padding_size;
2415 if (padding_left % 2 != 0) {
2416 vecs[vec_index] = .{
2417 .iov_base = &three_byte_nop,
2418 .iov_len = three_byte_nop.len,
2419 };
2420 vec_index += 1;
2421 padding_left -= three_byte_nop.len;
2422 }
2423 while (padding_left > page_of_nops.len) {
2424 vecs[vec_index] = .{
2425 .iov_base = &page_of_nops,
2426 .iov_len = page_of_nops.len,
2427 };
2428 vec_index += 1;
2429 padding_left -= page_of_nops.len;
2430 }
2431 if (padding_left > 0) {
2432 vecs[vec_index] = .{
2433 .iov_base = &page_of_nops,
2434 .iov_len = padding_left,
2435 };
2436 vec_index += 1;
2437 }
2438 }
2439
2440 vecs[vec_index] = .{
2441 .iov_base = buf.ptr,
2442 .iov_len = buf.len,
2443 };
2444 vec_index += 1;
2445
2446 {
2447 var padding_left = next_padding_size;
2448 if (padding_left % 2 != 0) {
2449 vecs[vec_index] = .{
2450 .iov_base = &three_byte_nop,
2451 .iov_len = three_byte_nop.len,
2452 };
2453 vec_index += 1;
2454 padding_left -= three_byte_nop.len;
2455 }
2456 while (padding_left > page_of_nops.len) {
2457 vecs[vec_index] = .{
2458 .iov_base = &page_of_nops,
2459 .iov_len = page_of_nops.len,
2460 };
2461 vec_index += 1;
2462 padding_left -= page_of_nops.len;
2463 }
2464 if (padding_left > 0) {
2465 vecs[vec_index] = .{
2466 .iov_base = &page_of_nops,
2467 .iov_len = padding_left,
2468 };
2469 vec_index += 1;
2470 }
2471 }
2472 try self.base.file.?.pwritevAll(vecs[0..vec_index], offset - prev_padding_size);
2473}
2474
2475/// Writes to the file a buffer, prefixed and suffixed by the specified number of
2476/// bytes of padding.
2477fn pwriteDbgInfoNops(
2478 self: *Elf,
2479 prev_padding_size: usize,
2480 buf: []const u8,
2481 next_padding_size: usize,
2482 trailing_zero: bool,
2483 offset: usize,
2484) !void {
2485 const tracy = trace(@src());
2486 defer tracy.end();
2487
2488 const page_of_nops = [1]u8{abbrev_pad1} ** 4096;
2489 var vecs: [32]std.os.iovec_const = undefined;
2490 var vec_index: usize = 0;
2491 {
2492 var padding_left = prev_padding_size;
2493 while (padding_left > page_of_nops.len) {
2494 vecs[vec_index] = .{
2495 .iov_base = &page_of_nops,
2496 .iov_len = page_of_nops.len,
2497 };
2498 vec_index += 1;
2499 padding_left -= page_of_nops.len;
2500 }
2501 if (padding_left > 0) {
2502 vecs[vec_index] = .{
2503 .iov_base = &page_of_nops,
2504 .iov_len = padding_left,
2505 };
2506 vec_index += 1;
2507 }
2508 }
2509
2510 vecs[vec_index] = .{
2511 .iov_base = buf.ptr,
2512 .iov_len = buf.len,
2513 };
2514 vec_index += 1;
2515
2516 {
2517 var padding_left = next_padding_size;
2518 while (padding_left > page_of_nops.len) {
2519 vecs[vec_index] = .{
2520 .iov_base = &page_of_nops,
2521 .iov_len = page_of_nops.len,
2522 };
2523 vec_index += 1;
2524 padding_left -= page_of_nops.len;
2525 }
2526 if (padding_left > 0) {
2527 vecs[vec_index] = .{
2528 .iov_base = &page_of_nops,
2529 .iov_len = padding_left,
2530 };
2531 vec_index += 1;
2532 }
2533 }
2534
2535 if (trailing_zero) {
2536 var zbuf = [1]u8{0};
2537 vecs[vec_index] = .{
2538 .iov_base = &zbuf,
2539 .iov_len = zbuf.len,
2540 };
2541 vec_index += 1;
2542 }
2543
2544 try self.base.file.?.pwritevAll(vecs[0..vec_index], offset - prev_padding_size);
2545}
2546
2547/// Saturating multiplication
2548fn satMul(a: anytype, b: anytype) @TypeOf(a, b) {
2549 const T = @TypeOf(a, b);
2550 return std.math.mul(T, a, b) catch std.math.maxInt(T);
2551}
2552
2553fn bswapAllFields(comptime S: type, ptr: *S) void {
2554 @panic("TODO implement bswapAllFields");
2555}
2556
2557fn progHeaderTo32(phdr: elf.Elf64_Phdr) elf.Elf32_Phdr {
2558 return .{
2559 .p_type = phdr.p_type,
2560 .p_flags = phdr.p_flags,
2561 .p_offset = @intCast(u32, phdr.p_offset),
2562 .p_vaddr = @intCast(u32, phdr.p_vaddr),
2563 .p_paddr = @intCast(u32, phdr.p_paddr),
2564 .p_filesz = @intCast(u32, phdr.p_filesz),
2565 .p_memsz = @intCast(u32, phdr.p_memsz),
2566 .p_align = @intCast(u32, phdr.p_align),
2567 };
2568}
2569
2570fn sectHeaderTo32(shdr: elf.Elf64_Shdr) elf.Elf32_Shdr {
2571 return .{
2572 .sh_name = shdr.sh_name,
2573 .sh_type = shdr.sh_type,
2574 .sh_flags = @intCast(u32, shdr.sh_flags),
2575 .sh_addr = @intCast(u32, shdr.sh_addr),
2576 .sh_offset = @intCast(u32, shdr.sh_offset),
2577 .sh_size = @intCast(u32, shdr.sh_size),
2578 .sh_link = shdr.sh_link,
2579 .sh_info = shdr.sh_info,
2580 .sh_addralign = @intCast(u32, shdr.sh_addralign),
2581 .sh_entsize = @intCast(u32, shdr.sh_entsize),
2582 };
2583}
src-self-hosted/link/MachO.zig+128-5
...@@ -4,15 +4,29 @@ const std = @import("std");...@@ -4,15 +4,29 @@ const std = @import("std");
4const Allocator = std.mem.Allocator;4const Allocator = std.mem.Allocator;
5const assert = std.debug.assert;5const assert = std.debug.assert;
6const fs = std.fs;6const fs = std.fs;
7const log = std.log.scoped(.link);
8const macho = std.macho;
9const math = std.math;
10const mem = std.mem;
711
8const Module = @import("../Module.zig");12const Module = @import("../Module.zig");
9const link = @import("../link.zig");13const link = @import("../link.zig");
10const File = link.File;14const File = link.File;
1115
12pub const base_tag: Tag = File.Tag.macho;16pub const base_tag: File.Tag = File.Tag.macho;
1317
14base: File,18base: File,
1519
20/// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write.
21/// Same order as in the file.
22segment_cmds: std.ArrayListUnmanaged(macho.segment_command_64) = std.ArrayListUnmanaged(macho.segment_command_64){},
23
24/// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write.
25/// Same order as in the file.
26sections: std.ArrayListUnmanaged(macho.section_64) = std.ArrayListUnmanaged(macho.section_64){},
27
28entry_addr: ?u64 = null,
29
16error_flags: File.ErrorFlags = File.ErrorFlags{},30error_flags: File.ErrorFlags = File.ErrorFlags{},
1731
18pub const TextBlock = struct {32pub const TextBlock = struct {
...@@ -67,15 +81,120 @@ fn openFile(allocator: *Allocator, file: fs.File, options: link.Options) !MachO...@@ -67,15 +81,120 @@ fn openFile(allocator: *Allocator, file: fs.File, options: link.Options) !MachO
67/// Returns an error if `file` is not already open with +read +write +seek abilities.81/// Returns an error if `file` is not already open with +read +write +seek abilities.
68fn createFile(allocator: *Allocator, file: fs.File, options: link.Options) !MachO {82fn createFile(allocator: *Allocator, file: fs.File, options: link.Options) !MachO {
69 switch (options.output_mode) {83 switch (options.output_mode) {
70 .Exe => return error.TODOImplementWritingMachOExeFiles,84 .Exe => {},
71 .Obj => return error.TODOImplementWritingMachOObjFiles,85 .Obj => {},
72 .Lib => return error.TODOImplementWritingLibFiles,86 .Lib => return error.TODOImplementWritingLibFiles,
73 }87 }
88
89 var self: MachO = .{
90 .base = .{
91 .file = file,
92 .tag = .macho,
93 .options = options,
94 .allocator = allocator,
95 },
96 };
97 errdefer self.deinit();
98
99 if (options.output_mode == .Exe) {
100 // The first segment command for executables is always a __PAGEZERO segment.
101 try self.segment_cmds.append(allocator, .{
102 .cmd = macho.LC_SEGMENT_64,
103 .cmdsize = @sizeOf(macho.segment_command_64),
104 .segname = self.makeString("__PAGEZERO"),
105 .vmaddr = 0,
106 .vmsize = 0,
107 .fileoff = 0,
108 .filesize = 0,
109 .maxprot = 0,
110 .initprot = 0,
111 .nsects = 0,
112 .flags = 0,
113 });
114 }
115
116 return self;
117}
118
119fn makeString(self: *MachO, comptime bytes: []const u8) [16]u8 {
120 var buf: [16]u8 = undefined;
121 if (bytes.len > buf.len) @compileError("MachO segment/section name too long");
122 mem.copy(u8, buf[0..], bytes);
123 return buf;
124}
125
126fn writeMachOHeader(self: *MachO) !void {
127 var hdr: macho.mach_header_64 = undefined;
128 hdr.magic = macho.MH_MAGIC_64;
129
130 const CpuInfo = struct {
131 cpu_type: macho.cpu_type_t,
132 cpu_subtype: macho.cpu_subtype_t,
133 };
134
135 const cpu_info: CpuInfo = switch (self.base.options.target.cpu.arch) {
136 .aarch64 => .{
137 .cpu_type = macho.CPU_TYPE_ARM64,
138 .cpu_subtype = macho.CPU_SUBTYPE_ARM_ALL,
139 },
140 .x86_64 => .{
141 .cpu_type = macho.CPU_TYPE_X86_64,
142 .cpu_subtype = macho.CPU_SUBTYPE_X86_64_ALL,
143 },
144 else => return error.UnsupportedMachOArchitecture,
145 };
146 hdr.cputype = cpu_info.cpu_type;
147 hdr.cpusubtype = cpu_info.cpu_subtype;
148
149 const filetype: u32 = switch (self.base.options.output_mode) {
150 .Exe => macho.MH_EXECUTE,
151 .Obj => macho.MH_OBJECT,
152 .Lib => switch (self.base.options.link_mode) {
153 .Static => return error.TODOStaticLibMachOType,
154 .Dynamic => macho.MH_DYLIB,
155 },
156 };
157 hdr.filetype = filetype;
158
159 // TODO consider other commands
160 const ncmds = try math.cast(u32, self.segment_cmds.items.len);
161 hdr.ncmds = ncmds;
162 hdr.sizeofcmds = ncmds * @sizeOf(macho.segment_command_64);
163
164 // TODO should these be set to something else?
165 hdr.flags = 0;
166 hdr.reserved = 0;
167
168 try self.base.file.?.pwriteAll(@ptrCast([*]const u8, &hdr)[0..@sizeOf(macho.mach_header_64)], 0);
74}169}
75170
76pub fn flush(self: *MachO, module: *Module) !void {}171pub fn flush(self: *MachO, module: *Module) !void {
172 // TODO implement flush
173 {
174 const buf = try self.base.allocator.alloc(macho.segment_command_64, self.segment_cmds.items.len);
175 defer self.base.allocator.free(buf);
176
177 for (buf) |*seg, i| {
178 seg.* = self.segment_cmds.items[i];
179 }
180
181 try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), @sizeOf(macho.mach_header_64));
182 }
183
184 if (self.entry_addr == null and self.base.options.output_mode == .Exe) {
185 log.debug("flushing. no_entry_point_found = true\n", .{});
186 self.error_flags.no_entry_point_found = true;
187 } else {
188 log.debug("flushing. no_entry_point_found = false\n", .{});
189 self.error_flags.no_entry_point_found = false;
190 try self.writeMachOHeader();
191 }
192}
77193
78pub fn deinit(self: *MachO) void {}194pub fn deinit(self: *MachO) void {
195 self.segment_cmds.deinit(self.base.allocator);
196 self.sections.deinit(self.base.allocator);
197}
79198
80pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void {}199pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void {}
81200
...@@ -91,3 +210,7 @@ pub fn updateDeclExports(...@@ -91,3 +210,7 @@ pub fn updateDeclExports(
91) !void {}210) !void {}
92211
93pub fn freeDecl(self: *MachO, decl: *Module.Decl) void {}212pub fn freeDecl(self: *MachO, decl: *Module.Decl) void {}
213
214pub fn getDeclVAddr(self: *MachO, decl: *const Module.Decl) u64 {
215 @panic("TODO implement getDeclVAddr for MachO");
216}
src-self-hosted/link/Wasm.zig+158-360
...@@ -32,19 +32,22 @@ const spec = struct {...@@ -32,19 +32,22 @@ const spec = struct {
32pub const base_tag = link.File.Tag.wasm;32pub const base_tag = link.File.Tag.wasm;
3333
34pub const FnData = struct {34pub const FnData = struct {
35 funcidx: u32,35 /// Generated code for the type of the function
36 functype: std.ArrayListUnmanaged(u8) = .{},
37 /// Generated code for the body of the function
38 code: std.ArrayListUnmanaged(u8) = .{},
39 /// Locations in the generated code where function indexes must be filled in.
40 /// This must be kept ordered by offset.
41 idx_refs: std.ArrayListUnmanaged(struct { offset: u32, decl: *Module.Decl }) = .{},
36};42};
3743
38base: link.File,44base: link.File,
3945
40types: Types,46/// List of all function Decls to be written to the output file. The index of
41funcs: Funcs,47/// each Decl in this list at the time of writing the binary is used as the
42exports: Exports,48/// function index.
4349/// TODO: can/should we access some data structure in Module directly?
44/// Array over the section structs used in the various sections above to50funcs: std.ArrayListUnmanaged(*Module.Decl) = .{},
45/// allow iteration when shifting sections to make space.
46/// TODO: this should eventually be size 11 when we use all the sections.
47sections: [4]*Section,
4851
49pub fn openPath(allocator: *Allocator, dir: fs.Dir, sub_path: []const u8, options: link.Options) !*link.File {52pub fn openPath(allocator: *Allocator, dir: fs.Dir, sub_path: []const u8, options: link.Options) !*link.File {
50 assert(options.object_format == .wasm);53 assert(options.object_format == .wasm);
...@@ -58,10 +61,6 @@ pub fn openPath(allocator: *Allocator, dir: fs.Dir, sub_path: []const u8, option...@@ -58,10 +61,6 @@ pub fn openPath(allocator: *Allocator, dir: fs.Dir, sub_path: []const u8, option
5861
59 try file.writeAll(&(spec.magic ++ spec.version));62 try file.writeAll(&(spec.magic ++ spec.version));
6063
61 // TODO: this should vary depending on the section and be less arbitrary
62 const size = 1024;
63 const offset = @sizeOf(@TypeOf(spec.magic ++ spec.version));
64
65 wasm.* = .{64 wasm.* = .{
66 .base = .{65 .base = .{
67 .tag = .wasm,66 .tag = .wasm,
...@@ -69,52 +68,42 @@ pub fn openPath(allocator: *Allocator, dir: fs.Dir, sub_path: []const u8, option...@@ -69,52 +68,42 @@ pub fn openPath(allocator: *Allocator, dir: fs.Dir, sub_path: []const u8, option
69 .file = file,68 .file = file,
70 .allocator = allocator,69 .allocator = allocator,
71 },70 },
72
73 .types = try Types.init(file, offset, size),
74 .funcs = try Funcs.init(file, offset + size, size, offset + 3 * size, size),
75 .exports = try Exports.init(file, offset + 2 * size, size),
76
77 // These must be ordered as they will appear in the output file
78 .sections = [_]*Section{
79 &wasm.types.typesec.section,
80 &wasm.funcs.funcsec,
81 &wasm.exports.exportsec,
82 &wasm.funcs.codesec.section,
83 },
84 };71 };
8572
86 try file.setEndPos(offset + 4 * size);
87
88 return &wasm.base;73 return &wasm.base;
89}74}
9075
91pub fn deinit(self: *Wasm) void {76pub fn deinit(self: *Wasm) void {
92 self.types.deinit();77 for (self.funcs.items) |decl| {
93 self.funcs.deinit();78 decl.fn_link.wasm.?.functype.deinit(self.base.allocator);
79 decl.fn_link.wasm.?.code.deinit(self.base.allocator);
80 decl.fn_link.wasm.?.idx_refs.deinit(self.base.allocator);
81 }
82 self.funcs.deinit(self.base.allocator);
94}83}
9584
85// Generate code for the Decl, storing it in memory to be later written to
86// the file on flush().
96pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void {87pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void {
97 if (decl.typed_value.most_recent.typed_value.ty.zigTypeTag() != .Fn)88 if (decl.typed_value.most_recent.typed_value.ty.zigTypeTag() != .Fn)
98 return error.TODOImplementNonFnDeclsForWasm;89 return error.TODOImplementNonFnDeclsForWasm;
9990
100 if (decl.fn_link.wasm) |fn_data| {91 if (decl.fn_link.wasm) |*fn_data| {
101 self.funcs.free(fn_data.funcidx);92 fn_data.functype.items.len = 0;
102 }93 fn_data.code.items.len = 0;
10394 fn_data.idx_refs.items.len = 0;
104 var buf = std.ArrayList(u8).init(self.base.allocator);95 } else {
105 defer buf.deinit();96 decl.fn_link.wasm = .{};
10697 try self.funcs.append(self.base.allocator, decl);
107 try codegen.genFunctype(&buf, decl);98 }
108 const typeidx = try self.types.new(buf.items);99 const fn_data = &decl.fn_link.wasm.?;
109 buf.items.len = 0;100
110101 var managed_functype = fn_data.functype.toManaged(self.base.allocator);
111 try codegen.genCode(&buf, decl);102 var managed_code = fn_data.code.toManaged(self.base.allocator);
112 const funcidx = try self.funcs.new(typeidx, buf.items);103 try codegen.genFunctype(&managed_functype, decl);
113104 try codegen.genCode(&managed_code, decl);
114 decl.fn_link.wasm = .{ .funcidx = funcidx };105 fn_data.functype = managed_functype.toUnmanaged();
115106 fn_data.code = managed_code.toUnmanaged();
116 // TODO: we should be more smart and set this only when needed
117 self.exports.dirty = true;
118}107}
119108
120pub fn updateDeclExports(109pub fn updateDeclExports(
...@@ -122,332 +111,141 @@ pub fn updateDeclExports(...@@ -122,332 +111,141 @@ pub fn updateDeclExports(
122 module: *Module,111 module: *Module,
123 decl: *const Module.Decl,112 decl: *const Module.Decl,
124 exports: []const *Module.Export,113 exports: []const *Module.Export,
125) !void {114) !void {}
126 self.exports.dirty = true;
127}
128115
129pub fn freeDecl(self: *Wasm, decl: *Module.Decl) void {116pub fn freeDecl(self: *Wasm, decl: *Module.Decl) void {
130 // TODO: remove this assert when non-function Decls are implemented117 // TODO: remove this assert when non-function Decls are implemented
131 assert(decl.typed_value.most_recent.typed_value.ty.zigTypeTag() == .Fn);118 assert(decl.typed_value.most_recent.typed_value.ty.zigTypeTag() == .Fn);
132 if (decl.fn_link.wasm) |fn_data| {119 _ = self.funcs.swapRemove(self.getFuncidx(decl).?);
133 self.funcs.free(fn_data.funcidx);120 decl.fn_link.wasm.?.functype.deinit(self.base.allocator);
134 decl.fn_link.wasm = null;121 decl.fn_link.wasm.?.code.deinit(self.base.allocator);
135 }122 decl.fn_link.wasm.?.idx_refs.deinit(self.base.allocator);
123 decl.fn_link.wasm = null;
136}124}
137125
138pub fn flush(self: *Wasm, module: *Module) !void {126pub fn flush(self: *Wasm, module: *Module) !void {
139 if (self.exports.dirty) try self.exports.writeAll(module);127 const file = self.base.file.?;
140}128 const header_size = 5 + 1;
141129
142/// This struct describes the location of a named section + custom section130 // No need to rewrite the magic/version header
143/// padding in the output file. This is all the data we need to allow for131 try file.setEndPos(@sizeOf(@TypeOf(spec.magic ++ spec.version)));
144/// shifting sections around when padding runs out.132 try file.seekTo(@sizeOf(@TypeOf(spec.magic ++ spec.version)));
145const Section = struct {133
146 /// The size of a section header: 1 byte section id + 5 bytes134 // Type section
147 /// for the fixed-width ULEB128 encoded contents size.135 {
148 const header_size = 1 + 5;136 const header_offset = try reserveVecSectionHeader(file);
149 /// Offset of the section id byte from the start of the file.137 for (self.funcs.items) |decl| {
150 offset: u64,138 try file.writeAll(decl.fn_link.wasm.?.functype.items);
151 /// Size of the section, including the header and directly
152 /// following custom section used for padding if any.
153 size: u64,
154
155 /// Resize the usable part of the section, handling the following custom
156 /// section used for padding. If there is not enough padding left, shift
157 /// all following sections to make space. Takes the current and target
158 /// contents sizes of the section as arguments.
159 fn resize(self: *Section, file: fs.File, current: u32, target: u32) !void {
160 // Section header + target contents size + custom section header
161 // + custom section name + empty custom section > owned chunk of the file
162 if (header_size + target + header_size + 1 + 0 > self.size)
163 return error.TODOImplementSectionShifting;
164
165 const new_custom_start = self.offset + header_size + target;
166 const new_custom_contents_size = self.size - target - 2 * header_size;
167 assert(new_custom_contents_size >= 1);
168 // +1 for the name of the custom section, which we set to an empty string
169 var custom_header: [header_size + 1]u8 = undefined;
170 custom_header[0] = spec.custom_id;
171 leb.writeUnsignedFixed(5, custom_header[1..header_size], @intCast(u32, new_custom_contents_size));
172 custom_header[header_size] = 0;
173 try file.pwriteAll(&custom_header, new_custom_start);
174 }
175};
176
177/// This can be used to manage the contents of any section which uses a vector
178/// of contents. This interface maintains index stability while allowing for
179/// reuse of "dead" indexes.
180const VecSection = struct {
181 /// Represents a single entry in the vector (e.g. a type in the type section)
182 const Entry = struct {
183 /// Offset from the start of the section contents in bytes
184 offset: u32,
185 /// Size in bytes of the entry
186 size: u32,
187 };
188 section: Section,
189 /// Size in bytes of the contents of the section. Does not include
190 /// the "header" containing the section id and this value.
191 contents_size: u32,
192 /// List of all entries in the contents of the section.
193 entries: std.ArrayListUnmanaged(Entry) = std.ArrayListUnmanaged(Entry){},
194 /// List of indexes of unreferenced entries which may be
195 /// overwritten and reused.
196 dead_list: std.ArrayListUnmanaged(u32) = std.ArrayListUnmanaged(u32){},
197
198 /// Write the headers of the section and custom padding section
199 fn init(comptime section_id: u8, file: fs.File, offset: u64, initial_size: u64) !VecSection {
200 // section id, section size, empty vector, custom section id,
201 // custom section size, empty custom section name
202 var initial_data: [1 + 5 + 5 + 1 + 5 + 1]u8 = undefined;
203
204 assert(initial_size >= initial_data.len);
205
206 comptime var i = 0;
207 initial_data[i] = section_id;
208 i += 1;
209 leb.writeUnsignedFixed(5, initial_data[i..(i + 5)], 5);
210 i += 5;
211 leb.writeUnsignedFixed(5, initial_data[i..(i + 5)], 0);
212 i += 5;
213 initial_data[i] = spec.custom_id;
214 i += 1;
215 leb.writeUnsignedFixed(5, initial_data[i..(i + 5)], @intCast(u32, initial_size - @sizeOf(@TypeOf(initial_data))));
216 i += 5;
217 initial_data[i] = 0;
218
219 try file.pwriteAll(&initial_data, offset);
220
221 return VecSection{
222 .section = .{
223 .offset = offset,
224 .size = initial_size,
225 },
226 .contents_size = 5,
227 };
228 }
229
230 fn deinit(self: *VecSection, allocator: *Allocator) void {
231 self.entries.deinit(allocator);
232 self.dead_list.deinit(allocator);
233 }
234
235 /// Write a new entry into the file, returning the index used.
236 fn addEntry(self: *VecSection, file: fs.File, allocator: *Allocator, data: []const u8) !u32 {
237 // First look for a dead entry we can reuse
238 for (self.dead_list.items) |dead_idx, i| {
239 const dead_entry = &self.entries.items[dead_idx];
240 if (dead_entry.size == data.len) {
241 // Found a dead entry of the right length, overwrite it
242 try file.pwriteAll(data, self.section.offset + Section.header_size + dead_entry.offset);
243 _ = self.dead_list.swapRemove(i);
244 return dead_idx;
245 }
246 }139 }
247140 try writeVecSectionHeader(
248 // TODO: We can be more efficient if we special-case one or141 file,
249 // more consecutive dead entries at the end of the vector.142 header_offset,
250143 spec.types_id,
251 // We failed to find a dead entry to reuse, so write the new144 @intCast(u32, (try file.getPos()) - header_offset - header_size),
252 // entry to the end of the section.145 @intCast(u32, self.funcs.items.len),
253 try self.section.resize(file, self.contents_size, self.contents_size + @intCast(u32, data.len));146 );
254 try file.pwriteAll(data, self.section.offset + Section.header_size + self.contents_size);147 }
255 try self.entries.append(allocator, .{148
256 .offset = self.contents_size,149 // Function section
257 .size = @intCast(u32, data.len),150 {
258 });151 const header_offset = try reserveVecSectionHeader(file);
259 self.contents_size += @intCast(u32, data.len);152 const writer = file.writer();
260 // Make sure the dead list always has enough space to store all free'd153 for (self.funcs.items) |_, typeidx| try leb.writeULEB128(writer, @intCast(u32, typeidx));
261 // entries. This makes it so that delEntry() cannot fail.154 try writeVecSectionHeader(
262 // TODO: figure out a better way that doesn't waste as much memory155 file,
263 try self.dead_list.ensureCapacity(allocator, self.entries.items.len);156 header_offset,
264157 spec.funcs_id,
265 // Update the size in the section header and the item count of158 @intCast(u32, (try file.getPos()) - header_offset - header_size),
266 // the contents vector.159 @intCast(u32, self.funcs.items.len),
267 var size_and_count: [10]u8 = undefined;160 );
268 leb.writeUnsignedFixed(5, size_and_count[0..5], self.contents_size);161 }
269 leb.writeUnsignedFixed(5, size_and_count[5..], @intCast(u32, self.entries.items.len));162
270 try file.pwriteAll(&size_and_count, self.section.offset + 1);163 // Export section
271164 {
272 return @intCast(u32, self.entries.items.len - 1);165 const header_offset = try reserveVecSectionHeader(file);
273 }166 const writer = file.writer();
274167 var count: u32 = 0;
275 /// Mark the type referenced by the given index as dead.
276 fn delEntry(self: *VecSection, index: u32) void {
277 self.dead_list.appendAssumeCapacity(index);
278 }
279};
280
281const Types = struct {
282 typesec: VecSection,
283
284 fn init(file: fs.File, offset: u64, initial_size: u64) !Types {
285 return Types{ .typesec = try VecSection.init(spec.types_id, file, offset, initial_size) };
286 }
287
288 fn deinit(self: *Types) void {
289 const wasm = @fieldParentPtr(Wasm, "types", self);
290 self.typesec.deinit(wasm.base.allocator);
291 }
292
293 fn new(self: *Types, data: []const u8) !u32 {
294 const wasm = @fieldParentPtr(Wasm, "types", self);
295 return self.typesec.addEntry(wasm.base.file.?, wasm.base.allocator, data);
296 }
297
298 fn free(self: *Types, typeidx: u32) void {
299 self.typesec.delEntry(typeidx);
300 }
301};
302
303const Funcs = struct {
304 /// This section needs special handling to keep the indexes matching with
305 /// the codesec, so we cant just use a VecSection.
306 funcsec: Section,
307 /// The typeidx stored for each function, indexed by funcidx.
308 func_types: std.ArrayListUnmanaged(u32) = std.ArrayListUnmanaged(u32){},
309 codesec: VecSection,
310
311 fn init(file: fs.File, funcs_offset: u64, funcs_size: u64, code_offset: u64, code_size: u64) !Funcs {
312 return Funcs{
313 .funcsec = (try VecSection.init(spec.funcs_id, file, funcs_offset, funcs_size)).section,
314 .codesec = try VecSection.init(spec.code_id, file, code_offset, code_size),
315 };
316 }
317
318 fn deinit(self: *Funcs) void {
319 const wasm = @fieldParentPtr(Wasm, "funcs", self);
320 self.func_types.deinit(wasm.base.allocator);
321 self.codesec.deinit(wasm.base.allocator);
322 }
323
324 /// Add a new function to the binary, first finding space for and writing
325 /// the code then writing the typeidx to the corresponding index in the
326 /// funcsec. Returns the function index used.
327 fn new(self: *Funcs, typeidx: u32, code: []const u8) !u32 {
328 const wasm = @fieldParentPtr(Wasm, "funcs", self);
329 const file = wasm.base.file.?;
330 const allocator = wasm.base.allocator;
331
332 assert(self.func_types.items.len == self.codesec.entries.items.len);
333
334 // TODO: consider nop-padding the code if there is a close but not perfect fit
335 const funcidx = try self.codesec.addEntry(file, allocator, code);
336
337 if (self.func_types.items.len < self.codesec.entries.items.len) {
338 // u32 vector length + funcs_count u32s in the vector
339 const current = 5 + @intCast(u32, self.func_types.items.len) * 5;
340 try self.funcsec.resize(file, current, current + 5);
341 try self.func_types.append(allocator, typeidx);
342
343 // Update the size in the section header and the item count of
344 // the contents vector.
345 const count = @intCast(u32, self.func_types.items.len);
346 var size_and_count: [10]u8 = undefined;
347 leb.writeUnsignedFixed(5, size_and_count[0..5], 5 + count * 5);
348 leb.writeUnsignedFixed(5, size_and_count[5..], count);
349 try file.pwriteAll(&size_and_count, self.funcsec.offset + 1);
350 } else {
351 // We are overwriting a dead function and may now free the type
352 wasm.types.free(self.func_types.items[funcidx]);
353 }
354
355 assert(self.func_types.items.len == self.codesec.entries.items.len);
356
357 var typeidx_leb: [5]u8 = undefined;
358 leb.writeUnsignedFixed(5, &typeidx_leb, typeidx);
359 try file.pwriteAll(&typeidx_leb, self.funcsec.offset + Section.header_size + 5 + funcidx * 5);
360
361 return funcidx;
362 }
363
364 fn free(self: *Funcs, funcidx: u32) void {
365 self.codesec.delEntry(funcidx);
366 }
367};
368
369/// Exports are tricky. We can't leave dead entries in the binary as they
370/// would obviously be visible from the execution environment. The simplest
371/// way to work around this is to re-emit the export section whenever
372/// something changes. This also makes it easier to ensure exported function
373/// and global indexes are updated as they change.
374const Exports = struct {
375 exportsec: Section,
376 /// Size in bytes of the contents of the section. Does not include
377 /// the "header" containing the section id and this value.
378 contents_size: u32,
379 /// If this is true, then exports will be rewritten on flush()
380 dirty: bool,
381
382 fn init(file: fs.File, offset: u64, initial_size: u64) !Exports {
383 return Exports{
384 .exportsec = (try VecSection.init(spec.exports_id, file, offset, initial_size)).section,
385 .contents_size = 5,
386 .dirty = false,
387 };
388 }
389
390 fn writeAll(self: *Exports, module: *Module) !void {
391 const wasm = @fieldParentPtr(Wasm, "exports", self);
392 const file = wasm.base.file.?;
393 var buf: [5]u8 = undefined;
394
395 // First ensure the section is the right size
396 var export_count: u32 = 0;
397 var new_contents_size: u32 = 5;
398 for (module.decl_exports.entries.items) |entry| {168 for (module.decl_exports.entries.items) |entry| {
399 for (entry.value) |e| {169 for (entry.value) |exprt| {
400 export_count += 1;170 // Export name length + name
401 new_contents_size += calcSize(e);171 try leb.writeULEB128(writer, @intCast(u32, exprt.options.name.len));
172 try writer.writeAll(exprt.options.name);
173
174 switch (exprt.exported_decl.typed_value.most_recent.typed_value.ty.zigTypeTag()) {
175 .Fn => {
176 // Type of the export
177 try writer.writeByte(0x00);
178 // Exported function index
179 try leb.writeULEB128(writer, self.getFuncidx(exprt.exported_decl).?);
180 },
181 else => return error.TODOImplementNonFnDeclsForWasm,
182 }
183
184 count += 1;
402 }185 }
403 }186 }
404 if (new_contents_size != self.contents_size) {187 try writeVecSectionHeader(
405 try self.exportsec.resize(file, self.contents_size, new_contents_size);188 file,
406 leb.writeUnsignedFixed(5, &buf, new_contents_size);189 header_offset,
407 try file.pwriteAll(&buf, self.exportsec.offset + 1);190 spec.exports_id,
408 }191 @intCast(u32, (try file.getPos()) - header_offset - header_size),
409192 count,
410 try file.seekTo(self.exportsec.offset + Section.header_size);193 );
194 }
195
196 // Code section
197 {
198 const header_offset = try reserveVecSectionHeader(file);
411 const writer = file.writer();199 const writer = file.writer();
200 for (self.funcs.items) |decl| {
201 const fn_data = &decl.fn_link.wasm.?;
202
203 // Write the already generated code to the file, inserting
204 // function indexes where required.
205 var current: u32 = 0;
206 for (fn_data.idx_refs.items) |idx_ref| {
207 try writer.writeAll(fn_data.code.items[current..idx_ref.offset]);
208 current = idx_ref.offset;
209 // Use a fixed width here to make calculating the code size
210 // in codegen.wasm.genCode() simpler.
211 var buf: [5]u8 = undefined;
212 leb.writeUnsignedFixed(5, &buf, self.getFuncidx(idx_ref.decl).?);
213 try writer.writeAll(&buf);
214 }
412215
413 // Length of the exports vec216 try writer.writeAll(fn_data.code.items[current..]);
414 leb.writeUnsignedFixed(5, &buf, export_count);217 }
415 try writer.writeAll(&buf);218 try writeVecSectionHeader(
416219 file,
417 for (module.decl_exports.entries.items) |entry|220 header_offset,
418 for (entry.value) |e| try writeExport(writer, e);221 spec.code_id,
419222 @intCast(u32, (try file.getPos()) - header_offset - header_size),
420 self.dirty = false;223 @intCast(u32, self.funcs.items.len),
224 );
421 }225 }
226}
422227
423 /// Return the total number of bytes an export will take.228/// Get the current index of a given Decl in the function list
424 /// TODO: fixed-width LEB128 is currently used for simplicity, but should229/// TODO: we could maintain a hash map to potentially make this
425 /// be replaced with proper variable-length LEB128 as it is inefficient.230fn getFuncidx(self: Wasm, decl: *Module.Decl) ?u32 {
426 fn calcSize(e: *Module.Export) u32 {231 return for (self.funcs.items) |func, idx| {
427 // LEB128 name length + name bytes + export type + LEB128 index232 if (func == decl) break @intCast(u32, idx);
428 return 5 + @intCast(u32, e.options.name.len) + 1 + 5;233 } else null;
429 }234}
430235
431 /// Write the data for a single export to the given file at a given offset.236fn reserveVecSectionHeader(file: fs.File) !u64 {
432 /// TODO: fixed-width LEB128 is currently used for simplicity, but should237 // section id + fixed leb contents size + fixed leb vector length
433 /// be replaced with proper variable-length LEB128 as it is inefficient.238 const header_size = 1 + 5 + 5;
434 fn writeExport(writer: anytype, e: *Module.Export) !void {239 // TODO: this should be a single lseek(2) call, but fs.File does not
435 var buf: [5]u8 = undefined;240 // currently provide a way to do this.
436241 try file.seekBy(header_size);
437 // Export name length + name242 return (try file.getPos()) - header_size;
438 leb.writeUnsignedFixed(5, &buf, @intCast(u32, e.options.name.len));243}
439 try writer.writeAll(&buf);244
440 try writer.writeAll(e.options.name);245fn writeVecSectionHeader(file: fs.File, offset: u64, section: u8, size: u32, items: u32) !void {
441246 var buf: [1 + 5 + 5]u8 = undefined;
442 switch (e.exported_decl.typed_value.most_recent.typed_value.ty.zigTypeTag()) {247 buf[0] = section;
443 .Fn => {248 leb.writeUnsignedFixed(5, buf[1..6], size);
444 // Type of the export249 leb.writeUnsignedFixed(5, buf[6..], items);
445 try writer.writeByte(0x00);250 try file.pwriteAll(&buf, offset);
446 // Exported function index251}
447 leb.writeUnsignedFixed(5, &buf, e.exported_decl.fn_link.wasm.?.funcidx);
448 try writer.writeAll(&buf);
449 },
450 else => return error.TODOImplementNonFnDeclsForWasm,
451 }
452 }
453};
src-self-hosted/link/cbe.h created+15
...@@ -0,0 +1,15 @@
1#if __STDC_VERSION__ >= 201112L
2#define zig_noreturn _Noreturn
3#elif __GNUC__
4#define zig_noreturn __attribute__ ((noreturn))
5#elif _MSC_VER
6#define zig_noreturn __declspec(noreturn)
7#else
8#define zig_noreturn
9#endif
10
11#if __GNUC__
12#define zig_unreachable() __builtin_unreachable()
13#else
14#define zig_unreachable()
15#endif
src-self-hosted/main.zig+2
...@@ -742,6 +742,7 @@ const FmtError = error{...@@ -742,6 +742,7 @@ const FmtError = error{
742 LinkQuotaExceeded,742 LinkQuotaExceeded,
743 FileBusy,743 FileBusy,
744 EndOfStream,744 EndOfStream,
745 NotOpenForWriting,
745} || fs.File.OpenError;746} || fs.File.OpenError;
746747
747fn fmtPath(fmt: *Fmt, file_path: []const u8, check_mode: bool, dir: fs.Dir, sub_path: []const u8) FmtError!void {748fn fmtPath(fmt: *Fmt, file_path: []const u8, check_mode: bool, dir: fs.Dir, sub_path: []const u8) FmtError!void {
...@@ -807,6 +808,7 @@ fn fmtPathFile(...@@ -807,6 +808,7 @@ fn fmtPathFile(
807 const source_code = source_file.readAllAlloc(fmt.gpa, stat.size, max_src_size) catch |err| switch (err) {808 const source_code = source_file.readAllAlloc(fmt.gpa, stat.size, max_src_size) catch |err| switch (err) {
808 error.ConnectionResetByPeer => unreachable,809 error.ConnectionResetByPeer => unreachable,
809 error.ConnectionTimedOut => unreachable,810 error.ConnectionTimedOut => unreachable,
811 error.NotOpenForReading => unreachable,
810 else => |e| return e,812 else => |e| return e,
811 };813 };
812 source_file.close();814 source_file.close();
src-self-hosted/stage2.zig+4
...@@ -153,6 +153,7 @@ export fn stage2_render_ast(tree: *ast.Tree, output_file: *FILE) Error {...@@ -153,6 +153,7 @@ export fn stage2_render_ast(tree: *ast.Tree, output_file: *FILE) Error {
153 const c_out_stream = std.io.cOutStream(output_file);153 const c_out_stream = std.io.cOutStream(output_file);
154 _ = std.zig.render(std.heap.c_allocator, c_out_stream, tree) catch |e| switch (e) {154 _ = std.zig.render(std.heap.c_allocator, c_out_stream, tree) catch |e| switch (e) {
155 error.WouldBlock => unreachable, // stage1 opens stuff in exclusively blocking mode155 error.WouldBlock => unreachable, // stage1 opens stuff in exclusively blocking mode
156 error.NotOpenForWriting => unreachable,
156 error.SystemResources => return .SystemResources,157 error.SystemResources => return .SystemResources,
157 error.OperationAborted => return .OperationAborted,158 error.OperationAborted => return .OperationAborted,
158 error.BrokenPipe => return .BrokenPipe,159 error.BrokenPipe => return .BrokenPipe,
...@@ -611,6 +612,8 @@ export fn stage2_libc_parse(stage1_libc: *Stage2LibCInstallation, libc_file_z: [...@@ -611,6 +612,8 @@ export fn stage2_libc_parse(stage1_libc: *Stage2LibCInstallation, libc_file_z: [
611 error.SystemResources => return .SystemResources,612 error.SystemResources => return .SystemResources,
612 error.OperationAborted => return .OperationAborted,613 error.OperationAborted => return .OperationAborted,
613 error.WouldBlock => unreachable,614 error.WouldBlock => unreachable,
615 error.NotOpenForWriting => unreachable,
616 error.NotOpenForReading => unreachable,
614 error.Unexpected => return .Unexpected,617 error.Unexpected => return .Unexpected,
615 error.EndOfStream => return .EndOfFile,618 error.EndOfStream => return .EndOfFile,
616 error.IsDir => return .IsDir,619 error.IsDir => return .IsDir,
...@@ -666,6 +669,7 @@ export fn stage2_libc_render(stage1_libc: *Stage2LibCInstallation, output_file:...@@ -666,6 +669,7 @@ export fn stage2_libc_render(stage1_libc: *Stage2LibCInstallation, output_file:
666 const c_out_stream = std.io.cOutStream(output_file);669 const c_out_stream = std.io.cOutStream(output_file);
667 libc.render(c_out_stream) catch |err| switch (err) {670 libc.render(c_out_stream) catch |err| switch (err) {
668 error.WouldBlock => unreachable, // stage1 opens stuff in exclusively blocking mode671 error.WouldBlock => unreachable, // stage1 opens stuff in exclusively blocking mode
672 error.NotOpenForWriting => unreachable,
669 error.SystemResources => return .SystemResources,673 error.SystemResources => return .SystemResources,
670 error.OperationAborted => return .OperationAborted,674 error.OperationAborted => return .OperationAborted,
671 error.BrokenPipe => return .BrokenPipe,675 error.BrokenPipe => return .BrokenPipe,
src-self-hosted/test.zig+1-1
...@@ -10,7 +10,7 @@ const enable_wine: bool = build_options.enable_wine;...@@ -10,7 +10,7 @@ const enable_wine: bool = build_options.enable_wine;
10const enable_wasmtime: bool = build_options.enable_wasmtime;10const enable_wasmtime: bool = build_options.enable_wasmtime;
11const glibc_multi_install_dir: ?[]const u8 = build_options.glibc_multi_install_dir;11const glibc_multi_install_dir: ?[]const u8 = build_options.glibc_multi_install_dir;
1212
13const cheader = @embedFile("cbe.h");13const cheader = @embedFile("link/cbe.h");
1414
15test "self-hosted" {15test "self-hosted" {
16 var ctx = TestContext.init();16 var ctx = TestContext.init();
src-self-hosted/translate_c.zig+41-13
...@@ -498,7 +498,7 @@ fn declVisitor(c: *Context, decl: *const ZigClangDecl) Error!void {...@@ -498,7 +498,7 @@ fn declVisitor(c: *Context, decl: *const ZigClangDecl) Error!void {
498 _ = try transRecordDecl(c, @ptrCast(*const ZigClangRecordDecl, decl));498 _ = try transRecordDecl(c, @ptrCast(*const ZigClangRecordDecl, decl));
499 },499 },
500 .Var => {500 .Var => {
501 return visitVarDecl(c, @ptrCast(*const ZigClangVarDecl, decl));501 return visitVarDecl(c, @ptrCast(*const ZigClangVarDecl, decl), null);
502 },502 },
503 .Empty => {503 .Empty => {
504 // Do nothing504 // Do nothing
...@@ -679,12 +679,13 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void {...@@ -679,12 +679,13 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void {
679 return addTopLevelDecl(c, fn_name, &proto_node.base);679 return addTopLevelDecl(c, fn_name, &proto_node.base);
680}680}
681681
682fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {682/// if mangled_name is not null, this var decl was declared in a block scope.
683 const var_name = try c.str(ZigClangNamedDecl_getName_bytes_begin(@ptrCast(*const ZigClangNamedDecl, var_decl)));683fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl, mangled_name: ?[]const u8) Error!void {
684 const var_name = mangled_name orelse try c.str(ZigClangNamedDecl_getName_bytes_begin(@ptrCast(*const ZigClangNamedDecl, var_decl)));
684 if (c.global_scope.sym_table.contains(var_name))685 if (c.global_scope.sym_table.contains(var_name))
685 return; // Avoid processing this decl twice686 return; // Avoid processing this decl twice
686 const rp = makeRestorePoint(c);687 const rp = makeRestorePoint(c);
687 const visib_tok = try appendToken(c, .Keyword_pub, "pub");688 const visib_tok = if (mangled_name) |_| null else try appendToken(c, .Keyword_pub, "pub");
688689
689 const thread_local_token = if (ZigClangVarDecl_getTLSKind(var_decl) == .None)690 const thread_local_token = if (ZigClangVarDecl_getTLSKind(var_decl) == .None)
690 null691 null
...@@ -701,8 +702,14 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {...@@ -701,8 +702,14 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {
701 const qual_type = ZigClangVarDecl_getTypeSourceInfo_getType(var_decl);702 const qual_type = ZigClangVarDecl_getTypeSourceInfo_getType(var_decl);
702 const storage_class = ZigClangVarDecl_getStorageClass(var_decl);703 const storage_class = ZigClangVarDecl_getStorageClass(var_decl);
703 const is_const = ZigClangQualType_isConstQualified(qual_type);704 const is_const = ZigClangQualType_isConstQualified(qual_type);
704705 const has_init = ZigClangVarDecl_hasInit(var_decl);
705 const extern_tok = if (storage_class == .Extern)706
707 // In C extern variables with initializers behave like Zig exports.
708 // extern int foo = 2;
709 // does the same as:
710 // extern int foo;
711 // int foo = 2;
712 const extern_tok = if (storage_class == .Extern and !has_init)
706 try appendToken(c, .Keyword_extern, "extern")713 try appendToken(c, .Keyword_extern, "extern")
707 else if (storage_class != .Static)714 else if (storage_class != .Static)
708 try appendToken(c, .Keyword_export, "export")715 try appendToken(c, .Keyword_export, "export")
...@@ -730,7 +737,7 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {...@@ -730,7 +737,7 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {
730 // If the initialization expression is not present, initialize with undefined.737 // If the initialization expression is not present, initialize with undefined.
731 // If it is an integer literal, we can skip the @as since it will be redundant738 // If it is an integer literal, we can skip the @as since it will be redundant
732 // with the variable type.739 // with the variable type.
733 if (ZigClangVarDecl_hasInit(var_decl)) {740 if (has_init) {
734 eq_tok = try appendToken(c, .Equal, "=");741 eq_tok = try appendToken(c, .Equal, "=");
735 init_node = if (ZigClangVarDecl_getInit(var_decl)) |expr|742 init_node = if (ZigClangVarDecl_getInit(var_decl)) |expr|
736 transExprCoercing(rp, &c.global_scope.base, expr, .used, .r_value) catch |err| switch (err) {743 transExprCoercing(rp, &c.global_scope.base, expr, .used, .r_value) catch |err| switch (err) {
...@@ -745,7 +752,22 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {...@@ -745,7 +752,22 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {
745 try transCreateNodeUndefinedLiteral(c);752 try transCreateNodeUndefinedLiteral(c);
746 } else if (storage_class != .Extern) {753 } else if (storage_class != .Extern) {
747 eq_tok = try appendToken(c, .Equal, "=");754 eq_tok = try appendToken(c, .Equal, "=");
748 init_node = try transCreateNodeIdentifierUnchecked(c, "undefined");755 // The C language specification states that variables with static or threadlocal
756 // storage without an initializer are initialized to a zero value.
757
758 // @import("std").mem.zeroes(T)
759 const import_fn_call = try c.createBuiltinCall("@import", 1);
760 const std_node = try transCreateNodeStringLiteral(c, "\"std\"");
761 import_fn_call.params()[0] = std_node;
762 import_fn_call.rparen_token = try appendToken(c, .RParen, ")");
763 const inner_field_access = try transCreateNodeFieldAccess(c, &import_fn_call.base, "mem");
764 const outer_field_access = try transCreateNodeFieldAccess(c, inner_field_access, "zeroes");
765
766 const zero_init_call = try c.createCall(outer_field_access, 1);
767 zero_init_call.params()[0] = type_node;
768 zero_init_call.rtoken = try appendToken(c, .RParen, ")");
769
770 init_node = &zero_init_call.base;
749 }771 }
750772
751 const linksection_expr = blk: {773 const linksection_expr = blk: {
...@@ -1561,15 +1583,22 @@ fn transDeclStmtOne(...@@ -1561,15 +1583,22 @@ fn transDeclStmtOne(
1561 .Var => {1583 .Var => {
1562 const var_decl = @ptrCast(*const ZigClangVarDecl, decl);1584 const var_decl = @ptrCast(*const ZigClangVarDecl, decl);
15631585
1564 const thread_local_token = if (ZigClangVarDecl_getTLSKind(var_decl) == .None)
1565 null
1566 else
1567 try appendToken(c, .Keyword_threadlocal, "threadlocal");
1568 const qual_type = ZigClangVarDecl_getTypeSourceInfo_getType(var_decl);1586 const qual_type = ZigClangVarDecl_getTypeSourceInfo_getType(var_decl);
1569 const name = try c.str(ZigClangNamedDecl_getName_bytes_begin(1587 const name = try c.str(ZigClangNamedDecl_getName_bytes_begin(
1570 @ptrCast(*const ZigClangNamedDecl, var_decl),1588 @ptrCast(*const ZigClangNamedDecl, var_decl),
1571 ));1589 ));
1572 const mangled_name = try block_scope.makeMangledName(c, name);1590 const mangled_name = try block_scope.makeMangledName(c, name);
1591
1592 switch (ZigClangVarDecl_getStorageClass(var_decl)) {
1593 .Extern, .Static => {
1594 // This is actually a global variable, put it in the global scope and reference it.
1595 // `_ = mangled_name;`
1596 try visitVarDecl(rp.c, var_decl, mangled_name);
1597 return try maybeSuppressResult(rp, scope, .unused, try transCreateNodeIdentifier(rp.c, mangled_name));
1598 },
1599 else => {},
1600 }
1601
1573 const mut_tok = if (ZigClangQualType_isConstQualified(qual_type))1602 const mut_tok = if (ZigClangQualType_isConstQualified(qual_type))
1574 try appendToken(c, .Keyword_const, "const")1603 try appendToken(c, .Keyword_const, "const")
1575 else1604 else
...@@ -1597,7 +1626,6 @@ fn transDeclStmtOne(...@@ -1597,7 +1626,6 @@ fn transDeclStmtOne(
1597 .mut_token = mut_tok,1626 .mut_token = mut_tok,
1598 .semicolon_token = semicolon_token,1627 .semicolon_token = semicolon_token,
1599 }, .{1628 }, .{
1600 .thread_local_token = thread_local_token,
1601 .eq_token = eq_token,1629 .eq_token = eq_token,
1602 .type_node = type_node,1630 .type_node = type_node,
1603 .init_node = init_node,1631 .init_node = init_node,
src-self-hosted/type.zig+516-55
...@@ -65,16 +65,25 @@ pub const Type = extern union {...@@ -65,16 +65,25 @@ pub const Type = extern union {
65 .fn_ccc_void_no_args => return .Fn,65 .fn_ccc_void_no_args => return .Fn,
66 .function => return .Fn,66 .function => return .Fn,
6767
68 .array, .array_u8_sentinel_0 => return .Array,68 .array, .array_u8_sentinel_0, .array_u8, .array_sentinel => return .Array,
69 .single_const_pointer => return .Pointer,69 .single_const_pointer_to_comptime_int,
70 .single_mut_pointer => return .Pointer,70 .const_slice_u8,
71 .single_const_pointer_to_comptime_int => return .Pointer,71 .single_const_pointer,
72 .const_slice_u8 => return .Pointer,72 .single_mut_pointer,
73 .many_const_pointer,
74 .many_mut_pointer,
75 .c_const_pointer,
76 .c_mut_pointer,
77 .const_slice,
78 .mut_slice,
79 .pointer,
80 => return .Pointer,
7381
74 .optional,82 .optional,
75 .optional_single_const_pointer,83 .optional_single_const_pointer,
76 .optional_single_mut_pointer,84 .optional_single_mut_pointer,
77 => return .Optional,85 => return .Optional,
86 .enum_literal => return .EnumLiteral,
78 }87 }
79 }88 }
8089
...@@ -107,13 +116,19 @@ pub const Type = extern union {...@@ -107,13 +116,19 @@ pub const Type = extern union {
107 return @fieldParentPtr(T, "base", self.ptr_otherwise);116 return @fieldParentPtr(T, "base", self.ptr_otherwise);
108 }117 }
109118
110 pub fn castPointer(self: Type) ?*Payload.Pointer {119 pub fn castPointer(self: Type) ?*Payload.PointerSimple {
111 return switch (self.tag()) {120 return switch (self.tag()) {
112 .single_const_pointer,121 .single_const_pointer,
113 .single_mut_pointer,122 .single_mut_pointer,
123 .many_const_pointer,
124 .many_mut_pointer,
125 .c_const_pointer,
126 .c_mut_pointer,
127 .const_slice,
128 .mut_slice,
114 .optional_single_const_pointer,129 .optional_single_const_pointer,
115 .optional_single_mut_pointer,130 .optional_single_mut_pointer,
116 => @fieldParentPtr(Payload.Pointer, "base", self.ptr_otherwise),131 => @fieldParentPtr(Payload.PointerSimple, "base", self.ptr_otherwise),
117 else => null,132 else => null,
118 };133 };
119 }134 }
...@@ -127,6 +142,7 @@ pub const Type = extern union {...@@ -127,6 +142,7 @@ pub const Type = extern union {
127 if (zig_tag_a != zig_tag_b)142 if (zig_tag_a != zig_tag_b)
128 return false;143 return false;
129 switch (zig_tag_a) {144 switch (zig_tag_a) {
145 .EnumLiteral => return true,
130 .Type => return true,146 .Type => return true,
131 .Void => return true,147 .Void => return true,
132 .Bool => return true,148 .Bool => return true,
...@@ -196,8 +212,8 @@ pub const Type = extern union {...@@ -196,8 +212,8 @@ pub const Type = extern union {
196 return true;212 return true;
197 },213 },
198 .Optional => {214 .Optional => {
199 var buf_a: Payload.Pointer = undefined;215 var buf_a: Payload.PointerSimple = undefined;
200 var buf_b: Payload.Pointer = undefined;216 var buf_b: Payload.PointerSimple = undefined;
201 return a.optionalChild(&buf_a).eql(b.optionalChild(&buf_b));217 return a.optionalChild(&buf_a).eql(b.optionalChild(&buf_b));
202 },218 },
203 .Float,219 .Float,
...@@ -211,7 +227,6 @@ pub const Type = extern union {...@@ -211,7 +227,6 @@ pub const Type = extern union {
211 .Frame,227 .Frame,
212 .AnyFrame,228 .AnyFrame,
213 .Vector,229 .Vector,
214 .EnumLiteral,
215 => std.debug.panic("TODO implement Type equality comparison of {} and {}", .{ a, b }),230 => std.debug.panic("TODO implement Type equality comparison of {} and {}", .{ a, b }),
216 }231 }
217 }232 }
...@@ -262,7 +277,7 @@ pub const Type = extern union {...@@ -262,7 +277,7 @@ pub const Type = extern union {
262 }277 }
263 },278 },
264 .Optional => {279 .Optional => {
265 var buf: Payload.Pointer = undefined;280 var buf: Payload.PointerSimple = undefined;
266 std.hash.autoHash(&hasher, self.optionalChild(&buf).hash());281 std.hash.autoHash(&hasher, self.optionalChild(&buf).hash());
267 },282 },
268 .Float,283 .Float,
...@@ -327,9 +342,11 @@ pub const Type = extern union {...@@ -327,9 +342,11 @@ pub const Type = extern union {
327 .fn_ccc_void_no_args,342 .fn_ccc_void_no_args,
328 .single_const_pointer_to_comptime_int,343 .single_const_pointer_to_comptime_int,
329 .const_slice_u8,344 .const_slice_u8,
345 .enum_literal,
330 => unreachable,346 => unreachable,
331347
332 .array_u8_sentinel_0 => return self.copyPayloadShallow(allocator, Payload.Array_u8_Sentinel0),348 .array_u8_sentinel_0 => return self.copyPayloadShallow(allocator, Payload.Array_u8_Sentinel0),
349 .array_u8 => return self.copyPayloadShallow(allocator, Payload.Array_u8),
333 .array => {350 .array => {
334 const payload = @fieldParentPtr(Payload.Array, "base", self.ptr_otherwise);351 const payload = @fieldParentPtr(Payload.Array, "base", self.ptr_otherwise);
335 const new_payload = try allocator.create(Payload.Array);352 const new_payload = try allocator.create(Payload.Array);
...@@ -340,6 +357,17 @@ pub const Type = extern union {...@@ -340,6 +357,17 @@ pub const Type = extern union {
340 };357 };
341 return Type{ .ptr_otherwise = &new_payload.base };358 return Type{ .ptr_otherwise = &new_payload.base };
342 },359 },
360 .array_sentinel => {
361 const payload = @fieldParentPtr(Payload.ArraySentinel, "base", self.ptr_otherwise);
362 const new_payload = try allocator.create(Payload.ArraySentinel);
363 new_payload.* = .{
364 .base = payload.base,
365 .len = payload.len,
366 .sentinel = try payload.sentinel.copy(allocator),
367 .elem_type = try payload.elem_type.copy(allocator),
368 };
369 return Type{ .ptr_otherwise = &new_payload.base };
370 },
343 .int_signed => return self.copyPayloadShallow(allocator, Payload.IntSigned),371 .int_signed => return self.copyPayloadShallow(allocator, Payload.IntSigned),
344 .int_unsigned => return self.copyPayloadShallow(allocator, Payload.IntUnsigned),372 .int_unsigned => return self.copyPayloadShallow(allocator, Payload.IntUnsigned),
345 .function => {373 .function => {
...@@ -360,9 +388,34 @@ pub const Type = extern union {...@@ -360,9 +388,34 @@ pub const Type = extern union {
360 .optional => return self.copyPayloadSingleField(allocator, Payload.Optional, "child_type"),388 .optional => return self.copyPayloadSingleField(allocator, Payload.Optional, "child_type"),
361 .single_const_pointer,389 .single_const_pointer,
362 .single_mut_pointer,390 .single_mut_pointer,
391 .many_const_pointer,
392 .many_mut_pointer,
393 .c_const_pointer,
394 .c_mut_pointer,
395 .const_slice,
396 .mut_slice,
363 .optional_single_mut_pointer,397 .optional_single_mut_pointer,
364 .optional_single_const_pointer,398 .optional_single_const_pointer,
365 => return self.copyPayloadSingleField(allocator, Payload.Pointer, "pointee_type"),399 => return self.copyPayloadSingleField(allocator, Payload.PointerSimple, "pointee_type"),
400
401 .pointer => {
402 const payload = @fieldParentPtr(Payload.Pointer, "base", self.ptr_otherwise);
403 const new_payload = try allocator.create(Payload.Pointer);
404 new_payload.* = .{
405 .base = payload.base,
406
407 .pointee_type = try payload.pointee_type.copy(allocator),
408 .sentinel = if (payload.sentinel) |some| try some.copy(allocator) else null,
409 .@"align" = payload.@"align",
410 .bit_offset = payload.bit_offset,
411 .host_size = payload.host_size,
412 .@"allowzero" = payload.@"allowzero",
413 .mutable = payload.mutable,
414 .@"volatile" = payload.@"volatile",
415 .size = payload.size,
416 };
417 return Type{ .ptr_otherwise = &new_payload.base };
418 },
366 }419 }
367 }420 }
368421
...@@ -425,6 +478,7 @@ pub const Type = extern union {...@@ -425,6 +478,7 @@ pub const Type = extern union {
425 .noreturn,478 .noreturn,
426 => return out_stream.writeAll(@tagName(t)),479 => return out_stream.writeAll(@tagName(t)),
427480
481 .enum_literal => return out_stream.writeAll("@TypeOf(.EnumLiteral)"),
428 .@"null" => return out_stream.writeAll("@TypeOf(null)"),482 .@"null" => return out_stream.writeAll("@TypeOf(null)"),
429 .@"undefined" => return out_stream.writeAll("@TypeOf(undefined)"),483 .@"undefined" => return out_stream.writeAll("@TypeOf(undefined)"),
430484
...@@ -442,9 +496,14 @@ pub const Type = extern union {...@@ -442,9 +496,14 @@ pub const Type = extern union {
442 try param_type.format("", .{}, out_stream);496 try param_type.format("", .{}, out_stream);
443 }497 }
444 try out_stream.writeAll(") ");498 try out_stream.writeAll(") ");
445 try payload.return_type.format("", .{}, out_stream);499 ty = payload.return_type;
500 continue;
446 },501 },
447502
503 .array_u8 => {
504 const payload = @fieldParentPtr(Payload.Array_u8, "base", ty.ptr_otherwise);
505 return out_stream.print("[{}]u8", .{payload.len});
506 },
448 .array_u8_sentinel_0 => {507 .array_u8_sentinel_0 => {
449 const payload = @fieldParentPtr(Payload.Array_u8_Sentinel0, "base", ty.ptr_otherwise);508 const payload = @fieldParentPtr(Payload.Array_u8_Sentinel0, "base", ty.ptr_otherwise);
450 return out_stream.print("[{}:0]u8", .{payload.len});509 return out_stream.print("[{}:0]u8", .{payload.len});
...@@ -455,18 +514,60 @@ pub const Type = extern union {...@@ -455,18 +514,60 @@ pub const Type = extern union {
455 ty = payload.elem_type;514 ty = payload.elem_type;
456 continue;515 continue;
457 },516 },
517 .array_sentinel => {
518 const payload = @fieldParentPtr(Payload.ArraySentinel, "base", ty.ptr_otherwise);
519 try out_stream.print("[{}:{}]", .{ payload.len, payload.sentinel });
520 ty = payload.elem_type;
521 continue;
522 },
458 .single_const_pointer => {523 .single_const_pointer => {
459 const payload = @fieldParentPtr(Payload.Pointer, "base", ty.ptr_otherwise);524 const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise);
460 try out_stream.writeAll("*const ");525 try out_stream.writeAll("*const ");
461 ty = payload.pointee_type;526 ty = payload.pointee_type;
462 continue;527 continue;
463 },528 },
464 .single_mut_pointer => {529 .single_mut_pointer => {
465 const payload = @fieldParentPtr(Payload.Pointer, "base", ty.ptr_otherwise);530 const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise);
466 try out_stream.writeAll("*");531 try out_stream.writeAll("*");
467 ty = payload.pointee_type;532 ty = payload.pointee_type;
468 continue;533 continue;
469 },534 },
535 .many_const_pointer => {
536 const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise);
537 try out_stream.writeAll("[*]const ");
538 ty = payload.pointee_type;
539 continue;
540 },
541 .many_mut_pointer => {
542 const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise);
543 try out_stream.writeAll("[*]");
544 ty = payload.pointee_type;
545 continue;
546 },
547 .c_const_pointer => {
548 const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise);
549 try out_stream.writeAll("[*c]const ");
550 ty = payload.pointee_type;
551 continue;
552 },
553 .c_mut_pointer => {
554 const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise);
555 try out_stream.writeAll("[*c]");
556 ty = payload.pointee_type;
557 continue;
558 },
559 .const_slice => {
560 const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise);
561 try out_stream.writeAll("[]const ");
562 ty = payload.pointee_type;
563 continue;
564 },
565 .mut_slice => {
566 const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise);
567 try out_stream.writeAll("[]");
568 ty = payload.pointee_type;
569 continue;
570 },
470 .int_signed => {571 .int_signed => {
471 const payload = @fieldParentPtr(Payload.IntSigned, "base", ty.ptr_otherwise);572 const payload = @fieldParentPtr(Payload.IntSigned, "base", ty.ptr_otherwise);
472 return out_stream.print("i{}", .{payload.bits});573 return out_stream.print("i{}", .{payload.bits});
...@@ -482,17 +583,45 @@ pub const Type = extern union {...@@ -482,17 +583,45 @@ pub const Type = extern union {
482 continue;583 continue;
483 },584 },
484 .optional_single_const_pointer => {585 .optional_single_const_pointer => {
485 const payload = @fieldParentPtr(Payload.Pointer, "base", ty.ptr_otherwise);586 const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise);
486 try out_stream.writeAll("?*const ");587 try out_stream.writeAll("?*const ");
487 ty = payload.pointee_type;588 ty = payload.pointee_type;
488 continue;589 continue;
489 },590 },
490 .optional_single_mut_pointer => {591 .optional_single_mut_pointer => {
491 const payload = @fieldParentPtr(Payload.Pointer, "base", ty.ptr_otherwise);592 const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise);
492 try out_stream.writeAll("?*");593 try out_stream.writeAll("?*");
493 ty = payload.pointee_type;594 ty = payload.pointee_type;
494 continue;595 continue;
495 },596 },
597
598 .pointer => {
599 const payload = @fieldParentPtr(Payload.Pointer, "base", ty.ptr_otherwise);
600 if (payload.sentinel) |some| switch (payload.size) {
601 .One, .C => unreachable,
602 .Many => try out_stream.writeAll("[*:{}]"),
603 .Slice => try out_stream.writeAll("[:{}]"),
604 } else switch (payload.size) {
605 .One => try out_stream.writeAll("*"),
606 .Many => try out_stream.writeAll("[*]"),
607 .C => try out_stream.writeAll("[*c]"),
608 .Slice => try out_stream.writeAll("[]"),
609 }
610 if (payload.@"align" != 0) {
611 try out_stream.print("align({}", .{payload.@"align"});
612
613 if (payload.bit_offset != 0) {
614 try out_stream.print(":{}:{}", .{ payload.bit_offset, payload.host_size });
615 }
616 try out_stream.writeAll(") ");
617 }
618 if (!payload.mutable) try out_stream.writeAll("const ");
619 if (payload.@"volatile") try out_stream.writeAll("volatile ");
620 if (payload.@"allowzero") try out_stream.writeAll("allowzero ");
621
622 ty = payload.pointee_type;
623 continue;
624 },
496 }625 }
497 unreachable;626 unreachable;
498 }627 }
...@@ -539,6 +668,7 @@ pub const Type = extern union {...@@ -539,6 +668,7 @@ pub const Type = extern union {
539 .fn_ccc_void_no_args => return Value.initTag(.fn_ccc_void_no_args_type),668 .fn_ccc_void_no_args => return Value.initTag(.fn_ccc_void_no_args_type),
540 .single_const_pointer_to_comptime_int => return Value.initTag(.single_const_pointer_to_comptime_int_type),669 .single_const_pointer_to_comptime_int => return Value.initTag(.single_const_pointer_to_comptime_int_type),
541 .const_slice_u8 => return Value.initTag(.const_slice_u8_type),670 .const_slice_u8 => return Value.initTag(.const_slice_u8_type),
671 .enum_literal => return Value.initTag(.enum_literal_type),
542 else => {672 else => {
543 const ty_payload = try allocator.create(Value.Payload.Ty);673 const ty_payload = try allocator.create(Value.Payload.Ty);
544 ty_payload.* = .{ .ty = self };674 ty_payload.* = .{ .ty = self };
...@@ -588,8 +718,8 @@ pub const Type = extern union {...@@ -588,8 +718,8 @@ pub const Type = extern union {
588 => true,718 => true,
589 // TODO lazy types719 // TODO lazy types
590 .array => self.elemType().hasCodeGenBits() and self.arrayLen() != 0,720 .array => self.elemType().hasCodeGenBits() and self.arrayLen() != 0,
591 .single_const_pointer => self.elemType().hasCodeGenBits(),721 .array_u8 => self.arrayLen() != 0,
592 .single_mut_pointer => self.elemType().hasCodeGenBits(),722 .array_sentinel, .single_const_pointer, .single_mut_pointer, .many_const_pointer, .many_mut_pointer, .c_const_pointer, .c_mut_pointer, .const_slice, .mut_slice, .pointer => self.elemType().hasCodeGenBits(),
593 .int_signed => self.cast(Payload.IntSigned).?.bits == 0,723 .int_signed => self.cast(Payload.IntSigned).?.bits == 0,
594 .int_unsigned => self.cast(Payload.IntUnsigned).?.bits == 0,724 .int_unsigned => self.cast(Payload.IntUnsigned).?.bits == 0,
595725
...@@ -601,6 +731,7 @@ pub const Type = extern union {...@@ -601,6 +731,7 @@ pub const Type = extern union {
601 .noreturn,731 .noreturn,
602 .@"null",732 .@"null",
603 .@"undefined",733 .@"undefined",
734 .enum_literal,
604 => false,735 => false,
605 };736 };
606 }737 }
...@@ -616,6 +747,7 @@ pub const Type = extern union {...@@ -616,6 +747,7 @@ pub const Type = extern union {
616 .i8,747 .i8,
617 .bool,748 .bool,
618 .array_u8_sentinel_0,749 .array_u8_sentinel_0,
750 .array_u8,
619 => return 1,751 => return 1,
620752
621 .fn_noreturn_no_args, // represents machine code; not a pointer753 .fn_noreturn_no_args, // represents machine code; not a pointer
...@@ -638,10 +770,23 @@ pub const Type = extern union {...@@ -638,10 +770,23 @@ pub const Type = extern union {
638 .const_slice_u8,770 .const_slice_u8,
639 .single_const_pointer,771 .single_const_pointer,
640 .single_mut_pointer,772 .single_mut_pointer,
773 .many_const_pointer,
774 .many_mut_pointer,
775 .c_const_pointer,
776 .c_mut_pointer,
777 .const_slice,
778 .mut_slice,
641 .optional_single_const_pointer,779 .optional_single_const_pointer,
642 .optional_single_mut_pointer,780 .optional_single_mut_pointer,
643 => return @divExact(target.cpu.arch.ptrBitWidth(), 8),781 => return @divExact(target.cpu.arch.ptrBitWidth(), 8),
644782
783 .pointer => {
784 const payload = @fieldParentPtr(Payload.Pointer, "base", self.ptr_otherwise);
785
786 if (payload.@"align" != 0) return payload.@"align";
787 return @divExact(target.cpu.arch.ptrBitWidth(), 8);
788 },
789
645 .c_short => return @divExact(CType.short.sizeInBits(target), 8),790 .c_short => return @divExact(CType.short.sizeInBits(target), 8),
646 .c_ushort => return @divExact(CType.ushort.sizeInBits(target), 8),791 .c_ushort => return @divExact(CType.ushort.sizeInBits(target), 8),
647 .c_int => return @divExact(CType.int.sizeInBits(target), 8),792 .c_int => return @divExact(CType.int.sizeInBits(target), 8),
...@@ -659,7 +804,7 @@ pub const Type = extern union {...@@ -659,7 +804,7 @@ pub const Type = extern union {
659804
660 .anyerror => return 2, // TODO revisit this when we have the concept of the error tag type805 .anyerror => return 2, // TODO revisit this when we have the concept of the error tag type
661806
662 .array => return self.cast(Payload.Array).?.elem_type.abiAlignment(target),807 .array, .array_sentinel => return self.elemType().abiAlignment(target),
663808
664 .int_signed, .int_unsigned => {809 .int_signed, .int_unsigned => {
665 const bits: u16 = if (self.cast(Payload.IntSigned)) |pl|810 const bits: u16 = if (self.cast(Payload.IntSigned)) |pl|
...@@ -673,7 +818,7 @@ pub const Type = extern union {...@@ -673,7 +818,7 @@ pub const Type = extern union {
673 },818 },
674819
675 .optional => {820 .optional => {
676 var buf: Payload.Pointer = undefined;821 var buf: Payload.PointerSimple = undefined;
677 const child_type = self.optionalChild(&buf);822 const child_type = self.optionalChild(&buf);
678 if (!child_type.hasCodeGenBits()) return 1;823 if (!child_type.hasCodeGenBits()) return 1;
679824
...@@ -691,6 +836,7 @@ pub const Type = extern union {...@@ -691,6 +836,7 @@ pub const Type = extern union {
691 .noreturn,836 .noreturn,
692 .@"null",837 .@"null",
693 .@"undefined",838 .@"undefined",
839 .enum_literal,
694 => unreachable,840 => unreachable,
695 };841 };
696 }842 }
...@@ -711,31 +857,55 @@ pub const Type = extern union {...@@ -711,31 +857,55 @@ pub const Type = extern union {
711 .noreturn => unreachable,857 .noreturn => unreachable,
712 .@"null" => unreachable,858 .@"null" => unreachable,
713 .@"undefined" => unreachable,859 .@"undefined" => unreachable,
860 .enum_literal => unreachable,
861 .single_const_pointer_to_comptime_int => unreachable,
714862
715 .u8,863 .u8,
716 .i8,864 .i8,
717 .bool,865 .bool,
718 => return 1,866 => return 1,
719867
720 .array_u8_sentinel_0 => @fieldParentPtr(Payload.Array_u8_Sentinel0, "base", self.ptr_otherwise).len,868 .array_u8 => @fieldParentPtr(Payload.Array_u8_Sentinel0, "base", self.ptr_otherwise).len,
869 .array_u8_sentinel_0 => @fieldParentPtr(Payload.Array_u8_Sentinel0, "base", self.ptr_otherwise).len + 1,
721 .array => {870 .array => {
722 const payload = @fieldParentPtr(Payload.Array, "base", self.ptr_otherwise);871 const payload = @fieldParentPtr(Payload.Array, "base", self.ptr_otherwise);
723 const elem_size = std.math.max(payload.elem_type.abiAlignment(target), payload.elem_type.abiSize(target));872 const elem_size = std.math.max(payload.elem_type.abiAlignment(target), payload.elem_type.abiSize(target));
724 return payload.len * elem_size;873 return payload.len * elem_size;
725 },874 },
875 .array_sentinel => {
876 const payload = @fieldParentPtr(Payload.ArraySentinel, "base", self.ptr_otherwise);
877 const elem_size = std.math.max(payload.elem_type.abiAlignment(target), payload.elem_type.abiSize(target));
878 return (payload.len + 1) * elem_size;
879 },
726 .i16, .u16 => return 2,880 .i16, .u16 => return 2,
727 .i32, .u32 => return 4,881 .i32, .u32 => return 4,
728 .i64, .u64 => return 8,882 .i64, .u64 => return 8,
729883
730 .isize,884 .isize, .usize => return @divExact(target.cpu.arch.ptrBitWidth(), 8),
731 .usize,885
732 .single_const_pointer_to_comptime_int,886 .const_slice,
887 .mut_slice,
733 .const_slice_u8,888 .const_slice_u8,
734 .single_const_pointer,889 => return @divExact(target.cpu.arch.ptrBitWidth(), 8) * 2,
735 .single_mut_pointer,890
736 .optional_single_const_pointer,891 .optional_single_const_pointer,
737 .optional_single_mut_pointer,892 .optional_single_mut_pointer,
738 => return @divExact(target.cpu.arch.ptrBitWidth(), 8),893 => {
894 if (self.elemType().hasCodeGenBits()) return 1;
895 return @divExact(target.cpu.arch.ptrBitWidth(), 8);
896 },
897
898 .single_const_pointer,
899 .single_mut_pointer,
900 .many_const_pointer,
901 .many_mut_pointer,
902 .c_const_pointer,
903 .c_mut_pointer,
904 .pointer,
905 => {
906 if (self.elemType().hasCodeGenBits()) return 0;
907 return @divExact(target.cpu.arch.ptrBitWidth(), 8);
908 },
739909
740 .c_short => return @divExact(CType.short.sizeInBits(target), 8),910 .c_short => return @divExact(CType.short.sizeInBits(target), 8),
741 .c_ushort => return @divExact(CType.ushort.sizeInBits(target), 8),911 .c_ushort => return @divExact(CType.ushort.sizeInBits(target), 8),
...@@ -766,7 +936,7 @@ pub const Type = extern union {...@@ -766,7 +936,7 @@ pub const Type = extern union {
766 },936 },
767937
768 .optional => {938 .optional => {
769 var buf: Payload.Pointer = undefined;939 var buf: Payload.PointerSimple = undefined;
770 const child_type = self.optionalChild(&buf);940 const child_type = self.optionalChild(&buf);
771 if (!child_type.hasCodeGenBits()) return 1;941 if (!child_type.hasCodeGenBits()) return 1;
772942
...@@ -818,6 +988,8 @@ pub const Type = extern union {...@@ -818,6 +988,8 @@ pub const Type = extern union {
818 .@"null",988 .@"null",
819 .@"undefined",989 .@"undefined",
820 .array,990 .array,
991 .array_sentinel,
992 .array_u8,
821 .array_u8_sentinel_0,993 .array_u8_sentinel_0,
822 .const_slice_u8,994 .const_slice_u8,
823 .fn_noreturn_no_args,995 .fn_noreturn_no_args,
...@@ -830,12 +1002,21 @@ pub const Type = extern union {...@@ -830,12 +1002,21 @@ pub const Type = extern union {
830 .optional,1002 .optional,
831 .optional_single_mut_pointer,1003 .optional_single_mut_pointer,
832 .optional_single_const_pointer,1004 .optional_single_const_pointer,
1005 .enum_literal,
1006 .many_const_pointer,
1007 .many_mut_pointer,
1008 .c_const_pointer,
1009 .c_mut_pointer,
1010 .const_slice,
1011 .mut_slice,
833 => false,1012 => false,
8341013
835 .single_const_pointer,1014 .single_const_pointer,
836 .single_mut_pointer,1015 .single_mut_pointer,
837 .single_const_pointer_to_comptime_int,1016 .single_const_pointer_to_comptime_int,
838 => true,1017 => true,
1018
1019 .pointer => self.cast(Payload.Pointer).?.size == .One,
839 };1020 };
840 }1021 }
8411022
...@@ -875,9 +1056,15 @@ pub const Type = extern union {...@@ -875,9 +1056,15 @@ pub const Type = extern union {
875 .@"null",1056 .@"null",
876 .@"undefined",1057 .@"undefined",
877 .array,1058 .array,
1059 .array_sentinel,
1060 .array_u8,
878 .array_u8_sentinel_0,1061 .array_u8_sentinel_0,
879 .single_const_pointer,1062 .single_const_pointer,
880 .single_mut_pointer,1063 .single_mut_pointer,
1064 .many_const_pointer,
1065 .many_mut_pointer,
1066 .c_const_pointer,
1067 .c_mut_pointer,
881 .single_const_pointer_to_comptime_int,1068 .single_const_pointer_to_comptime_int,
882 .fn_noreturn_no_args,1069 .fn_noreturn_no_args,
883 .fn_void_no_args,1070 .fn_void_no_args,
...@@ -889,9 +1076,15 @@ pub const Type = extern union {...@@ -889,9 +1076,15 @@ pub const Type = extern union {
889 .optional,1076 .optional,
890 .optional_single_mut_pointer,1077 .optional_single_mut_pointer,
891 .optional_single_const_pointer,1078 .optional_single_const_pointer,
1079 .enum_literal,
892 => false,1080 => false,
8931081
894 .const_slice_u8 => true,1082 .const_slice,
1083 .mut_slice,
1084 .const_slice_u8,
1085 => true,
1086
1087 .pointer => self.cast(Payload.Pointer).?.size == .Slice,
895 };1088 };
896 }1089 }
8971090
...@@ -931,6 +1124,8 @@ pub const Type = extern union {...@@ -931,6 +1124,8 @@ pub const Type = extern union {
931 .@"null",1124 .@"null",
932 .@"undefined",1125 .@"undefined",
933 .array,1126 .array,
1127 .array_sentinel,
1128 .array_u8,
934 .array_u8_sentinel_0,1129 .array_u8_sentinel_0,
935 .fn_noreturn_no_args,1130 .fn_noreturn_no_args,
936 .fn_void_no_args,1131 .fn_void_no_args,
...@@ -940,15 +1135,24 @@ pub const Type = extern union {...@@ -940,15 +1135,24 @@ pub const Type = extern union {
940 .int_unsigned,1135 .int_unsigned,
941 .int_signed,1136 .int_signed,
942 .single_mut_pointer,1137 .single_mut_pointer,
1138 .many_mut_pointer,
1139 .c_mut_pointer,
943 .optional,1140 .optional,
944 .optional_single_mut_pointer,1141 .optional_single_mut_pointer,
945 .optional_single_const_pointer,1142 .optional_single_const_pointer,
1143 .enum_literal,
1144 .mut_slice,
946 => false,1145 => false,
9471146
948 .single_const_pointer,1147 .single_const_pointer,
1148 .many_const_pointer,
1149 .c_const_pointer,
949 .single_const_pointer_to_comptime_int,1150 .single_const_pointer_to_comptime_int,
950 .const_slice_u8,1151 .const_slice_u8,
1152 .const_slice,
951 => true,1153 => true,
1154
1155 .pointer => !self.cast(Payload.Pointer).?.mutable,
952 };1156 };
953 }1157 }
9541158
...@@ -988,6 +1192,8 @@ pub const Type = extern union {...@@ -988,6 +1192,8 @@ pub const Type = extern union {
988 .@"null",1192 .@"null",
989 .@"undefined",1193 .@"undefined",
990 .array,1194 .array,
1195 .array_sentinel,
1196 .array_u8,
991 .array_u8_sentinel_0,1197 .array_u8_sentinel_0,
992 .fn_noreturn_no_args,1198 .fn_noreturn_no_args,
993 .fn_void_no_args,1199 .fn_void_no_args,
...@@ -998,12 +1204,24 @@ pub const Type = extern union {...@@ -998,12 +1204,24 @@ pub const Type = extern union {
998 .int_signed,1204 .int_signed,
999 .single_mut_pointer,1205 .single_mut_pointer,
1000 .single_const_pointer,1206 .single_const_pointer,
1207 .many_const_pointer,
1208 .many_mut_pointer,
1209 .c_const_pointer,
1210 .c_mut_pointer,
1211 .const_slice,
1212 .mut_slice,
1001 .single_const_pointer_to_comptime_int,1213 .single_const_pointer_to_comptime_int,
1002 .const_slice_u8,1214 .const_slice_u8,
1003 .optional,1215 .optional,
1004 .optional_single_mut_pointer,1216 .optional_single_mut_pointer,
1005 .optional_single_const_pointer,1217 .optional_single_const_pointer,
1218 .enum_literal,
1006 => false,1219 => false,
1220
1221 .pointer => {
1222 const payload = @fieldParentPtr(Payload.Pointer, "base", self.ptr_otherwise);
1223 return payload.@"volatile";
1224 },
1007 };1225 };
1008 }1226 }
10091227
...@@ -1012,7 +1230,7 @@ pub const Type = extern union {...@@ -1012,7 +1230,7 @@ pub const Type = extern union {
1012 switch (self.tag()) {1230 switch (self.tag()) {
1013 .optional_single_const_pointer, .optional_single_mut_pointer => return true,1231 .optional_single_const_pointer, .optional_single_mut_pointer => return true,
1014 .optional => {1232 .optional => {
1015 var buf: Payload.Pointer = undefined;1233 var buf: Payload.PointerSimple = undefined;
1016 const child_type = self.optionalChild(&buf);1234 const child_type = self.optionalChild(&buf);
1017 // optionals of zero sized pointers behave like bools1235 // optionals of zero sized pointers behave like bools
1018 if (!child_type.hasCodeGenBits()) return false;1236 if (!child_type.hasCodeGenBits()) return false;
...@@ -1023,6 +1241,45 @@ pub const Type = extern union {...@@ -1023,6 +1241,45 @@ pub const Type = extern union {
1023 }1241 }
1024 }1242 }
10251243
1244 /// Returns if type can be used for a runtime variable
1245 pub fn isValidVarType(self: Type, is_extern: bool) bool {
1246 var ty = self;
1247 while (true) switch (ty.zigTypeTag()) {
1248 .Bool,
1249 .Int,
1250 .Float,
1251 .ErrorSet,
1252 .Enum,
1253 .Frame,
1254 .AnyFrame,
1255 .Vector,
1256 => return true,
1257
1258 .Opaque => return is_extern,
1259 .BoundFn,
1260 .ComptimeFloat,
1261 .ComptimeInt,
1262 .EnumLiteral,
1263 .NoReturn,
1264 .Type,
1265 .Void,
1266 .Undefined,
1267 .Null,
1268 => return false,
1269
1270 .Optional => {
1271 var buf: Payload.PointerSimple = undefined;
1272 return ty.optionalChild(&buf).isValidVarType(is_extern);
1273 },
1274 .Pointer, .Array => ty = ty.elemType(),
1275
1276 .ErrorUnion => @panic("TODO fn isValidVarType"),
1277 .Fn => @panic("TODO fn isValidVarType"),
1278 .Struct => @panic("TODO struct isValidVarType"),
1279 .Union => @panic("TODO union isValidVarType"),
1280 };
1281 }
1282
1026 /// Asserts the type is a pointer or array type.1283 /// Asserts the type is a pointer or array type.
1027 pub fn elemType(self: Type) Type {1284 pub fn elemType(self: Type) Type {
1028 return switch (self.tag()) {1285 return switch (self.tag()) {
...@@ -1069,18 +1326,28 @@ pub const Type = extern union {...@@ -1069,18 +1326,28 @@ pub const Type = extern union {
1069 .optional,1326 .optional,
1070 .optional_single_const_pointer,1327 .optional_single_const_pointer,
1071 .optional_single_mut_pointer,1328 .optional_single_mut_pointer,
1329 .enum_literal,
1072 => unreachable,1330 => unreachable,
10731331
1074 .array => self.cast(Payload.Array).?.elem_type,1332 .array => self.cast(Payload.Array).?.elem_type,
1075 .single_const_pointer => self.castPointer().?.pointee_type,1333 .array_sentinel => self.cast(Payload.ArraySentinel).?.elem_type,
1076 .single_mut_pointer => self.castPointer().?.pointee_type,1334 .single_const_pointer,
1077 .array_u8_sentinel_0, .const_slice_u8 => Type.initTag(.u8),1335 .single_mut_pointer,
1336 .many_const_pointer,
1337 .many_mut_pointer,
1338 .c_const_pointer,
1339 .c_mut_pointer,
1340 .const_slice,
1341 .mut_slice,
1342 => self.castPointer().?.pointee_type,
1343 .array_u8, .array_u8_sentinel_0, .const_slice_u8 => Type.initTag(.u8),
1078 .single_const_pointer_to_comptime_int => Type.initTag(.comptime_int),1344 .single_const_pointer_to_comptime_int => Type.initTag(.comptime_int),
1345 .pointer => self.cast(Payload.Pointer).?.pointee_type,
1079 };1346 };
1080 }1347 }
10811348
1082 /// Asserts that the type is an optional.1349 /// Asserts that the type is an optional.
1083 pub fn optionalChild(self: Type, buf: *Payload.Pointer) Type {1350 pub fn optionalChild(self: Type, buf: *Payload.PointerSimple) Type {
1084 return switch (self.tag()) {1351 return switch (self.tag()) {
1085 .optional => self.cast(Payload.Optional).?.child_type,1352 .optional => self.cast(Payload.Optional).?.child_type,
1086 .optional_single_mut_pointer => {1353 .optional_single_mut_pointer => {
...@@ -1107,7 +1374,7 @@ pub const Type = extern union {...@@ -1107,7 +1374,7 @@ pub const Type = extern union {
1107 return switch (self.tag()) {1374 return switch (self.tag()) {
1108 .optional => self.cast(Payload.Optional).?.child_type,1375 .optional => self.cast(Payload.Optional).?.child_type,
1109 .optional_single_mut_pointer, .optional_single_const_pointer => {1376 .optional_single_mut_pointer, .optional_single_const_pointer => {
1110 const payload = try allocator.create(Payload.Pointer);1377 const payload = try allocator.create(Payload.PointerSimple);
1111 payload.* = .{1378 payload.* = .{
1112 .base = .{1379 .base = .{
1113 .tag = if (self.tag() == .optional_single_const_pointer)1380 .tag = if (self.tag() == .optional_single_const_pointer)
...@@ -1164,8 +1431,15 @@ pub const Type = extern union {...@@ -1164,8 +1431,15 @@ pub const Type = extern union {
1164 .fn_naked_noreturn_no_args,1431 .fn_naked_noreturn_no_args,
1165 .fn_ccc_void_no_args,1432 .fn_ccc_void_no_args,
1166 .function,1433 .function,
1434 .pointer,
1167 .single_const_pointer,1435 .single_const_pointer,
1168 .single_mut_pointer,1436 .single_mut_pointer,
1437 .many_const_pointer,
1438 .many_mut_pointer,
1439 .c_const_pointer,
1440 .c_mut_pointer,
1441 .const_slice,
1442 .mut_slice,
1169 .single_const_pointer_to_comptime_int,1443 .single_const_pointer_to_comptime_int,
1170 .const_slice_u8,1444 .const_slice_u8,
1171 .int_unsigned,1445 .int_unsigned,
...@@ -1173,9 +1447,12 @@ pub const Type = extern union {...@@ -1173,9 +1447,12 @@ pub const Type = extern union {
1173 .optional,1447 .optional,
1174 .optional_single_mut_pointer,1448 .optional_single_mut_pointer,
1175 .optional_single_const_pointer,1449 .optional_single_const_pointer,
1450 .enum_literal,
1176 => unreachable,1451 => unreachable,
11771452
1178 .array => self.cast(Payload.Array).?.len,1453 .array => self.cast(Payload.Array).?.len,
1454 .array_sentinel => self.cast(Payload.ArraySentinel).?.len,
1455 .array_u8 => self.cast(Payload.Array_u8).?.len,
1179 .array_u8_sentinel_0 => self.cast(Payload.Array_u8_Sentinel0).?.len,1456 .array_u8_sentinel_0 => self.cast(Payload.Array_u8_Sentinel0).?.len,
1180 };1457 };
1181 }1458 }
...@@ -1221,8 +1498,15 @@ pub const Type = extern union {...@@ -1221,8 +1498,15 @@ pub const Type = extern union {
1221 .fn_naked_noreturn_no_args,1498 .fn_naked_noreturn_no_args,
1222 .fn_ccc_void_no_args,1499 .fn_ccc_void_no_args,
1223 .function,1500 .function,
1501 .pointer,
1224 .single_const_pointer,1502 .single_const_pointer,
1225 .single_mut_pointer,1503 .single_mut_pointer,
1504 .many_const_pointer,
1505 .many_mut_pointer,
1506 .c_const_pointer,
1507 .c_mut_pointer,
1508 .const_slice,
1509 .mut_slice,
1226 .single_const_pointer_to_comptime_int,1510 .single_const_pointer_to_comptime_int,
1227 .const_slice_u8,1511 .const_slice_u8,
1228 .int_unsigned,1512 .int_unsigned,
...@@ -1230,9 +1514,11 @@ pub const Type = extern union {...@@ -1230,9 +1514,11 @@ pub const Type = extern union {
1230 .optional,1514 .optional,
1231 .optional_single_mut_pointer,1515 .optional_single_mut_pointer,
1232 .optional_single_const_pointer,1516 .optional_single_const_pointer,
1517 .enum_literal,
1233 => unreachable,1518 => unreachable,
12341519
1235 .array => return null,1520 .array, .array_u8 => return null,
1521 .array_sentinel => return self.cast(Payload.ArraySentinel).?.sentinel,
1236 .array_u8_sentinel_0 => return Value.initTag(.zero),1522 .array_u8_sentinel_0 => return Value.initTag(.zero),
1237 };1523 };
1238 }1524 }
...@@ -1266,10 +1552,19 @@ pub const Type = extern union {...@@ -1266,10 +1552,19 @@ pub const Type = extern union {
1266 .fn_ccc_void_no_args,1552 .fn_ccc_void_no_args,
1267 .function,1553 .function,
1268 .array,1554 .array,
1555 .array_sentinel,
1556 .array_u8,
1557 .array_u8_sentinel_0,
1558 .pointer,
1269 .single_const_pointer,1559 .single_const_pointer,
1270 .single_mut_pointer,1560 .single_mut_pointer,
1561 .many_const_pointer,
1562 .many_mut_pointer,
1563 .c_const_pointer,
1564 .c_mut_pointer,
1565 .const_slice,
1566 .mut_slice,
1271 .single_const_pointer_to_comptime_int,1567 .single_const_pointer_to_comptime_int,
1272 .array_u8_sentinel_0,
1273 .const_slice_u8,1568 .const_slice_u8,
1274 .int_unsigned,1569 .int_unsigned,
1275 .u8,1570 .u8,
...@@ -1284,6 +1579,7 @@ pub const Type = extern union {...@@ -1284,6 +1579,7 @@ pub const Type = extern union {
1284 .optional,1579 .optional,
1285 .optional_single_mut_pointer,1580 .optional_single_mut_pointer,
1286 .optional_single_const_pointer,1581 .optional_single_const_pointer,
1582 .enum_literal,
1287 => false,1583 => false,
12881584
1289 .int_signed,1585 .int_signed,
...@@ -1324,10 +1620,19 @@ pub const Type = extern union {...@@ -1324,10 +1620,19 @@ pub const Type = extern union {
1324 .fn_ccc_void_no_args,1620 .fn_ccc_void_no_args,
1325 .function,1621 .function,
1326 .array,1622 .array,
1623 .array_sentinel,
1624 .array_u8,
1625 .array_u8_sentinel_0,
1626 .pointer,
1327 .single_const_pointer,1627 .single_const_pointer,
1328 .single_mut_pointer,1628 .single_mut_pointer,
1629 .many_const_pointer,
1630 .many_mut_pointer,
1631 .c_const_pointer,
1632 .c_mut_pointer,
1633 .const_slice,
1634 .mut_slice,
1329 .single_const_pointer_to_comptime_int,1635 .single_const_pointer_to_comptime_int,
1330 .array_u8_sentinel_0,
1331 .const_slice_u8,1636 .const_slice_u8,
1332 .int_signed,1637 .int_signed,
1333 .i8,1638 .i8,
...@@ -1342,6 +1647,7 @@ pub const Type = extern union {...@@ -1342,6 +1647,7 @@ pub const Type = extern union {
1342 .optional,1647 .optional,
1343 .optional_single_mut_pointer,1648 .optional_single_mut_pointer,
1344 .optional_single_const_pointer,1649 .optional_single_const_pointer,
1650 .enum_literal,
1345 => false,1651 => false,
13461652
1347 .int_unsigned,1653 .int_unsigned,
...@@ -1382,14 +1688,24 @@ pub const Type = extern union {...@@ -1382,14 +1688,24 @@ pub const Type = extern union {
1382 .fn_ccc_void_no_args,1688 .fn_ccc_void_no_args,
1383 .function,1689 .function,
1384 .array,1690 .array,
1691 .array_sentinel,
1692 .array_u8,
1693 .array_u8_sentinel_0,
1694 .pointer,
1385 .single_const_pointer,1695 .single_const_pointer,
1386 .single_mut_pointer,1696 .single_mut_pointer,
1697 .many_const_pointer,
1698 .many_mut_pointer,
1699 .c_const_pointer,
1700 .c_mut_pointer,
1701 .const_slice,
1702 .mut_slice,
1387 .single_const_pointer_to_comptime_int,1703 .single_const_pointer_to_comptime_int,
1388 .array_u8_sentinel_0,
1389 .const_slice_u8,1704 .const_slice_u8,
1390 .optional,1705 .optional,
1391 .optional_single_mut_pointer,1706 .optional_single_mut_pointer,
1392 .optional_single_const_pointer,1707 .optional_single_const_pointer,
1708 .enum_literal,
1393 => unreachable,1709 => unreachable,
13941710
1395 .int_unsigned => .{ .signed = false, .bits = self.cast(Payload.IntUnsigned).?.bits },1711 .int_unsigned => .{ .signed = false, .bits = self.cast(Payload.IntUnsigned).?.bits },
...@@ -1438,10 +1754,19 @@ pub const Type = extern union {...@@ -1438,10 +1754,19 @@ pub const Type = extern union {
1438 .fn_ccc_void_no_args,1754 .fn_ccc_void_no_args,
1439 .function,1755 .function,
1440 .array,1756 .array,
1757 .array_sentinel,
1758 .array_u8,
1759 .array_u8_sentinel_0,
1760 .pointer,
1441 .single_const_pointer,1761 .single_const_pointer,
1442 .single_mut_pointer,1762 .single_mut_pointer,
1763 .many_const_pointer,
1764 .many_mut_pointer,
1765 .c_const_pointer,
1766 .c_mut_pointer,
1767 .const_slice,
1768 .mut_slice,
1443 .single_const_pointer_to_comptime_int,1769 .single_const_pointer_to_comptime_int,
1444 .array_u8_sentinel_0,
1445 .const_slice_u8,1770 .const_slice_u8,
1446 .int_unsigned,1771 .int_unsigned,
1447 .int_signed,1772 .int_signed,
...@@ -1456,6 +1781,7 @@ pub const Type = extern union {...@@ -1456,6 +1781,7 @@ pub const Type = extern union {
1456 .optional,1781 .optional,
1457 .optional_single_mut_pointer,1782 .optional_single_mut_pointer,
1458 .optional_single_const_pointer,1783 .optional_single_const_pointer,
1784 .enum_literal,
1459 => false,1785 => false,
14601786
1461 .usize,1787 .usize,
...@@ -1523,10 +1849,19 @@ pub const Type = extern union {...@@ -1523,10 +1849,19 @@ pub const Type = extern union {
1523 .@"null",1849 .@"null",
1524 .@"undefined",1850 .@"undefined",
1525 .array,1851 .array,
1852 .array_sentinel,
1853 .array_u8,
1854 .array_u8_sentinel_0,
1855 .pointer,
1526 .single_const_pointer,1856 .single_const_pointer,
1527 .single_mut_pointer,1857 .single_mut_pointer,
1858 .many_const_pointer,
1859 .many_mut_pointer,
1860 .c_const_pointer,
1861 .c_mut_pointer,
1862 .const_slice,
1863 .mut_slice,
1528 .single_const_pointer_to_comptime_int,1864 .single_const_pointer_to_comptime_int,
1529 .array_u8_sentinel_0,
1530 .const_slice_u8,1865 .const_slice_u8,
1531 .u8,1866 .u8,
1532 .i8,1867 .i8,
...@@ -1551,6 +1886,7 @@ pub const Type = extern union {...@@ -1551,6 +1886,7 @@ pub const Type = extern union {
1551 .optional,1886 .optional,
1552 .optional_single_mut_pointer,1887 .optional_single_mut_pointer,
1553 .optional_single_const_pointer,1888 .optional_single_const_pointer,
1889 .enum_literal,
1554 => unreachable,1890 => unreachable,
1555 };1891 };
1556 }1892 }
...@@ -1584,10 +1920,19 @@ pub const Type = extern union {...@@ -1584,10 +1920,19 @@ pub const Type = extern union {
1584 .@"null",1920 .@"null",
1585 .@"undefined",1921 .@"undefined",
1586 .array,1922 .array,
1923 .array_sentinel,
1924 .array_u8,
1925 .array_u8_sentinel_0,
1926 .pointer,
1587 .single_const_pointer,1927 .single_const_pointer,
1588 .single_mut_pointer,1928 .single_mut_pointer,
1929 .many_const_pointer,
1930 .many_mut_pointer,
1931 .c_const_pointer,
1932 .c_mut_pointer,
1933 .const_slice,
1934 .mut_slice,
1589 .single_const_pointer_to_comptime_int,1935 .single_const_pointer_to_comptime_int,
1590 .array_u8_sentinel_0,
1591 .const_slice_u8,1936 .const_slice_u8,
1592 .u8,1937 .u8,
1593 .i8,1938 .i8,
...@@ -1612,6 +1957,7 @@ pub const Type = extern union {...@@ -1612,6 +1957,7 @@ pub const Type = extern union {
1612 .optional,1957 .optional,
1613 .optional_single_mut_pointer,1958 .optional_single_mut_pointer,
1614 .optional_single_const_pointer,1959 .optional_single_const_pointer,
1960 .enum_literal,
1615 => unreachable,1961 => unreachable,
1616 }1962 }
1617 }1963 }
...@@ -1644,10 +1990,19 @@ pub const Type = extern union {...@@ -1644,10 +1990,19 @@ pub const Type = extern union {
1644 .@"null",1990 .@"null",
1645 .@"undefined",1991 .@"undefined",
1646 .array,1992 .array,
1993 .array_sentinel,
1994 .array_u8,
1995 .array_u8_sentinel_0,
1996 .pointer,
1647 .single_const_pointer,1997 .single_const_pointer,
1648 .single_mut_pointer,1998 .single_mut_pointer,
1999 .many_const_pointer,
2000 .many_mut_pointer,
2001 .c_const_pointer,
2002 .c_mut_pointer,
2003 .const_slice,
2004 .mut_slice,
1649 .single_const_pointer_to_comptime_int,2005 .single_const_pointer_to_comptime_int,
1650 .array_u8_sentinel_0,
1651 .const_slice_u8,2006 .const_slice_u8,
1652 .u8,2007 .u8,
1653 .i8,2008 .i8,
...@@ -1672,6 +2027,7 @@ pub const Type = extern union {...@@ -1672,6 +2027,7 @@ pub const Type = extern union {
1672 .optional,2027 .optional,
1673 .optional_single_mut_pointer,2028 .optional_single_mut_pointer,
1674 .optional_single_const_pointer,2029 .optional_single_const_pointer,
2030 .enum_literal,
1675 => unreachable,2031 => unreachable,
1676 }2032 }
1677 }2033 }
...@@ -1704,10 +2060,19 @@ pub const Type = extern union {...@@ -1704,10 +2060,19 @@ pub const Type = extern union {
1704 .@"null",2060 .@"null",
1705 .@"undefined",2061 .@"undefined",
1706 .array,2062 .array,
2063 .array_sentinel,
2064 .array_u8,
2065 .array_u8_sentinel_0,
2066 .pointer,
1707 .single_const_pointer,2067 .single_const_pointer,
1708 .single_mut_pointer,2068 .single_mut_pointer,
2069 .many_const_pointer,
2070 .many_mut_pointer,
2071 .c_const_pointer,
2072 .c_mut_pointer,
2073 .const_slice,
2074 .mut_slice,
1709 .single_const_pointer_to_comptime_int,2075 .single_const_pointer_to_comptime_int,
1710 .array_u8_sentinel_0,
1711 .const_slice_u8,2076 .const_slice_u8,
1712 .u8,2077 .u8,
1713 .i8,2078 .i8,
...@@ -1732,6 +2097,7 @@ pub const Type = extern union {...@@ -1732,6 +2097,7 @@ pub const Type = extern union {
1732 .optional,2097 .optional,
1733 .optional_single_mut_pointer,2098 .optional_single_mut_pointer,
1734 .optional_single_const_pointer,2099 .optional_single_const_pointer,
2100 .enum_literal,
1735 => unreachable,2101 => unreachable,
1736 };2102 };
1737 }2103 }
...@@ -1761,10 +2127,19 @@ pub const Type = extern union {...@@ -1761,10 +2127,19 @@ pub const Type = extern union {
1761 .@"null",2127 .@"null",
1762 .@"undefined",2128 .@"undefined",
1763 .array,2129 .array,
2130 .array_sentinel,
2131 .array_u8,
2132 .array_u8_sentinel_0,
2133 .pointer,
1764 .single_const_pointer,2134 .single_const_pointer,
1765 .single_mut_pointer,2135 .single_mut_pointer,
2136 .many_const_pointer,
2137 .many_mut_pointer,
2138 .c_const_pointer,
2139 .c_mut_pointer,
2140 .const_slice,
2141 .mut_slice,
1766 .single_const_pointer_to_comptime_int,2142 .single_const_pointer_to_comptime_int,
1767 .array_u8_sentinel_0,
1768 .const_slice_u8,2143 .const_slice_u8,
1769 .u8,2144 .u8,
1770 .i8,2145 .i8,
...@@ -1789,6 +2164,7 @@ pub const Type = extern union {...@@ -1789,6 +2164,7 @@ pub const Type = extern union {
1789 .optional,2164 .optional,
1790 .optional_single_mut_pointer,2165 .optional_single_mut_pointer,
1791 .optional_single_const_pointer,2166 .optional_single_const_pointer,
2167 .enum_literal,
1792 => unreachable,2168 => unreachable,
1793 };2169 };
1794 }2170 }
...@@ -1818,10 +2194,19 @@ pub const Type = extern union {...@@ -1818,10 +2194,19 @@ pub const Type = extern union {
1818 .@"null",2194 .@"null",
1819 .@"undefined",2195 .@"undefined",
1820 .array,2196 .array,
2197 .array_sentinel,
2198 .array_u8,
2199 .array_u8_sentinel_0,
2200 .pointer,
1821 .single_const_pointer,2201 .single_const_pointer,
1822 .single_mut_pointer,2202 .single_mut_pointer,
2203 .many_const_pointer,
2204 .many_mut_pointer,
2205 .c_const_pointer,
2206 .c_mut_pointer,
2207 .const_slice,
2208 .mut_slice,
1823 .single_const_pointer_to_comptime_int,2209 .single_const_pointer_to_comptime_int,
1824 .array_u8_sentinel_0,
1825 .const_slice_u8,2210 .const_slice_u8,
1826 .u8,2211 .u8,
1827 .i8,2212 .i8,
...@@ -1846,6 +2231,7 @@ pub const Type = extern union {...@@ -1846,6 +2231,7 @@ pub const Type = extern union {
1846 .optional,2231 .optional,
1847 .optional_single_mut_pointer,2232 .optional_single_mut_pointer,
1848 .optional_single_const_pointer,2233 .optional_single_const_pointer,
2234 .enum_literal,
1849 => unreachable,2235 => unreachable,
1850 };2236 };
1851 }2237 }
...@@ -1895,14 +2281,24 @@ pub const Type = extern union {...@@ -1895,14 +2281,24 @@ pub const Type = extern union {
1895 .fn_ccc_void_no_args,2281 .fn_ccc_void_no_args,
1896 .function,2282 .function,
1897 .array,2283 .array,
2284 .array_sentinel,
2285 .array_u8,
2286 .array_u8_sentinel_0,
2287 .pointer,
1898 .single_const_pointer,2288 .single_const_pointer,
1899 .single_mut_pointer,2289 .single_mut_pointer,
2290 .many_const_pointer,
2291 .many_mut_pointer,
2292 .c_const_pointer,
2293 .c_mut_pointer,
2294 .const_slice,
2295 .mut_slice,
1900 .single_const_pointer_to_comptime_int,2296 .single_const_pointer_to_comptime_int,
1901 .array_u8_sentinel_0,
1902 .const_slice_u8,2297 .const_slice_u8,
1903 .optional,2298 .optional,
1904 .optional_single_mut_pointer,2299 .optional_single_mut_pointer,
1905 .optional_single_const_pointer,2300 .optional_single_const_pointer,
2301 .enum_literal,
1906 => false,2302 => false,
1907 };2303 };
1908 }2304 }
...@@ -1944,12 +2340,16 @@ pub const Type = extern union {...@@ -1944,12 +2340,16 @@ pub const Type = extern union {
1944 .fn_ccc_void_no_args,2340 .fn_ccc_void_no_args,
1945 .function,2341 .function,
1946 .single_const_pointer_to_comptime_int,2342 .single_const_pointer_to_comptime_int,
2343 .array_sentinel,
1947 .array_u8_sentinel_0,2344 .array_u8_sentinel_0,
1948 .const_slice_u8,2345 .const_slice_u8,
2346 .const_slice,
2347 .mut_slice,
1949 .c_void,2348 .c_void,
1950 .optional,2349 .optional,
1951 .optional_single_mut_pointer,2350 .optional_single_mut_pointer,
1952 .optional_single_const_pointer,2351 .optional_single_const_pointer,
2352 .enum_literal,
1953 => return null,2353 => return null,
19542354
1955 .void => return Value.initTag(.void_value),2355 .void => return Value.initTag(.void_value),
...@@ -1971,18 +2371,27 @@ pub const Type = extern union {...@@ -1971,18 +2371,27 @@ pub const Type = extern union {
1971 return null;2371 return null;
1972 }2372 }
1973 },2373 },
1974 .array => {2374 .array, .array_u8 => {
1975 const array = ty.cast(Payload.Array).?;2375 if (ty.arrayLen() == 0)
1976 if (array.len == 0)
1977 return Value.initTag(.empty_array);2376 return Value.initTag(.empty_array);
1978 ty = array.elem_type;2377 ty = ty.elemType();
1979 continue;2378 continue;
1980 },2379 },
1981 .single_const_pointer, .single_mut_pointer => {2380 .many_const_pointer,
2381 .many_mut_pointer,
2382 .c_const_pointer,
2383 .c_mut_pointer,
2384 .single_const_pointer,
2385 .single_mut_pointer,
2386 => {
1982 const ptr = ty.castPointer().?;2387 const ptr = ty.castPointer().?;
1983 ty = ptr.pointee_type;2388 ty = ptr.pointee_type;
1984 continue;2389 continue;
1985 },2390 },
2391 .pointer => {
2392 ty = ty.cast(Payload.Pointer).?.pointee_type;
2393 continue;
2394 },
1986 };2395 };
1987 }2396 }
19882397
...@@ -2022,7 +2431,6 @@ pub const Type = extern union {...@@ -2022,7 +2431,6 @@ pub const Type = extern union {
2022 .fn_ccc_void_no_args,2431 .fn_ccc_void_no_args,
2023 .function,2432 .function,
2024 .single_const_pointer_to_comptime_int,2433 .single_const_pointer_to_comptime_int,
2025 .array_u8_sentinel_0,
2026 .const_slice_u8,2434 .const_slice_u8,
2027 .c_void,2435 .c_void,
2028 .void,2436 .void,
...@@ -2032,12 +2440,26 @@ pub const Type = extern union {...@@ -2032,12 +2440,26 @@ pub const Type = extern union {
2032 .int_unsigned,2440 .int_unsigned,
2033 .int_signed,2441 .int_signed,
2034 .array,2442 .array,
2443 .array_sentinel,
2444 .array_u8,
2445 .array_u8_sentinel_0,
2035 .single_const_pointer,2446 .single_const_pointer,
2036 .single_mut_pointer,2447 .single_mut_pointer,
2448 .many_const_pointer,
2449 .many_mut_pointer,
2450 .const_slice,
2451 .mut_slice,
2037 .optional,2452 .optional,
2038 .optional_single_mut_pointer,2453 .optional_single_mut_pointer,
2039 .optional_single_const_pointer,2454 .optional_single_const_pointer,
2455 .enum_literal,
2040 => return false,2456 => return false,
2457
2458 .c_const_pointer,
2459 .c_mut_pointer,
2460 => return true,
2461
2462 .pointer => self.cast(Payload.Pointer).?.size == .C,
2041 };2463 };
2042 }2464 }
20432465
...@@ -2080,6 +2502,7 @@ pub const Type = extern union {...@@ -2080,6 +2502,7 @@ pub const Type = extern union {
2080 comptime_int,2502 comptime_int,
2081 comptime_float,2503 comptime_float,
2082 noreturn,2504 noreturn,
2505 enum_literal,
2083 @"null",2506 @"null",
2084 @"undefined",2507 @"undefined",
2085 fn_noreturn_no_args,2508 fn_noreturn_no_args,
...@@ -2090,10 +2513,19 @@ pub const Type = extern union {...@@ -2090,10 +2513,19 @@ pub const Type = extern union {
2090 const_slice_u8, // See last_no_payload_tag below.2513 const_slice_u8, // See last_no_payload_tag below.
2091 // After this, the tag requires a payload.2514 // After this, the tag requires a payload.
20922515
2516 array_u8,
2093 array_u8_sentinel_0,2517 array_u8_sentinel_0,
2094 array,2518 array,
2519 array_sentinel,
2520 pointer,
2095 single_const_pointer,2521 single_const_pointer,
2096 single_mut_pointer,2522 single_mut_pointer,
2523 many_const_pointer,
2524 many_mut_pointer,
2525 c_const_pointer,
2526 c_mut_pointer,
2527 const_slice,
2528 mut_slice,
2097 int_signed,2529 int_signed,
2098 int_unsigned,2530 int_unsigned,
2099 function,2531 function,
...@@ -2114,14 +2546,28 @@ pub const Type = extern union {...@@ -2114,14 +2546,28 @@ pub const Type = extern union {
2114 len: u64,2546 len: u64,
2115 };2547 };
21162548
2549 pub const Array_u8 = struct {
2550 base: Payload = Payload{ .tag = .array_u8 },
2551
2552 len: u64,
2553 };
2554
2117 pub const Array = struct {2555 pub const Array = struct {
2118 base: Payload = Payload{ .tag = .array },2556 base: Payload = Payload{ .tag = .array },
21192557
2558 len: u64,
2120 elem_type: Type,2559 elem_type: Type,
2560 };
2561
2562 pub const ArraySentinel = struct {
2563 base: Payload = Payload{ .tag = .array_sentinel },
2564
2121 len: u64,2565 len: u64,
2566 sentinel: Value,
2567 elem_type: Type,
2122 };2568 };
21232569
2124 pub const Pointer = struct {2570 pub const PointerSimple = struct {
2125 base: Payload,2571 base: Payload,
21262572
2127 pointee_type: Type,2573 pointee_type: Type,
...@@ -2152,6 +2598,21 @@ pub const Type = extern union {...@@ -2152,6 +2598,21 @@ pub const Type = extern union {
21522598
2153 child_type: Type,2599 child_type: Type,
2154 };2600 };
2601
2602 pub const Pointer = struct {
2603 base: Payload = .{ .tag = .pointer },
2604
2605 pointee_type: Type,
2606 sentinel: ?Value,
2607 /// If zero use pointee_type.AbiAlign()
2608 @"align": u32,
2609 bit_offset: u16,
2610 host_size: u16,
2611 @"allowzero": bool,
2612 mutable: bool,
2613 @"volatile": bool,
2614 size: std.builtin.TypeInfo.Pointer.Size,
2615 };
2155 };2616 };
2156};2617};
21572618
src-self-hosted/value.zig+60-1
...@@ -60,6 +60,7 @@ pub const Value = extern union {...@@ -60,6 +60,7 @@ pub const Value = extern union {
60 fn_ccc_void_no_args_type,60 fn_ccc_void_no_args_type,
61 single_const_pointer_to_comptime_int_type,61 single_const_pointer_to_comptime_int_type,
62 const_slice_u8_type,62 const_slice_u8_type,
63 enum_literal_type,
6364
64 undef,65 undef,
65 zero,66 zero,
...@@ -78,6 +79,7 @@ pub const Value = extern union {...@@ -78,6 +79,7 @@ pub const Value = extern union {
78 int_big_positive,79 int_big_positive,
79 int_big_negative,80 int_big_negative,
80 function,81 function,
82 variable,
81 ref_val,83 ref_val,
82 decl_ref,84 decl_ref,
83 elem_ptr,85 elem_ptr,
...@@ -87,6 +89,7 @@ pub const Value = extern union {...@@ -87,6 +89,7 @@ pub const Value = extern union {
87 float_32,89 float_32,
88 float_64,90 float_64,
89 float_128,91 float_128,
92 enum_literal,
9093
91 pub const last_no_payload_tag = Tag.bool_false;94 pub const last_no_payload_tag = Tag.bool_false;
92 pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;95 pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;
...@@ -164,6 +167,7 @@ pub const Value = extern union {...@@ -164,6 +167,7 @@ pub const Value = extern union {
164 .fn_ccc_void_no_args_type,167 .fn_ccc_void_no_args_type,
165 .single_const_pointer_to_comptime_int_type,168 .single_const_pointer_to_comptime_int_type,
166 .const_slice_u8_type,169 .const_slice_u8_type,
170 .enum_literal_type,
167 .undef,171 .undef,
168 .zero,172 .zero,
169 .void_value,173 .void_value,
...@@ -193,6 +197,7 @@ pub const Value = extern union {...@@ -193,6 +197,7 @@ pub const Value = extern union {
193 @panic("TODO implement copying of big ints");197 @panic("TODO implement copying of big ints");
194 },198 },
195 .function => return self.copyPayloadShallow(allocator, Payload.Function),199 .function => return self.copyPayloadShallow(allocator, Payload.Function),
200 .variable => return self.copyPayloadShallow(allocator, Payload.Variable),
196 .ref_val => {201 .ref_val => {
197 const payload = @fieldParentPtr(Payload.RefVal, "base", self.ptr_otherwise);202 const payload = @fieldParentPtr(Payload.RefVal, "base", self.ptr_otherwise);
198 const new_payload = try allocator.create(Payload.RefVal);203 const new_payload = try allocator.create(Payload.RefVal);
...@@ -227,6 +232,15 @@ pub const Value = extern union {...@@ -227,6 +232,15 @@ pub const Value = extern union {
227 .float_32 => return self.copyPayloadShallow(allocator, Payload.Float_32),232 .float_32 => return self.copyPayloadShallow(allocator, Payload.Float_32),
228 .float_64 => return self.copyPayloadShallow(allocator, Payload.Float_64),233 .float_64 => return self.copyPayloadShallow(allocator, Payload.Float_64),
229 .float_128 => return self.copyPayloadShallow(allocator, Payload.Float_128),234 .float_128 => return self.copyPayloadShallow(allocator, Payload.Float_128),
235 .enum_literal => {
236 const payload = @fieldParentPtr(Payload.Bytes, "base", self.ptr_otherwise);
237 const new_payload = try allocator.create(Payload.Bytes);
238 new_payload.* = .{
239 .base = payload.base,
240 .data = try allocator.dupe(u8, payload.data),
241 };
242 return Value{ .ptr_otherwise = &new_payload.base };
243 },
230 }244 }
231 }245 }
232246
...@@ -285,6 +299,7 @@ pub const Value = extern union {...@@ -285,6 +299,7 @@ pub const Value = extern union {
285 .fn_ccc_void_no_args_type => return out_stream.writeAll("fn() callconv(.C) void"),299 .fn_ccc_void_no_args_type => return out_stream.writeAll("fn() callconv(.C) void"),
286 .single_const_pointer_to_comptime_int_type => return out_stream.writeAll("*const comptime_int"),300 .single_const_pointer_to_comptime_int_type => return out_stream.writeAll("*const comptime_int"),
287 .const_slice_u8_type => return out_stream.writeAll("[]const u8"),301 .const_slice_u8_type => return out_stream.writeAll("[]const u8"),
302 .enum_literal_type => return out_stream.writeAll("@TypeOf(.EnumLiteral)"),
288303
289 .null_value => return out_stream.writeAll("null"),304 .null_value => return out_stream.writeAll("null"),
290 .undef => return out_stream.writeAll("undefined"),305 .undef => return out_stream.writeAll("undefined"),
...@@ -306,6 +321,7 @@ pub const Value = extern union {...@@ -306,6 +321,7 @@ pub const Value = extern union {
306 .int_big_positive => return out_stream.print("{}", .{val.cast(Payload.IntBigPositive).?.asBigInt()}),321 .int_big_positive => return out_stream.print("{}", .{val.cast(Payload.IntBigPositive).?.asBigInt()}),
307 .int_big_negative => return out_stream.print("{}", .{val.cast(Payload.IntBigNegative).?.asBigInt()}),322 .int_big_negative => return out_stream.print("{}", .{val.cast(Payload.IntBigNegative).?.asBigInt()}),
308 .function => return out_stream.writeAll("(function)"),323 .function => return out_stream.writeAll("(function)"),
324 .variable => return out_stream.writeAll("(variable)"),
309 .ref_val => {325 .ref_val => {
310 const ref_val = val.cast(Payload.RefVal).?;326 const ref_val = val.cast(Payload.RefVal).?;
311 try out_stream.writeAll("&const ");327 try out_stream.writeAll("&const ");
...@@ -318,7 +334,7 @@ pub const Value = extern union {...@@ -318,7 +334,7 @@ pub const Value = extern union {
318 val = elem_ptr.array_ptr;334 val = elem_ptr.array_ptr;
319 },335 },
320 .empty_array => return out_stream.writeAll(".{}"),336 .empty_array => return out_stream.writeAll(".{}"),
321 .bytes => return std.zig.renderStringLiteral(self.cast(Payload.Bytes).?.data, out_stream),337 .enum_literal, .bytes => return std.zig.renderStringLiteral(self.cast(Payload.Bytes).?.data, out_stream),
322 .repeated => {338 .repeated => {
323 try out_stream.writeAll("(repeated) ");339 try out_stream.writeAll("(repeated) ");
324 val = val.cast(Payload.Repeated).?.val;340 val = val.cast(Payload.Repeated).?.val;
...@@ -391,6 +407,7 @@ pub const Value = extern union {...@@ -391,6 +407,7 @@ pub const Value = extern union {
391 .fn_ccc_void_no_args_type => Type.initTag(.fn_ccc_void_no_args),407 .fn_ccc_void_no_args_type => Type.initTag(.fn_ccc_void_no_args),
392 .single_const_pointer_to_comptime_int_type => Type.initTag(.single_const_pointer_to_comptime_int),408 .single_const_pointer_to_comptime_int_type => Type.initTag(.single_const_pointer_to_comptime_int),
393 .const_slice_u8_type => Type.initTag(.const_slice_u8),409 .const_slice_u8_type => Type.initTag(.const_slice_u8),
410 .enum_literal_type => Type.initTag(.enum_literal),
394411
395 .undef,412 .undef,
396 .zero,413 .zero,
...@@ -405,6 +422,7 @@ pub const Value = extern union {...@@ -405,6 +422,7 @@ pub const Value = extern union {
405 .int_big_positive,422 .int_big_positive,
406 .int_big_negative,423 .int_big_negative,
407 .function,424 .function,
425 .variable,
408 .ref_val,426 .ref_val,
409 .decl_ref,427 .decl_ref,
410 .elem_ptr,428 .elem_ptr,
...@@ -414,6 +432,7 @@ pub const Value = extern union {...@@ -414,6 +432,7 @@ pub const Value = extern union {
414 .float_32,432 .float_32,
415 .float_64,433 .float_64,
416 .float_128,434 .float_128,
435 .enum_literal,
417 => unreachable,436 => unreachable,
418 };437 };
419 }438 }
...@@ -462,8 +481,10 @@ pub const Value = extern union {...@@ -462,8 +481,10 @@ pub const Value = extern union {
462 .fn_ccc_void_no_args_type,481 .fn_ccc_void_no_args_type,
463 .single_const_pointer_to_comptime_int_type,482 .single_const_pointer_to_comptime_int_type,
464 .const_slice_u8_type,483 .const_slice_u8_type,
484 .enum_literal_type,
465 .null_value,485 .null_value,
466 .function,486 .function,
487 .variable,
467 .ref_val,488 .ref_val,
468 .decl_ref,489 .decl_ref,
469 .elem_ptr,490 .elem_ptr,
...@@ -476,6 +497,7 @@ pub const Value = extern union {...@@ -476,6 +497,7 @@ pub const Value = extern union {
476 .void_value,497 .void_value,
477 .unreachable_value,498 .unreachable_value,
478 .empty_array,499 .empty_array,
500 .enum_literal,
479 => unreachable,501 => unreachable,
480502
481 .undef => unreachable,503 .undef => unreachable,
...@@ -537,8 +559,10 @@ pub const Value = extern union {...@@ -537,8 +559,10 @@ pub const Value = extern union {
537 .fn_ccc_void_no_args_type,559 .fn_ccc_void_no_args_type,
538 .single_const_pointer_to_comptime_int_type,560 .single_const_pointer_to_comptime_int_type,
539 .const_slice_u8_type,561 .const_slice_u8_type,
562 .enum_literal_type,
540 .null_value,563 .null_value,
541 .function,564 .function,
565 .variable,
542 .ref_val,566 .ref_val,
543 .decl_ref,567 .decl_ref,
544 .elem_ptr,568 .elem_ptr,
...@@ -551,6 +575,7 @@ pub const Value = extern union {...@@ -551,6 +575,7 @@ pub const Value = extern union {
551 .void_value,575 .void_value,
552 .unreachable_value,576 .unreachable_value,
553 .empty_array,577 .empty_array,
578 .enum_literal,
554 => unreachable,579 => unreachable,
555580
556 .undef => unreachable,581 .undef => unreachable,
...@@ -612,8 +637,10 @@ pub const Value = extern union {...@@ -612,8 +637,10 @@ pub const Value = extern union {
612 .fn_ccc_void_no_args_type,637 .fn_ccc_void_no_args_type,
613 .single_const_pointer_to_comptime_int_type,638 .single_const_pointer_to_comptime_int_type,
614 .const_slice_u8_type,639 .const_slice_u8_type,
640 .enum_literal_type,
615 .null_value,641 .null_value,
616 .function,642 .function,
643 .variable,
617 .ref_val,644 .ref_val,
618 .decl_ref,645 .decl_ref,
619 .elem_ptr,646 .elem_ptr,
...@@ -626,6 +653,7 @@ pub const Value = extern union {...@@ -626,6 +653,7 @@ pub const Value = extern union {
626 .void_value,653 .void_value,
627 .unreachable_value,654 .unreachable_value,
628 .empty_array,655 .empty_array,
656 .enum_literal,
629 => unreachable,657 => unreachable,
630658
631 .undef => unreachable,659 .undef => unreachable,
...@@ -713,8 +741,10 @@ pub const Value = extern union {...@@ -713,8 +741,10 @@ pub const Value = extern union {
713 .fn_ccc_void_no_args_type,741 .fn_ccc_void_no_args_type,
714 .single_const_pointer_to_comptime_int_type,742 .single_const_pointer_to_comptime_int_type,
715 .const_slice_u8_type,743 .const_slice_u8_type,
744 .enum_literal_type,
716 .null_value,745 .null_value,
717 .function,746 .function,
747 .variable,
718 .ref_val,748 .ref_val,
719 .decl_ref,749 .decl_ref,
720 .elem_ptr,750 .elem_ptr,
...@@ -728,6 +758,7 @@ pub const Value = extern union {...@@ -728,6 +758,7 @@ pub const Value = extern union {
728 .void_value,758 .void_value,
729 .unreachable_value,759 .unreachable_value,
730 .empty_array,760 .empty_array,
761 .enum_literal,
731 => unreachable,762 => unreachable,
732763
733 .zero,764 .zero,
...@@ -793,8 +824,10 @@ pub const Value = extern union {...@@ -793,8 +824,10 @@ pub const Value = extern union {
793 .fn_ccc_void_no_args_type,824 .fn_ccc_void_no_args_type,
794 .single_const_pointer_to_comptime_int_type,825 .single_const_pointer_to_comptime_int_type,
795 .const_slice_u8_type,826 .const_slice_u8_type,
827 .enum_literal_type,
796 .null_value,828 .null_value,
797 .function,829 .function,
830 .variable,
798 .ref_val,831 .ref_val,
799 .decl_ref,832 .decl_ref,
800 .elem_ptr,833 .elem_ptr,
...@@ -807,6 +840,7 @@ pub const Value = extern union {...@@ -807,6 +840,7 @@ pub const Value = extern union {
807 .void_value,840 .void_value,
808 .unreachable_value,841 .unreachable_value,
809 .empty_array,842 .empty_array,
843 .enum_literal,
810 => unreachable,844 => unreachable,
811845
812 .zero,846 .zero,
...@@ -953,10 +987,12 @@ pub const Value = extern union {...@@ -953,10 +987,12 @@ pub const Value = extern union {
953 .fn_ccc_void_no_args_type,987 .fn_ccc_void_no_args_type,
954 .single_const_pointer_to_comptime_int_type,988 .single_const_pointer_to_comptime_int_type,
955 .const_slice_u8_type,989 .const_slice_u8_type,
990 .enum_literal_type,
956 .bool_true,991 .bool_true,
957 .bool_false,992 .bool_false,
958 .null_value,993 .null_value,
959 .function,994 .function,
995 .variable,
960 .ref_val,996 .ref_val,
961 .decl_ref,997 .decl_ref,
962 .elem_ptr,998 .elem_ptr,
...@@ -970,6 +1006,7 @@ pub const Value = extern union {...@@ -970,6 +1006,7 @@ pub const Value = extern union {
970 .empty_array,1006 .empty_array,
971 .void_value,1007 .void_value,
972 .unreachable_value,1008 .unreachable_value,
1009 .enum_literal,
973 => unreachable,1010 => unreachable,
9741011
975 .zero => false,1012 .zero => false,
...@@ -1025,8 +1062,10 @@ pub const Value = extern union {...@@ -1025,8 +1062,10 @@ pub const Value = extern union {
1025 .fn_ccc_void_no_args_type,1062 .fn_ccc_void_no_args_type,
1026 .single_const_pointer_to_comptime_int_type,1063 .single_const_pointer_to_comptime_int_type,
1027 .const_slice_u8_type,1064 .const_slice_u8_type,
1065 .enum_literal_type,
1028 .null_value,1066 .null_value,
1029 .function,1067 .function,
1068 .variable,
1030 .ref_val,1069 .ref_val,
1031 .decl_ref,1070 .decl_ref,
1032 .elem_ptr,1071 .elem_ptr,
...@@ -1036,6 +1075,7 @@ pub const Value = extern union {...@@ -1036,6 +1075,7 @@ pub const Value = extern union {
1036 .void_value,1075 .void_value,
1037 .unreachable_value,1076 .unreachable_value,
1038 .empty_array,1077 .empty_array,
1078 .enum_literal,
1039 => unreachable,1079 => unreachable,
10401080
1041 .zero,1081 .zero,
...@@ -1102,6 +1142,11 @@ pub const Value = extern union {...@@ -1102,6 +1142,11 @@ pub const Value = extern union {
1102 }1142 }
11031143
1104 pub fn eql(a: Value, b: Value) bool {1144 pub fn eql(a: Value, b: Value) bool {
1145 if (a.tag() == b.tag() and a.tag() == .enum_literal) {
1146 const a_name = @fieldParentPtr(Payload.Bytes, "base", a.ptr_otherwise).data;
1147 const b_name = @fieldParentPtr(Payload.Bytes, "base", b.ptr_otherwise).data;
1148 return std.mem.eql(u8, a_name, b_name);
1149 }
1105 // TODO non numerical comparisons1150 // TODO non numerical comparisons
1106 return compare(a, .eq, b);1151 return compare(a, .eq, b);
1107 }1152 }
...@@ -1151,11 +1196,13 @@ pub const Value = extern union {...@@ -1151,11 +1196,13 @@ pub const Value = extern union {
1151 .fn_ccc_void_no_args_type,1196 .fn_ccc_void_no_args_type,
1152 .single_const_pointer_to_comptime_int_type,1197 .single_const_pointer_to_comptime_int_type,
1153 .const_slice_u8_type,1198 .const_slice_u8_type,
1199 .enum_literal_type,
1154 .zero,1200 .zero,
1155 .bool_true,1201 .bool_true,
1156 .bool_false,1202 .bool_false,
1157 .null_value,1203 .null_value,
1158 .function,1204 .function,
1205 .variable,
1159 .int_u64,1206 .int_u64,
1160 .int_i64,1207 .int_i64,
1161 .int_big_positive,1208 .int_big_positive,
...@@ -1170,6 +1217,7 @@ pub const Value = extern union {...@@ -1170,6 +1217,7 @@ pub const Value = extern union {
1170 .void_value,1217 .void_value,
1171 .unreachable_value,1218 .unreachable_value,
1172 .empty_array,1219 .empty_array,
1220 .enum_literal,
1173 => unreachable,1221 => unreachable,
11741222
1175 .ref_val => self.cast(Payload.RefVal).?.val,1223 .ref_val => self.cast(Payload.RefVal).?.val,
...@@ -1227,11 +1275,13 @@ pub const Value = extern union {...@@ -1227,11 +1275,13 @@ pub const Value = extern union {
1227 .fn_ccc_void_no_args_type,1275 .fn_ccc_void_no_args_type,
1228 .single_const_pointer_to_comptime_int_type,1276 .single_const_pointer_to_comptime_int_type,
1229 .const_slice_u8_type,1277 .const_slice_u8_type,
1278 .enum_literal_type,
1230 .zero,1279 .zero,
1231 .bool_true,1280 .bool_true,
1232 .bool_false,1281 .bool_false,
1233 .null_value,1282 .null_value,
1234 .function,1283 .function,
1284 .variable,
1235 .int_u64,1285 .int_u64,
1236 .int_i64,1286 .int_i64,
1237 .int_big_positive,1287 .int_big_positive,
...@@ -1246,6 +1296,7 @@ pub const Value = extern union {...@@ -1246,6 +1296,7 @@ pub const Value = extern union {
1246 .float_128,1296 .float_128,
1247 .void_value,1297 .void_value,
1248 .unreachable_value,1298 .unreachable_value,
1299 .enum_literal,
1249 => unreachable,1300 => unreachable,
12501301
1251 .empty_array => unreachable, // out of bounds array index1302 .empty_array => unreachable, // out of bounds array index
...@@ -1320,11 +1371,13 @@ pub const Value = extern union {...@@ -1320,11 +1371,13 @@ pub const Value = extern union {
1320 .fn_ccc_void_no_args_type,1371 .fn_ccc_void_no_args_type,
1321 .single_const_pointer_to_comptime_int_type,1372 .single_const_pointer_to_comptime_int_type,
1322 .const_slice_u8_type,1373 .const_slice_u8_type,
1374 .enum_literal_type,
1323 .zero,1375 .zero,
1324 .empty_array,1376 .empty_array,
1325 .bool_true,1377 .bool_true,
1326 .bool_false,1378 .bool_false,
1327 .function,1379 .function,
1380 .variable,
1328 .int_u64,1381 .int_u64,
1329 .int_i64,1382 .int_i64,
1330 .int_big_positive,1383 .int_big_positive,
...@@ -1339,6 +1392,7 @@ pub const Value = extern union {...@@ -1339,6 +1392,7 @@ pub const Value = extern union {
1339 .float_64,1392 .float_64,
1340 .float_128,1393 .float_128,
1341 .void_value,1394 .void_value,
1395 .enum_literal,
1342 => false,1396 => false,
13431397
1344 .undef => unreachable,1398 .undef => unreachable,
...@@ -1398,6 +1452,11 @@ pub const Value = extern union {...@@ -1398,6 +1452,11 @@ pub const Value = extern union {
1398 func: *Module.Fn,1452 func: *Module.Fn,
1399 };1453 };
14001454
1455 pub const Variable = struct {
1456 base: Payload = Payload{ .tag = .variable },
1457 variable: *Module.Var,
1458 };
1459
1401 pub const ArraySentinel0_u8_Type = struct {1460 pub const ArraySentinel0_u8_Type = struct {
1402 base: Payload = Payload{ .tag = .array_sentinel_0_u8_type },1461 base: Payload = Payload{ .tag = .array_sentinel_0_u8_type },
1403 len: u64,1462 len: u64,
src-self-hosted/zir.zig+146-9
...@@ -47,6 +47,10 @@ pub const Inst = struct {...@@ -47,6 +47,10 @@ pub const Inst = struct {
47 array_cat,47 array_cat,
48 /// Array multiplication `a ** b`48 /// Array multiplication `a ** b`
49 array_mul,49 array_mul,
50 /// Create an array type
51 array_type,
52 /// Create an array type with sentinel
53 array_type_sentinel,
50 /// Function parameter value. These must be first in a function's main block,54 /// Function parameter value. These must be first in a function's main block,
51 /// in respective order with the parameters.55 /// in respective order with the parameters.
52 arg,56 arg,
...@@ -58,11 +62,11 @@ pub const Inst = struct {...@@ -58,11 +62,11 @@ pub const Inst = struct {
58 bitand,62 bitand,
59 /// TODO delete this instruction, it has no purpose.63 /// TODO delete this instruction, it has no purpose.
60 bitcast,64 bitcast,
61 /// An arbitrary typed pointer, which is to be used as an L-Value, is pointer-casted65 /// An arbitrary typed pointer is pointer-casted to a new Pointer.
62 /// to a new L-Value. The destination type is given by LHS. The cast is to be evaluated66 /// The destination type is given by LHS. The cast is to be evaluated
63 /// as if it were a bit-cast operation from the operand pointer element type to the67 /// as if it were a bit-cast operation from the operand pointer element type to the
64 /// provided destination type.68 /// provided destination type.
65 bitcast_lvalue,69 bitcast_ref,
66 /// A typed result location pointer is bitcasted to a new result location pointer.70 /// A typed result location pointer is bitcasted to a new result location pointer.
67 /// The new result location pointer has an inferred type.71 /// The new result location pointer has an inferred type.
68 bitcast_result_ptr,72 bitcast_result_ptr,
...@@ -190,10 +194,22 @@ pub const Inst = struct {...@@ -190,10 +194,22 @@ pub const Inst = struct {
190 shl,194 shl,
191 /// Integer shift-right. Arithmetic or logical depending on the signedness of the integer type.195 /// Integer shift-right. Arithmetic or logical depending on the signedness of the integer type.
192 shr,196 shr,
193 /// Create a const pointer type based on the element type. `*const T`197 /// Create a const pointer type with element type T. `*const T`
194 single_const_ptr_type,198 single_const_ptr_type,
195 /// Create a mutable pointer type based on the element type. `*T`199 /// Create a mutable pointer type with element type T. `*T`
196 single_mut_ptr_type,200 single_mut_ptr_type,
201 /// Create a const pointer type with element type T. `[*]const T`
202 many_const_ptr_type,
203 /// Create a mutable pointer type with element type T. `[*]T`
204 many_mut_ptr_type,
205 /// Create a const pointer type with element type T. `[*c]const T`
206 c_const_ptr_type,
207 /// Create a mutable pointer type with element type T. `[*c]T`
208 c_mut_ptr_type,
209 /// Create a mutable slice type with element type T. `[]T`
210 mut_slice_type,
211 /// Create a const slice type with element type T. `[]T`
212 const_slice_type,
197 /// Create a pointer type with attributes213 /// Create a pointer type with attributes
198 ptr_type,214 ptr_type,
199 /// Write a value to a pointer. For loading, see `deref`.215 /// Write a value to a pointer. For loading, see `deref`.
...@@ -225,6 +241,10 @@ pub const Inst = struct {...@@ -225,6 +241,10 @@ pub const Inst = struct {
225 unwrap_err_safe,241 unwrap_err_safe,
226 /// Same as previous, but without safety checks. Used for orelse, if and while242 /// Same as previous, but without safety checks. Used for orelse, if and while
227 unwrap_err_unsafe,243 unwrap_err_unsafe,
244 /// Takes a *E!T and raises a compiler error if T != void
245 ensure_err_payload_void,
246 /// Enum literal
247 enum_literal,
228248
229 pub fn Type(tag: Tag) type {249 pub fn Type(tag: Tag) type {
230 return switch (tag) {250 return switch (tag) {
...@@ -250,21 +270,29 @@ pub const Inst = struct {...@@ -250,21 +270,29 @@ pub const Inst = struct {
250 .ensure_result_non_error,270 .ensure_result_non_error,
251 .bitcast_result_ptr,271 .bitcast_result_ptr,
252 .ref,272 .ref,
253 .bitcast_lvalue,273 .bitcast_ref,
254 .typeof,274 .typeof,
255 .single_const_ptr_type,275 .single_const_ptr_type,
256 .single_mut_ptr_type,276 .single_mut_ptr_type,
277 .many_const_ptr_type,
278 .many_mut_ptr_type,
279 .c_const_ptr_type,
280 .c_mut_ptr_type,
281 .mut_slice_type,
282 .const_slice_type,
257 .optional_type,283 .optional_type,
258 .unwrap_optional_safe,284 .unwrap_optional_safe,
259 .unwrap_optional_unsafe,285 .unwrap_optional_unsafe,
260 .unwrap_err_safe,286 .unwrap_err_safe,
261 .unwrap_err_unsafe,287 .unwrap_err_unsafe,
288 .ensure_err_payload_void,
262 => UnOp,289 => UnOp,
263290
264 .add,291 .add,
265 .addwrap,292 .addwrap,
266 .array_cat,293 .array_cat,
267 .array_mul,294 .array_mul,
295 .array_type,
268 .bitand,296 .bitand,
269 .bitor,297 .bitor,
270 .div,298 .div,
...@@ -291,6 +319,7 @@ pub const Inst = struct {...@@ -291,6 +319,7 @@ pub const Inst = struct {
291 => BinOp,319 => BinOp,
292320
293 .arg => Arg,321 .arg => Arg,
322 .array_type_sentinel => ArrayTypeSentinel,
294 .block => Block,323 .block => Block,
295 .@"break" => Break,324 .@"break" => Break,
296 .breakvoid => BreakVoid,325 .breakvoid => BreakVoid,
...@@ -317,6 +346,7 @@ pub const Inst = struct {...@@ -317,6 +346,7 @@ pub const Inst = struct {
317 .elemptr => ElemPtr,346 .elemptr => ElemPtr,
318 .condbr => CondBr,347 .condbr => CondBr,
319 .ptr_type => PtrType,348 .ptr_type => PtrType,
349 .enum_literal => EnumLiteral,
320 };350 };
321 }351 }
322352
...@@ -330,12 +360,14 @@ pub const Inst = struct {...@@ -330,12 +360,14 @@ pub const Inst = struct {
330 .alloc_inferred,360 .alloc_inferred,
331 .array_cat,361 .array_cat,
332 .array_mul,362 .array_mul,
363 .array_type,
364 .array_type_sentinel,
333 .arg,365 .arg,
334 .as,366 .as,
335 .@"asm",367 .@"asm",
336 .bitand,368 .bitand,
337 .bitcast,369 .bitcast,
338 .bitcast_lvalue,370 .bitcast_ref,
339 .bitcast_result_ptr,371 .bitcast_result_ptr,
340 .bitor,372 .bitor,
341 .block,373 .block,
...@@ -386,6 +418,12 @@ pub const Inst = struct {...@@ -386,6 +418,12 @@ pub const Inst = struct {
386 .shr,418 .shr,
387 .single_const_ptr_type,419 .single_const_ptr_type,
388 .single_mut_ptr_type,420 .single_mut_ptr_type,
421 .many_const_ptr_type,
422 .many_mut_ptr_type,
423 .c_const_ptr_type,
424 .c_mut_ptr_type,
425 .mut_slice_type,
426 .const_slice_type,
389 .store,427 .store,
390 .str,428 .str,
391 .sub,429 .sub,
...@@ -398,6 +436,8 @@ pub const Inst = struct {...@@ -398,6 +436,8 @@ pub const Inst = struct {
398 .unwrap_err_safe,436 .unwrap_err_safe,
399 .unwrap_err_unsafe,437 .unwrap_err_unsafe,
400 .ptr_type,438 .ptr_type,
439 .ensure_err_payload_void,
440 .enum_literal,
401 => false,441 => false,
402442
403 .@"break",443 .@"break",
...@@ -840,11 +880,34 @@ pub const Inst = struct {...@@ -840,11 +880,34 @@ pub const Inst = struct {
840 @"align": ?*Inst = null,880 @"align": ?*Inst = null,
841 align_bit_start: ?*Inst = null,881 align_bit_start: ?*Inst = null,
842 align_bit_end: ?*Inst = null,882 align_bit_end: ?*Inst = null,
843 @"const": bool = true,883 mutable: bool = true,
844 @"volatile": bool = false,884 @"volatile": bool = false,
845 sentinel: ?*Inst = null,885 sentinel: ?*Inst = null,
886 size: std.builtin.TypeInfo.Pointer.Size = .One,
846 },887 },
847 };888 };
889
890 pub const ArrayTypeSentinel = struct {
891 pub const base_tag = Tag.array_type_sentinel;
892 base: Inst,
893
894 positionals: struct {
895 len: *Inst,
896 sentinel: *Inst,
897 elem_type: *Inst,
898 },
899 kw_args: struct {},
900 };
901
902 pub const EnumLiteral = struct {
903 pub const base_tag = Tag.enum_literal;
904 base: Inst,
905
906 positionals: struct {
907 name: []const u8,
908 },
909 kw_args: struct {},
910 };
848};911};
849912
850pub const ErrorMsg = struct {913pub const ErrorMsg = struct {
...@@ -1714,6 +1777,9 @@ const EmitZIR = struct {...@@ -1714,6 +1777,9 @@ const EmitZIR = struct {
1714 const decl_ref = try self.emitDeclRef(inst.src, declref.decl);1777 const decl_ref = try self.emitDeclRef(inst.src, declref.decl);
1715 try new_body.instructions.append(decl_ref);1778 try new_body.instructions.append(decl_ref);
1716 break :blk decl_ref;1779 break :blk decl_ref;
1780 } else if (const_inst.val.cast(Value.Payload.Variable)) |var_pl| blk: {
1781 const owner_decl = var_pl.variable.owner_decl;
1782 break :blk try self.emitDeclVal(inst.src, mem.spanZ(owner_decl.name));
1717 } else blk: {1783 } else blk: {
1718 break :blk (try self.emitTypedValue(inst.src, .{ .ty = inst.ty, .val = const_inst.val })).inst;1784 break :blk (try self.emitTypedValue(inst.src, .{ .ty = inst.ty, .val = const_inst.val })).inst;
1719 };1785 };
...@@ -1837,6 +1903,11 @@ const EmitZIR = struct {...@@ -1837,6 +1903,11 @@ const EmitZIR = struct {
1837 if (typed_value.val.cast(Value.Payload.DeclRef)) |decl_ref| {1903 if (typed_value.val.cast(Value.Payload.DeclRef)) |decl_ref| {
1838 const decl = decl_ref.decl;1904 const decl = decl_ref.decl;
1839 return try self.emitUnnamedDecl(try self.emitDeclRef(src, decl));1905 return try self.emitUnnamedDecl(try self.emitDeclRef(src, decl));
1906 } else if (typed_value.val.cast(Value.Payload.Variable)) |variable| {
1907 return self.emitTypedValue(src, .{
1908 .ty = typed_value.ty,
1909 .val = variable.variable.init,
1910 });
1840 }1911 }
1841 if (typed_value.val.isUndef()) {1912 if (typed_value.val.isUndef()) {
1842 const as_inst = try self.arena.allocator.create(Inst.BinOp);1913 const as_inst = try self.arena.allocator.create(Inst.BinOp);
...@@ -1922,6 +1993,25 @@ const EmitZIR = struct {...@@ -1922,6 +1993,25 @@ const EmitZIR = struct {
1922 return self.emitUnnamedDecl(&str_inst.base);1993 return self.emitUnnamedDecl(&str_inst.base);
1923 },1994 },
1924 .Void => return self.emitPrimitive(src, .void_value),1995 .Void => return self.emitPrimitive(src, .void_value),
1996 .Bool => if (typed_value.val.toBool())
1997 return self.emitPrimitive(src, .@"true")
1998 else
1999 return self.emitPrimitive(src, .@"false"),
2000 .EnumLiteral => {
2001 const enum_literal = @fieldParentPtr(Value.Payload.Bytes, "base", typed_value.val.ptr_otherwise);
2002 const inst = try self.arena.allocator.create(Inst.Str);
2003 inst.* = .{
2004 .base = .{
2005 .src = src,
2006 .tag = .enum_literal,
2007 },
2008 .positionals = .{
2009 .bytes = enum_literal.data,
2010 },
2011 .kw_args = .{},
2012 };
2013 return self.emitUnnamedDecl(&inst.base);
2014 },
1925 else => |t| std.debug.panic("TODO implement emitTypedValue for {}", .{@tagName(t)}),2015 else => |t| std.debug.panic("TODO implement emitTypedValue for {}", .{@tagName(t)}),
1926 }2016 }
1927 }2017 }
...@@ -2269,6 +2359,8 @@ const EmitZIR = struct {...@@ -2269,6 +2359,8 @@ const EmitZIR = struct {
2269 };2359 };
2270 break :blk &new_inst.base;2360 break :blk &new_inst.base;
2271 },2361 },
2362
2363 .varptr => @panic("TODO"),
2272 };2364 };
2273 try self.metadata.put(new_inst, .{ .deaths = inst.deaths });2365 try self.metadata.put(new_inst, .{ .deaths = inst.deaths });
2274 try instructions.append(new_inst);2366 try instructions.append(new_inst);
...@@ -2376,7 +2468,7 @@ const EmitZIR = struct {...@@ -2376,7 +2468,7 @@ const EmitZIR = struct {
2376 }2468 }
2377 },2469 },
2378 .Optional => {2470 .Optional => {
2379 var buf: Type.Payload.Pointer = undefined;2471 var buf: Type.Payload.PointerSimple = undefined;
2380 const inst = try self.arena.allocator.create(Inst.UnOp);2472 const inst = try self.arena.allocator.create(Inst.UnOp);
2381 inst.* = .{2473 inst.* = .{
2382 .base = .{2474 .base = .{
...@@ -2390,6 +2482,51 @@ const EmitZIR = struct {...@@ -2390,6 +2482,51 @@ const EmitZIR = struct {
2390 };2482 };
2391 return self.emitUnnamedDecl(&inst.base);2483 return self.emitUnnamedDecl(&inst.base);
2392 },2484 },
2485 .Array => {
2486 var len_pl = Value.Payload.Int_u64{ .int = ty.arrayLen() };
2487 const len = Value.initPayload(&len_pl.base);
2488
2489 const inst = if (ty.arraySentinel()) |sentinel| blk: {
2490 const inst = try self.arena.allocator.create(Inst.ArrayTypeSentinel);
2491 inst.* = .{
2492 .base = .{
2493 .src = src,
2494 .tag = .array_type,
2495 },
2496 .positionals = .{
2497 .len = (try self.emitTypedValue(src, .{
2498 .ty = Type.initTag(.usize),
2499 .val = len,
2500 })).inst,
2501 .sentinel = (try self.emitTypedValue(src, .{
2502 .ty = ty.elemType(),
2503 .val = sentinel,
2504 })).inst,
2505 .elem_type = (try self.emitType(src, ty.elemType())).inst,
2506 },
2507 .kw_args = .{},
2508 };
2509 break :blk &inst.base;
2510 } else blk: {
2511 const inst = try self.arena.allocator.create(Inst.BinOp);
2512 inst.* = .{
2513 .base = .{
2514 .src = src,
2515 .tag = .array_type,
2516 },
2517 .positionals = .{
2518 .lhs = (try self.emitTypedValue(src, .{
2519 .ty = Type.initTag(.usize),
2520 .val = len,
2521 })).inst,
2522 .rhs = (try self.emitType(src, ty.elemType())).inst,
2523 },
2524 .kw_args = .{},
2525 };
2526 break :blk &inst.base;
2527 };
2528 return self.emitUnnamedDecl(inst);
2529 },
2393 else => std.debug.panic("TODO implement emitType for {}", .{ty}),2530 else => std.debug.panic("TODO implement emitType for {}", .{ty}),
2394 },2531 },
2395 }2532 }
src-self-hosted/zir_sema.zig+112-46
...@@ -29,7 +29,7 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!...@@ -29,7 +29,7 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!
29 .alloc => return analyzeInstAlloc(mod, scope, old_inst.castTag(.alloc).?),29 .alloc => return analyzeInstAlloc(mod, scope, old_inst.castTag(.alloc).?),
30 .alloc_inferred => return analyzeInstAllocInferred(mod, scope, old_inst.castTag(.alloc_inferred).?),30 .alloc_inferred => return analyzeInstAllocInferred(mod, scope, old_inst.castTag(.alloc_inferred).?),
31 .arg => return analyzeInstArg(mod, scope, old_inst.castTag(.arg).?),31 .arg => return analyzeInstArg(mod, scope, old_inst.castTag(.arg).?),
32 .bitcast_lvalue => return analyzeInstBitCastLValue(mod, scope, old_inst.castTag(.bitcast_lvalue).?),32 .bitcast_ref => return analyzeInstBitCastRef(mod, scope, old_inst.castTag(.bitcast_ref).?),
33 .bitcast_result_ptr => return analyzeInstBitCastResultPtr(mod, scope, old_inst.castTag(.bitcast_result_ptr).?),33 .bitcast_result_ptr => return analyzeInstBitCastResultPtr(mod, scope, old_inst.castTag(.bitcast_result_ptr).?),
34 .block => return analyzeInstBlock(mod, scope, old_inst.castTag(.block).?),34 .block => return analyzeInstBlock(mod, scope, old_inst.castTag(.block).?),
35 .@"break" => return analyzeInstBreak(mod, scope, old_inst.castTag(.@"break").?),35 .@"break" => return analyzeInstBreak(mod, scope, old_inst.castTag(.@"break").?),
...@@ -51,8 +51,14 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!...@@ -51,8 +51,14 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!
51 .ref => return analyzeInstRef(mod, scope, old_inst.castTag(.ref).?),51 .ref => return analyzeInstRef(mod, scope, old_inst.castTag(.ref).?),
52 .ret_ptr => return analyzeInstRetPtr(mod, scope, old_inst.castTag(.ret_ptr).?),52 .ret_ptr => return analyzeInstRetPtr(mod, scope, old_inst.castTag(.ret_ptr).?),
53 .ret_type => return analyzeInstRetType(mod, scope, old_inst.castTag(.ret_type).?),53 .ret_type => return analyzeInstRetType(mod, scope, old_inst.castTag(.ret_type).?),
54 .single_const_ptr_type => return analyzeInstSingleConstPtrType(mod, scope, old_inst.castTag(.single_const_ptr_type).?),54 .single_const_ptr_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.single_const_ptr_type).?, false, .One),
55 .single_mut_ptr_type => return analyzeInstSingleMutPtrType(mod, scope, old_inst.castTag(.single_mut_ptr_type).?),55 .single_mut_ptr_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.single_mut_ptr_type).?, true, .One),
56 .many_const_ptr_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.many_const_ptr_type).?, false, .Many),
57 .many_mut_ptr_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.many_mut_ptr_type).?, true, .Many),
58 .c_const_ptr_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.c_const_ptr_type).?, false, .C),
59 .c_mut_ptr_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.c_mut_ptr_type).?, true, .C),
60 .const_slice_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.const_slice_type).?, false, .Slice),
61 .mut_slice_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.mut_slice_type).?, true, .Slice),
56 .ptr_type => return analyzeInstPtrType(mod, scope, old_inst.castTag(.ptr_type).?),62 .ptr_type => return analyzeInstPtrType(mod, scope, old_inst.castTag(.ptr_type).?),
57 .store => return analyzeInstStore(mod, scope, old_inst.castTag(.store).?),63 .store => return analyzeInstStore(mod, scope, old_inst.castTag(.store).?),
58 .str => return analyzeInstStr(mod, scope, old_inst.castTag(.str).?),64 .str => return analyzeInstStr(mod, scope, old_inst.castTag(.str).?),
...@@ -112,6 +118,10 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!...@@ -112,6 +118,10 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!
112 .unwrap_optional_unsafe => return analyzeInstUnwrapOptional(mod, scope, old_inst.castTag(.unwrap_optional_unsafe).?, false),118 .unwrap_optional_unsafe => return analyzeInstUnwrapOptional(mod, scope, old_inst.castTag(.unwrap_optional_unsafe).?, false),
113 .unwrap_err_safe => return analyzeInstUnwrapErr(mod, scope, old_inst.castTag(.unwrap_err_safe).?, true),119 .unwrap_err_safe => return analyzeInstUnwrapErr(mod, scope, old_inst.castTag(.unwrap_err_safe).?, true),
114 .unwrap_err_unsafe => return analyzeInstUnwrapErr(mod, scope, old_inst.castTag(.unwrap_err_unsafe).?, false),120 .unwrap_err_unsafe => return analyzeInstUnwrapErr(mod, scope, old_inst.castTag(.unwrap_err_unsafe).?, false),
121 .ensure_err_payload_void => return analyzeInstEnsureErrPayloadVoid(mod, scope, old_inst.castTag(.ensure_err_payload_void).?),
122 .array_type => return analyzeInstArrayType(mod, scope, old_inst.castTag(.array_type).?),
123 .array_type_sentinel => return analyzeInstArrayTypeSentinel(mod, scope, old_inst.castTag(.array_type_sentinel).?),
124 .enum_literal => return analyzeInstEnumLiteral(mod, scope, old_inst.castTag(.enum_literal).?),
115 }125 }
116}126}
117127
...@@ -263,6 +273,14 @@ fn resolveType(mod: *Module, scope: *Scope, old_inst: *zir.Inst) !Type {...@@ -263,6 +273,14 @@ fn resolveType(mod: *Module, scope: *Scope, old_inst: *zir.Inst) !Type {
263 return val.toType();273 return val.toType();
264}274}
265275
276fn resolveInt(mod: *Module, scope: *Scope, old_inst: *zir.Inst, dest_type: Type) !u64 {
277 const new_inst = try resolveInst(mod, scope, old_inst);
278 const coerced = try mod.coerce(scope, dest_type, new_inst);
279 const val = try mod.resolveConstValue(scope, coerced);
280
281 return val.toUnsignedInt();
282}
283
266pub fn resolveInstConst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!TypedValue {284pub fn resolveInstConst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!TypedValue {
267 const new_inst = try resolveInst(mod, scope, old_inst);285 const new_inst = try resolveInst(mod, scope, old_inst);
268 const val = try mod.resolveConstValue(scope, new_inst);286 const val = try mod.resolveConstValue(scope, new_inst);
...@@ -295,8 +313,8 @@ fn analyzeInstCoerceResultBlockPtr(...@@ -295,8 +313,8 @@ fn analyzeInstCoerceResultBlockPtr(
295 return mod.fail(scope, inst.base.src, "TODO implement analyzeInstCoerceResultBlockPtr", .{});313 return mod.fail(scope, inst.base.src, "TODO implement analyzeInstCoerceResultBlockPtr", .{});
296}314}
297315
298fn analyzeInstBitCastLValue(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {316fn analyzeInstBitCastRef(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
299 return mod.fail(scope, inst.base.src, "TODO implement analyzeInstBitCastLValue", .{});317 return mod.fail(scope, inst.base.src, "TODO implement analyzeInstBitCastRef", .{});
300}318}
301319
302fn analyzeInstBitCastResultPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {320fn analyzeInstBitCastResultPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
...@@ -320,7 +338,7 @@ fn analyzeInstRetPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerErr...@@ -320,7 +338,7 @@ fn analyzeInstRetPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerErr
320338
321fn analyzeInstRef(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {339fn analyzeInstRef(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
322 const operand = try resolveInst(mod, scope, inst.positionals.operand);340 const operand = try resolveInst(mod, scope, inst.positionals.operand);
323 const ptr_type = try mod.singlePtrType(scope, inst.base.src, false, operand.ty);341 const ptr_type = try mod.simplePtrType(scope, inst.base.src, operand.ty, false, .One);
324342
325 if (operand.value()) |val| {343 if (operand.value()) |val| {
326 const ref_payload = try scope.arena().create(Value.Payload.RefVal);344 const ref_payload = try scope.arena().create(Value.Payload.RefVal);
...@@ -361,7 +379,11 @@ fn analyzeInstEnsureResultNonError(mod: *Module, scope: *Scope, inst: *zir.Inst....@@ -361,7 +379,11 @@ fn analyzeInstEnsureResultNonError(mod: *Module, scope: *Scope, inst: *zir.Inst.
361379
362fn analyzeInstAlloc(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {380fn analyzeInstAlloc(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
363 const var_type = try resolveType(mod, scope, inst.positionals.operand);381 const var_type = try resolveType(mod, scope, inst.positionals.operand);
364 const ptr_type = try mod.singlePtrType(scope, inst.base.src, true, var_type);382 // TODO this should happen only for var allocs
383 if (!var_type.isValidVarType(false)) {
384 return mod.fail(scope, inst.base.src, "variable of type '{}' must be const or comptime", .{var_type});
385 }
386 const ptr_type = try mod.simplePtrType(scope, inst.base.src, var_type, true, .One);
365 const b = try mod.requireRuntimeBlock(scope, inst.base.src);387 const b = try mod.requireRuntimeBlock(scope, inst.base.src);
366 return mod.addNoOp(b, inst.base.src, ptr_type, .alloc);388 return mod.addNoOp(b, inst.base.src, ptr_type, .alloc);
367}389}
...@@ -573,8 +595,7 @@ fn analyzeInstDeclVal(mod: *Module, scope: *Scope, inst: *zir.Inst.DeclVal) Inne...@@ -573,8 +595,7 @@ fn analyzeInstDeclVal(mod: *Module, scope: *Scope, inst: *zir.Inst.DeclVal) Inne
573595
574fn analyzeInstDeclValInModule(mod: *Module, scope: *Scope, inst: *zir.Inst.DeclValInModule) InnerError!*Inst {596fn analyzeInstDeclValInModule(mod: *Module, scope: *Scope, inst: *zir.Inst.DeclValInModule) InnerError!*Inst {
575 const decl = inst.positionals.decl;597 const decl = inst.positionals.decl;
576 const ptr = try mod.analyzeDeclRef(scope, inst.base.src, decl);598 return mod.analyzeDeclRef(scope, inst.base.src, decl);
577 return mod.analyzeDeref(scope, inst.base.src, ptr, inst.base.src);
578}599}
579600
580fn analyzeInstCall(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError!*Inst {601fn analyzeInstCall(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError!*Inst {
...@@ -675,31 +696,36 @@ fn analyzeInstIntType(mod: *Module, scope: *Scope, inttype: *zir.Inst.IntType) I...@@ -675,31 +696,36 @@ fn analyzeInstIntType(mod: *Module, scope: *Scope, inttype: *zir.Inst.IntType) I
675fn analyzeInstOptionalType(mod: *Module, scope: *Scope, optional: *zir.Inst.UnOp) InnerError!*Inst {696fn analyzeInstOptionalType(mod: *Module, scope: *Scope, optional: *zir.Inst.UnOp) InnerError!*Inst {
676 const child_type = try resolveType(mod, scope, optional.positionals.operand);697 const child_type = try resolveType(mod, scope, optional.positionals.operand);
677698
678 return mod.constType(scope, optional.base.src, Type.initPayload(switch (child_type.tag()) {699 return mod.constType(scope, optional.base.src, try mod.optionalType(scope, child_type));
679 .single_const_pointer => blk: {700}
680 const payload = try scope.arena().create(Type.Payload.Pointer);701
681 payload.* = .{702fn analyzeInstArrayType(mod: *Module, scope: *Scope, array: *zir.Inst.BinOp) InnerError!*Inst {
682 .base = .{ .tag = .optional_single_const_pointer },703 // TODO these should be lazily evaluated
683 .pointee_type = child_type.elemType(),704 const len = try resolveInstConst(mod, scope, array.positionals.lhs);
684 };705 const elem_type = try resolveType(mod, scope, array.positionals.rhs);
685 break :blk &payload.base;706
686 },707 return mod.constType(scope, array.base.src, try mod.arrayType(scope, len.val.toUnsignedInt(), null, elem_type));
687 .single_mut_pointer => blk: {708}
688 const payload = try scope.arena().create(Type.Payload.Pointer);709
689 payload.* = .{710fn analyzeInstArrayTypeSentinel(mod: *Module, scope: *Scope, array: *zir.Inst.ArrayTypeSentinel) InnerError!*Inst {
690 .base = .{ .tag = .optional_single_mut_pointer },711 // TODO these should be lazily evaluated
691 .pointee_type = child_type.elemType(),712 const len = try resolveInstConst(mod, scope, array.positionals.len);
692 };713 const sentinel = try resolveInstConst(mod, scope, array.positionals.sentinel);
693 break :blk &payload.base;714 const elem_type = try resolveType(mod, scope, array.positionals.elem_type);
694 },715
695 else => blk: {716 return mod.constType(scope, array.base.src, try mod.arrayType(scope, len.val.toUnsignedInt(), sentinel.val, elem_type));
696 const payload = try scope.arena().create(Type.Payload.Optional);717}
697 payload.* = .{718
698 .child_type = child_type,719fn analyzeInstEnumLiteral(mod: *Module, scope: *Scope, inst: *zir.Inst.EnumLiteral) InnerError!*Inst {
699 };720 const payload = try scope.arena().create(Value.Payload.Bytes);
700 break :blk &payload.base;721 payload.* = .{
701 },722 .base = .{ .tag = .enum_literal },
702 }));723 .data = try scope.arena().dupe(u8, inst.positionals.name),
724 };
725 return mod.constInst(scope, inst.base.src, .{
726 .ty = Type.initTag(.enum_literal),
727 .val = Value.initPayload(&payload.base),
728 });
703}729}
704730
705fn analyzeInstUnwrapOptional(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp, safety_check: bool) InnerError!*Inst {731fn analyzeInstUnwrapOptional(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp, safety_check: bool) InnerError!*Inst {
...@@ -711,7 +737,7 @@ fn analyzeInstUnwrapOptional(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp...@@ -711,7 +737,7 @@ fn analyzeInstUnwrapOptional(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp
711 }737 }
712738
713 const child_type = try operand.ty.elemType().optionalChildAlloc(scope.arena());739 const child_type = try operand.ty.elemType().optionalChildAlloc(scope.arena());
714 const child_pointer = try mod.singlePtrType(scope, unwrap.base.src, operand.ty.isConstPtr(), child_type);740 const child_pointer = try mod.simplePtrType(scope, unwrap.base.src, child_type, operand.ty.isConstPtr(), .One);
715741
716 if (operand.value()) |val| {742 if (operand.value()) |val| {
717 if (val.isNull()) {743 if (val.isNull()) {
...@@ -735,6 +761,10 @@ fn analyzeInstUnwrapErr(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp, saf...@@ -735,6 +761,10 @@ fn analyzeInstUnwrapErr(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp, saf
735 return mod.fail(scope, unwrap.base.src, "TODO implement analyzeInstUnwrapErr", .{});761 return mod.fail(scope, unwrap.base.src, "TODO implement analyzeInstUnwrapErr", .{});
736}762}
737763
764fn analyzeInstEnsureErrPayloadVoid(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp) InnerError!*Inst {
765 return mod.fail(scope, unwrap.base.src, "TODO implement analyzeInstEnsureErrPayloadVoid", .{});
766}
767
738fn analyzeInstFnType(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnType) InnerError!*Inst {768fn analyzeInstFnType(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnType) InnerError!*Inst {
739 const return_type = try resolveType(mod, scope, fntype.positionals.return_type);769 const return_type = try resolveType(mod, scope, fntype.positionals.return_type);
740770
...@@ -760,7 +790,12 @@ fn analyzeInstFnType(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnType) Inne...@@ -760,7 +790,12 @@ fn analyzeInstFnType(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnType) Inne
760 const arena = scope.arena();790 const arena = scope.arena();
761 const param_types = try arena.alloc(Type, fntype.positionals.param_types.len);791 const param_types = try arena.alloc(Type, fntype.positionals.param_types.len);
762 for (fntype.positionals.param_types) |param_type, i| {792 for (fntype.positionals.param_types) |param_type, i| {
763 param_types[i] = try resolveType(mod, scope, param_type);793 const resolved = try resolveType(mod, scope, param_type);
794 // TODO skip for comptime params
795 if (!resolved.isValidVarType(false)) {
796 return mod.fail(scope, param_type.src, "parameter of type '{}' must be declared comptime", .{resolved});
797 }
798 param_types[i] = resolved;
764 }799 }
765800
766 const payload = try arena.create(Type.Payload.Function);801 const payload = try arena.create(Type.Payload.Function);
...@@ -919,7 +954,7 @@ fn analyzeInstElemPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.ElemPtr) Inne...@@ -919,7 +954,7 @@ fn analyzeInstElemPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.ElemPtr) Inne
919 // required a larger index.954 // required a larger index.
920 const elem_ptr = try array_ptr_val.elemPtr(scope.arena(), @intCast(usize, index_u64));955 const elem_ptr = try array_ptr_val.elemPtr(scope.arena(), @intCast(usize, index_u64));
921956
922 const type_payload = try scope.arena().create(Type.Payload.Pointer);957 const type_payload = try scope.arena().create(Type.Payload.PointerSimple);
923 type_payload.* = .{958 type_payload.* = .{
924 .base = .{ .tag = .single_const_pointer },959 .base = .{ .tag = .single_const_pointer },
925 .pointee_type = array_ptr.ty.elemType().elemType(),960 .pointee_type = array_ptr.ty.elemType().elemType(),
...@@ -1290,18 +1325,49 @@ fn analyzeDeclVal(mod: *Module, scope: *Scope, inst: *zir.Inst.DeclVal) InnerErr...@@ -1290,18 +1325,49 @@ fn analyzeDeclVal(mod: *Module, scope: *Scope, inst: *zir.Inst.DeclVal) InnerErr
1290 return decl;1325 return decl;
1291}1326}
12921327
1293fn analyzeInstSingleConstPtrType(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {1328fn analyzeInstSimplePtrType(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp, mutable: bool, size: std.builtin.TypeInfo.Pointer.Size) InnerError!*Inst {
1294 const elem_type = try resolveType(mod, scope, inst.positionals.operand);1329 const elem_type = try resolveType(mod, scope, inst.positionals.operand);
1295 const ty = try mod.singlePtrType(scope, inst.base.src, false, elem_type);1330 const ty = try mod.simplePtrType(scope, inst.base.src, elem_type, mutable, size);
1296 return mod.constType(scope, inst.base.src, ty);
1297}
1298
1299fn analyzeInstSingleMutPtrType(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
1300 const elem_type = try resolveType(mod, scope, inst.positionals.operand);
1301 const ty = try mod.singlePtrType(scope, inst.base.src, true, elem_type);
1302 return mod.constType(scope, inst.base.src, ty);1331 return mod.constType(scope, inst.base.src, ty);
1303}1332}
13041333
1305fn analyzeInstPtrType(mod: *Module, scope: *Scope, inst: *zir.Inst.PtrType) InnerError!*Inst {1334fn analyzeInstPtrType(mod: *Module, scope: *Scope, inst: *zir.Inst.PtrType) InnerError!*Inst {
1306 return mod.fail(scope, inst.base.src, "TODO implement ptr_type", .{});1335 // TODO lazy values
1336 const @"align" = if (inst.kw_args.@"align") |some|
1337 @truncate(u32, try resolveInt(mod, scope, some, Type.initTag(.u32)))
1338 else
1339 0;
1340 const bit_offset = if (inst.kw_args.align_bit_start) |some|
1341 @truncate(u16, try resolveInt(mod, scope, some, Type.initTag(.u16)))
1342 else
1343 0;
1344 const host_size = if (inst.kw_args.align_bit_end) |some|
1345 @truncate(u16, try resolveInt(mod, scope, some, Type.initTag(.u16)))
1346 else
1347 0;
1348
1349 if (host_size != 0 and bit_offset >= host_size * 8)
1350 return mod.fail(scope, inst.base.src, "bit offset starts after end of host integer", .{});
1351
1352 const sentinel = if (inst.kw_args.sentinel) |some|
1353 (try resolveInstConst(mod, scope, some)).val
1354 else
1355 null;
1356
1357 const elem_type = try resolveType(mod, scope, inst.positionals.child_type);
1358
1359 const ty = try mod.ptrType(
1360 scope,
1361 inst.base.src,
1362 elem_type,
1363 sentinel,
1364 @"align",
1365 bit_offset,
1366 host_size,
1367 inst.kw_args.mutable,
1368 inst.kw_args.@"allowzero",
1369 inst.kw_args.@"volatile",
1370 inst.kw_args.size,
1371 );
1372 return mod.constType(scope, inst.base.src, ty);
1307}1373}
src/all_types.hpp+1
...@@ -1420,6 +1420,7 @@ struct ZigTypeStruct {...@@ -1420,6 +1420,7 @@ struct ZigTypeStruct {
1420 bool requires_comptime;1420 bool requires_comptime;
1421 bool resolve_loop_flag_zero_bits;1421 bool resolve_loop_flag_zero_bits;
1422 bool resolve_loop_flag_other;1422 bool resolve_loop_flag_other;
1423 bool created_by_at_type;
1423};1424};
14241425
1425struct ZigTypeOptional {1426struct ZigTypeOptional {
src/analyze.cpp+5-5
...@@ -138,7 +138,7 @@ void init_scope(CodeGen *g, Scope *dest, ScopeId id, AstNode *source_node, Scope...@@ -138,7 +138,7 @@ void init_scope(CodeGen *g, Scope *dest, ScopeId id, AstNode *source_node, Scope
138 dest->parent = parent;138 dest->parent = parent;
139}139}
140140
141static ScopeDecls *create_decls_scope(CodeGen *g, AstNode *node, Scope *parent, ZigType *container_type,141ScopeDecls *create_decls_scope(CodeGen *g, AstNode *node, Scope *parent, ZigType *container_type,
142 ZigType *import, Buf *bare_name)142 ZigType *import, Buf *bare_name)
143{143{
144 ScopeDecls *scope = heap::c_allocator.create<ScopeDecls>();144 ScopeDecls *scope = heap::c_allocator.create<ScopeDecls>();
...@@ -2821,7 +2821,7 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) {...@@ -2821,7 +2821,7 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) {
28212821
2822 src_assert(struct_type->data.structure.fields == nullptr, decl_node);2822 src_assert(struct_type->data.structure.fields == nullptr, decl_node);
2823 struct_type->data.structure.fields = alloc_type_struct_fields(field_count);2823 struct_type->data.structure.fields = alloc_type_struct_fields(field_count);
2824 } else if (is_anon_container(struct_type)) {2824 } else if (is_anon_container(struct_type) || struct_type->data.structure.created_by_at_type) {
2825 field_count = struct_type->data.structure.src_field_count;2825 field_count = struct_type->data.structure.src_field_count;
28262826
2827 src_assert(field_count == 0 || struct_type->data.structure.fields != nullptr, decl_node);2827 src_assert(field_count == 0 || struct_type->data.structure.fields != nullptr, decl_node);
...@@ -2856,7 +2856,7 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) {...@@ -2856,7 +2856,7 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) {
2856 struct_type->data.structure.resolve_status = ResolveStatusInvalid;2856 struct_type->data.structure.resolve_status = ResolveStatusInvalid;
2857 return ErrorSemanticAnalyzeFail;2857 return ErrorSemanticAnalyzeFail;
2858 }2858 }
2859 } else if (is_anon_container(struct_type)) {2859 } else if (is_anon_container(struct_type) || struct_type->data.structure.created_by_at_type) {
2860 field_node = type_struct_field->decl_node;2860 field_node = type_struct_field->decl_node;
28612861
2862 src_assert(type_struct_field->type_entry != nullptr, field_node);2862 src_assert(type_struct_field->type_entry != nullptr, field_node);
...@@ -2883,7 +2883,7 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) {...@@ -2883,7 +2883,7 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) {
2883 type_struct_field->type_val = field_type_val;2883 type_struct_field->type_val = field_type_val;
2884 if (struct_type->data.structure.resolve_status == ResolveStatusInvalid)2884 if (struct_type->data.structure.resolve_status == ResolveStatusInvalid)
2885 return ErrorSemanticAnalyzeFail;2885 return ErrorSemanticAnalyzeFail;
2886 } else if (is_anon_container(struct_type)) {2886 } else if (is_anon_container(struct_type) || struct_type->data.structure.created_by_at_type) {
2887 field_type_val = type_struct_field->type_val;2887 field_type_val = type_struct_field->type_val;
2888 } else zig_unreachable();2888 } else zig_unreachable();
28892889
...@@ -8331,7 +8331,7 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS...@@ -8331,7 +8331,7 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS
8331 ZigLLVMDIFile *di_file;8331 ZigLLVMDIFile *di_file;
8332 ZigLLVMDIScope *di_scope;8332 ZigLLVMDIScope *di_scope;
8333 unsigned line;8333 unsigned line;
8334 if (decl_node != nullptr) {8334 if (decl_node != nullptr && !struct_type->data.structure.created_by_at_type) {
8335 Scope *scope = &struct_type->data.structure.decls_scope->base;8335 Scope *scope = &struct_type->data.structure.decls_scope->base;
8336 ZigType *import = get_scope_import(scope);8336 ZigType *import = get_scope_import(scope);
8337 di_file = import->data.structure.root_struct->di_file;8337 di_file = import->data.structure.root_struct->di_file;
src/analyze.hpp+1
...@@ -116,6 +116,7 @@ void eval_min_max_value_int(CodeGen *g, ZigType *int_type, BigInt *bigint, bool...@@ -116,6 +116,7 @@ void eval_min_max_value_int(CodeGen *g, ZigType *int_type, BigInt *bigint, bool
116116
117void render_const_value(CodeGen *g, Buf *buf, ZigValue *const_val);117void render_const_value(CodeGen *g, Buf *buf, ZigValue *const_val);
118118
119ScopeDecls *create_decls_scope(CodeGen *g, AstNode *node, Scope *parent, ZigType *container_type, ZigType *import, Buf *bare_name);
119ScopeBlock *create_block_scope(CodeGen *g, AstNode *node, Scope *parent);120ScopeBlock *create_block_scope(CodeGen *g, AstNode *node, Scope *parent);
120ScopeDefer *create_defer_scope(CodeGen *g, AstNode *node, Scope *parent);121ScopeDefer *create_defer_scope(CodeGen *g, AstNode *node, Scope *parent);
121ScopeDeferExpr *create_defer_expr_scope(CodeGen *g, AstNode *node, Scope *parent);122ScopeDeferExpr *create_defer_expr_scope(CodeGen *g, AstNode *node, Scope *parent);
src/codegen.cpp+5-4
...@@ -293,13 +293,14 @@ static void add_uwtable_attr(CodeGen *g, LLVMValueRef fn_val) {...@@ -293,13 +293,14 @@ static void add_uwtable_attr(CodeGen *g, LLVMValueRef fn_val) {
293 }293 }
294}294}
295295
296static LLVMLinkage to_llvm_linkage(GlobalLinkageId id) {296static LLVMLinkage to_llvm_linkage(GlobalLinkageId id, bool is_extern) {
297 switch (id) {297 switch (id) {
298 case GlobalLinkageIdInternal:298 case GlobalLinkageIdInternal:
299 return LLVMInternalLinkage;299 return LLVMInternalLinkage;
300 case GlobalLinkageIdStrong:300 case GlobalLinkageIdStrong:
301 return LLVMExternalLinkage;301 return LLVMExternalLinkage;
302 case GlobalLinkageIdWeak:302 case GlobalLinkageIdWeak:
303 if (is_extern) return LLVMExternalWeakLinkage;
303 return LLVMWeakODRLinkage;304 return LLVMWeakODRLinkage;
304 case GlobalLinkageIdLinkOnce:305 case GlobalLinkageIdLinkOnce:
305 return LLVMLinkOnceODRLinkage;306 return LLVMLinkOnceODRLinkage;
...@@ -522,7 +523,7 @@ static LLVMValueRef make_fn_llvm_value(CodeGen *g, ZigFn *fn) {...@@ -522,7 +523,7 @@ static LLVMValueRef make_fn_llvm_value(CodeGen *g, ZigFn *fn) {
522 }523 }
523524
524525
525 LLVMSetLinkage(llvm_fn, to_llvm_linkage(linkage));526 LLVMSetLinkage(llvm_fn, to_llvm_linkage(linkage, fn->body_node == nullptr));
526527
527 if (linkage == GlobalLinkageIdInternal) {528 if (linkage == GlobalLinkageIdInternal) {
528 LLVMSetUnnamedAddr(llvm_fn, true);529 LLVMSetUnnamedAddr(llvm_fn, true);
...@@ -7963,7 +7964,7 @@ static void do_code_gen(CodeGen *g) {...@@ -7963,7 +7964,7 @@ static void do_code_gen(CodeGen *g) {
7963 global_value = LLVMAddGlobal(g->module, get_llvm_type(g, var->var_type), symbol_name);7964 global_value = LLVMAddGlobal(g->module, get_llvm_type(g, var->var_type), symbol_name);
7964 // TODO debug info for the extern variable7965 // TODO debug info for the extern variable
79657966
7966 LLVMSetLinkage(global_value, to_llvm_linkage(linkage));7967 LLVMSetLinkage(global_value, to_llvm_linkage(linkage, true));
7967 maybe_import_dll(g, global_value, GlobalLinkageIdStrong);7968 maybe_import_dll(g, global_value, GlobalLinkageIdStrong);
7968 LLVMSetAlignment(global_value, var->align_bytes);7969 LLVMSetAlignment(global_value, var->align_bytes);
7969 LLVMSetGlobalConstant(global_value, var->gen_is_const);7970 LLVMSetGlobalConstant(global_value, var->gen_is_const);
...@@ -7976,7 +7977,7 @@ static void do_code_gen(CodeGen *g) {...@@ -7976,7 +7977,7 @@ static void do_code_gen(CodeGen *g) {
7976 global_value = var->const_value->llvm_global;7977 global_value = var->const_value->llvm_global;
79777978
7978 if (exported) {7979 if (exported) {
7979 LLVMSetLinkage(global_value, to_llvm_linkage(linkage));7980 LLVMSetLinkage(global_value, to_llvm_linkage(linkage, false));
7980 maybe_export_dll(g, global_value, GlobalLinkageIdStrong);7981 maybe_export_dll(g, global_value, GlobalLinkageIdStrong);
7981 }7982 }
7982 if (var->section_name) {7983 if (var->section_name) {
src/ir.cpp+120-50
...@@ -25679,37 +25679,20 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy...@@ -25679,37 +25679,20 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy
25679 struct_field_val->type = type_info_struct_field_type;25679 struct_field_val->type = type_info_struct_field_type;
2568025680
25681 ZigValue **inner_fields = alloc_const_vals_ptrs(ira->codegen, 4);25681 ZigValue **inner_fields = alloc_const_vals_ptrs(ira->codegen, 4);
25682 inner_fields[1]->special = ConstValSpecialStatic;
25683 inner_fields[1]->type = get_optional_type(ira->codegen, ira->codegen->builtin_types.entry_num_lit_int);
25684
25685 ZigType *field_type = resolve_struct_field_type(ira->codegen, struct_field);
25686 if (field_type == nullptr)
25687 return ErrorSemanticAnalyzeFail;
25688 if ((err = type_resolve(ira->codegen, field_type, ResolveStatusZeroBitsKnown)))
25689 return err;
25690 if (!type_has_bits(ira->codegen, struct_field->type_entry)) {
25691 inner_fields[1]->data.x_optional = nullptr;
25692 } else {
25693 size_t byte_offset = struct_field->offset;
25694 inner_fields[1]->data.x_optional = ira->codegen->pass1_arena->create<ZigValue>();
25695 inner_fields[1]->data.x_optional->special = ConstValSpecialStatic;
25696 inner_fields[1]->data.x_optional->type = ira->codegen->builtin_types.entry_num_lit_int;
25697 bigint_init_unsigned(&inner_fields[1]->data.x_optional->data.x_bigint, byte_offset);
25698 }
2569925682
25700 inner_fields[2]->special = ConstValSpecialStatic;25683 inner_fields[1]->special = ConstValSpecialStatic;
25701 inner_fields[2]->type = ira->codegen->builtin_types.entry_type;25684 inner_fields[1]->type = ira->codegen->builtin_types.entry_type;
25702 inner_fields[2]->data.x_type = struct_field->type_entry;25685 inner_fields[1]->data.x_type = struct_field->type_entry;
2570325686
25704 // default_value: anytype25687 // default_value: anytype
25705 inner_fields[3]->special = ConstValSpecialStatic;25688 inner_fields[2]->special = ConstValSpecialStatic;
25706 inner_fields[3]->type = get_optional_type2(ira->codegen, struct_field->type_entry);25689 inner_fields[2]->type = get_optional_type2(ira->codegen, struct_field->type_entry);
25707 if (inner_fields[3]->type == nullptr) return ErrorSemanticAnalyzeFail;25690 if (inner_fields[2]->type == nullptr) return ErrorSemanticAnalyzeFail;
25708 memoize_field_init_val(ira->codegen, type_entry, struct_field);25691 memoize_field_init_val(ira->codegen, type_entry, struct_field);
25709 if(struct_field->init_val != nullptr && type_is_invalid(struct_field->init_val->type)){25692 if(struct_field->init_val != nullptr && type_is_invalid(struct_field->init_val->type)){
25710 return ErrorSemanticAnalyzeFail;25693 return ErrorSemanticAnalyzeFail;
25711 }25694 }
25712 set_optional_payload(inner_fields[3], struct_field->init_val);25695 set_optional_payload(inner_fields[2], struct_field->init_val);
2571325696
25714 ZigValue *name = create_const_str_lit(ira->codegen, struct_field->name)->data.x_ptr.data.ref.pointee;25697 ZigValue *name = create_const_str_lit(ira->codegen, struct_field->name)->data.x_ptr.data.ref.pointee;
25715 init_const_slice(ira->codegen, inner_fields[0], name, 0, buf_len(struct_field->name), true);25698 init_const_slice(ira->codegen, inner_fields[0], name, 0, buf_len(struct_field->name), true);
...@@ -25960,6 +25943,36 @@ static ZigType *get_const_field_meta_type_optional(IrAnalyze *ira, AstNode *sour...@@ -25960,6 +25943,36 @@ static ZigType *get_const_field_meta_type_optional(IrAnalyze *ira, AstNode *sour
25960 return value->data.x_optional->data.x_type;25943 return value->data.x_optional->data.x_type;
25961}25944}
2596225945
25946static Error get_const_field_buf(IrAnalyze *ira, AstNode *source_node, ZigValue *struct_value,
25947 const char *name, size_t field_index, Buf *out)
25948{
25949 ZigValue *slice = get_const_field(ira, source_node, struct_value, name, field_index);
25950 ZigValue *ptr = slice->data.x_struct.fields[slice_ptr_index];
25951 ZigValue *len = slice->data.x_struct.fields[slice_len_index];
25952 assert(ptr->data.x_ptr.special == ConstPtrSpecialBaseArray);
25953 assert(ptr->data.x_ptr.data.base_array.elem_index == 0);
25954 ZigValue *arr = ptr->data.x_ptr.data.base_array.array_val;
25955 assert(arr->special == ConstValSpecialStatic);
25956 switch (arr->data.x_array.special) {
25957 case ConstArraySpecialUndef:
25958 return ErrorSemanticAnalyzeFail;
25959 case ConstArraySpecialNone: {
25960 buf_resize(out, 0);
25961 size_t count = bigint_as_usize(&len->data.x_bigint);
25962 for (size_t j = 0; j < count; j++) {
25963 ZigValue *ch_val = &arr->data.x_array.data.s_none.elements[j];
25964 unsigned ch = bigint_as_u32(&ch_val->data.x_bigint);
25965 buf_append_char(out, ch);
25966 }
25967 break;
25968 }
25969 case ConstArraySpecialBuf:
25970 buf_init_from_buf(out, arr->data.x_array.data.s_buf);
25971 break;
25972 }
25973 return ErrorNone;
25974}
25975
25963static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeId tagTypeId, ZigValue *payload) {25976static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeId tagTypeId, ZigValue *payload) {
25964 Error err;25977 Error err;
25965 switch (tagTypeId) {25978 switch (tagTypeId) {
...@@ -26163,30 +26176,9 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeI...@@ -26163,30 +26176,9 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeI
26163 assert(error->type == ir_type_info_get_type(ira, "Error", nullptr));26176 assert(error->type == ir_type_info_get_type(ira, "Error", nullptr));
26164 ErrorTableEntry *err_entry = heap::c_allocator.create<ErrorTableEntry>();26177 ErrorTableEntry *err_entry = heap::c_allocator.create<ErrorTableEntry>();
26165 err_entry->decl_node = source_instr->source_node;26178 err_entry->decl_node = source_instr->source_node;
26166 ZigValue *name_slice = get_const_field(ira, source_instr->source_node, error, "name", 0);26179 Error err;
26167 ZigValue *name_ptr = name_slice->data.x_struct.fields[slice_ptr_index];26180 if ((err = get_const_field_buf(ira, source_instr->source_node, error, "name", 0, &err_entry->name)))
26168 ZigValue *name_len = name_slice->data.x_struct.fields[slice_len_index];26181 return ira->codegen->invalid_inst_gen->value->type;
26169 assert(name_ptr->data.x_ptr.special == ConstPtrSpecialBaseArray);
26170 assert(name_ptr->data.x_ptr.data.base_array.elem_index == 0);
26171 ZigValue *name_arr = name_ptr->data.x_ptr.data.base_array.array_val;
26172 assert(name_arr->special == ConstValSpecialStatic);
26173 switch (name_arr->data.x_array.special) {
26174 case ConstArraySpecialUndef:
26175 return ira->codegen->invalid_inst_gen->value->type;
26176 case ConstArraySpecialNone: {
26177 buf_resize(&err_entry->name, 0);
26178 size_t name_count = bigint_as_usize(&name_len->data.x_bigint);
26179 for (size_t j = 0; j < name_count; j++) {
26180 ZigValue *ch_val = &name_arr->data.x_array.data.s_none.elements[j];
26181 unsigned ch = bigint_as_u32(&ch_val->data.x_bigint);
26182 buf_append_char(&err_entry->name, ch);
26183 }
26184 break;
26185 }
26186 case ConstArraySpecialBuf:
26187 buf_init_from_buf(&err_entry->name, name_arr->data.x_array.data.s_buf);
26188 break;
26189 }
26190 auto existing_entry = ira->codegen->error_table.put_unique(&err_entry->name, err_entry);26182 auto existing_entry = ira->codegen->error_table.put_unique(&err_entry->name, err_entry);
26191 if (existing_entry) {26183 if (existing_entry) {
26192 err_entry->value = existing_entry->value->value;26184 err_entry->value = existing_entry->value->value;
...@@ -26206,14 +26198,92 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeI...@@ -26206,14 +26198,92 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeI
26206 }26198 }
26207 return err_set_type;26199 return err_set_type;
26208 }26200 }
26201 case ZigTypeIdStruct: {
26202 assert(payload->special == ConstValSpecialStatic);
26203 assert(payload->type == ir_type_info_get_type(ira, "Struct", nullptr));
26204
26205 ZigValue *layout_value = get_const_field(ira, source_instr->source_node, payload, "layout", 0);
26206 assert(layout_value->special == ConstValSpecialStatic);
26207 assert(layout_value->type == ir_type_info_get_type(ira, "ContainerLayout", nullptr));
26208 ContainerLayout layout = (ContainerLayout)bigint_as_u32(&layout_value->data.x_enum_tag);
26209
26210 ZigValue *fields_value = get_const_field(ira, source_instr->source_node, payload, "fields", 1);
26211 assert(fields_value->special == ConstValSpecialStatic);
26212 assert(is_slice(fields_value->type));
26213 ZigValue *fields_ptr = fields_value->data.x_struct.fields[slice_ptr_index];
26214 ZigValue *fields_len_value = fields_value->data.x_struct.fields[slice_len_index];
26215 size_t fields_len = bigint_as_usize(&fields_len_value->data.x_bigint);
26216
26217 ZigValue *decls_value = get_const_field(ira, source_instr->source_node, payload, "decls", 2);
26218 assert(decls_value->special == ConstValSpecialStatic);
26219 assert(is_slice(decls_value->type));
26220 ZigValue *decls_len_value = decls_value->data.x_struct.fields[slice_len_index];
26221 size_t decls_len = bigint_as_usize(&decls_len_value->data.x_bigint);
26222 if (decls_len != 0) {
26223 ir_add_error(ira, source_instr, buf_create_from_str("TypeInfo.Struct.decls must be empty for @Type"));
26224 return ira->codegen->invalid_inst_gen->value->type;
26225 }
26226
26227 bool is_tuple;
26228 get_const_field_bool(ira, source_instr->source_node, payload, "is_tuple", 3, &is_tuple);
26229
26230 ZigType *entry = new_type_table_entry(ZigTypeIdStruct);
26231 buf_init_from_buf(&entry->name,
26232 get_anon_type_name(ira->codegen, ira->old_irb.exec, "struct", source_instr->scope, source_instr->source_node, &entry->name));
26233 entry->data.structure.decl_node = source_instr->source_node;
26234 entry->data.structure.fields = alloc_type_struct_fields(fields_len);
26235 entry->data.structure.fields_by_name.init(fields_len);
26236 entry->data.structure.src_field_count = fields_len;
26237 entry->data.structure.layout = layout;
26238 entry->data.structure.special = is_tuple ? StructSpecialInferredTuple : StructSpecialNone;
26239 entry->data.structure.created_by_at_type = true;
26240 entry->data.structure.decls_scope = create_decls_scope(ira->codegen, nullptr, nullptr, entry, entry, &entry->name);
26241
26242 assert(fields_ptr->data.x_ptr.special == ConstPtrSpecialBaseArray);
26243 assert(fields_ptr->data.x_ptr.data.base_array.elem_index == 0);
26244 ZigValue *fields_arr = fields_ptr->data.x_ptr.data.base_array.array_val;
26245 assert(fields_arr->special == ConstValSpecialStatic);
26246 assert(fields_arr->data.x_array.special == ConstArraySpecialNone);
26247 for (size_t i = 0; i < fields_len; i++) {
26248 ZigValue *field_value = &fields_arr->data.x_array.data.s_none.elements[i];
26249 assert(field_value->type == ir_type_info_get_type(ira, "StructField", nullptr));
26250 TypeStructField *field = entry->data.structure.fields[i];
26251 field->name = buf_alloc();
26252 if ((err = get_const_field_buf(ira, source_instr->source_node, field_value, "name", 0, field->name)))
26253 return ira->codegen->invalid_inst_gen->value->type;
26254 field->decl_node = source_instr->source_node;
26255 ZigValue *type_value = get_const_field(ira, source_instr->source_node, field_value, "field_type", 1);
26256 field->type_val = type_value;
26257 field->type_entry = type_value->data.x_type;
26258 if (entry->data.structure.fields_by_name.put_unique(field->name, field) != nullptr) {
26259 ir_add_error(ira, source_instr, buf_sprintf("duplicate struct field '%s'", buf_ptr(field->name)));
26260 return ira->codegen->invalid_inst_gen->value->type;
26261 }
26262 ZigValue *default_value = get_const_field(ira, source_instr->source_node, field_value, "default_value", 2);
26263 if (default_value->type->id == ZigTypeIdNull) {
26264 field->init_val = nullptr;
26265 } else if (default_value->type->id == ZigTypeIdOptional && default_value->type->data.maybe.child_type == field->type_entry) {
26266 field->init_val = default_value->data.x_optional;
26267 } else if (default_value->type == field->type_entry) {
26268 field->init_val = default_value;
26269 } else {
26270 ir_add_error(ira, source_instr,
26271 buf_sprintf("default_value of field '%s' is of type '%s', expected '%s' or '?%s'",
26272 buf_ptr(field->name), buf_ptr(&default_value->type->name),
26273 buf_ptr(&field->type_entry->name), buf_ptr(&field->type_entry->name)));
26274 return ira->codegen->invalid_inst_gen->value->type;
26275 }
26276 }
26277
26278 return entry;
26279 }
26209 case ZigTypeIdEnum:26280 case ZigTypeIdEnum:
26281 case ZigTypeIdUnion:
26210 ir_add_error(ira, source_instr, buf_sprintf(26282 ir_add_error(ira, source_instr, buf_sprintf(
26211 "TODO implement @Type for 'TypeInfo.%s': see https://github.com/ziglang/zig/issues/2907", type_id_name(tagTypeId)));26283 "TODO implement @Type for 'TypeInfo.%s': see https://github.com/ziglang/zig/issues/2907", type_id_name(tagTypeId)));
26212 return ira->codegen->invalid_inst_gen->value->type;26284 return ira->codegen->invalid_inst_gen->value->type;
26213 case ZigTypeIdUnion:
26214 case ZigTypeIdFn:26285 case ZigTypeIdFn:
26215 case ZigTypeIdBoundFn:26286 case ZigTypeIdBoundFn:
26216 case ZigTypeIdStruct:
26217 ir_add_error(ira, source_instr, buf_sprintf(26287 ir_add_error(ira, source_instr, buf_sprintf(
26218 "@Type not available for 'TypeInfo.%s'", type_id_name(tagTypeId)));26288 "@Type not available for 'TypeInfo.%s'", type_id_name(tagTypeId)));
26219 return ira->codegen->invalid_inst_gen->value->type;26289 return ira->codegen->invalid_inst_gen->value->type;
src/parser.cpp+3
...@@ -680,6 +680,9 @@ static AstNode *ast_parse_top_level_decl(ParseContext *pc, VisibMod visib_mod, B...@@ -680,6 +680,9 @@ static AstNode *ast_parse_top_level_decl(ParseContext *pc, VisibMod visib_mod, B
680 AstNode *var_decl = ast_parse_var_decl(pc);680 AstNode *var_decl = ast_parse_var_decl(pc);
681 if (var_decl != nullptr) {681 if (var_decl != nullptr) {
682 assert(var_decl->type == NodeTypeVariableDeclaration);682 assert(var_decl->type == NodeTypeVariableDeclaration);
683 if (first->id == TokenIdKeywordExtern && var_decl->data.variable_declaration.expr != nullptr) {
684 ast_error(pc, first, "extern variables have no initializers");
685 }
683 var_decl->line = first->start_line;686 var_decl->line = first->start_line;
684 var_decl->column = first->start_column;687 var_decl->column = first->start_column;
685 var_decl->data.variable_declaration.threadlocal_tok = thread_local_kw;688 var_decl->data.variable_declaration.threadlocal_tok = thread_local_kw;
test/compile_errors.zig+9-3
...@@ -2,6 +2,12 @@ const tests = @import("tests.zig");...@@ -2,6 +2,12 @@ const tests = @import("tests.zig");
2const std = @import("std");2const std = @import("std");
33
4pub fn addCases(cases: *tests.CompileErrorContext) void {4pub fn addCases(cases: *tests.CompileErrorContext) void {
5 cases.addTest("reject extern variables with initializers",
6 \\extern var foo: int = 2;
7 , &[_][]const u8{
8 "tmp.zig:1:1: error: extern variables have no initializers",
9 });
10
5 cases.addTest("duplicate/unused labels",11 cases.addTest("duplicate/unused labels",
6 \\comptime {12 \\comptime {
7 \\ blk: { blk: while (false) {} }13 \\ blk: { blk: while (false) {} }
...@@ -1395,12 +1401,12 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1395,12 +1401,12 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1395 "tmp.zig:3:36: error: expected type 'std.builtin.TypeInfo', found 'std.builtin.Int'",1401 "tmp.zig:3:36: error: expected type 'std.builtin.TypeInfo', found 'std.builtin.Int'",
1396 });1402 });
13971403
1398 cases.add("Struct unavailable for @Type",1404 cases.add("struct with declarations unavailable for @Type",
1399 \\export fn entry() void {1405 \\export fn entry() void {
1400 \\ _ = @Type(@typeInfo(struct { }));1406 \\ _ = @Type(@typeInfo(struct { const foo = 1; }));
1401 \\}1407 \\}
1402 , &[_][]const u8{1408 , &[_][]const u8{
1403 "tmp.zig:2:15: error: @Type not available for 'TypeInfo.Struct'",1409 "tmp.zig:2:15: error: TypeInfo.Struct.decls must be empty for @Type",
1404 });1410 });
14051411
1406 cases.add("wrong type for argument tuple to @asyncCall",1412 cases.add("wrong type for argument tuple to @asyncCall",
test/run_translated_c.zig+14
...@@ -3,6 +3,20 @@ const tests = @import("tests.zig");...@@ -3,6 +3,20 @@ const tests = @import("tests.zig");
3const nl = std.cstr.line_sep;3const nl = std.cstr.line_sep;
44
5pub fn addCases(cases: *tests.RunTranslatedCContext) void {5pub fn addCases(cases: *tests.RunTranslatedCContext) void {
6 cases.add("static variable in block scope",
7 \\#include <stdlib.h>
8 \\int foo() {
9 \\ static int bar;
10 \\ bar += 1;
11 \\ return bar;
12 \\}
13 \\int main() {
14 \\ foo();
15 \\ foo();
16 \\ if (foo() != 3) abort();
17 \\}
18 , "");
19
6 cases.add("array initializer",20 cases.add("array initializer",
7 \\#include <stdlib.h>21 \\#include <stdlib.h>
8 \\int main(int argc, char **argv) {22 \\int main(int argc, char **argv) {
test/stack_traces.zig+3-3
...@@ -282,10 +282,10 @@ pub fn addCases(cases: *tests.StackTracesContext) void {...@@ -282,10 +282,10 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
282 \\source.zig:10:8: [address] in main (test)282 \\source.zig:10:8: [address] in main (test)
283 \\ foo();283 \\ foo();
284 \\ ^284 \\ ^
285 \\start.zig:249:29: [address] in std.start.posixCallMainAndExit (test)285 \\start.zig:254:29: [address] in std.start.posixCallMainAndExit (test)
286 \\ return root.main();286 \\ return root.main();
287 \\ ^287 \\ ^
288 \\start.zig:123:5: [address] in std.start._start (test)288 \\start.zig:128:5: [address] in std.start._start (test)
289 \\ @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});289 \\ @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});
290 \\ ^290 \\ ^
291 \\291 \\
...@@ -294,7 +294,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {...@@ -294,7 +294,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
294 switch (std.Target.current.cpu.arch) {294 switch (std.Target.current.cpu.arch) {
295 .aarch64 => "", // TODO disabled; results in segfault295 .aarch64 => "", // TODO disabled; results in segfault
296 else => 296 else =>
297 \\start.zig:123:5: [address] in std.start._start (test)297 \\start.zig:128:5: [address] in std.start._start (test)
298 \\ @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});298 \\ @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});
299 \\ ^299 \\ ^
300 \\300 \\
test/stage1/behavior/type.zig+44
...@@ -236,3 +236,47 @@ test "Type.ErrorSet" {...@@ -236,3 +236,47 @@ test "Type.ErrorSet" {
236 _ = @Type(@typeInfo(error{A}));236 _ = @Type(@typeInfo(error{A}));
237 _ = @Type(@typeInfo(error{ A, B, C }));237 _ = @Type(@typeInfo(error{ A, B, C }));
238}238}
239
240test "Type.Struct" {
241 const A = @Type(@typeInfo(struct { x: u8, y: u32 }));
242 const infoA = @typeInfo(A).Struct;
243 testing.expectEqual(TypeInfo.ContainerLayout.Auto, infoA.layout);
244 testing.expectEqualSlices(u8, "x", infoA.fields[0].name);
245 testing.expectEqual(u8, infoA.fields[0].field_type);
246 testing.expectEqual(@as(?u8, null), infoA.fields[0].default_value);
247 testing.expectEqualSlices(u8, "y", infoA.fields[1].name);
248 testing.expectEqual(u32, infoA.fields[1].field_type);
249 testing.expectEqual(@as(?u32, null), infoA.fields[1].default_value);
250 testing.expectEqualSlices(TypeInfo.Declaration, &[_]TypeInfo.Declaration{}, infoA.decls);
251 testing.expectEqual(@as(bool, false), infoA.is_tuple);
252
253 var a = A{ .x = 0, .y = 1 };
254 testing.expectEqual(@as(u8, 0), a.x);
255 testing.expectEqual(@as(u32, 1), a.y);
256 a.y += 1;
257 testing.expectEqual(@as(u32, 2), a.y);
258
259 const B = @Type(@typeInfo(extern struct { x: u8, y: u32 = 5 }));
260 const infoB = @typeInfo(B).Struct;
261 testing.expectEqual(TypeInfo.ContainerLayout.Extern, infoB.layout);
262 testing.expectEqualSlices(u8, "x", infoB.fields[0].name);
263 testing.expectEqual(u8, infoB.fields[0].field_type);
264 testing.expectEqual(@as(?u8, null), infoB.fields[0].default_value);
265 testing.expectEqualSlices(u8, "y", infoB.fields[1].name);
266 testing.expectEqual(u32, infoB.fields[1].field_type);
267 testing.expectEqual(@as(?u32, 5), infoB.fields[1].default_value);
268 testing.expectEqual(@as(usize, 0), infoB.decls.len);
269 testing.expectEqual(@as(bool, false), infoB.is_tuple);
270
271 const C = @Type(@typeInfo(packed struct { x: u8 = 3, y: u32 = 5 }));
272 const infoC = @typeInfo(C).Struct;
273 testing.expectEqual(TypeInfo.ContainerLayout.Packed, infoC.layout);
274 testing.expectEqualSlices(u8, "x", infoC.fields[0].name);
275 testing.expectEqual(u8, infoC.fields[0].field_type);
276 testing.expectEqual(@as(?u8, 3), infoC.fields[0].default_value);
277 testing.expectEqualSlices(u8, "y", infoC.fields[1].name);
278 testing.expectEqual(u32, infoC.fields[1].field_type);
279 testing.expectEqual(@as(?u32, 5), infoC.fields[1].default_value);
280 testing.expectEqual(@as(usize, 0), infoC.decls.len);
281 testing.expectEqual(@as(bool, false), infoC.is_tuple);
282}
test/stage1/behavior/type_info.zig-11
...@@ -238,7 +238,6 @@ fn testStruct() void {...@@ -238,7 +238,6 @@ fn testStruct() void {
238 expect(struct_info == .Struct);238 expect(struct_info == .Struct);
239 expect(struct_info.Struct.layout == .Packed);239 expect(struct_info.Struct.layout == .Packed);
240 expect(struct_info.Struct.fields.len == 4);240 expect(struct_info.Struct.fields.len == 4);
241 expect(struct_info.Struct.fields[1].offset == null);
242 expect(struct_info.Struct.fields[2].field_type == *TestStruct);241 expect(struct_info.Struct.fields[2].field_type == *TestStruct);
243 expect(struct_info.Struct.fields[2].default_value == null);242 expect(struct_info.Struct.fields[2].default_value == null);
244 expect(struct_info.Struct.fields[3].default_value.? == 4);243 expect(struct_info.Struct.fields[3].default_value.? == 4);
...@@ -320,16 +319,6 @@ fn testAnyFrame() void {...@@ -320,16 +319,6 @@ fn testAnyFrame() void {
320 }319 }
321}320}
322321
323test "type info: optional field unwrapping" {
324 const Struct = struct {
325 cdOffset: u32,
326 };
327
328 const field = @typeInfo(Struct).Struct.fields[0];
329
330 _ = field.offset orelse 0;
331}
332
333test "type info: pass to function" {322test "type info: pass to function" {
334 _ = passTypeInfo(@typeInfo(void));323 _ = passTypeInfo(@typeInfo(void));
335 _ = comptime passTypeInfo(@typeInfo(void));324 _ = comptime passTypeInfo(@typeInfo(void));
test/stage2/compare_output.zig deleted-578
...@@ -1,578 +0,0 @@
1const std = @import("std");
2const TestContext = @import("../../src-self-hosted/test.zig").TestContext;
3// self-hosted does not yet support PE executable files / COFF object files
4// or mach-o files. So we do these test cases cross compiling for x86_64-linux.
5const linux_x64 = std.zig.CrossTarget{
6 .cpu_arch = .x86_64,
7 .os_tag = .linux,
8};
9
10const linux_riscv64 = std.zig.CrossTarget{
11 .cpu_arch = .riscv64,
12 .os_tag = .linux,
13};
14
15const wasi = std.zig.CrossTarget{
16 .cpu_arch = .wasm32,
17 .os_tag = .wasi,
18};
19
20pub fn addCases(ctx: *TestContext) !void {
21 {
22 var case = ctx.exe("hello world with updates", linux_x64);
23
24 case.addError("", &[_][]const u8{":1:1: error: no entry point found"});
25
26 case.addError(
27 \\export fn _start() noreturn {
28 \\}
29 , &[_][]const u8{":2:1: error: expected noreturn, found void"});
30
31 // Regular old hello world
32 case.addCompareOutput(
33 \\export fn _start() noreturn {
34 \\ print();
35 \\
36 \\ exit();
37 \\}
38 \\
39 \\fn print() void {
40 \\ asm volatile ("syscall"
41 \\ :
42 \\ : [number] "{rax}" (1),
43 \\ [arg1] "{rdi}" (1),
44 \\ [arg2] "{rsi}" (@ptrToInt("Hello, World!\n")),
45 \\ [arg3] "{rdx}" (14)
46 \\ : "rcx", "r11", "memory"
47 \\ );
48 \\ return;
49 \\}
50 \\
51 \\fn exit() noreturn {
52 \\ asm volatile ("syscall"
53 \\ :
54 \\ : [number] "{rax}" (231),
55 \\ [arg1] "{rdi}" (0)
56 \\ : "rcx", "r11", "memory"
57 \\ );
58 \\ unreachable;
59 \\}
60 ,
61 "Hello, World!\n",
62 );
63 // Now change the message only
64 case.addCompareOutput(
65 \\export fn _start() noreturn {
66 \\ print();
67 \\
68 \\ exit();
69 \\}
70 \\
71 \\fn print() void {
72 \\ asm volatile ("syscall"
73 \\ :
74 \\ : [number] "{rax}" (1),
75 \\ [arg1] "{rdi}" (1),
76 \\ [arg2] "{rsi}" (@ptrToInt("What is up? This is a longer message that will force the data to be relocated in virtual address space.\n")),
77 \\ [arg3] "{rdx}" (104)
78 \\ : "rcx", "r11", "memory"
79 \\ );
80 \\ return;
81 \\}
82 \\
83 \\fn exit() noreturn {
84 \\ asm volatile ("syscall"
85 \\ :
86 \\ : [number] "{rax}" (231),
87 \\ [arg1] "{rdi}" (0)
88 \\ : "rcx", "r11", "memory"
89 \\ );
90 \\ unreachable;
91 \\}
92 ,
93 "What is up? This is a longer message that will force the data to be relocated in virtual address space.\n",
94 );
95 // Now we print it twice.
96 case.addCompareOutput(
97 \\export fn _start() noreturn {
98 \\ print();
99 \\ print();
100 \\
101 \\ exit();
102 \\}
103 \\
104 \\fn print() void {
105 \\ asm volatile ("syscall"
106 \\ :
107 \\ : [number] "{rax}" (1),
108 \\ [arg1] "{rdi}" (1),
109 \\ [arg2] "{rsi}" (@ptrToInt("What is up? This is a longer message that will force the data to be relocated in virtual address space.\n")),
110 \\ [arg3] "{rdx}" (104)
111 \\ : "rcx", "r11", "memory"
112 \\ );
113 \\ return;
114 \\}
115 \\
116 \\fn exit() noreturn {
117 \\ asm volatile ("syscall"
118 \\ :
119 \\ : [number] "{rax}" (231),
120 \\ [arg1] "{rdi}" (0)
121 \\ : "rcx", "r11", "memory"
122 \\ );
123 \\ unreachable;
124 \\}
125 ,
126 \\What is up? This is a longer message that will force the data to be relocated in virtual address space.
127 \\What is up? This is a longer message that will force the data to be relocated in virtual address space.
128 \\
129 );
130 }
131
132 {
133 var case = ctx.exe("hello world", linux_riscv64);
134 // Regular old hello world
135 case.addCompareOutput(
136 \\export fn _start() noreturn {
137 \\ print();
138 \\
139 \\ exit();
140 \\}
141 \\
142 \\fn print() void {
143 \\ asm volatile ("ecall"
144 \\ :
145 \\ : [number] "{a7}" (64),
146 \\ [arg1] "{a0}" (1),
147 \\ [arg2] "{a1}" (@ptrToInt("Hello, World!\n")),
148 \\ [arg3] "{a2}" ("Hello, World!\n".len)
149 \\ : "rcx", "r11", "memory"
150 \\ );
151 \\ return;
152 \\}
153 \\
154 \\fn exit() noreturn {
155 \\ asm volatile ("ecall"
156 \\ :
157 \\ : [number] "{a7}" (94),
158 \\ [arg1] "{a0}" (0)
159 \\ : "rcx", "r11", "memory"
160 \\ );
161 \\ unreachable;
162 \\}
163 ,
164 "Hello, World!\n",
165 );
166 }
167
168 {
169 var case = ctx.exe("adding numbers at comptime", linux_x64);
170 case.addCompareOutput(
171 \\export fn _start() noreturn {
172 \\ asm volatile ("syscall"
173 \\ :
174 \\ : [number] "{rax}" (1),
175 \\ [arg1] "{rdi}" (1),
176 \\ [arg2] "{rsi}" (@ptrToInt("Hello, World!\n")),
177 \\ [arg3] "{rdx}" (10 + 4)
178 \\ : "rcx", "r11", "memory"
179 \\ );
180 \\ asm volatile ("syscall"
181 \\ :
182 \\ : [number] "{rax}" (@as(usize, 230) + @as(usize, 1)),
183 \\ [arg1] "{rdi}" (0)
184 \\ : "rcx", "r11", "memory"
185 \\ );
186 \\ unreachable;
187 \\}
188 ,
189 "Hello, World!\n",
190 );
191 }
192
193 {
194 var case = ctx.exe("adding numbers at runtime", linux_x64);
195 case.addCompareOutput(
196 \\export fn _start() noreturn {
197 \\ add(3, 4);
198 \\
199 \\ exit();
200 \\}
201 \\
202 \\fn add(a: u32, b: u32) void {
203 \\ if (a + b != 7) unreachable;
204 \\}
205 \\
206 \\fn exit() noreturn {
207 \\ asm volatile ("syscall"
208 \\ :
209 \\ : [number] "{rax}" (231),
210 \\ [arg1] "{rdi}" (0)
211 \\ : "rcx", "r11", "memory"
212 \\ );
213 \\ unreachable;
214 \\}
215 ,
216 "",
217 );
218 }
219
220 {
221 var case = ctx.exe("substracting numbers at runtime", linux_x64);
222 case.addCompareOutput(
223 \\export fn _start() noreturn {
224 \\ sub(7, 4);
225 \\
226 \\ exit();
227 \\}
228 \\
229 \\fn sub(a: u32, b: u32) void {
230 \\ if (a - b != 3) unreachable;
231 \\}
232 \\
233 \\fn exit() noreturn {
234 \\ asm volatile ("syscall"
235 \\ :
236 \\ : [number] "{rax}" (231),
237 \\ [arg1] "{rdi}" (0)
238 \\ : "rcx", "r11", "memory"
239 \\ );
240 \\ unreachable;
241 \\}
242 ,
243 "",
244 );
245 }
246
247 {
248 var case = ctx.exe("assert function", linux_x64);
249 case.addCompareOutput(
250 \\export fn _start() noreturn {
251 \\ add(3, 4);
252 \\
253 \\ exit();
254 \\}
255 \\
256 \\fn add(a: u32, b: u32) void {
257 \\ assert(a + b == 7);
258 \\}
259 \\
260 \\pub fn assert(ok: bool) void {
261 \\ if (!ok) unreachable; // assertion failure
262 \\}
263 \\
264 \\fn exit() noreturn {
265 \\ asm volatile ("syscall"
266 \\ :
267 \\ : [number] "{rax}" (231),
268 \\ [arg1] "{rdi}" (0)
269 \\ : "rcx", "r11", "memory"
270 \\ );
271 \\ unreachable;
272 \\}
273 ,
274 "",
275 );
276
277 // Tests copying a register. For the `c = a + b`, it has to
278 // preserve both a and b, because they are both used later.
279 case.addCompareOutput(
280 \\export fn _start() noreturn {
281 \\ add(3, 4);
282 \\
283 \\ exit();
284 \\}
285 \\
286 \\fn add(a: u32, b: u32) void {
287 \\ const c = a + b; // 7
288 \\ const d = a + c; // 10
289 \\ const e = d + b; // 14
290 \\ assert(e == 14);
291 \\}
292 \\
293 \\pub fn assert(ok: bool) void {
294 \\ if (!ok) unreachable; // assertion failure
295 \\}
296 \\
297 \\fn exit() noreturn {
298 \\ asm volatile ("syscall"
299 \\ :
300 \\ : [number] "{rax}" (231),
301 \\ [arg1] "{rdi}" (0)
302 \\ : "rcx", "r11", "memory"
303 \\ );
304 \\ unreachable;
305 \\}
306 ,
307 "",
308 );
309
310 // More stress on the liveness detection.
311 case.addCompareOutput(
312 \\export fn _start() noreturn {
313 \\ add(3, 4);
314 \\
315 \\ exit();
316 \\}
317 \\
318 \\fn add(a: u32, b: u32) void {
319 \\ const c = a + b; // 7
320 \\ const d = a + c; // 10
321 \\ const e = d + b; // 14
322 \\ const f = d + e; // 24
323 \\ const g = e + f; // 38
324 \\ const h = f + g; // 62
325 \\ const i = g + h; // 100
326 \\ assert(i == 100);
327 \\}
328 \\
329 \\pub fn assert(ok: bool) void {
330 \\ if (!ok) unreachable; // assertion failure
331 \\}
332 \\
333 \\fn exit() noreturn {
334 \\ asm volatile ("syscall"
335 \\ :
336 \\ : [number] "{rax}" (231),
337 \\ [arg1] "{rdi}" (0)
338 \\ : "rcx", "r11", "memory"
339 \\ );
340 \\ unreachable;
341 \\}
342 ,
343 "",
344 );
345
346 // Requires a second move. The register allocator should figure out to re-use rax.
347 case.addCompareOutput(
348 \\export fn _start() noreturn {
349 \\ add(3, 4);
350 \\
351 \\ exit();
352 \\}
353 \\
354 \\fn add(a: u32, b: u32) void {
355 \\ const c = a + b; // 7
356 \\ const d = a + c; // 10
357 \\ const e = d + b; // 14
358 \\ const f = d + e; // 24
359 \\ const g = e + f; // 38
360 \\ const h = f + g; // 62
361 \\ const i = g + h; // 100
362 \\ const j = i + d; // 110
363 \\ assert(j == 110);
364 \\}
365 \\
366 \\pub fn assert(ok: bool) void {
367 \\ if (!ok) unreachable; // assertion failure
368 \\}
369 \\
370 \\fn exit() noreturn {
371 \\ asm volatile ("syscall"
372 \\ :
373 \\ : [number] "{rax}" (231),
374 \\ [arg1] "{rdi}" (0)
375 \\ : "rcx", "r11", "memory"
376 \\ );
377 \\ unreachable;
378 \\}
379 ,
380 "",
381 );
382
383 // Now we test integer return values.
384 case.addCompareOutput(
385 \\export fn _start() noreturn {
386 \\ assert(add(3, 4) == 7);
387 \\ assert(add(20, 10) == 30);
388 \\
389 \\ exit();
390 \\}
391 \\
392 \\fn add(a: u32, b: u32) u32 {
393 \\ return a + b;
394 \\}
395 \\
396 \\pub fn assert(ok: bool) void {
397 \\ if (!ok) unreachable; // assertion failure
398 \\}
399 \\
400 \\fn exit() noreturn {
401 \\ asm volatile ("syscall"
402 \\ :
403 \\ : [number] "{rax}" (231),
404 \\ [arg1] "{rdi}" (0)
405 \\ : "rcx", "r11", "memory"
406 \\ );
407 \\ unreachable;
408 \\}
409 ,
410 "",
411 );
412
413 // Local mutable variables.
414 case.addCompareOutput(
415 \\export fn _start() noreturn {
416 \\ assert(add(3, 4) == 7);
417 \\ assert(add(20, 10) == 30);
418 \\
419 \\ exit();
420 \\}
421 \\
422 \\fn add(a: u32, b: u32) u32 {
423 \\ var x: u32 = undefined;
424 \\ x = 0;
425 \\ x += a;
426 \\ x += b;
427 \\ return x;
428 \\}
429 \\
430 \\pub fn assert(ok: bool) void {
431 \\ if (!ok) unreachable; // assertion failure
432 \\}
433 \\
434 \\fn exit() noreturn {
435 \\ asm volatile ("syscall"
436 \\ :
437 \\ : [number] "{rax}" (231),
438 \\ [arg1] "{rdi}" (0)
439 \\ : "rcx", "r11", "memory"
440 \\ );
441 \\ unreachable;
442 \\}
443 ,
444 "",
445 );
446
447 // Optionals
448 case.addCompareOutput(
449 \\export fn _start() noreturn {
450 \\ const a: u32 = 2;
451 \\ const b: ?u32 = a;
452 \\ const c = b.?;
453 \\ if (c != 2) unreachable;
454 \\
455 \\ exit();
456 \\}
457 \\
458 \\fn exit() noreturn {
459 \\ asm volatile ("syscall"
460 \\ :
461 \\ : [number] "{rax}" (231),
462 \\ [arg1] "{rdi}" (0)
463 \\ : "rcx", "r11", "memory"
464 \\ );
465 \\ unreachable;
466 \\}
467 ,
468 "",
469 );
470
471 // While loops
472 case.addCompareOutput(
473 \\export fn _start() noreturn {
474 \\ var i: u32 = 0;
475 \\ while (i < 4) : (i += 1) print();
476 \\ assert(i == 4);
477 \\
478 \\ exit();
479 \\}
480 \\
481 \\fn print() void {
482 \\ asm volatile ("syscall"
483 \\ :
484 \\ : [number] "{rax}" (1),
485 \\ [arg1] "{rdi}" (1),
486 \\ [arg2] "{rsi}" (@ptrToInt("hello\n")),
487 \\ [arg3] "{rdx}" (6)
488 \\ : "rcx", "r11", "memory"
489 \\ );
490 \\ return;
491 \\}
492 \\
493 \\pub fn assert(ok: bool) void {
494 \\ if (!ok) unreachable; // assertion failure
495 \\}
496 \\
497 \\fn exit() noreturn {
498 \\ asm volatile ("syscall"
499 \\ :
500 \\ : [number] "{rax}" (231),
501 \\ [arg1] "{rdi}" (0)
502 \\ : "rcx", "r11", "memory"
503 \\ );
504 \\ unreachable;
505 \\}
506 ,
507 "hello\nhello\nhello\nhello\n",
508 );
509
510 // Labeled blocks (no conditional branch)
511 case.addCompareOutput(
512 \\export fn _start() noreturn {
513 \\ assert(add(3, 4) == 20);
514 \\
515 \\ exit();
516 \\}
517 \\
518 \\fn add(a: u32, b: u32) u32 {
519 \\ const x: u32 = blk: {
520 \\ const c = a + b; // 7
521 \\ const d = a + c; // 10
522 \\ const e = d + b; // 14
523 \\ break :blk e;
524 \\ };
525 \\ const y = x + a; // 17
526 \\ const z = y + a; // 20
527 \\ return z;
528 \\}
529 \\
530 \\pub fn assert(ok: bool) void {
531 \\ if (!ok) unreachable; // assertion failure
532 \\}
533 \\
534 \\fn exit() noreturn {
535 \\ asm volatile ("syscall"
536 \\ :
537 \\ : [number] "{rax}" (231),
538 \\ [arg1] "{rdi}" (0)
539 \\ : "rcx", "r11", "memory"
540 \\ );
541 \\ unreachable;
542 \\}
543 ,
544 "",
545 );
546 }
547
548 {
549 var case = ctx.exe("wasm returns", wasi);
550
551 case.addCompareOutput(
552 \\export fn _start() u32 {
553 \\ return 42;
554 \\}
555 ,
556 "42\n",
557 );
558
559 case.addCompareOutput(
560 \\export fn _start() i64 {
561 \\ return 42;
562 \\}
563 ,
564 "42\n",
565 );
566
567 case.addCompareOutput(
568 \\export fn _start() f32 {
569 \\ return 42.0;
570 \\}
571 ,
572 // This is what you get when you take the bits of the IEE-754
573 // representation of 42.0 and reinterpret them as an unsigned
574 // integer. Guess that's a bug in wasmtime.
575 "1109917696\n",
576 );
577 }
578}
test/stage2/compile_errors.zig deleted-135
...@@ -1,135 +0,0 @@
1const TestContext = @import("../../src-self-hosted/test.zig").TestContext;
2const std = @import("std");
3
4const ErrorMsg = @import("../../src-self-hosted/Module.zig").ErrorMsg;
5
6const linux_x64 = std.zig.CrossTarget{
7 .cpu_arch = .x86_64,
8 .os_tag = .linux,
9};
10
11pub fn addCases(ctx: *TestContext) !void {
12 ctx.compileErrorZIR("call undefined local", linux_x64,
13 \\@noreturn = primitive(noreturn)
14 \\
15 \\@start_fnty = fntype([], @noreturn, cc=Naked)
16 \\@start = fn(@start_fnty, {
17 \\ %0 = call(%test, [])
18 \\})
19 // TODO: address inconsistency in this message and the one in the next test
20 , &[_][]const u8{":5:13: error: unrecognized identifier: %test"});
21
22 ctx.compileErrorZIR("call with non-existent target", linux_x64,
23 \\@noreturn = primitive(noreturn)
24 \\
25 \\@start_fnty = fntype([], @noreturn, cc=Naked)
26 \\@start = fn(@start_fnty, {
27 \\ %0 = call(@notafunc, [])
28 \\})
29 \\@0 = str("_start")
30 \\@1 = export(@0, "start")
31 , &[_][]const u8{":5:13: error: decl 'notafunc' not found"});
32
33 // TODO: this error should occur at the call site, not the fntype decl
34 ctx.compileErrorZIR("call naked function", linux_x64,
35 \\@noreturn = primitive(noreturn)
36 \\
37 \\@start_fnty = fntype([], @noreturn, cc=Naked)
38 \\@s = fn(@start_fnty, {})
39 \\@start = fn(@start_fnty, {
40 \\ %0 = call(@s, [])
41 \\})
42 \\@0 = str("_start")
43 \\@1 = export(@0, "start")
44 , &[_][]const u8{":4:9: error: unable to call function with naked calling convention"});
45
46 ctx.incrementalFailureZIR("exported symbol collision", linux_x64,
47 \\@noreturn = primitive(noreturn)
48 \\
49 \\@start_fnty = fntype([], @noreturn)
50 \\@start = fn(@start_fnty, {})
51 \\
52 \\@0 = str("_start")
53 \\@1 = export(@0, "start")
54 \\@2 = export(@0, "start")
55 , &[_][]const u8{":8:13: error: exported symbol collision: _start"},
56 \\@noreturn = primitive(noreturn)
57 \\
58 \\@start_fnty = fntype([], @noreturn)
59 \\@start = fn(@start_fnty, {})
60 \\
61 \\@0 = str("_start")
62 \\@1 = export(@0, "start")
63 );
64
65 ctx.compileError("function redefinition", linux_x64,
66 \\fn entry() void {}
67 \\fn entry() void {}
68 , &[_][]const u8{":2:4: error: redefinition of 'entry'"});
69
70 //ctx.incrementalFailure("function redefinition", linux_x64,
71 // \\fn entry() void {}
72 // \\fn entry() void {}
73 //, &[_][]const u8{":2:4: error: redefinition of 'entry'"},
74 // \\fn entry() void {}
75 //);
76
77 //// TODO: need to make sure this works with other variants of export.
78 //ctx.incrementalFailure("exported symbol collision", linux_x64,
79 // \\export fn entry() void {}
80 // \\export fn entry() void {}
81 //, &[_][]const u8{":2:11: error: redefinition of 'entry'"},
82 // \\export fn entry() void {}
83 //);
84
85 // ctx.incrementalFailure("missing function name", linux_x64,
86 // \\fn() void {}
87 // , &[_][]const u8{":1:3: error: missing function name"},
88 // \\fn a() void {}
89 // );
90
91 // TODO: re-enable these tests.
92 // https://github.com/ziglang/zig/issues/1364
93
94 //ctx.testCompileError(
95 // \\comptime {
96 // \\ return;
97 // \\}
98 //, "1.zig", 2, 5, "return expression outside function definition");
99
100 //ctx.testCompileError(
101 // \\export fn entry() void {
102 // \\ defer return;
103 // \\}
104 //, "1.zig", 2, 11, "cannot return from defer expression");
105
106 //ctx.testCompileError(
107 // \\export fn entry() c_int {
108 // \\ return 36893488147419103232;
109 // \\}
110 //, "1.zig", 2, 12, "integer value '36893488147419103232' cannot be stored in type 'c_int'");
111
112 //ctx.testCompileError(
113 // \\comptime {
114 // \\ var a: *align(4) align(4) i32 = 0;
115 // \\}
116 //, "1.zig", 2, 22, "Extra align qualifier");
117
118 //ctx.testCompileError(
119 // \\comptime {
120 // \\ var b: *const const i32 = 0;
121 // \\}
122 //, "1.zig", 2, 19, "Extra align qualifier");
123
124 //ctx.testCompileError(
125 // \\comptime {
126 // \\ var c: *volatile volatile i32 = 0;
127 // \\}
128 //, "1.zig", 2, 22, "Extra align qualifier");
129
130 //ctx.testCompileError(
131 // \\comptime {
132 // \\ var d: *allowzero allowzero i32 = 0;
133 // \\}
134 //, "1.zig", 2, 23, "Extra align qualifier");
135}
test/stage2/test.zig+730-2
...@@ -1,8 +1,736 @@...@@ -1,8 +1,736 @@
1const std = @import("std");
1const TestContext = @import("../../src-self-hosted/test.zig").TestContext;2const TestContext = @import("../../src-self-hosted/test.zig").TestContext;
23
4// self-hosted does not yet support PE executable files / COFF object files
5// or mach-o files. So we do these test cases cross compiling for x86_64-linux.
6const linux_x64 = std.zig.CrossTarget{
7 .cpu_arch = .x86_64,
8 .os_tag = .linux,
9};
10
11const macosx_x64 = std.zig.CrossTarget{
12 .cpu_arch = .x86_64,
13 .os_tag = .macosx,
14};
15
16const linux_riscv64 = std.zig.CrossTarget{
17 .cpu_arch = .riscv64,
18 .os_tag = .linux,
19};
20
21const wasi = std.zig.CrossTarget{
22 .cpu_arch = .wasm32,
23 .os_tag = .wasi,
24};
25
3pub fn addCases(ctx: *TestContext) !void {26pub fn addCases(ctx: *TestContext) !void {
4 try @import("compile_errors.zig").addCases(ctx);
5 try @import("compare_output.zig").addCases(ctx);
6 try @import("zir.zig").addCases(ctx);27 try @import("zir.zig").addCases(ctx);
7 try @import("cbe.zig").addCases(ctx);28 try @import("cbe.zig").addCases(ctx);
29 {
30 var case = ctx.exe("hello world with updates", linux_x64);
31
32 case.addError("", &[_][]const u8{":1:1: error: no entry point found"});
33
34 // Incorrect return type
35 case.addError(
36 \\export fn _start() noreturn {
37 \\}
38 , &[_][]const u8{":2:1: error: expected noreturn, found void"});
39
40 // Regular old hello world
41 case.addCompareOutput(
42 \\export fn _start() noreturn {
43 \\ print();
44 \\
45 \\ exit();
46 \\}
47 \\
48 \\fn print() void {
49 \\ asm volatile ("syscall"
50 \\ :
51 \\ : [number] "{rax}" (1),
52 \\ [arg1] "{rdi}" (1),
53 \\ [arg2] "{rsi}" (@ptrToInt("Hello, World!\n")),
54 \\ [arg3] "{rdx}" (14)
55 \\ : "rcx", "r11", "memory"
56 \\ );
57 \\ return;
58 \\}
59 \\
60 \\fn exit() noreturn {
61 \\ asm volatile ("syscall"
62 \\ :
63 \\ : [number] "{rax}" (231),
64 \\ [arg1] "{rdi}" (0)
65 \\ : "rcx", "r11", "memory"
66 \\ );
67 \\ unreachable;
68 \\}
69 ,
70 "Hello, World!\n",
71 );
72 // Now change the message only
73 case.addCompareOutput(
74 \\export fn _start() noreturn {
75 \\ print();
76 \\
77 \\ exit();
78 \\}
79 \\
80 \\fn print() void {
81 \\ asm volatile ("syscall"
82 \\ :
83 \\ : [number] "{rax}" (1),
84 \\ [arg1] "{rdi}" (1),
85 \\ [arg2] "{rsi}" (@ptrToInt("What is up? This is a longer message that will force the data to be relocated in virtual address space.\n")),
86 \\ [arg3] "{rdx}" (104)
87 \\ : "rcx", "r11", "memory"
88 \\ );
89 \\ return;
90 \\}
91 \\
92 \\fn exit() noreturn {
93 \\ asm volatile ("syscall"
94 \\ :
95 \\ : [number] "{rax}" (231),
96 \\ [arg1] "{rdi}" (0)
97 \\ : "rcx", "r11", "memory"
98 \\ );
99 \\ unreachable;
100 \\}
101 ,
102 "What is up? This is a longer message that will force the data to be relocated in virtual address space.\n",
103 );
104 // Now we print it twice.
105 case.addCompareOutput(
106 \\export fn _start() noreturn {
107 \\ print();
108 \\ print();
109 \\
110 \\ exit();
111 \\}
112 \\
113 \\fn print() void {
114 \\ asm volatile ("syscall"
115 \\ :
116 \\ : [number] "{rax}" (1),
117 \\ [arg1] "{rdi}" (1),
118 \\ [arg2] "{rsi}" (@ptrToInt("What is up? This is a longer message that will force the data to be relocated in virtual address space.\n")),
119 \\ [arg3] "{rdx}" (104)
120 \\ : "rcx", "r11", "memory"
121 \\ );
122 \\ return;
123 \\}
124 \\
125 \\fn exit() noreturn {
126 \\ asm volatile ("syscall"
127 \\ :
128 \\ : [number] "{rax}" (231),
129 \\ [arg1] "{rdi}" (0)
130 \\ : "rcx", "r11", "memory"
131 \\ );
132 \\ unreachable;
133 \\}
134 ,
135 \\What is up? This is a longer message that will force the data to be relocated in virtual address space.
136 \\What is up? This is a longer message that will force the data to be relocated in virtual address space.
137 \\
138 );
139 }
140
141 {
142 var case = ctx.exe("hello world", macosx_x64);
143 case.addError("", &[_][]const u8{":1:1: error: no entry point found"});
144 }
145
146 {
147 var case = ctx.exe("hello world", linux_riscv64);
148 // Regular old hello world
149 case.addCompareOutput(
150 \\export fn _start() noreturn {
151 \\ print();
152 \\
153 \\ exit();
154 \\}
155 \\
156 \\fn print() void {
157 \\ asm volatile ("ecall"
158 \\ :
159 \\ : [number] "{a7}" (64),
160 \\ [arg1] "{a0}" (1),
161 \\ [arg2] "{a1}" (@ptrToInt("Hello, World!\n")),
162 \\ [arg3] "{a2}" ("Hello, World!\n".len)
163 \\ : "rcx", "r11", "memory"
164 \\ );
165 \\ return;
166 \\}
167 \\
168 \\fn exit() noreturn {
169 \\ asm volatile ("ecall"
170 \\ :
171 \\ : [number] "{a7}" (94),
172 \\ [arg1] "{a0}" (0)
173 \\ : "rcx", "r11", "memory"
174 \\ );
175 \\ unreachable;
176 \\}
177 ,
178 "Hello, World!\n",
179 );
180 }
181
182 {
183 var case = ctx.exe("adding numbers at comptime", linux_x64);
184 case.addCompareOutput(
185 \\export fn _start() noreturn {
186 \\ asm volatile ("syscall"
187 \\ :
188 \\ : [number] "{rax}" (1),
189 \\ [arg1] "{rdi}" (1),
190 \\ [arg2] "{rsi}" (@ptrToInt("Hello, World!\n")),
191 \\ [arg3] "{rdx}" (10 + 4)
192 \\ : "rcx", "r11", "memory"
193 \\ );
194 \\ asm volatile ("syscall"
195 \\ :
196 \\ : [number] "{rax}" (@as(usize, 230) + @as(usize, 1)),
197 \\ [arg1] "{rdi}" (0)
198 \\ : "rcx", "r11", "memory"
199 \\ );
200 \\ unreachable;
201 \\}
202 ,
203 "Hello, World!\n",
204 );
205 }
206
207 {
208 var case = ctx.exe("adding numbers at runtime", linux_x64);
209 case.addCompareOutput(
210 \\export fn _start() noreturn {
211 \\ add(3, 4);
212 \\
213 \\ exit();
214 \\}
215 \\
216 \\fn add(a: u32, b: u32) void {
217 \\ if (a + b != 7) unreachable;
218 \\}
219 \\
220 \\fn exit() noreturn {
221 \\ asm volatile ("syscall"
222 \\ :
223 \\ : [number] "{rax}" (231),
224 \\ [arg1] "{rdi}" (0)
225 \\ : "rcx", "r11", "memory"
226 \\ );
227 \\ unreachable;
228 \\}
229 ,
230 "",
231 );
232 }
233
234 {
235 var case = ctx.exe("substracting numbers at runtime", linux_x64);
236 case.addCompareOutput(
237 \\export fn _start() noreturn {
238 \\ sub(7, 4);
239 \\
240 \\ exit();
241 \\}
242 \\
243 \\fn sub(a: u32, b: u32) void {
244 \\ if (a - b != 3) unreachable;
245 \\}
246 \\
247 \\fn exit() noreturn {
248 \\ asm volatile ("syscall"
249 \\ :
250 \\ : [number] "{rax}" (231),
251 \\ [arg1] "{rdi}" (0)
252 \\ : "rcx", "r11", "memory"
253 \\ );
254 \\ unreachable;
255 \\}
256 ,
257 "",
258 );
259 }
260
261 {
262 var case = ctx.exe("assert function", linux_x64);
263 case.addCompareOutput(
264 \\export fn _start() noreturn {
265 \\ add(3, 4);
266 \\
267 \\ exit();
268 \\}
269 \\
270 \\fn add(a: u32, b: u32) void {
271 \\ assert(a + b == 7);
272 \\}
273 \\
274 \\pub fn assert(ok: bool) void {
275 \\ if (!ok) unreachable; // assertion failure
276 \\}
277 \\
278 \\fn exit() noreturn {
279 \\ asm volatile ("syscall"
280 \\ :
281 \\ : [number] "{rax}" (231),
282 \\ [arg1] "{rdi}" (0)
283 \\ : "rcx", "r11", "memory"
284 \\ );
285 \\ unreachable;
286 \\}
287 ,
288 "",
289 );
290
291 // Tests copying a register. For the `c = a + b`, it has to
292 // preserve both a and b, because they are both used later.
293 case.addCompareOutput(
294 \\export fn _start() noreturn {
295 \\ add(3, 4);
296 \\
297 \\ exit();
298 \\}
299 \\
300 \\fn add(a: u32, b: u32) void {
301 \\ const c = a + b; // 7
302 \\ const d = a + c; // 10
303 \\ const e = d + b; // 14
304 \\ assert(e == 14);
305 \\}
306 \\
307 \\pub fn assert(ok: bool) void {
308 \\ if (!ok) unreachable; // assertion failure
309 \\}
310 \\
311 \\fn exit() noreturn {
312 \\ asm volatile ("syscall"
313 \\ :
314 \\ : [number] "{rax}" (231),
315 \\ [arg1] "{rdi}" (0)
316 \\ : "rcx", "r11", "memory"
317 \\ );
318 \\ unreachable;
319 \\}
320 ,
321 "",
322 );
323
324 // More stress on the liveness detection.
325 case.addCompareOutput(
326 \\export fn _start() noreturn {
327 \\ add(3, 4);
328 \\
329 \\ exit();
330 \\}
331 \\
332 \\fn add(a: u32, b: u32) void {
333 \\ const c = a + b; // 7
334 \\ const d = a + c; // 10
335 \\ const e = d + b; // 14
336 \\ const f = d + e; // 24
337 \\ const g = e + f; // 38
338 \\ const h = f + g; // 62
339 \\ const i = g + h; // 100
340 \\ assert(i == 100);
341 \\}
342 \\
343 \\pub fn assert(ok: bool) void {
344 \\ if (!ok) unreachable; // assertion failure
345 \\}
346 \\
347 \\fn exit() noreturn {
348 \\ asm volatile ("syscall"
349 \\ :
350 \\ : [number] "{rax}" (231),
351 \\ [arg1] "{rdi}" (0)
352 \\ : "rcx", "r11", "memory"
353 \\ );
354 \\ unreachable;
355 \\}
356 ,
357 "",
358 );
359
360 // Requires a second move. The register allocator should figure out to re-use rax.
361 case.addCompareOutput(
362 \\export fn _start() noreturn {
363 \\ add(3, 4);
364 \\
365 \\ exit();
366 \\}
367 \\
368 \\fn add(a: u32, b: u32) void {
369 \\ const c = a + b; // 7
370 \\ const d = a + c; // 10
371 \\ const e = d + b; // 14
372 \\ const f = d + e; // 24
373 \\ const g = e + f; // 38
374 \\ const h = f + g; // 62
375 \\ const i = g + h; // 100
376 \\ const j = i + d; // 110
377 \\ assert(j == 110);
378 \\}
379 \\
380 \\pub fn assert(ok: bool) void {
381 \\ if (!ok) unreachable; // assertion failure
382 \\}
383 \\
384 \\fn exit() noreturn {
385 \\ asm volatile ("syscall"
386 \\ :
387 \\ : [number] "{rax}" (231),
388 \\ [arg1] "{rdi}" (0)
389 \\ : "rcx", "r11", "memory"
390 \\ );
391 \\ unreachable;
392 \\}
393 ,
394 "",
395 );
396
397 // Now we test integer return values.
398 case.addCompareOutput(
399 \\export fn _start() noreturn {
400 \\ assert(add(3, 4) == 7);
401 \\ assert(add(20, 10) == 30);
402 \\
403 \\ exit();
404 \\}
405 \\
406 \\fn add(a: u32, b: u32) u32 {
407 \\ return a + b;
408 \\}
409 \\
410 \\pub fn assert(ok: bool) void {
411 \\ if (!ok) unreachable; // assertion failure
412 \\}
413 \\
414 \\fn exit() noreturn {
415 \\ asm volatile ("syscall"
416 \\ :
417 \\ : [number] "{rax}" (231),
418 \\ [arg1] "{rdi}" (0)
419 \\ : "rcx", "r11", "memory"
420 \\ );
421 \\ unreachable;
422 \\}
423 ,
424 "",
425 );
426
427 // Local mutable variables.
428 case.addCompareOutput(
429 \\export fn _start() noreturn {
430 \\ assert(add(3, 4) == 7);
431 \\ assert(add(20, 10) == 30);
432 \\
433 \\ exit();
434 \\}
435 \\
436 \\fn add(a: u32, b: u32) u32 {
437 \\ var x: u32 = undefined;
438 \\ x = 0;
439 \\ x += a;
440 \\ x += b;
441 \\ return x;
442 \\}
443 \\
444 \\pub fn assert(ok: bool) void {
445 \\ if (!ok) unreachable; // assertion failure
446 \\}
447 \\
448 \\fn exit() noreturn {
449 \\ asm volatile ("syscall"
450 \\ :
451 \\ : [number] "{rax}" (231),
452 \\ [arg1] "{rdi}" (0)
453 \\ : "rcx", "r11", "memory"
454 \\ );
455 \\ unreachable;
456 \\}
457 ,
458 "",
459 );
460
461 // Optionals
462 case.addCompareOutput(
463 \\export fn _start() noreturn {
464 \\ const a: u32 = 2;
465 \\ const b: ?u32 = a;
466 \\ const c = b.?;
467 \\ if (c != 2) unreachable;
468 \\
469 \\ exit();
470 \\}
471 \\
472 \\fn exit() noreturn {
473 \\ asm volatile ("syscall"
474 \\ :
475 \\ : [number] "{rax}" (231),
476 \\ [arg1] "{rdi}" (0)
477 \\ : "rcx", "r11", "memory"
478 \\ );
479 \\ unreachable;
480 \\}
481 ,
482 "",
483 );
484
485 // While loops
486 case.addCompareOutput(
487 \\export fn _start() noreturn {
488 \\ var i: u32 = 0;
489 \\ while (i < 4) : (i += 1) print();
490 \\ assert(i == 4);
491 \\
492 \\ exit();
493 \\}
494 \\
495 \\fn print() void {
496 \\ asm volatile ("syscall"
497 \\ :
498 \\ : [number] "{rax}" (1),
499 \\ [arg1] "{rdi}" (1),
500 \\ [arg2] "{rsi}" (@ptrToInt("hello\n")),
501 \\ [arg3] "{rdx}" (6)
502 \\ : "rcx", "r11", "memory"
503 \\ );
504 \\ return;
505 \\}
506 \\
507 \\pub fn assert(ok: bool) void {
508 \\ if (!ok) unreachable; // assertion failure
509 \\}
510 \\
511 \\fn exit() noreturn {
512 \\ asm volatile ("syscall"
513 \\ :
514 \\ : [number] "{rax}" (231),
515 \\ [arg1] "{rdi}" (0)
516 \\ : "rcx", "r11", "memory"
517 \\ );
518 \\ unreachable;
519 \\}
520 ,
521 "hello\nhello\nhello\nhello\n",
522 );
523
524 // Labeled blocks (no conditional branch)
525 case.addCompareOutput(
526 \\export fn _start() noreturn {
527 \\ assert(add(3, 4) == 20);
528 \\
529 \\ exit();
530 \\}
531 \\
532 \\fn add(a: u32, b: u32) u32 {
533 \\ const x: u32 = blk: {
534 \\ const c = a + b; // 7
535 \\ const d = a + c; // 10
536 \\ const e = d + b; // 14
537 \\ break :blk e;
538 \\ };
539 \\ const y = x + a; // 17
540 \\ const z = y + a; // 20
541 \\ return z;
542 \\}
543 \\
544 \\pub fn assert(ok: bool) void {
545 \\ if (!ok) unreachable; // assertion failure
546 \\}
547 \\
548 \\fn exit() noreturn {
549 \\ asm volatile ("syscall"
550 \\ :
551 \\ : [number] "{rax}" (231),
552 \\ [arg1] "{rdi}" (0)
553 \\ : "rcx", "r11", "memory"
554 \\ );
555 \\ unreachable;
556 \\}
557 ,
558 "",
559 );
560
561 // This catches a possible bug in the logic for re-using dying operands.
562 case.addCompareOutput(
563 \\export fn _start() noreturn {
564 \\ assert(add(3, 4) == 116);
565 \\
566 \\ exit();
567 \\}
568 \\
569 \\fn add(a: u32, b: u32) u32 {
570 \\ const x: u32 = blk: {
571 \\ const c = a + b; // 7
572 \\ const d = a + c; // 10
573 \\ const e = d + b; // 14
574 \\ const f = d + e; // 24
575 \\ const g = e + f; // 38
576 \\ const h = f + g; // 62
577 \\ const i = g + h; // 100
578 \\ const j = i + d; // 110
579 \\ break :blk j;
580 \\ };
581 \\ const y = x + a; // 113
582 \\ const z = y + a; // 116
583 \\ return z;
584 \\}
585 \\
586 \\pub fn assert(ok: bool) void {
587 \\ if (!ok) unreachable; // assertion failure
588 \\}
589 \\
590 \\fn exit() noreturn {
591 \\ asm volatile ("syscall"
592 \\ :
593 \\ : [number] "{rax}" (231),
594 \\ [arg1] "{rdi}" (0)
595 \\ : "rcx", "r11", "memory"
596 \\ );
597 \\ unreachable;
598 \\}
599 ,
600 "",
601 );
602
603 // Character literals and multiline strings.
604 case.addCompareOutput(
605 \\export fn _start() noreturn {
606 \\ const ignore =
607 \\ \\ cool thx
608 \\ \\
609 \\ ;
610 \\ add('ぁ', '\x03');
611 \\
612 \\ exit();
613 \\}
614 \\
615 \\fn add(a: u32, b: u32) void {
616 \\ assert(a + b == 12356);
617 \\}
618 \\
619 \\pub fn assert(ok: bool) void {
620 \\ if (!ok) unreachable; // assertion failure
621 \\}
622 \\
623 \\fn exit() noreturn {
624 \\ asm volatile ("syscall"
625 \\ :
626 \\ : [number] "{rax}" (231),
627 \\ [arg1] "{rdi}" (0)
628 \\ : "rcx", "r11", "memory"
629 \\ );
630 \\ unreachable;
631 \\}
632 ,
633 "",
634 );
635
636 // Global const.
637 case.addCompareOutput(
638 \\export fn _start() noreturn {
639 \\ add(aa, bb);
640 \\
641 \\ exit();
642 \\}
643 \\
644 \\const aa = 'ぁ';
645 \\const bb = '\x03';
646 \\
647 \\fn add(a: u32, b: u32) void {
648 \\ assert(a + b == 12356);
649 \\}
650 \\
651 \\pub fn assert(ok: bool) void {
652 \\ if (!ok) unreachable; // assertion failure
653 \\}
654 \\
655 \\fn exit() noreturn {
656 \\ asm volatile ("syscall"
657 \\ :
658 \\ : [number] "{rax}" (231),
659 \\ [arg1] "{rdi}" (0)
660 \\ : "rcx", "r11", "memory"
661 \\ );
662 \\ unreachable;
663 \\}
664 ,
665 "",
666 );
667 }
668
669 {
670 var case = ctx.exe("wasm function calls", wasi);
671
672 case.addCompareOutput(
673 \\export fn _start() u32 {
674 \\ foo();
675 \\ bar();
676 \\ return 42;
677 \\}
678 \\fn foo() void {
679 \\ bar();
680 \\ bar();
681 \\}
682 \\fn bar() void {}
683 ,
684 "42\n",
685 );
686
687 case.addCompareOutput(
688 \\export fn _start() i64 {
689 \\ bar();
690 \\ foo();
691 \\ foo();
692 \\ bar();
693 \\ foo();
694 \\ bar();
695 \\ return 42;
696 \\}
697 \\fn foo() void {
698 \\ bar();
699 \\}
700 \\fn bar() void {}
701 ,
702 "42\n",
703 );
704
705 case.addCompareOutput(
706 \\export fn _start() f32 {
707 \\ bar();
708 \\ foo();
709 \\ return 42.0;
710 \\}
711 \\fn foo() void {
712 \\ bar();
713 \\ bar();
714 \\ bar();
715 \\}
716 \\fn bar() void {}
717 ,
718 // This is what you get when you take the bits of the IEE-754
719 // representation of 42.0 and reinterpret them as an unsigned
720 // integer. Guess that's a bug in wasmtime.
721 "1109917696\n",
722 );
723 }
724
725 ctx.compileError("function redefinition", linux_x64,
726 \\fn entry() void {}
727 \\fn entry() void {}
728 , &[_][]const u8{":2:4: error: redefinition of 'entry'"});
729
730 ctx.compileError("extern variable has no type", linux_x64,
731 \\comptime {
732 \\ _ = foo;
733 \\}
734 \\extern var foo;
735 , &[_][]const u8{":4:1: error: unable to infer variable type"});
8}736}
test/standalone/global_linkage/obj1.zig+2-2
...@@ -1,5 +1,5 @@...@@ -1,5 +1,5 @@
1extern var internal_integer: usize = 1;1var internal_integer: usize = 1;
2extern var obj1_integer: usize = 421;2var obj1_integer: usize = 421;
33
4comptime {4comptime {
5 @export(internal_integer, .{ .name = "internal_integer", .linkage = .Internal });5 @export(internal_integer, .{ .name = "internal_integer", .linkage = .Internal });
test/standalone/global_linkage/obj2.zig+2-2
...@@ -1,5 +1,5 @@...@@ -1,5 +1,5 @@
1extern var internal_integer: usize = 2;1var internal_integer: usize = 2;
2extern var obj2_integer: usize = 422;2var obj2_integer: usize = 422;
33
4comptime {4comptime {
5 @export(internal_integer, .{ .name = "internal_integer", .linkage = .Internal });5 @export(internal_integer, .{ .name = "internal_integer", .linkage = .Internal });
test/translate_c.zig+18-3
...@@ -3,6 +3,20 @@ const std = @import("std");...@@ -3,6 +3,20 @@ const std = @import("std");
3const CrossTarget = std.zig.CrossTarget;3const CrossTarget = std.zig.CrossTarget;
44
5pub fn addCases(cases: *tests.TranslateCContext) void {5pub fn addCases(cases: *tests.TranslateCContext) void {
6 cases.add("extern variable in block scope",
7 \\float bar;
8 \\int foo() {
9 \\ _Thread_local static int bar = 2;
10 \\}
11 , &[_][]const u8{
12 \\pub export var bar: f32 = @import("std").mem.zeroes(f32);
13 \\threadlocal var bar_1: c_int = 2;
14 \\pub export fn foo() c_int {
15 \\ _ = bar_1;
16 \\ return 0;
17 \\}
18 });
19
6 cases.add("missing return stmt",20 cases.add("missing return stmt",
7 \\int foo() {}21 \\int foo() {}
8 \\int bar() {22 \\int bar() {
...@@ -466,7 +480,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -466,7 +480,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
466 , &[_][]const u8{480 , &[_][]const u8{
467 \\pub extern var extern_var: c_int;481 \\pub extern var extern_var: c_int;
468 \\pub const int_var: c_int = 13;482 \\pub const int_var: c_int = 13;
469 \\pub export var foo: c_int = undefined;483 \\pub export var foo: c_int = @import("std").mem.zeroes(c_int);
470 });484 });
471485
472 cases.add("const ptr initializer",486 cases.add("const ptr initializer",
...@@ -480,8 +494,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -480,8 +494,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
480 \\ static const char v2[] = "2.2.2";494 \\ static const char v2[] = "2.2.2";
481 \\}495 \\}
482 , &[_][]const u8{496 , &[_][]const u8{
497 \\const v2: [*c]const u8 = "2.2.2";
483 \\pub export fn foo() void {498 \\pub export fn foo() void {
484 \\ const v2: [*c]const u8 = "2.2.2";499 \\ _ = v2;
485 \\}500 \\}
486 });501 });
487502
...@@ -1327,7 +1342,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1327,7 +1342,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1327 \\static char arr1[] = "hello";1342 \\static char arr1[] = "hello";
1328 \\char arr2[] = "hello";1343 \\char arr2[] = "hello";
1329 , &[_][]const u8{1344 , &[_][]const u8{
1330 \\pub extern var arr0: [*c]u8 = "hello";1345 \\pub export var arr0: [*c]u8 = "hello";
1331 \\pub var arr1: [*c]u8 = "hello";1346 \\pub var arr1: [*c]u8 = "hello";
1332 \\pub export var arr2: [*c]u8 = "hello";1347 \\pub export var arr2: [*c]u8 = "hello";
1333 });1348 });
tools/process_headers.zig+1-1
...@@ -313,7 +313,7 @@ pub fn main() !void {...@@ -313,7 +313,7 @@ pub fn main() !void {
313 var max_bytes_saved: usize = 0;313 var max_bytes_saved: usize = 0;
314 var total_bytes: usize = 0;314 var total_bytes: usize = 0;
315315
316 var hasher = std.crypto.Sha256.init();316 var hasher = std.crypto.hash.sha2.Sha256.init(.{});
317317
318 for (libc_targets) |libc_target| {318 for (libc_targets) |libc_target| {
319 const dest_target = DestTarget{319 const dest_target = DestTarget{