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 {
3838 const test_step = b.step("test", "Run all the tests");
3939
4040 var test_stage2 = b.addTest("src-self-hosted/test.zig");
41 test_stage2.setBuildMode(.Debug); // note this is only the mode of the test harness
41 test_stage2.setBuildMode(mode);
4242 test_stage2.addPackagePath("stage2_tests", "test/stage2/test.zig");
4343
4444 const fmt_build_zig = b.addFmt(&[_][]const u8{"build.zig"});
lib/std/array_list.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std.zig");
27const debug = std.debug;
38const assert = debug.assert;
lib/std/array_list_sentineled.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std.zig");
27const debug = std.debug;
38const mem = std.mem;
lib/std/ascii.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Does NOT look at the locale the way C89's toupper(3), isspace() et cetera does.
27// I could have taken only a u7 to make this clear, but it would be slower
38// It is my opinion that encodings other than UTF-8 should not be supported.
lib/std/atomic.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16pub const Stack = @import("atomic/stack.zig").Stack;
27pub const Queue = @import("atomic/queue.zig").Queue;
38pub const Int = @import("atomic/int.zig").Int;
lib/std/atomic/int.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16/// Thread-safe, lock-free integer
27pub fn Int(comptime T: type) type {
38 return struct {
lib/std/atomic/queue.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const builtin = @import("builtin");
38const assert = std.debug.assert;
lib/std/atomic/stack.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const assert = std.debug.assert;
27const builtin = @import("builtin");
38const expect = std.testing.expect;
lib/std/base64.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std.zig");
27const assert = std.debug.assert;
38const testing = std.testing;
lib/std/bloom_filter.zig+6-1
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const builtin = @import("builtin");
27const std = @import("std.zig");
38const math = std.math;
......@@ -153,7 +158,7 @@ pub fn BloomFilter(
153158}
154159
155160fn 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(.{});
157162 st.update(std.mem.asBytes(&Ki));
158163 st.update(in);
159164 st.final(out);
lib/std/buf_map.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std.zig");
27const StringHashMap = std.StringHashMap;
38const mem = std.mem;
lib/std/buf_set.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std.zig");
27const StringHashMap = std.StringHashMap;
38const mem = @import("mem.zig");
lib/std/build.zig+32-1
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std.zig");
27const builtin = std.builtin;
38const io = std.io;
......@@ -449,7 +454,33 @@ pub const Builder = struct {
449454 return null;
450455 },
451456 },
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 },
453484 .Float => panic("TODO float options to build script", .{}),
454485 .Enum => switch (entry.value.value) {
455486 .Flag => {
lib/std/build/check_file.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const build = std.build;
38const Step = build.Step;
lib/std/build/emit_raw.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std");
27
38const Allocator = std.mem.Allocator;
lib/std/build/fmt.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const build = @import("../build.zig");
38const Step = build.Step;
lib/std/build/run.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const builtin = std.builtin;
38const build = std.build;
lib/std/build/translate_c.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const build = std.build;
38const Step = build.Step;
lib/std/build/write_file.zig+6-1
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const build = @import("../build.zig");
38const Step = build.Step;
......@@ -53,7 +58,7 @@ pub const WriteFileStep = struct {
5358 // TODO port the cache system from stage1 to zig std lib. Until then we use blake2b
5459 // directly and construct the path, and no "cache hit" detection happens; the files
5560 // are always written.
56 var hash = std.crypto.Blake2b384.init();
61 var hash = std.crypto.hash.blake2.Blake2b384.init(.{});
5762
5863 // Random bytes to make WriteFileStep unique. Refresh this with
5964 // new random bytes when WriteFileStep implementation is modified
lib/std/builtin.zig+5-1
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16pub usingnamespace @import("builtin");
27
38/// Deprecated: use `std.Target`.
......@@ -254,7 +259,6 @@ pub const TypeInfo = union(enum) {
254259 /// therefore must be kept in sync with the compiler implementation.
255260 pub const StructField = struct {
256261 name: []const u8,
257 offset: ?comptime_int,
258262 field_type: type,
259263 default_value: anytype,
260264 };
lib/std/c.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std");
27const builtin = std.builtin;
38const page_size = std.mem.page_size;
lib/std/c/ast.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std");
27const SegmentedList = std.SegmentedList;
38const Token = std.c.Token;
lib/std/c/darwin.zig+8-2
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const assert = std.debug.assert;
38const builtin = @import("builtin");
......@@ -41,10 +46,11 @@ const mach_hdr = if (@sizeOf(usize) == 8) mach_header_64 else mach_header;
4146/// on this operating system. However when building object files or libraries,
4247/// the system libc won't be linked until the final executable. So we
4348/// 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;
4551comptime {
4652 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 });
4854 }
4955}
5056
lib/std/c/dragonfly.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27usingnamespace std.c;
38extern "c" threadlocal var errno: c_int;
lib/std/c/emscripten.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16pub const pthread_mutex_t = extern struct {
27 size: [__SIZEOF_PTHREAD_MUTEX_T]u8 align(4) = [_]u8{0} ** __SIZEOF_PTHREAD_MUTEX_T,
38};
lib/std/c/freebsd.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27usingnamespace std.c;
38
lib/std/c/fuchsia.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16pub const pthread_mutex_t = extern struct {
27 size: [__SIZEOF_PTHREAD_MUTEX_T]u8 align(@alignOf(usize)) = [_]u8{0} ** __SIZEOF_PTHREAD_MUTEX_T,
38};
lib/std/c/haiku.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16pub const pthread_mutex_t = extern struct {
27 flags: u32 = 0,
38 lock: i32 = 0,
lib/std/c/hermit.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16pub const pthread_mutex_t = extern struct {
27 inner: usize = ~@as(usize, 0),
38};
lib/std/c/linux.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const builtin = @import("builtin");
27const std = @import("../std.zig");
38const maxInt = std.math.maxInt;
lib/std/c/minix.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const builtin = @import("builtin");
27pub const pthread_mutex_t = extern struct {
38 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// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const builtin = std.builtin;
38
lib/std/c/openbsd.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16pub const pthread_mutex_t = extern struct {
27 inner: ?*c_void = null,
38};
lib/std/c/parse.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std");
27const mem = std.mem;
38const assert = std.debug.assert;
lib/std/c/solaris.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16pub const pthread_mutex_t = extern struct {
27 __pthread_mutex_flag1: u16 = 0,
38 __pthread_mutex_flag2: u8 = 0,
lib/std/c/tokenizer.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std");
27const mem = std.mem;
38
lib/std/c/windows.zig+5
......@@ -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.
16pub extern "c" fn _errno() *c_int;
lib/std/cache_hash.zig+11-6
......@@ -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.
16const std = @import("std.zig");
2const Blake3 = std.crypto.Blake3;
7const Blake3 = std.crypto.hash.Blake3;
38const fs = std.fs;
49const base64 = std.base64;
510const ArrayList = std.ArrayList;
......@@ -51,7 +56,7 @@ pub const CacheHash = struct {
5156 pub fn init(allocator: *Allocator, dir: fs.Dir, manifest_dir_path: []const u8) !CacheHash {
5257 return CacheHash{
5358 .allocator = allocator,
54 .blake3 = Blake3.init(),
59 .blake3 = Blake3.init(.{}),
5560 .manifest_dir = try dir.makeOpenPath(manifest_dir_path, .{}),
5661 .manifest_file = null,
5762 .manifest_dirty = false,
......@@ -132,7 +137,7 @@ pub const CacheHash = struct {
132137
133138 base64_encoder.encode(self.b64_digest[0..], &bin_digest);
134139
135 self.blake3 = Blake3.init();
140 self.blake3 = Blake3.init(.{});
136141 self.blake3.update(&bin_digest);
137142
138143 const manifest_file_path = try fmt.allocPrint(self.allocator, "{}.txt", .{self.b64_digest});
......@@ -251,7 +256,7 @@ pub const CacheHash = struct {
251256 // cache miss
252257 // keep the manifest file open
253258 // reset the hash
254 self.blake3 = Blake3.init();
259 self.blake3 = Blake3.init(.{});
255260 self.blake3.update(&bin_digest);
256261
257262 // Remove files not in the initial hash
......@@ -299,7 +304,7 @@ pub const CacheHash = struct {
299304
300305 // Hash while reading from disk, to keep the contents in the cpu cache while
301306 // doing hashing.
302 var blake3 = Blake3.init();
307 var blake3 = Blake3.init(.{});
303308 var off: usize = 0;
304309 while (true) {
305310 // give me everything you've got, captain
......@@ -429,7 +434,7 @@ pub const CacheHash = struct {
429434};
430435
431436fn hashFile(file: fs.File, bin_digest: []u8) !void {
432 var blake3 = Blake3.init();
437 var blake3 = Blake3.init(.{});
433438 var buf: [1024]u8 = undefined;
434439
435440 while (true) {
lib/std/child_process.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std.zig");
27const cstr = std.cstr;
38const unicode = std.unicode;
lib/std/coff.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const builtin = @import("builtin");
27const std = @import("std.zig");
38const io = std.io;
lib/std/comptime_string_map.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std.zig");
27const mem = std.mem;
38
lib/std/crypto.zig+74-56
......@@ -1,55 +1,68 @@
1pub const Md5 = @import("crypto/md5.zig").Md5;
2pub const Sha1 = @import("crypto/sha1.zig").Sha1;
3
4const sha2 = @import("crypto/sha2.zig");
5pub const Sha224 = sha2.Sha224;
6pub const Sha256 = sha2.Sha256;
7pub const Sha384 = sha2.Sha384;
8pub const Sha512 = sha2.Sha512;
9
10const sha3 = @import("crypto/sha3.zig");
11pub const Sha3_224 = sha3.Sha3_224;
12pub const Sha3_256 = sha3.Sha3_256;
13pub const Sha3_384 = sha3.Sha3_384;
14pub const Sha3_512 = sha3.Sha3_512;
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
6
7/// Hash functions.
8pub const hash = struct {
9 pub const Md5 = @import("crypto/md5.zig").Md5;
10 pub const Sha1 = @import("crypto/sha1.zig").Sha1;
11 pub const sha2 = @import("crypto/sha2.zig");
12 pub const sha3 = @import("crypto/sha3.zig");
13 pub const blake2 = @import("crypto/blake2.zig");
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");
19pub const Blake2s224 = blake2.Blake2s224;
20pub const Blake2s256 = blake2.Blake2s256;
21pub const Blake2b384 = blake2.Blake2b384;
22pub const Blake2b512 = blake2.Blake2b512;
23/// Authenticated Encryption with Associated Data
24pub const aead = struct {
25 const chacha20 = @import("crypto/chacha20.zig");
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");
27pub const HmacMd5 = hmac.HmacMd5;
28pub const HmacSha1 = hmac.HmacSha1;
29pub const HmacSha256 = hmac.HmacSha256;
30pub const HmacBlake2s256 = hmac.HmacBlake2s256;
32/// MAC functions requiring single-use secret keys.
33pub const onetimeauth = struct {
34 pub const Poly1305 = @import("crypto/poly1305.zig").Poly1305;
35};
3136
32pub const chacha20 = @import("crypto/chacha20.zig");
33pub const chaCha20IETF = chacha20.chaCha20IETF;
34pub const chaCha20With64BitNonce = chacha20.chaCha20With64BitNonce;
35pub const xChaCha20IETF = chacha20.xChaCha20IETF;
37/// Core functions, that should rarely be used directly by applications.
38pub const core = struct {
39 pub const aes = @import("crypto/aes.zig");
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");
40pub const AES128 = import_aes.AES128;
41pub const AES256 = import_aes.AES256;
50/// Diffie-Hellman key exchange functions.
51pub const dh = struct {
52 pub const X25519 = @import("crypto/25519/x25519.zig").X25519;
53};
4254
43pub const Curve25519 = @import("crypto/25519/curve25519.zig").Curve25519;
44pub const Ed25519 = @import("crypto/25519/ed25519.zig").Ed25519;
45pub const Edwards25519 = @import("crypto/25519/edwards25519.zig").Edwards25519;
46pub const X25519 = @import("crypto/25519/x25519.zig").X25519;
47pub const Ristretto255 = @import("crypto/25519/ristretto255.zig").Ristretto255;
55/// Digital signature functions.
56pub const sign = struct {
57 pub const Ed25519 = @import("crypto/25519/ed25519.zig").Ed25519;
58};
4859
49pub const aead = struct {
50 pub const Gimli = gimli.Aead;
51 pub const ChaCha20Poly1305 = chacha20.Chacha20Poly1305;
52 pub const XChaCha20Poly1305 = chacha20.XChacha20Poly1305;
60/// Stream ciphers. These do not provide any kind of authentication.
61/// Most applications should be using AEAD constructions instead of stream ciphers directly.
62pub const stream = struct {
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;
5366};
5467
5568const std = @import("std.zig");
......@@ -78,27 +91,32 @@ test "crypto" {
7891
7992test "issue #4532: no index out of bounds" {
8093 const types = [_]type{
81 Md5,
82 Sha1,
83 Sha224,
84 Sha256,
85 Sha384,
86 Sha512,
87 Blake2s224,
88 Blake2s256,
89 Blake2b384,
90 Blake2b512,
94 hash.Md5,
95 hash.Sha1,
96 hash.sha2.Sha224,
97 hash.sha2.Sha256,
98 hash.sha2.Sha384,
99 hash.sha2.Sha512,
100 hash.sha3.Sha3_224,
101 hash.sha3.Sha3_256,
102 hash.sha3.Sha3_384,
103 hash.sha3.Sha3_512,
104 hash.blake2.Blake2s224,
105 hash.blake2.Blake2s256,
106 hash.blake2.Blake2b384,
107 hash.blake2.Blake2b512,
108 hash.Gimli,
91109 };
92110
93111 inline for (types) |Hasher| {
94112 var block = [_]u8{'#'} ** Hasher.block_length;
95113 var out1: [Hasher.digest_length]u8 = undefined;
96114 var out2: [Hasher.digest_length]u8 = undefined;
97
98 var h = Hasher.init();
115 const h0 = Hasher.init(.{});
116 var h = h0;
99117 h.update(block[0..]);
100118 h.final(out1[0..]);
101 h.reset();
119 h = h0;
102120 h.update(block[0..1]);
103121 h.update(block[1..]);
104122 h.final(out2[0..]);
lib/std/crypto/25519/curve25519.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std");
27
38/// Group operations over Curve25519.
lib/std/crypto/25519/ed25519.zig+11-6
......@@ -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.
16const std = @import("std");
27const fmt = std.fmt;
38const mem = std.mem;
4const Sha512 = std.crypto.Sha512;
9const Sha512 = std.crypto.hash.sha2.Sha512;
510
611/// Ed25519 (EdDSA) signatures.
712pub const Ed25519 = struct {
......@@ -28,7 +33,7 @@ pub const Ed25519 = struct {
2833 /// from which the actual secret is derived.
2934 pub fn createKeyPair(seed: [seed_length]u8) ![keypair_length]u8 {
3035 var az: [Sha512.digest_length]u8 = undefined;
31 var h = Sha512.init();
36 var h = Sha512.init(.{});
3237 h.update(&seed);
3338 h.final(&az);
3439 const p = try Curve.basePoint.clampedMul(az[0..32].*);
......@@ -51,11 +56,11 @@ pub const Ed25519 = struct {
5156 pub fn sign(msg: []const u8, key_pair: [keypair_length]u8, noise: ?[noise_length]u8) ![signature_length]u8 {
5257 const public_key = key_pair[32..];
5358 var az: [Sha512.digest_length]u8 = undefined;
54 var h = Sha512.init();
59 var h = Sha512.init(.{});
5560 h.update(key_pair[0..seed_length]);
5661 h.final(&az);
5762
58 h = Sha512.init();
63 h = Sha512.init(.{});
5964 if (noise) |*z| {
6065 h.update(z);
6166 }
......@@ -69,7 +74,7 @@ pub const Ed25519 = struct {
6974 var sig: [signature_length]u8 = undefined;
7075 mem.copy(u8, sig[0..32], &r.toBytes());
7176 mem.copy(u8, sig[32..], public_key);
72 h = Sha512.init();
77 h = Sha512.init(.{});
7378 h.update(&sig);
7479 h.update(msg);
7580 var hram64: [Sha512.digest_length]u8 = undefined;
......@@ -93,7 +98,7 @@ pub const Ed25519 = struct {
9398 const a = try Curve.fromBytes(public_key);
9499 try a.rejectIdentity();
95100
96 var h = Sha512.init();
101 var h = Sha512.init(.{});
97102 h.update(r);
98103 h.update(&public_key);
99104 h.update(msg);
lib/std/crypto/25519/edwards25519.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std");
27const fmt = std.fmt;
38
lib/std/crypto/25519/field.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std");
27const readIntLittle = std.mem.readIntLittle;
38const writeIntLittle = std.mem.writeIntLittle;
lib/std/crypto/25519/ristretto255.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std");
27const fmt = std.fmt;
38
lib/std/crypto/25519/scalar.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std");
27const mem = std.mem;
38
lib/std/crypto/25519/x25519.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std");
27const mem = std.mem;
38const fmt = std.fmt;
lib/std/crypto/aes.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Based on Go stdlib implementation
27
38const std = @import("../std.zig");
lib/std/crypto/benchmark.zig+25-19
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// zig run benchmark.zig --release-fast --override-lib-dir ..
27
38const builtin = @import("builtin");
......@@ -17,20 +22,20 @@ const Crypto = struct {
1722};
1823
1924const hashes = [_]Crypto{
20 Crypto{ .ty = crypto.Md5, .name = "md5" },
21 Crypto{ .ty = crypto.Sha1, .name = "sha1" },
22 Crypto{ .ty = crypto.Sha256, .name = "sha256" },
23 Crypto{ .ty = crypto.Sha512, .name = "sha512" },
24 Crypto{ .ty = crypto.Sha3_256, .name = "sha3-256" },
25 Crypto{ .ty = crypto.Sha3_512, .name = "sha3-512" },
26 Crypto{ .ty = crypto.gimli.Hash, .name = "gimli-hash" },
27 Crypto{ .ty = crypto.Blake2s256, .name = "blake2s" },
28 Crypto{ .ty = crypto.Blake2b512, .name = "blake2b" },
29 Crypto{ .ty = crypto.Blake3, .name = "blake3" },
25 Crypto{ .ty = crypto.hash.Md5, .name = "md5" },
26 Crypto{ .ty = crypto.hash.Sha1, .name = "sha1" },
27 Crypto{ .ty = crypto.hash.sha2.Sha256, .name = "sha256" },
28 Crypto{ .ty = crypto.hash.sha2.Sha512, .name = "sha512" },
29 Crypto{ .ty = crypto.hash.sha3.Sha3_256, .name = "sha3-256" },
30 Crypto{ .ty = crypto.hash.sha3.Sha3_512, .name = "sha3-512" },
31 Crypto{ .ty = crypto.hash.Gimli, .name = "gimli-hash" },
32 Crypto{ .ty = crypto.hash.blake2.Blake2s256, .name = "blake2s" },
33 Crypto{ .ty = crypto.hash.blake2.Blake2b512, .name = "blake2b" },
34 Crypto{ .ty = crypto.hash.Blake3, .name = "blake3" },
3035};
3136
3237pub fn benchmarkHash(comptime Hash: anytype, comptime bytes: comptime_int) !u64 {
33 var h = Hash.init();
38 var h = Hash.init(.{});
3439
3540 var block: [Hash.digest_length]u8 = undefined;
3641 prng.random.bytes(block[0..]);
......@@ -50,19 +55,20 @@ pub fn benchmarkHash(comptime Hash: anytype, comptime bytes: comptime_int) !u64
5055}
5156
5257const macs = [_]Crypto{
53 Crypto{ .ty = crypto.Poly1305, .name = "poly1305" },
54 Crypto{ .ty = crypto.HmacMd5, .name = "hmac-md5" },
55 Crypto{ .ty = crypto.HmacSha1, .name = "hmac-sha1" },
56 Crypto{ .ty = crypto.HmacSha256, .name = "hmac-sha256" },
58 Crypto{ .ty = crypto.onetimeauth.Poly1305, .name = "poly1305" },
59 Crypto{ .ty = crypto.auth.hmac.HmacMd5, .name = "hmac-md5" },
60 Crypto{ .ty = crypto.auth.hmac.HmacSha1, .name = "hmac-sha1" },
61 Crypto{ .ty = crypto.auth.hmac.sha2.HmacSha256, .name = "hmac-sha256" },
62 Crypto{ .ty = crypto.auth.hmac.sha2.HmacSha512, .name = "hmac-sha512" },
5763};
5864
5965pub 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
6268 var in: [1 * MiB]u8 = undefined;
6369 prng.random.bytes(in[0..]);
6470
65 var key: [32]u8 = undefined;
71 var key: [64]u8 = undefined;
6672 prng.random.bytes(key[0..]);
6773
6874 var offset: usize = 0;
......@@ -79,7 +85,7 @@ pub fn benchmarkMac(comptime Mac: anytype, comptime bytes: comptime_int) !u64 {
7985 return throughput;
8086}
8187
82const exchanges = [_]Crypto{Crypto{ .ty = crypto.X25519, .name = "x25519" }};
88const exchanges = [_]Crypto{Crypto{ .ty = crypto.dh.X25519, .name = "x25519" }};
8389
8490pub fn benchmarkKeyExchange(comptime DhKeyExchange: anytype, comptime exchange_count: comptime_int) !u64 {
8591 std.debug.assert(DhKeyExchange.minimum_key_length >= DhKeyExchange.secret_length);
......@@ -106,7 +112,7 @@ pub fn benchmarkKeyExchange(comptime DhKeyExchange: anytype, comptime exchange_c
106112 return throughput;
107113}
108114
109const signatures = [_]Crypto{Crypto{ .ty = crypto.Ed25519, .name = "ed25519" }};
115const signatures = [_]Crypto{Crypto{ .ty = crypto.sign.Ed25519, .name = "ed25519" }};
110116
111117pub fn benchmarkSignatures(comptime Signature: anytype, comptime signatures_count: comptime_int) !u64 {
112118 var seed: [Signature.seed_length]u8 = undefined;
lib/std/crypto/blake2.zig+107-78
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const mem = @import("../mem.zig");
27const builtin = @import("builtin");
38const debug = @import("../debug.zig");
......@@ -35,6 +40,7 @@ pub fn Blake2s(comptime out_len: usize) type {
3540 const Self = @This();
3641 pub const block_length = 64;
3742 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
3945 const iv = [8]u32{
4046 0x6A09E667,
......@@ -66,42 +72,36 @@ pub fn Blake2s(comptime out_len: usize) type {
6672 buf: [64]u8,
6773 buf_len: u8,
6874
69 key: []const u8,
70
71 pub fn init() Self {
72 return init_keyed("");
73 }
74
75 pub fn init_keyed(key: []const u8) Self {
75 pub fn init(options: Options) Self {
7676 debug.assert(8 <= out_len and out_len <= 512);
7777
78 var s: Self = undefined;
79 s.key = key;
80 s.reset();
81 return s;
82 }
83
84 pub fn reset(d: *Self) void {
78 var d: Self = undefined;
8579 mem.copy(u32, d.h[0..], iv[0..]);
8680
81 const key_len = if (options.key) |key| key.len else 0;
8782 // 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);
8984 d.t = 0;
9085 d.buf_len = 0;
9186
92 if (d.key.len > 0) {
93 mem.set(u8, d.buf[d.key.len..], 0);
94 d.update(d.key);
87 if (options.salt) |salt| {
88 d.h[4] ^= mem.readIntLittle(u32, salt[0..4]);
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.?);
9598 d.buf_len = 64;
9699 }
100 return d;
97101 }
98102
99 pub fn hash(b: []const u8, out: []u8) void {
100 Self.hash_keyed("", b, out);
101 }
102
103 pub fn hash_keyed(key: []const u8, b: []const u8, out: []u8) void {
104 var d = Self.init_keyed(key);
103 pub fn hash(b: []const u8, out: []u8, options: Options) void {
104 var d = Self.init(options);
105105 d.update(b);
106106 d.final(out);
107107 }
......@@ -210,7 +210,7 @@ test "blake2s224 single" {
210210}
211211
212212test "blake2s224 streaming" {
213 var h = Blake2s224.init();
213 var h = Blake2s224.init(.{});
214214 var out: [28]u8 = undefined;
215215
216216 const h1 = "1fa1291e65248b37b3433475b2a0dd63d54a11ecc4e3e034e7bc1ef4";
......@@ -220,12 +220,12 @@ test "blake2s224 streaming" {
220220
221221 const h2 = "0b033fc226df7abde29f67a05d3dc62cf271ef3dfea4d387407fbd55";
222222
223 h.reset();
223 h = Blake2s224.init(.{});
224224 h.update("abc");
225225 h.final(out[0..]);
226226 htest.assertEqual(h2, out[0..]);
227227
228 h.reset();
228 h = Blake2s224.init(.{});
229229 h.update("a");
230230 h.update("b");
231231 h.update("c");
......@@ -234,16 +234,29 @@ test "blake2s224 streaming" {
234234
235235 const h3 = "557381a78facd2b298640f4e32113e58967d61420af1aa939d0cfe01";
236236
237 h.reset();
237 h = Blake2s224.init(.{});
238238 h.update("a" ** 32);
239239 h.update("b" ** 32);
240240 h.final(out[0..]);
241241 htest.assertEqual(h3, out[0..]);
242242
243 h.reset();
243 h = Blake2s224.init(.{});
244244 h.update("a" ** 32 ++ "b" ** 32);
245245 h.final(out[0..]);
246246 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..]);
247260}
248261
249262test "comptime blake2s224" {
......@@ -256,7 +269,7 @@ test "comptime blake2s224" {
256269
257270 htest.assertEqualHash(Blake2s224, h1, block[0..]);
258271
259 var h = Blake2s224.init();
272 var h = Blake2s224.init(.{});
260273 h.update(&block);
261274 h.final(out[0..]);
262275
......@@ -279,7 +292,7 @@ test "blake2s256 single" {
279292}
280293
281294test "blake2s256 streaming" {
282 var h = Blake2s256.init();
295 var h = Blake2s256.init(.{});
283296 var out: [32]u8 = undefined;
284297
285298 const h1 = "69217a3079908094e11121d042354a7c1f55b6482ca1a51e1b250dfd1ed0eef9";
......@@ -289,12 +302,12 @@ test "blake2s256 streaming" {
289302
290303 const h2 = "508c5e8c327c14e2e1a72ba34eeb452f37458b209ed63a294d999b4c86675982";
291304
292 h.reset();
305 h = Blake2s256.init(.{});
293306 h.update("abc");
294307 h.final(out[0..]);
295308 htest.assertEqual(h2, out[0..]);
296309
297 h.reset();
310 h = Blake2s256.init(.{});
298311 h.update("a");
299312 h.update("b");
300313 h.update("c");
......@@ -303,13 +316,13 @@ test "blake2s256 streaming" {
303316
304317 const h3 = "8d8711dade07a6b92b9a3ea1f40bee9b2c53ff3edd2a273dec170b0163568977";
305318
306 h.reset();
319 h = Blake2s256.init(.{});
307320 h.update("a" ** 32);
308321 h.update("b" ** 32);
309322 h.final(out[0..]);
310323 htest.assertEqual(h3, out[0..]);
311324
312 h.reset();
325 h = Blake2s256.init(.{});
313326 h.update("a" ** 32 ++ "b" ** 32);
314327 h.final(out[0..]);
315328 htest.assertEqual(h3, out[0..]);
......@@ -321,16 +334,16 @@ test "blake2s256 keyed" {
321334 const h1 = "10f918da4d74fab3302e48a5d67d03804b1ec95372a62a0f33b7c9fa28ba1ae6";
322335 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 });
325338 htest.assertEqual(h1, out[0..]);
326339
327 var h = Blake2s256.init_keyed(key);
340 var h = Blake2s256.init(.{ .key = key });
328341 h.update("a" ** 64 ++ "b" ** 64);
329342 h.final(out[0..]);
330343
331344 htest.assertEqual(h1, out[0..]);
332345
333 h.reset();
346 h = Blake2s256.init(.{ .key = key });
334347 h.update("a" ** 64);
335348 h.update("b" ** 64);
336349 h.final(out[0..]);
......@@ -348,7 +361,7 @@ test "comptime blake2s256" {
348361
349362 htest.assertEqualHash(Blake2s256, h1, block[0..]);
350363
351 var h = Blake2s256.init();
364 var h = Blake2s256.init(.{});
352365 h.update(&block);
353366 h.final(out[0..]);
354367
......@@ -359,6 +372,7 @@ test "comptime blake2s256" {
359372/////////////////////
360373// Blake2b
361374
375pub const Blake2b256 = Blake2b(256);
362376pub const Blake2b384 = Blake2b(384);
363377pub const Blake2b512 = Blake2b(512);
364378
......@@ -367,6 +381,7 @@ pub fn Blake2b(comptime out_len: usize) type {
367381 const Self = @This();
368382 pub const block_length = 128;
369383 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
371386 const iv = [8]u64{
372387 0x6a09e667f3bcc908,
......@@ -400,42 +415,36 @@ pub fn Blake2b(comptime out_len: usize) type {
400415 buf: [128]u8,
401416 buf_len: u8,
402417
403 key: []const u8,
404
405 pub fn init() Self {
406 return init_keyed("");
407 }
408
409 pub fn init_keyed(key: []const u8) Self {
418 pub fn init(options: Options) Self {
410419 debug.assert(8 <= out_len and out_len <= 512);
411420
412 var s: Self = undefined;
413 s.key = key;
414 s.reset();
415 return s;
416 }
417
418 pub fn reset(d: *Self) void {
421 var d: Self = undefined;
419422 mem.copy(u64, d.h[0..], iv[0..]);
420423
424 const key_len = if (options.key) |key| key.len else 0;
421425 // 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);
423427 d.t = 0;
424428 d.buf_len = 0;
425429
426 if (d.key.len > 0) {
427 mem.set(u8, d.buf[d.key.len..], 0);
428 d.update(d.key);
430 if (options.salt) |salt| {
431 d.h[4] ^= mem.readIntLittle(u64, salt[0..8]);
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.?);
429441 d.buf_len = 128;
430442 }
443 return d;
431444 }
432445
433 pub fn hash(b: []const u8, out: []u8) void {
434 Self.hash_keyed("", b, out);
435 }
436
437 pub fn hash_keyed(key: []const u8, b: []const u8, out: []u8) void {
438 var d = Self.init_keyed(key);
446 pub fn hash(b: []const u8, out: []u8, options: Options) void {
447 var d = Self.init(options);
439448 d.update(b);
440449 d.final(out);
441450 }
......@@ -542,7 +551,7 @@ test "blake2b384 single" {
542551}
543552
544553test "blake2b384 streaming" {
545 var h = Blake2b384.init();
554 var h = Blake2b384.init(.{});
546555 var out: [48]u8 = undefined;
547556
548557 const h1 = "b32811423377f52d7862286ee1a72ee540524380fda1724a6f25d7978c6fd3244a6caf0498812673c5e05ef583825100";
......@@ -552,12 +561,12 @@ test "blake2b384 streaming" {
552561
553562 const h2 = "6f56a82c8e7ef526dfe182eb5212f7db9df1317e57815dbda46083fc30f54ee6c66ba83be64b302d7cba6ce15bb556f4";
554563
555 h.reset();
564 h = Blake2b384.init(.{});
556565 h.update("abc");
557566 h.final(out[0..]);
558567 htest.assertEqual(h2, out[0..]);
559568
560 h.reset();
569 h = Blake2b384.init(.{});
561570 h.update("a");
562571 h.update("b");
563572 h.update("c");
......@@ -566,16 +575,36 @@ test "blake2b384 streaming" {
566575
567576 const h3 = "b7283f0172fecbbd7eca32ce10d8a6c06b453cb3cf675b33eb4246f0da2bb94a6c0bdd6eec0b5fd71ec4fd51be80bf4c";
568577
569 h.reset();
578 h = Blake2b384.init(.{});
570579 h.update("a" ** 64 ++ "b" ** 64);
571580 h.final(out[0..]);
572581 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(.{});
575590 h.update("a" ** 64);
576591 h.update("b" ** 64);
577592 h.final(out[0..]);
578593 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..]);
579608}
580609
581610test "comptime blake2b384" {
......@@ -588,7 +617,7 @@ test "comptime blake2b384" {
588617
589618 htest.assertEqualHash(Blake2b384, h1, block[0..]);
590619
591 var h = Blake2b384.init();
620 var h = Blake2b384.init(.{});
592621 h.update(&block);
593622 h.final(out[0..]);
594623
......@@ -611,7 +640,7 @@ test "blake2b512 single" {
611640}
612641
613642test "blake2b512 streaming" {
614 var h = Blake2b512.init();
643 var h = Blake2b512.init(.{});
615644 var out: [64]u8 = undefined;
616645
617646 const h1 = "786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce";
......@@ -621,12 +650,12 @@ test "blake2b512 streaming" {
621650
622651 const h2 = "ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d17d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923";
623652
624 h.reset();
653 h = Blake2b512.init(.{});
625654 h.update("abc");
626655 h.final(out[0..]);
627656 htest.assertEqual(h2, out[0..]);
628657
629 h.reset();
658 h = Blake2b512.init(.{});
630659 h.update("a");
631660 h.update("b");
632661 h.update("c");
......@@ -635,12 +664,12 @@ test "blake2b512 streaming" {
635664
636665 const h3 = "049980af04d6a2cf16b4b49793c3ed7e40732073788806f2c989ebe9547bda0541d63abe298ec8955d08af48ae731f2e8a0bd6d201655a5473b4aa79d211b920";
637666
638 h.reset();
667 h = Blake2b512.init(.{});
639668 h.update("a" ** 64 ++ "b" ** 64);
640669 h.final(out[0..]);
641670 htest.assertEqual(h3, out[0..]);
642671
643 h.reset();
672 h = Blake2b512.init(.{});
644673 h.update("a" ** 64);
645674 h.update("b" ** 64);
646675 h.final(out[0..]);
......@@ -653,16 +682,16 @@ test "blake2b512 keyed" {
653682 const h1 = "8a978060ccaf582f388f37454363071ac9a67e3a704585fd879fb8a419a447e389c7c6de790faa20a7a7dccf197de736bc5b40b98a930b36df5bee7555750c4d";
654683 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 });
657686 htest.assertEqual(h1, out[0..]);
658687
659 var h = Blake2b512.init_keyed(key);
688 var h = Blake2b512.init(.{ .key = key });
660689 h.update("a" ** 64 ++ "b" ** 64);
661690 h.final(out[0..]);
662691
663692 htest.assertEqual(h1, out[0..]);
664693
665 h.reset();
694 h = Blake2b512.init(.{ .key = key });
666695 h.update("a" ** 64);
667696 h.update("b" ** 64);
668697 h.final(out[0..]);
......@@ -680,7 +709,7 @@ test "comptime blake2b512" {
680709
681710 htest.assertEqualHash(Blake2b512, h1, block[0..]);
682711
683 var h = Blake2b512.init();
712 var h = Blake2b512.init(.{});
684713 h.update(&block);
685714 h.final(out[0..]);
686715
lib/std/crypto/blake3.zig+29-23
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Translated from BLAKE3 reference implementation.
27// Source: https://github.com/BLAKE3-team/BLAKE3
38
......@@ -274,6 +279,9 @@ fn parent_cv(
274279
275280/// An incremental hasher that can accept any number of writes.
276281pub const Blake3 = struct {
282 pub const Options = struct { key: ?[KEY_LEN]u8 = null };
283 pub const KdfOptions = struct {};
284
277285 chunk_state: ChunkState,
278286 key: [8]u32,
279287 cv_stack: [54][8]u32 = undefined, // Space for 54 subtree chaining values:
......@@ -291,21 +299,20 @@ pub const Blake3 = struct {
291299 };
292300 }
293301
294 /// Construct a new `Blake3` for the regular hash function.
295 pub fn init() Blake3 {
296 return Blake3.init_internal(IV, 0);
297 }
298
299 /// Construct a new `Blake3` for the keyed hash function.
300 pub fn init_keyed(key: [KEY_LEN]u8) Blake3 {
301 var key_words: [8]u32 = undefined;
302 words_from_little_endian_bytes(key_words[0..], key[0..]);
303 return Blake3.init_internal(key_words, KEYED_HASH);
302 /// Construct a new `Blake3` for the hash function, with an optional key
303 pub fn init(options: Options) Blake3 {
304 if (options.key) |key| {
305 var key_words: [8]u32 = undefined;
306 words_from_little_endian_bytes(key_words[0..], key[0..]);
307 return Blake3.init_internal(key_words, KEYED_HASH);
308 } else {
309 return Blake3.init_internal(IV, 0);
310 }
304311 }
305312
306313 /// Construct a new `Blake3` for the key derivation function. The context
307314 /// 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 {
309316 var context_hasher = Blake3.init_internal(IV, DERIVE_KEY_CONTEXT);
310317 context_hasher.update(context);
311318 var context_key: [KEY_LEN]u8 = undefined;
......@@ -315,18 +322,12 @@ pub const Blake3 = struct {
315322 return Blake3.init_internal(context_key_words, DERIVE_KEY_MATERIAL);
316323 }
317324
318 pub fn hash(in: []const u8, out: []u8) void {
319 var hasher = Blake3.init();
325 pub fn hash(in: []const u8, out: []u8, options: Options) void {
326 var hasher = Blake3.init(options);
320327 hasher.update(in);
321328 hasher.final(out);
322329 }
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
330331 fn push_cv(self: *Blake3, cv: [8]u32) void {
331332 self.cv_stack[self.cv_stack_len] = cv;
332333 self.cv_stack_len += 1;
......@@ -561,6 +562,9 @@ const reference_test = ReferenceTest{
561562};
562563
563564fn test_blake3(hasher: *Blake3, input_len: usize, expected_hex: [262]u8) void {
565 // Save initial state
566 const initial_state = hasher.*;
567
564568 // Setup input pattern
565569 var input_pattern: [251]u8 = undefined;
566570 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 {
576580 // Read final hash value
577581 var actual_bytes: [expected_hex.len / 2]u8 = undefined;
578582 hasher.final(actual_bytes[0..]);
579 hasher.reset();
580583
581584 // Compare to expected value
582585 var expected_bytes: [expected_hex.len / 2]u8 = undefined;
583586 fmt.hexToBytes(expected_bytes[0..], expected_hex[0..]) catch unreachable;
584587 testing.expectEqual(actual_bytes, expected_bytes);
588
589 // Restore initial state
590 hasher.* = initial_state;
585591}
586592
587593test "BLAKE3 reference test cases" {
588 var hash = &Blake3.init();
589 var keyed_hash = &Blake3.init_keyed(reference_test.key.*);
590 var derive_key = &Blake3.init_derive_key(reference_test.context_string);
594 var hash = &Blake3.init(.{});
595 var keyed_hash = &Blake3.init(.{ .key = reference_test.key.* });
596 var derive_key = &Blake3.initKdf(reference_test.context_string, .{});
591597
592598 for (reference_test.cases) |t| {
593599 test_blake3(hash, t.input_len, t.hash.*);
lib/std/crypto/chacha20.zig+79-68
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Based on public domain Supercop by Daniel J. Bernstein
27
38const std = @import("../std.zig");
......@@ -7,7 +12,7 @@ const assert = std.debug.assert;
712const testing = std.testing;
813const builtin = @import("builtin");
914const maxInt = std.math.maxInt;
10const Poly1305 = std.crypto.Poly1305;
15const Poly1305 = std.crypto.onetimeauth.Poly1305;
1116
1217const QuarterRound = struct {
1318 a: usize,
......@@ -132,56 +137,60 @@ fn keyToWords(key: [32]u8) [8]u32 {
132137///
133138/// ChaCha20 is self-reversing. To decrypt just run the cipher with the same
134139/// counter, nonce, and key.
135pub fn chaCha20IETF(out: []u8, in: []const u8, counter: u32, key: [32]u8, nonce: [12]u8) void {
136 assert(in.len >= out.len);
137 assert((in.len >> 6) + counter <= maxInt(u32));
138
139 var c: [4]u32 = undefined;
140 c[0] = counter;
141 c[1] = mem.readIntLittle(u32, nonce[0..4]);
142 c[2] = mem.readIntLittle(u32, nonce[4..8]);
143 c[3] = mem.readIntLittle(u32, nonce[8..12]);
144 chaCha20_internal(out, in, keyToWords(key), c);
145}
140pub const ChaCha20IETF = struct {
141 pub fn xor(out: []u8, in: []const u8, counter: u32, key: [32]u8, nonce: [12]u8) void {
142 assert(in.len >= out.len);
143 assert((in.len >> 6) + counter <= maxInt(u32));
144
145 var c: [4]u32 = undefined;
146 c[0] = counter;
147 c[1] = mem.readIntLittle(u32, nonce[0..4]);
148 c[2] = mem.readIntLittle(u32, nonce[4..8]);
149 c[3] = mem.readIntLittle(u32, nonce[8..12]);
150 chaCha20_internal(out, in, keyToWords(key), c);
151 }
152};
146153
147154/// This is the original ChaCha20 before RFC 7539, which recommends using the
148155/// orgininal version on applications such as disk or file encryption that might
149156/// 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 {
151 assert(in.len >= out.len);
152 assert(counter +% (in.len >> 6) >= counter);
153
154 var cursor: usize = 0;
155 const k = keyToWords(key);
156 var c: [4]u32 = undefined;
157 c[0] = @truncate(u32, counter);
158 c[1] = @truncate(u32, counter >> 32);
159 c[2] = mem.readIntLittle(u32, nonce[0..4]);
160 c[3] = mem.readIntLittle(u32, nonce[4..8]);
161
162 const block_size = (1 << 6);
163 // The full block size is greater than the address space on a 32bit machine
164 const big_block = if (@sizeOf(usize) > 4) (block_size << 32) else maxInt(usize);
165
166 // first partial big block
167 if (((@intCast(u64, maxInt(u32) - @truncate(u32, counter)) + 1) << 6) < in.len) {
168 chaCha20_internal(out[cursor..big_block], in[cursor..big_block], k, c);
169 cursor = big_block - cursor;
170 c[1] += 1;
171 if (comptime @sizeOf(usize) > 4) {
172 // A big block is giant: 256 GiB, but we can avoid this limitation
173 var remaining_blocks: u32 = @intCast(u32, (in.len / big_block));
174 var i: u32 = 0;
175 while (remaining_blocks > 0) : (remaining_blocks -= 1) {
176 chaCha20_internal(out[cursor .. cursor + big_block], in[cursor .. cursor + big_block], k, c);
177 c[1] += 1; // upper 32-bit of counter, generic chaCha20_internal() doesn't know about this.
178 cursor += big_block;
157pub const ChaCha20With64BitNonce = struct {
158 pub fn xor(out: []u8, in: []const u8, counter: u64, key: [32]u8, nonce: [8]u8) void {
159 assert(in.len >= out.len);
160 assert(counter +% (in.len >> 6) >= counter);
161
162 var cursor: usize = 0;
163 const k = keyToWords(key);
164 var c: [4]u32 = undefined;
165 c[0] = @truncate(u32, counter);
166 c[1] = @truncate(u32, counter >> 32);
167 c[2] = mem.readIntLittle(u32, nonce[0..4]);
168 c[3] = mem.readIntLittle(u32, nonce[4..8]);
169
170 const block_size = (1 << 6);
171 // The full block size is greater than the address space on a 32bit machine
172 const big_block = if (@sizeOf(usize) > 4) (block_size << 32) else maxInt(usize);
173
174 // first partial big block
175 if (((@intCast(u64, maxInt(u32) - @truncate(u32, counter)) + 1) << 6) < in.len) {
176 chaCha20_internal(out[cursor..big_block], in[cursor..big_block], k, c);
177 cursor = big_block - cursor;
178 c[1] += 1;
179 if (comptime @sizeOf(usize) > 4) {
180 // A big block is giant: 256 GiB, but we can avoid this limitation
181 var remaining_blocks: u32 = @intCast(u32, (in.len / big_block));
182 var i: u32 = 0;
183 while (remaining_blocks > 0) : (remaining_blocks -= 1) {
184 chaCha20_internal(out[cursor .. cursor + big_block], in[cursor .. cursor + big_block], k, c);
185 c[1] += 1; // upper 32-bit of counter, generic chaCha20_internal() doesn't know about this.
186 cursor += big_block;
187 }
179188 }
180189 }
181 }
182190
183 chaCha20_internal(out[cursor..], in[cursor..], k, c);
184}
191 chaCha20_internal(out[cursor..], in[cursor..], k, c);
192 }
193};
185194
186195// https://tools.ietf.org/html/rfc7539#section-2.4.2
187196test "crypto.chacha20 test vector sunscreen" {
......@@ -216,12 +225,12 @@ test "crypto.chacha20 test vector sunscreen" {
216225 0, 0, 0, 0,
217226 };
218227
219 chaCha20IETF(result[0..], input[0..], 1, key, nonce);
228 ChaCha20IETF.xor(result[0..], input[0..], 1, key, nonce);
220229 testing.expectEqualSlices(u8, &expected_result, &result);
221230
222231 // Chacha20 is self-reversing.
223232 var plaintext: [114]u8 = undefined;
224 chaCha20IETF(plaintext[0..], result[0..], 1, key, nonce);
233 ChaCha20IETF.xor(plaintext[0..], result[0..], 1, key, nonce);
225234 testing.expect(mem.order(u8, input, &plaintext) == .eq);
226235}
227236
......@@ -256,7 +265,7 @@ test "crypto.chacha20 test vector 1" {
256265 };
257266 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);
260269 testing.expectEqualSlices(u8, &expected_result, &result);
261270}
262271
......@@ -290,7 +299,7 @@ test "crypto.chacha20 test vector 2" {
290299 };
291300 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);
294303 testing.expectEqualSlices(u8, &expected_result, &result);
295304}
296305
......@@ -324,7 +333,7 @@ test "crypto.chacha20 test vector 3" {
324333 };
325334 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);
328337 testing.expectEqualSlices(u8, &expected_result, &result);
329338}
330339
......@@ -358,7 +367,7 @@ test "crypto.chacha20 test vector 4" {
358367 };
359368 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);
362371 testing.expectEqualSlices(u8, &expected_result, &result);
363372}
364373
......@@ -430,21 +439,21 @@ test "crypto.chacha20 test vector 5" {
430439 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
431440 };
432441
433 chaCha20With64BitNonce(result[0..], input[0..], 0, key, nonce);
442 ChaCha20With64BitNonce.xor(result[0..], input[0..], 0, key, nonce);
434443 testing.expectEqualSlices(u8, &expected_result, &result);
435444}
436445
437446pub 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 {
440449 assert(ciphertext.len >= plaintext.len);
441450
442451 // derive poly1305 key
443452 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
446455 // encrypt plaintext
447 chaCha20IETF(ciphertext[0..plaintext.len], plaintext, 1, key, nonce);
456 ChaCha20IETF.xor(ciphertext[0..plaintext.len], plaintext, 1, key, nonce);
448457
449458 // construct mac
450459 var mac = Poly1305.init(polyKey[0..]);
......@@ -467,18 +476,18 @@ pub fn chacha20poly1305SealDetached(ciphertext: []u8, tag: *[chacha20poly1305_ta
467476 mac.final(tag);
468477}
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 {
471480 return chacha20poly1305SealDetached(ciphertextAndTag[0..plaintext.len], ciphertextAndTag[plaintext.len..][0..chacha20poly1305_tag_size], plaintext, data, key, nonce);
472481}
473482
474483/// 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 {
476485 // split ciphertext and tag
477486 assert(dst.len >= ciphertext.len);
478487
479488 // derive poly1305 key
480489 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
483492 // construct mac
484493 var mac = Poly1305.init(polyKey[0..]);
......@@ -514,11 +523,11 @@ pub fn chacha20poly1305OpenDetached(dst: []u8, ciphertext: []const u8, tag: *con
514523 }
515524
516525 // decrypt ciphertext
517 chaCha20IETF(dst[0..ciphertext.len], ciphertext, 1, key, nonce);
526 ChaCha20IETF.xor(dst[0..ciphertext.len], ciphertext, 1, key, nonce);
518527}
519528
520529/// 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 {
522531 if (ciphertextAndTag.len < chacha20poly1305_tag_size) {
523532 return error.InvalidMessage;
524533 }
......@@ -557,31 +566,33 @@ fn extend(key: [32]u8, nonce: [24]u8) struct { key: [32]u8, nonce: [12]u8 } {
557566 };
558567}
559568
560pub fn xChaCha20IETF(out: []u8, in: []const u8, counter: u32, key: [32]u8, nonce: [24]u8) void {
561 const extended = extend(key, nonce);
562 chaCha20IETF(out, in, counter, extended.key, extended.nonce);
563}
569pub const XChaCha20IETF = struct {
570 pub fn xor(out: []u8, in: []const u8, counter: u32, key: [32]u8, nonce: [24]u8) void {
571 const extended = extend(key, nonce);
572 ChaCha20IETF.xor(out, in, counter, extended.key, extended.nonce);
573 }
574};
564575
565576pub 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 {
568579 const extended = extend(key, nonce);
569580 return chacha20poly1305SealDetached(ciphertext, tag, plaintext, data, extended.key, extended.nonce);
570581}
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 {
573584 const extended = extend(key, nonce);
574585 return chacha20poly1305Seal(ciphertextAndTag, plaintext, data, extended.key, extended.nonce);
575586}
576587
577588/// 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 {
579590 const extended = extend(key, nonce);
580591 return try chacha20poly1305OpenDetached(plaintext, ciphertext, tag, data, extended.key, extended.nonce);
581592}
582593
583594/// 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 {
585596 const extended = extend(key, nonce);
586597 return try chacha20poly1305Open(ciphertextAndTag, msgAndTag, data, extended.key, extended.nonce);
587598}
......@@ -709,7 +720,7 @@ test "crypto.xchacha20" {
709720 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.";
710721 {
711722 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);
713724 var buf: [2 * ciphertext.len]u8 = undefined;
714725 testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{ciphertext}), "E0A1BCF939654AFDBDC1746EC49832647C19D891F0D1A81FC0C1703B4514BDEA584B512F6908C2C5E9DD18D5CBC1805DE5803FE3B9CA5F193FB8359E91FAB0C3BB40309A292EB1CF49685C65C4A3ADF4F11DB0CD2B6B67FBC174BC2E860E8F769FD3565BBFAD1C845E05A0FED9BE167C240D");
715726 }
lib/std/crypto/gimli.zig+13-7
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Gimli is a 384-bit permutation designed to achieve high security with high
27// performance across a broad range of platforms, including 64-bit Intel/AMD
38// server CPUs, 64-bit and 32-bit ARM smartphone CPUs, 32-bit ARM
......@@ -104,13 +109,14 @@ pub const Hash = struct {
104109 state: State,
105110 buf_off: usize,
106111
112 pub const block_length = State.RATE;
113 pub const Options = struct {};
114
107115 const Self = @This();
108116
109 pub fn init() Self {
117 pub fn init(options: Options) Self {
110118 return Self{
111 .state = State{
112 .data = [_]u32{0} ** (State.BLOCKBYTES / 4),
113 },
119 .state = State{ .data = [_]u32{0} ** (State.BLOCKBYTES / 4) },
114120 .buf_off = 0,
115121 };
116122 }
......@@ -155,8 +161,8 @@ pub const Hash = struct {
155161 }
156162};
157163
158pub fn hash(out: []u8, in: []const u8) void {
159 var st = Hash.init();
164pub fn hash(out: []u8, in: []const u8, options: Hash.Options) void {
165 var st = Hash.init(options);
160166 st.update(in);
161167 st.final(out);
162168}
......@@ -169,7 +175,7 @@ test "hash" {
169175 var msg: [58 / 2]u8 = undefined;
170176 try std.fmt.hexToBytes(&msg, "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C");
171177 var md: [32]u8 = undefined;
172 hash(&md, &msg);
178 hash(&md, &msg, .{});
173179 htest.assertEqual("1C9A03DC6A5DDC5444CFC6F4B154CFF5CF081633B2CEA4D7D0AE7CCFED5AAA44", &md);
174180}
175181
lib/std/crypto/hmac.zig+27-13
......@@ -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.
16const std = @import("../std.zig");
27const crypto = std.crypto;
38const debug = std.debug;
49const mem = std.mem;
510
6pub const HmacMd5 = Hmac(crypto.Md5);
7pub const HmacSha1 = Hmac(crypto.Sha1);
8pub const HmacSha256 = Hmac(crypto.Sha256);
9pub const HmacBlake2s256 = Hmac(crypto.Blake2s256);
11pub const HmacMd5 = Hmac(crypto.hash.Md5);
12pub const HmacSha1 = Hmac(crypto.hash.Sha1);
13
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
1125pub fn Hmac(comptime Hash: type) type {
1226 return struct {
......@@ -31,7 +45,7 @@ pub fn Hmac(comptime Hash: type) type {
3145
3246 // Normalize key length to block size of hash
3347 if (key.len > Hash.block_length) {
34 Hash.hash(key, ctx.scratch[0..mac_length]);
48 Hash.hash(key, ctx.scratch[0..mac_length], .{});
3549 mem.set(u8, ctx.scratch[mac_length..Hash.block_length], 0);
3650 } else if (key.len < Hash.block_length) {
3751 mem.copy(u8, ctx.scratch[0..key.len], key);
......@@ -48,7 +62,7 @@ pub fn Hmac(comptime Hash: type) type {
4862 b.* = ctx.scratch[i] ^ 0x36;
4963 }
5064
51 ctx.hash = Hash.init();
65 ctx.hash = Hash.init(.{});
5266 ctx.hash.update(ctx.i_key_pad[0..]);
5367 return ctx;
5468 }
......@@ -61,10 +75,10 @@ pub fn Hmac(comptime Hash: type) type {
6175 debug.assert(Hash.block_length >= out.len and out.len >= mac_length);
6276
6377 ctx.hash.final(ctx.scratch[0..mac_length]);
64 ctx.hash.reset();
65 ctx.hash.update(ctx.o_key_pad[0..]);
66 ctx.hash.update(ctx.scratch[0..mac_length]);
67 ctx.hash.final(out[0..mac_length]);
78 var ohash = Hash.init(.{});
79 ohash.update(ctx.o_key_pad[0..]);
80 ohash.update(ctx.scratch[0..mac_length]);
81 ohash.final(out[0..mac_length]);
6882 }
6983 };
7084}
......@@ -90,10 +104,10 @@ test "hmac sha1" {
90104}
91105
92106test "hmac sha256" {
93 var out: [HmacSha256.mac_length]u8 = undefined;
94 HmacSha256.create(out[0..], "", "");
107 var out: [sha2.HmacSha256.mac_length]u8 = undefined;
108 sha2.HmacSha256.create(out[0..], "", "");
95109 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");
98112 htest.assertEqual("f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8", out[0..]);
99113}
lib/std/crypto/md5.zig+27-19
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const mem = @import("../mem.zig");
27const math = @import("../math.zig");
38const 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
2732 };
2833}
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.
3038pub const Md5 = struct {
3139 const Self = @This();
3240 pub const block_length = 64;
3341 pub const digest_length = 16;
42 pub const Options = struct {};
3443
3544 s: [4]u32,
3645 // Streaming Cache
......@@ -38,23 +47,22 @@ pub const Md5 = struct {
3847 buf_len: u8,
3948 total_len: u64,
4049
41 pub fn init() Self {
42 var d: Self = undefined;
43 d.reset();
44 return d;
45 }
46
47 pub fn reset(d: *Self) void {
48 d.s[0] = 0x67452301;
49 d.s[1] = 0xEFCDAB89;
50 d.s[2] = 0x98BADCFE;
51 d.s[3] = 0x10325476;
52 d.buf_len = 0;
53 d.total_len = 0;
50 pub fn init(options: Options) Self {
51 return Self{
52 .s = [_]u32{
53 0x67452301,
54 0xEFCDAB89,
55 0x98BADCFE,
56 0x10325476,
57 },
58 .buf = undefined,
59 .buf_len = 0,
60 .total_len = 0,
61 };
5462 }
5563
56 pub fn hash(b: []const u8, out: []u8) void {
57 var d = Md5.init();
64 pub fn hash(b: []const u8, out: []u8, options: Options) void {
65 var d = Md5.init(options);
5866 d.update(b);
5967 d.final(out);
6068 }
......@@ -250,18 +258,18 @@ test "md5 single" {
250258}
251259
252260test "md5 streaming" {
253 var h = Md5.init();
261 var h = Md5.init(.{});
254262 var out: [16]u8 = undefined;
255263
256264 h.final(out[0..]);
257265 htest.assertEqual("d41d8cd98f00b204e9800998ecf8427e", out[0..]);
258266
259 h.reset();
267 h = Md5.init(.{});
260268 h.update("abc");
261269 h.final(out[0..]);
262270 htest.assertEqual("900150983cd24fb0d6963f7d28e17f72", out[0..]);
263271
264 h.reset();
272 h = Md5.init(.{});
265273 h.update("a");
266274 h.update("b");
267275 h.update("c");
......@@ -274,7 +282,7 @@ test "md5 aligned final" {
274282 var block = [_]u8{0} ** Md5.block_length;
275283 var out: [Md5.digest_length]u8 = undefined;
276284
277 var h = Md5.init();
285 var h = Md5.init(.{});
278286 h.update(&block);
279287 h.final(out[0..]);
280288}
lib/std/crypto/poly1305.zig+169-191
......@@ -1,221 +1,199 @@
1// Translated from monocypher which is licensed under CC-0/BSD-3.
2//
3// https://monocypher.org/
4
5const std = @import("../std.zig");
6const builtin = std.builtin;
7
8const Endian = builtin.Endian;
9const readIntLittle = std.mem.readIntLittle;
10const writeIntLittle = std.mem.writeIntLittle;
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
6const std = @import("std");
7const mem = std.mem;
118
129pub const Poly1305 = struct {
13 const Self = @This();
14
10 pub const block_size: usize = 16;
1511 pub const mac_length = 16;
1612 pub const minimum_key_length = 32;
1713
1814 // constant multiplier (from the secret key)
19 r: [4]u32,
15 r: [3]u64,
2016 // accumulated hash
21 h: [5]u32,
22 // chunk of the message
23 c: [5]u32,
17 h: [3]u64 = [_]u64{ 0, 0, 0 },
2418 // random number added at the end (from the secret key)
25 pad: [4]u32,
26 // How many bytes are there in the chunk.
27 c_idx: usize,
28
29 fn secureZero(self: *Self) void {
30 std.mem.secureZero(u8, @ptrCast([*]u8, self)[0..@sizeOf(Poly1305)]);
31 }
19 pad: [2]u64,
20 // how many bytes are waiting to be processed in a partial block
21 leftover: usize = 0,
22 // partial block buffer
23 buf: [block_size]u8 align(16) = undefined,
3224
33 pub fn create(out: []u8, msg: []const u8, key: []const u8) void {
34 std.debug.assert(out.len >= mac_length);
25 pub fn init(key: []const u8) Poly1305 {
3526 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);
38 ctx.update(msg);
39 ctx.final(out);
42 fn blocks(st: *Poly1305, m: []const u8, last: comptime bool) void {
43 const hibit: u64 = if (last) 0 else 1 << 40;
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 };
4081 }
4182
42 // Initialize the MAC context.
43 // - key.len is sufficient size.
44 pub fn init(key: []const u8) Self {
45 var ctx: Poly1305 = undefined;
83 pub fn update(st: *Poly1305, m: []const u8) void {
84 var mb = m;
4685
47 // Initial hash is zero
48 {
49 var i: usize = 0;
50 while (i < 5) : (i += 1) {
51 ctx.h[i] = 0;
86 // handle leftover
87 if (st.leftover > 0) {
88 const want = std.math.min(block_size - st.leftover, mb.len);
89 const mc = mb[0..want];
90 for (mc) |x, i| {
91 st.buf[st.leftover + i] = x;
5292 }
53 }
54 // add 2^130 to every input block
55 ctx.c[4] = 1;
56 polyClearC(&ctx);
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;
93 mb = mb[want..];
94 st.leftover += want;
95 if (st.leftover > block_size) {
96 return;
6397 }
98 st.blocks(&st.buf, false);
99 st.leftover = 0;
64100 }
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 {
139 const word = ctx.c_idx >> 2;
140 const byte = ctx.c_idx & 3;
141 ctx.c[word] |= std.math.shl(u32, input, byte * 8);
142 ctx.c_idx += 1;
143 }
102 // process full blocks
103 if (mb.len >= block_size) {
104 const want = mb.len & ~(block_size - 1);
105 st.blocks(mb[0..want], false);
106 mb = mb[want..];
107 }
144108
145 fn polyUpdate(ctx: *Self, msg: []const u8) void {
146 for (msg) |b| {
147 polyTakeInput(ctx, b);
148 if (ctx.c_idx == 16) {
149 polyBlock(ctx);
150 polyClearC(ctx);
109 // store leftover
110 if (mb.len > 0) {
111 for (mb) |x, i| {
112 st.buf[st.leftover + i] = x;
151113 }
114 st.leftover += mb.len;
152115 }
153116 }
154117
155 fn alignTo(x: usize, block_size: usize) usize {
156 return ((~x) +% 1) & (block_size - 1);
157 }
158
159 // Feed data into the MAC context.
160 pub fn update(ctx: *Self, msg: []const u8) void {
161 // Align ourselves with block boundaries
162 const alignm = std.math.min(alignTo(ctx.c_idx, 16), msg.len);
163 polyUpdate(ctx, msg[0..alignm]);
164
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);
118 pub fn final(st: *Poly1305, out: []u8) void {
119 std.debug.assert(out.len >= mac_length);
120 if (st.leftover > 0) {
121 var i = st.leftover;
122 st.buf[i] = 1;
123 i += 1;
124 while (i < block_size) : (i += 1) {
125 st.buf[i] = 0;
126 }
127 st.blocks(&st.buf, true);
180128 }
181
182 // remaining bytes
183 polyUpdate(ctx, nmsg[0..]);
129 // fully carry h
130 var carry = st.h[1] >> 44;
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)]);
184188 }
185189
186 // Finalize the MAC and output into buffer provided by caller.
187 pub fn final(ctx: *Self, out: []u8) void {
188 // Process the last block (if any)
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 }
190 pub fn create(out: []u8, msg: []const u8, key: []const u8) void {
191 std.debug.assert(out.len >= mac_length);
192 std.debug.assert(key.len >= minimum_key_length);
197193
198 // check if we should subtract 2^130-5 by performing the
199 // corresponding carry propagation.
200 const _u0 = @as(u64, 5) + ctx.h[0]; // <= 1_00000004
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();
194 var st = Poly1305.init(key);
195 st.update(msg);
196 st.final(out);
219197 }
220198};
221199
lib/std/crypto/sha1.zig+29-24
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const mem = @import("../mem.zig");
27const math = @import("../math.zig");
38const endian = @import("../endian.zig");
......@@ -24,35 +29,35 @@ fn Rp(a: usize, b: usize, c: usize, d: usize, e: usize, i: u32) RoundParam {
2429 };
2530}
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.
2735pub const Sha1 = struct {
2836 const Self = @This();
2937 pub const block_length = 64;
3038 pub const digest_length = 20;
39 pub const Options = struct {};
3140
3241 s: [5]u32,
3342 // Streaming Cache
34 buf: [64]u8,
35 buf_len: u8,
36 total_len: u64,
37
38 pub fn init() Self {
39 var d: Self = undefined;
40 d.reset();
41 return d;
42 }
43
44 pub fn reset(d: *Self) void {
45 d.s[0] = 0x67452301;
46 d.s[1] = 0xEFCDAB89;
47 d.s[2] = 0x98BADCFE;
48 d.s[3] = 0x10325476;
49 d.s[4] = 0xC3D2E1F0;
50 d.buf_len = 0;
51 d.total_len = 0;
43 buf: [64]u8 = undefined,
44 buf_len: u8 = 0,
45 total_len: u64 = 0,
46
47 pub fn init(options: Options) Self {
48 return Self{
49 .s = [_]u32{
50 0x67452301,
51 0xEFCDAB89,
52 0x98BADCFE,
53 0x10325476,
54 0xC3D2E1F0,
55 },
56 };
5257 }
5358
54 pub fn hash(b: []const u8, out: []u8) void {
55 var d = Sha1.init();
59 pub fn hash(b: []const u8, out: []u8, options: Options) void {
60 var d = Sha1.init(options);
5661 d.update(b);
5762 d.final(out);
5863 }
......@@ -272,18 +277,18 @@ test "sha1 single" {
272277}
273278
274279test "sha1 streaming" {
275 var h = Sha1.init();
280 var h = Sha1.init(.{});
276281 var out: [20]u8 = undefined;
277282
278283 h.final(out[0..]);
279284 htest.assertEqual("da39a3ee5e6b4b0d3255bfef95601890afd80709", out[0..]);
280285
281 h.reset();
286 h = Sha1.init(.{});
282287 h.update("abc");
283288 h.final(out[0..]);
284289 htest.assertEqual("a9993e364706816aba3e25717850c26c9cd0d89d", out[0..]);
285290
286 h.reset();
291 h = Sha1.init(.{});
287292 h.update("a");
288293 h.update("b");
289294 h.update("c");
......@@ -295,7 +300,7 @@ test "sha1 aligned final" {
295300 var block = [_]u8{0} ** Sha1.block_length;
296301 var out: [Sha1.digest_length]u8 = undefined;
297302
298 var h = Sha1.init();
303 var h = Sha1.init(.{});
299304 h.update(&block);
300305 h.final(out[0..]);
301306}
lib/std/crypto/sha2.zig+95-60
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const mem = @import("../mem.zig");
27const math = @import("../math.zig");
38const endian = @import("../endian.zig");
......@@ -72,7 +77,10 @@ const Sha256Params = Sha2Params32{
7277 .out_len = 256,
7378};
7479
80/// SHA-224
7581pub const Sha224 = Sha2_32(Sha224Params);
82
83/// SHA-256
7684pub const Sha256 = Sha2_32(Sha256Params);
7785
7886fn Sha2_32(comptime params: Sha2Params32) type {
......@@ -80,34 +88,31 @@ fn Sha2_32(comptime params: Sha2Params32) type {
8088 const Self = @This();
8189 pub const block_length = 64;
8290 pub const digest_length = params.out_len / 8;
91 pub const Options = struct {};
8392
8493 s: [8]u32,
8594 // Streaming Cache
86 buf: [64]u8,
87 buf_len: u8,
88 total_len: u64,
89
90 pub fn init() Self {
91 var d: Self = undefined;
92 d.reset();
93 return d;
94 }
95
96 pub fn reset(d: *Self) void {
97 d.s[0] = params.iv0;
98 d.s[1] = params.iv1;
99 d.s[2] = params.iv2;
100 d.s[3] = params.iv3;
101 d.s[4] = params.iv4;
102 d.s[5] = params.iv5;
103 d.s[6] = params.iv6;
104 d.s[7] = params.iv7;
105 d.buf_len = 0;
106 d.total_len = 0;
95 buf: [64]u8 = undefined,
96 buf_len: u8 = 0,
97 total_len: u64 = 0,
98
99 pub fn init(options: Options) Self {
100 return Self{
101 .s = [_]u32{
102 params.iv0,
103 params.iv1,
104 params.iv2,
105 params.iv3,
106 params.iv4,
107 params.iv5,
108 params.iv6,
109 params.iv7,
110 },
111 };
107112 }
108113
109 pub fn hash(b: []const u8, out: []u8) void {
110 var d = Self.init();
114 pub fn hash(b: []const u8, out: []u8, options: Options) void {
115 var d = Self.init(options);
111116 d.update(b);
112117 d.final(out);
113118 }
......@@ -292,18 +297,18 @@ test "sha224 single" {
292297}
293298
294299test "sha224 streaming" {
295 var h = Sha224.init();
300 var h = Sha224.init(.{});
296301 var out: [28]u8 = undefined;
297302
298303 h.final(out[0..]);
299304 htest.assertEqual("d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f", out[0..]);
300305
301 h.reset();
306 h = Sha224.init(.{});
302307 h.update("abc");
303308 h.final(out[0..]);
304309 htest.assertEqual("23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7", out[0..]);
305310
306 h.reset();
311 h = Sha224.init(.{});
307312 h.update("a");
308313 h.update("b");
309314 h.update("c");
......@@ -318,18 +323,18 @@ test "sha256 single" {
318323}
319324
320325test "sha256 streaming" {
321 var h = Sha256.init();
326 var h = Sha256.init(.{});
322327 var out: [32]u8 = undefined;
323328
324329 h.final(out[0..]);
325330 htest.assertEqual("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", out[0..]);
326331
327 h.reset();
332 h = Sha256.init(.{});
328333 h.update("abc");
329334 h.final(out[0..]);
330335 htest.assertEqual("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", out[0..]);
331336
332 h.reset();
337 h = Sha256.init(.{});
333338 h.update("a");
334339 h.update("b");
335340 h.update("c");
......@@ -341,7 +346,7 @@ test "sha256 aligned final" {
341346 var block = [_]u8{0} ** Sha256.block_length;
342347 var out: [Sha256.digest_length]u8 = undefined;
343348
344 var h = Sha256.init();
349 var h = Sha256.init(.{});
345350 h.update(&block);
346351 h.final(out[0..]);
347352}
......@@ -413,42 +418,72 @@ const Sha512Params = Sha2Params64{
413418 .out_len = 512,
414419};
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
416446pub const Sha384 = Sha2_64(Sha384Params);
447
448/// SHA-512
417449pub 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
419457fn Sha2_64(comptime params: Sha2Params64) type {
420458 return struct {
421459 const Self = @This();
422460 pub const block_length = 128;
423461 pub const digest_length = params.out_len / 8;
462 pub const Options = struct {};
424463
425464 s: [8]u64,
426465 // Streaming Cache
427 buf: [128]u8,
428 buf_len: u8,
429 total_len: u128,
430
431 pub fn init() Self {
432 var d: Self = undefined;
433 d.reset();
434 return d;
435 }
436
437 pub fn reset(d: *Self) void {
438 d.s[0] = params.iv0;
439 d.s[1] = params.iv1;
440 d.s[2] = params.iv2;
441 d.s[3] = params.iv3;
442 d.s[4] = params.iv4;
443 d.s[5] = params.iv5;
444 d.s[6] = params.iv6;
445 d.s[7] = params.iv7;
446 d.buf_len = 0;
447 d.total_len = 0;
466 buf: [128]u8 = undefined,
467 buf_len: u8 = 0,
468 total_len: u128 = 0,
469
470 pub fn init(options: Options) Self {
471 return Self{
472 .s = [_]u64{
473 params.iv0,
474 params.iv1,
475 params.iv2,
476 params.iv3,
477 params.iv4,
478 params.iv5,
479 params.iv6,
480 params.iv7,
481 },
482 };
448483 }
449484
450 pub fn hash(b: []const u8, out: []u8) void {
451 var d = Self.init();
485 pub fn hash(b: []const u8, out: []u8, options: Options) void {
486 var d = Self.init(options);
452487 d.update(b);
453488 d.final(out);
454489 }
......@@ -660,7 +695,7 @@ test "sha384 single" {
660695}
661696
662697test "sha384 streaming" {
663 var h = Sha384.init();
698 var h = Sha384.init(.{});
664699 var out: [48]u8 = undefined;
665700
666701 const h1 = "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b";
......@@ -669,12 +704,12 @@ test "sha384 streaming" {
669704
670705 const h2 = "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7";
671706
672 h.reset();
707 h = Sha384.init(.{});
673708 h.update("abc");
674709 h.final(out[0..]);
675710 htest.assertEqual(h2, out[0..]);
676711
677 h.reset();
712 h = Sha384.init(.{});
678713 h.update("a");
679714 h.update("b");
680715 h.update("c");
......@@ -694,7 +729,7 @@ test "sha512 single" {
694729}
695730
696731test "sha512 streaming" {
697 var h = Sha512.init();
732 var h = Sha512.init(.{});
698733 var out: [64]u8 = undefined;
699734
700735 const h1 = "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e";
......@@ -703,12 +738,12 @@ test "sha512 streaming" {
703738
704739 const h2 = "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f";
705740
706 h.reset();
741 h = Sha512.init(.{});
707742 h.update("abc");
708743 h.final(out[0..]);
709744 htest.assertEqual(h2, out[0..]);
710745
711 h.reset();
746 h = Sha512.init(.{});
712747 h.update("a");
713748 h.update("b");
714749 h.update("c");
......@@ -720,7 +755,7 @@ test "sha512 aligned final" {
720755 var block = [_]u8{0} ** Sha512.block_length;
721756 var out: [Sha512.digest_length]u8 = undefined;
722757
723 var h = Sha512.init();
758 var h = Sha512.init(.{});
724759 h.update(&block);
725760 h.final(out[0..]);
726761}
lib/std/crypto/sha3.zig+24-26
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const mem = @import("../mem.zig");
27const math = @import("../math.zig");
38const endian = @import("../endian.zig");
......@@ -15,25 +20,18 @@ fn Keccak(comptime bits: usize, comptime delim: u8) type {
1520 const Self = @This();
1621 pub const block_length = 200;
1722 pub const digest_length = bits / 8;
23 pub const Options = struct {};
1824
1925 s: [200]u8,
2026 offset: usize,
2127 rate: usize,
2228
23 pub fn init() Self {
24 var d: Self = undefined;
25 d.reset();
26 return d;
29 pub fn init(options: Options) Self {
30 return Self{ .s = [_]u8{0} ** 200, .offset = 0, .rate = 200 - (bits / 4) };
2731 }
2832
29 pub fn reset(d: *Self) void {
30 mem.set(u8, d.s[0..], 0);
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();
33 pub fn hash(b: []const u8, out: []u8, options: Options) void {
34 var d = Self.init(options);
3735 d.update(b);
3836 d.final(out);
3937 }
......@@ -178,18 +176,18 @@ test "sha3-224 single" {
178176}
179177
180178test "sha3-224 streaming" {
181 var h = Sha3_224.init();
179 var h = Sha3_224.init(.{});
182180 var out: [28]u8 = undefined;
183181
184182 h.final(out[0..]);
185183 htest.assertEqual("6b4e03423667dbb73b6e15454f0eb1abd4597f9a1b078e3f5b5a6bc7", out[0..]);
186184
187 h.reset();
185 h = Sha3_224.init(.{});
188186 h.update("abc");
189187 h.final(out[0..]);
190188 htest.assertEqual("e642824c3f8cf24ad09234ee7d3c766fc9a3a5168d0c94ad73b46fdf", out[0..]);
191189
192 h.reset();
190 h = Sha3_224.init(.{});
193191 h.update("a");
194192 h.update("b");
195193 h.update("c");
......@@ -204,18 +202,18 @@ test "sha3-256 single" {
204202}
205203
206204test "sha3-256 streaming" {
207 var h = Sha3_256.init();
205 var h = Sha3_256.init(.{});
208206 var out: [32]u8 = undefined;
209207
210208 h.final(out[0..]);
211209 htest.assertEqual("a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a", out[0..]);
212210
213 h.reset();
211 h = Sha3_256.init(.{});
214212 h.update("abc");
215213 h.final(out[0..]);
216214 htest.assertEqual("3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532", out[0..]);
217215
218 h.reset();
216 h = Sha3_256.init(.{});
219217 h.update("a");
220218 h.update("b");
221219 h.update("c");
......@@ -227,7 +225,7 @@ test "sha3-256 aligned final" {
227225 var block = [_]u8{0} ** Sha3_256.block_length;
228226 var out: [Sha3_256.digest_length]u8 = undefined;
229227
230 var h = Sha3_256.init();
228 var h = Sha3_256.init(.{});
231229 h.update(&block);
232230 h.final(out[0..]);
233231}
......@@ -242,7 +240,7 @@ test "sha3-384 single" {
242240}
243241
244242test "sha3-384 streaming" {
245 var h = Sha3_384.init();
243 var h = Sha3_384.init(.{});
246244 var out: [48]u8 = undefined;
247245
248246 const h1 = "0c63a75b845e4f7d01107d852e4c2485c51a50aaaa94fc61995e71bbee983a2ac3713831264adb47fb6bd1e058d5f004";
......@@ -250,12 +248,12 @@ test "sha3-384 streaming" {
250248 htest.assertEqual(h1, out[0..]);
251249
252250 const h2 = "ec01498288516fc926459f58e2c6ad8df9b473cb0fc08c2596da7cf0e49be4b298d88cea927ac7f539f1edf228376d25";
253 h.reset();
251 h = Sha3_384.init(.{});
254252 h.update("abc");
255253 h.final(out[0..]);
256254 htest.assertEqual(h2, out[0..]);
257255
258 h.reset();
256 h = Sha3_384.init(.{});
259257 h.update("a");
260258 h.update("b");
261259 h.update("c");
......@@ -273,7 +271,7 @@ test "sha3-512 single" {
273271}
274272
275273test "sha3-512 streaming" {
276 var h = Sha3_512.init();
274 var h = Sha3_512.init(.{});
277275 var out: [64]u8 = undefined;
278276
279277 const h1 = "a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a615b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26";
......@@ -281,12 +279,12 @@ test "sha3-512 streaming" {
281279 htest.assertEqual(h1, out[0..]);
282280
283281 const h2 = "b751850b1a57168a5693cd924b6b096e08f621827444f70d884f5d0240d2712e10e116e9192af3c91a7ec57647e3934057340b4cf408d5a56592f8274eec53f0";
284 h.reset();
282 h = Sha3_512.init(.{});
285283 h.update("abc");
286284 h.final(out[0..]);
287285 htest.assertEqual(h2, out[0..]);
288286
289 h.reset();
287 h = Sha3_512.init(.{});
290288 h.update("a");
291289 h.update("b");
292290 h.update("c");
......@@ -298,7 +296,7 @@ test "sha3-512 aligned final" {
298296 var block = [_]u8{0} ** Sha3_512.block_length;
299297 var out: [Sha3_512.digest_length]u8 = undefined;
300298
301 var h = Sha3_512.init();
299 var h = Sha3_512.init(.{});
302300 h.update(&block);
303301 h.final(out[0..]);
304302}
lib/std/crypto/test.zig+6-1
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const testing = std.testing;
38const mem = std.mem;
......@@ -6,7 +11,7 @@ const fmt = std.fmt;
611// Hash using the specified hasher `H` asserting `expected == H(input)`.
712pub fn assertEqualHash(comptime Hasher: anytype, comptime expected: []const u8, input: []const u8) void {
813 var h: [expected.len / 2]u8 = undefined;
9 Hasher.hash(input, h[0..]);
14 Hasher.hash(input, h[0..], .{});
1015
1116 assertEqual(expected, &h);
1217}
lib/std/cstr.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std.zig");
27const builtin = @import("builtin");
38const debug = std.debug;
lib/std/debug.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std.zig");
27const builtin = std.builtin;
38const math = std.math;
lib/std/debug/leb128.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std");
27const testing = std.testing;
38
lib/std/dwarf.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std.zig");
27const builtin = @import("builtin");
38const debug = std.debug;
lib/std/dwarf_bits.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16pub const TAG_padding = 0x00;
27pub const TAG_array_type = 0x01;
38pub const TAG_class_type = 0x02;
lib/std/dynamic_library.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const builtin = @import("builtin");
27
38const std = @import("std.zig");
lib/std/elf.zig+6
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std.zig");
27const builtin = std.builtin;
38const io = std.io;
......@@ -558,6 +563,7 @@ fn preadNoEof(file: std.fs.File, buf: []u8, offset: u64) !void {
558563 error.InputOutput => return error.FileSystem,
559564 error.Unexpected => return error.Unexpected,
560565 error.WouldBlock => return error.Unexpected,
566 error.NotOpenForReading => return error.Unexpected,
561567 error.AccessDenied => return error.Unexpected,
562568 };
563569 if (len == 0) return error.UnexpectedEndOfFile;
lib/std/event.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16pub const Channel = @import("event/channel.zig").Channel;
27pub const Future = @import("event/future.zig").Future;
38pub const Group = @import("event/group.zig").Group;
lib/std/event/batch.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const testing = std.testing;
38
lib/std/event/channel.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const builtin = @import("builtin");
38const assert = std.debug.assert;
lib/std/event/future.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const assert = std.debug.assert;
38const testing = std.testing;
lib/std/event/group.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const builtin = @import("builtin");
38const Lock = std.event.Lock;
lib/std/event/lock.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const builtin = @import("builtin");
38const assert = std.debug.assert;
lib/std/event/locked.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const Lock = std.event.Lock;
38
lib/std/event/loop.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const builtin = @import("builtin");
38const root = @import("root");
lib/std/event/rwlock.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const builtin = @import("builtin");
38const assert = std.debug.assert;
lib/std/event/rwlocked.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const RwLock = std.event.RwLock;
38
lib/std/fifo.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// FIFO of fixed size items
27// Usually used for e.g. byte buffers
38
lib/std/fmt.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std.zig");
27const math = std.math;
38const assert = std.debug.assert;
lib/std/fmt/errol.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const enum3 = @import("errol/enum3.zig").enum3;
38const enum3_data = @import("errol/enum3.zig").enum3_data;
lib/std/fmt/errol/enum3.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16pub const enum3 = [_]u64{
27 0x4e2e2785c3a2a20b,
38 0x240a28877a09a4e1,
lib/std/fmt/errol/lookup.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16pub const HP = struct {
27 val: f64,
38 off: f64,
lib/std/fmt/parse_float.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Adapted from https://github.com/grzegorz-kraszewski/stringtofloat.
27
38// MIT License
lib/std/fs.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const builtin = @import("builtin");
27const std = @import("std.zig");
38const os = std.os;
lib/std/fs/file.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const builtin = @import("builtin");
38const os = std.os;
lib/std/fs/get_app_data_dir.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const builtin = @import("builtin");
38const unicode = std.unicode;
lib/std/fs/path.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const builtin = @import("builtin");
27const std = @import("../std.zig");
38const debug = std.debug;
lib/std/fs/test.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const testing = std.testing;
38const builtin = std.builtin;
lib/std/fs/wasi.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std");
27const os = std.os;
38const mem = std.mem;
lib/std/fs/watch.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const builtin = @import("builtin");
38const event = std.event;
lib/std/hash.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const adler = @import("hash/adler.zig");
27pub const Adler32 = adler.Adler32;
38
lib/std/hash/adler.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Adler32 checksum.
27//
38// https://tools.ietf.org/html/rfc1950#section-9
lib/std/hash/auto_hash.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std");
27const builtin = @import("builtin");
38const assert = std.debug.assert;
lib/std/hash/benchmark.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// zig run benchmark.zig --release-fast --override-lib-dir ..
27
38const builtin = @import("builtin");
lib/std/hash/cityhash.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std");
27const builtin = @import("builtin");
38
lib/std/hash/crc.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// There are two implementations of CRC32 implemented with the following key characteristics:
27//
38// - Crc32WithPoly uses 8Kb of tables but is ~10x faster than the small method.
lib/std/hash/fnv.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// FNV1a - Fowler-Noll-Vo hash function
27//
38// FNV1a is a fast, non-cryptographic hash function with fairly good distribution properties.
lib/std/hash/murmur.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std");
27const builtin = @import("builtin");
38const testing = std.testing;
lib/std/hash/siphash.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Siphash
27//
38// SipHash is a moderately fast, non-cryptographic keyed hash function designed for resistance
lib/std/hash/wyhash.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std");
27const mem = std.mem;
38
lib/std/hash_map.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std.zig");
27const debug = std.debug;
38const assert = debug.assert;
lib/std/heap.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std.zig");
27const root = @import("root");
38const debug = std.debug;
lib/std/heap/arena_allocator.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const assert = std.debug.assert;
38const mem = std.mem;
lib/std/heap/general_purpose_allocator.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16//! # General Purpose Allocator
27//!
38//! ## Design Priorities
lib/std/heap/logging_allocator.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const Allocator = std.mem.Allocator;
38
lib/std/http.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16test "std.http" {
27 _ = @import("http/headers.zig");
38}
lib/std/http/headers.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// HTTP Header data structure/type
27// Based on lua-http's http.header module
38//
lib/std/io.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std.zig");
27const builtin = @import("builtin");
38const root = @import("root");
lib/std/io/bit_in_stream.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16/// Deprecated: use `std.io.bit_reader.BitReader`
27pub const BitInStream = @import("./bit_reader.zig").BitReader;
38
lib/std/io/bit_out_stream.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16/// Deprecated: use `std.io.bit_writer.BitWriter`
27pub const BitOutStream = @import("./bit_writer.zig").BitWriter;
38
lib/std/io/bit_reader.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const builtin = std.builtin;
38const io = std.io;
lib/std/io/bit_writer.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const builtin = std.builtin;
38const io = std.io;
lib/std/io/buffered_atomic_file.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const mem = std.mem;
38const fs = std.fs;
lib/std/io/buffered_in_stream.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16/// Deprecated: use `std.io.buffered_reader.BufferedReader`
27pub const BufferedInStream = @import("./buffered_reader.zig").BufferedReader;
38
lib/std/io/buffered_out_stream.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16/// Deprecated: use `std.io.buffered_writer.BufferedWriter`
27pub const BufferedOutStream = @import("./buffered_writer.zig").BufferedWriter;
38
lib/std/io/buffered_reader.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const io = std.io;
38const assert = std.debug.assert;
lib/std/io/buffered_writer.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const io = std.io;
38
lib/std/io/c_out_stream.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16/// Deprecated: use `std.io.c_writer.CWriter`
27pub const COutStream = @import("./c_writer.zig").CWriter;
38
lib/std/io/c_writer.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const builtin = std.builtin;
38const io = std.io;
lib/std/io/counting_out_stream.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16/// Deprecated: use `std.io.counting_writer.CountingWriter`
27pub const CountingOutStream = @import("./counting_writer.zig").CountingWriter;
38
lib/std/io/counting_writer.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const io = std.io;
38const testing = std.testing;
lib/std/io/fixed_buffer_stream.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const io = std.io;
38const testing = std.testing;
lib/std/io/in_stream.zig+5
......@@ -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.
16/// Deprecated: use `std.io.reader.Reader`
27pub const InStream = @import("./reader.zig").Reader;
lib/std/io/multi_out_stream.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16/// Deprecated: use `std.io.multi_writer.MultiWriter`
27pub const MultiOutStream = @import("./multi_writer.zig").MultiWriter;
38
lib/std/io/multi_writer.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const io = std.io;
38const testing = std.testing;
lib/std/io/out_stream.zig+5
......@@ -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.
16/// Deprecated: use `std.io.writer.Writer`
27pub const OutStream = @import("./writer.zig").Writer;
lib/std/io/peek_stream.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const io = std.io;
38const mem = std.mem;
lib/std/io/reader.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const builtin = std.builtin;
38const math = std.math;
lib/std/io/seekable_stream.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27
38pub fn SeekableStream(
lib/std/io/serialization.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const builtin = std.builtin;
38const io = std.io;
lib/std/io/stream_source.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const io = std.io;
38const testing = std.testing;
lib/std/io/test.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std");
27const builtin = std.builtin;
38const io = std.io;
lib/std/io/writer.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const builtin = std.builtin;
38const mem = std.mem;
lib/std/json.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// JSON parser conforming to RFC8259.
27//
38// https://tools.ietf.org/html/rfc8259
lib/std/json/test.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// RFC 8529 conformance tests.
27//
38// Tests are taken from https://github.com/nst/JSONTestSuite
lib/std/json/write_stream.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const assert = std.debug.assert;
38const maxInt = std.math.maxInt;
lib/std/linked_list.zig+38-91
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std.zig");
27const debug = std.debug;
38const assert = debug.assert;
......@@ -178,21 +183,9 @@ pub fn TailQueue(comptime T: type) type {
178183 }
179184 };
180185
181 first: ?*Node,
182 last: ?*Node,
183 len: usize,
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 }
186 first: ?*Node = null,
187 last: ?*Node = null,
188 len: usize = 0,
196189
197190 /// Insert a new node after an existing one.
198191 ///
......@@ -335,65 +328,24 @@ pub fn TailQueue(comptime T: type) type {
335328 list.remove(first);
336329 return first;
337330 }
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 }
372331 };
373332}
374333
375334test "basic TailQueue test" {
376 const allocator = testing.allocator;
377 var list = TailQueue(u32).init();
378
379 var one = try list.createNode(1, allocator);
380 var two = try list.createNode(2, allocator);
381 var three = try list.createNode(3, allocator);
382 var four = try list.createNode(4, allocator);
383 var five = try list.createNode(5, allocator);
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 }
335 const L = TailQueue(u32);
336 var list = L{};
337
338 var one = L.Node{ .data = 1 };
339 var two = L.Node{ .data = 2 };
340 var three = L.Node{ .data = 3 };
341 var four = L.Node{ .data = 4 };
342 var five = L.Node{ .data = 5 };
391343
392 list.append(two); // {2}
393 list.append(five); // {2, 5}
394 list.prepend(one); // {1, 2, 5}
395 list.insertBefore(five, four); // {1, 2, 4, 5}
396 list.insertAfter(two, three); // {1, 2, 3, 4, 5}
344 list.append(&two); // {2}
345 list.append(&five); // {2, 5}
346 list.prepend(&one); // {1, 2, 5}
347 list.insertBefore(&five, &four); // {1, 2, 4, 5}
348 list.insertAfter(&two, &three); // {1, 2, 3, 4, 5}
397349
398350 // Traverse forwards.
399351 {
......@@ -417,7 +369,7 @@ test "basic TailQueue test" {
417369
418370 var first = list.popFirst(); // {2, 3, 4, 5}
419371 var last = list.pop(); // {2, 3, 4}
420 list.remove(three); // {2, 4}
372 list.remove(&three); // {2, 4}
421373
422374 testing.expect(list.first.?.data == 2);
423375 testing.expect(list.last.?.data == 4);
......@@ -425,30 +377,25 @@ test "basic TailQueue test" {
425377}
426378
427379test "TailQueue concatenation" {
428 const allocator = testing.allocator;
429 var list1 = TailQueue(u32).init();
430 var list2 = TailQueue(u32).init();
431
432 var one = try list1.createNode(1, allocator);
433 defer list1.destroyNode(one, allocator);
434 var two = try list1.createNode(2, allocator);
435 defer list1.destroyNode(two, allocator);
436 var three = try list1.createNode(3, allocator);
437 defer list1.destroyNode(three, allocator);
438 var four = try list1.createNode(4, allocator);
439 defer list1.destroyNode(four, allocator);
440 var five = try list1.createNode(5, allocator);
441 defer list1.destroyNode(five, allocator);
442
443 list1.append(one);
444 list1.append(two);
445 list2.append(three);
446 list2.append(four);
447 list2.append(five);
380 const L = TailQueue(u32);
381 var list1 = L{};
382 var list2 = L{};
383
384 var one = L.Node{ .data = 1 };
385 var two = L.Node{ .data = 2 };
386 var three = L.Node{ .data = 3 };
387 var four = L.Node{ .data = 4 };
388 var five = L.Node{ .data = 5 };
389
390 list1.append(&one);
391 list1.append(&two);
392 list2.append(&three);
393 list2.append(&four);
394 list2.append(&five);
448395
449396 list1.concatByMoving(&list2);
450397
451 testing.expect(list1.last == five);
398 testing.expect(list1.last == &five);
452399 testing.expect(list1.len == 5);
453400 testing.expect(list2.first == null);
454401 testing.expect(list2.last == null);
lib/std/log.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std.zig");
27const builtin = std.builtin;
38const root = @import("root");
lib/std/macho.zig+17
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16pub const mach_header = extern struct {
27 magic: u32,
38 cputype: cpu_type_t,
......@@ -703,3 +708,15 @@ pub const cpu_type_t = integer_t;
703708pub const cpu_subtype_t = integer_t;
704709pub const integer_t = c_int;
705710pub 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// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std.zig");
27const assert = std.debug.assert;
38const testing = std.testing;
lib/std/math/acos.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Ported from musl, which is licensed under the MIT license:
27// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
38//
lib/std/math/acosh.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Ported from musl, which is licensed under the MIT license:
27// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
38//
lib/std/math/asin.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Ported from musl, which is licensed under the MIT license:
27// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
38//
lib/std/math/asinh.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Ported from musl, which is licensed under the MIT license:
27// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
38//
lib/std/math/atan.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Ported from musl, which is licensed under the MIT license:
27// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
38//
lib/std/math/atan2.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Ported from musl, which is licensed under the MIT license:
27// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
38//
lib/std/math/atanh.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Ported from musl, which is licensed under the MIT license:
27// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
38//
lib/std/math/big.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const assert = std.debug.assert;
38
lib/std/math/big/int.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../../std.zig");
27const math = std.math;
38const Limb = std.math.big.Limb;
lib/std/math/big/int_test.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../../std.zig");
27const mem = std.mem;
38const testing = std.testing;
lib/std/math/big/rational.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../../std.zig");
27const debug = std.debug;
38const math = std.math;
lib/std/math/cbrt.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Ported from musl, which is licensed under the MIT license:
27// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
38//
lib/std/math/ceil.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Ported from musl, which is licensed under the MIT license:
27// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
38//
lib/std/math/complex.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const testing = std.testing;
38const math = std.math;
lib/std/math/complex/abs.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../../std.zig");
27const testing = std.testing;
38const math = std.math;
lib/std/math/complex/acos.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../../std.zig");
27const testing = std.testing;
38const math = std.math;
lib/std/math/complex/acosh.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../../std.zig");
27const testing = std.testing;
38const math = std.math;
lib/std/math/complex/arg.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../../std.zig");
27const testing = std.testing;
38const math = std.math;
lib/std/math/complex/asin.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../../std.zig");
27const testing = std.testing;
38const math = std.math;
lib/std/math/complex/asinh.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../../std.zig");
27const testing = std.testing;
38const math = std.math;
lib/std/math/complex/atan.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Ported from musl, which is licensed under the MIT license:
27// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
38//
lib/std/math/complex/atanh.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../../std.zig");
27const testing = std.testing;
38const math = std.math;
lib/std/math/complex/conj.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../../std.zig");
27const testing = std.testing;
38const math = std.math;
lib/std/math/complex/cos.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../../std.zig");
27const testing = std.testing;
38const math = std.math;
lib/std/math/complex/cosh.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Ported from musl, which is licensed under the MIT license:
27// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
38//
lib/std/math/complex/exp.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Ported from musl, which is licensed under the MIT license:
27// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
38//
lib/std/math/complex/ldexp.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Ported from musl, which is licensed under the MIT license:
27// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
38//
lib/std/math/complex/log.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../../std.zig");
27const testing = std.testing;
38const math = std.math;
lib/std/math/complex/pow.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../../std.zig");
27const testing = std.testing;
38const math = std.math;
lib/std/math/complex/proj.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../../std.zig");
27const testing = std.testing;
38const math = std.math;
lib/std/math/complex/sin.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../../std.zig");
27const testing = std.testing;
38const math = std.math;
lib/std/math/complex/sinh.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Ported from musl, which is licensed under the MIT license:
27// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
38//
lib/std/math/complex/sqrt.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Ported from musl, which is licensed under the MIT license:
27// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
38//
lib/std/math/complex/tan.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../../std.zig");
27const testing = std.testing;
38const math = std.math;
lib/std/math/complex/tanh.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Ported from musl, which is licensed under the MIT license:
27// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
38//
lib/std/math/copysign.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Ported from musl, which is licensed under the MIT license:
27// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
38//
lib/std/math/cos.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Ported from go, which is licensed under a BSD-3 license.
27// https://golang.org/LICENSE
38//
lib/std/math/cosh.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Ported from musl, which is licensed under the MIT license:
27// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
38//
lib/std/math/exp.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Ported from musl, which is licensed under the MIT license:
27// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
38//
lib/std/math/exp2.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Ported from musl, which is licensed under the MIT license:
27// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
38//
lib/std/math/expm1.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Ported from musl, which is licensed under the MIT license:
27// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
38//
lib/std/math/expo2.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Ported from musl, which is licensed under the MIT license:
27// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
38//
lib/std/math/fabs.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Ported from musl, which is licensed under the MIT license:
27// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
38//
lib/std/math/floor.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Ported from musl, which is licensed under the MIT license:
27// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
38//
lib/std/math/fma.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Ported from musl, which is licensed under the MIT license:
27// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
38//
lib/std/math/frexp.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Ported from musl, which is licensed under the MIT license:
27// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
38//
lib/std/math/hypot.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Ported from musl, which is licensed under the MIT license:
27// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
38//
lib/std/math/ilogb.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Ported from musl, which is licensed under the MIT license:
27// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
38//
lib/std/math/inf.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const math = std.math;
38
lib/std/math/isfinite.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const math = std.math;
38const expect = std.testing.expect;
lib/std/math/isinf.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const math = std.math;
38const expect = std.testing.expect;
lib/std/math/isnan.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const math = std.math;
38const expect = std.testing.expect;
lib/std/math/isnormal.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const math = std.math;
38const expect = std.testing.expect;
lib/std/math/ln.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Ported from musl, which is licensed under the MIT license:
27// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
38//
lib/std/math/log.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Ported from musl, which is licensed under the MIT license:
27// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
38//
lib/std/math/log10.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Ported from musl, which is licensed under the MIT license:
27// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
38//
lib/std/math/log1p.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Ported from musl, which is licensed under the MIT license:
27// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
38//
lib/std/math/log2.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Ported from musl, which is licensed under the MIT license:
27// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
38//
lib/std/math/modf.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Ported from musl, which is licensed under the MIT license:
27// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
38//
lib/std/math/nan.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const math = @import("../math.zig");
27
38/// Returns the nan representation for type T.
lib/std/math/pow.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Ported from go, which is licensed under a BSD-3 license.
27// https://golang.org/LICENSE
38//
lib/std/math/powi.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Based on Rust, which is licensed under the MIT license.
27// https://github.com/rust-lang/rust/blob/360432f1e8794de58cd94f34c9c17ad65871e5b5/LICENSE-MIT
38//
lib/std/math/round.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Ported from musl, which is licensed under the MIT license:
27// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
38//
lib/std/math/scalbn.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Ported from musl, which is licensed under the MIT license:
27// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
38//
lib/std/math/signbit.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const math = std.math;
38const expect = std.testing.expect;
lib/std/math/sin.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Ported from go, which is licensed under a BSD-3 license.
27// https://golang.org/LICENSE
38//
lib/std/math/sinh.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Ported from musl, which is licensed under the MIT license:
27// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
38//
lib/std/math/sqrt.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const math = std.math;
38const expect = std.testing.expect;
lib/std/math/tan.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Ported from go, which is licensed under a BSD-3 license.
27// https://golang.org/LICENSE
38//
lib/std/math/tanh.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Ported from musl, which is licensed under the MIT license:
27// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
38//
lib/std/math/trunc.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Ported from musl, which is licensed under the MIT license:
27// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
38//
lib/std/mem.zig+24-1
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std.zig");
27const debug = std.debug;
38const assert = debug.assert;
......@@ -221,9 +226,19 @@ pub fn zeroes(comptime T: type) T {
221226 .Vector => |info| {
222227 return @splat(info.len, zeroes(info.child));
223228 },
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 },
224240 .ErrorUnion,
225241 .ErrorSet,
226 .Union,
227242 .Fn,
228243 .BoundFn,
229244 .Type,
......@@ -312,6 +327,14 @@ test "mem.zeroes" {
312327 for (b.sentinel) |e| {
313328 testing.expectEqual(@as(u8, 0), e);
314329 }
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);
315338}
316339
317340/// Sets a slice to zeroes.
lib/std/mem/Allocator.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16//! The standard memory allocation interface.
27
38const std = @import("../std.zig");
lib/std/meta.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std.zig");
27const builtin = @import("builtin");
38const debug = std.debug;
lib/std/meta/trailer_flags.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const meta = std.meta;
38const testing = std.testing;
lib/std/meta/trait.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const builtin = std.builtin;
38const mem = std.mem;
lib/std/mutex.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std.zig");
27const builtin = @import("builtin");
38const os = std.os;
lib/std/net.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std.zig");
27const builtin = @import("builtin");
38const assert = std.debug.assert;
lib/std/net/test.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const builtin = std.builtin;
38const net = std.net;
lib/std/once.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std.zig");
27const builtin = std.builtin;
38const testing = std.testing;
lib/std/os.zig+24-17
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// This file contains thin wrappers around OS-specific APIs, with these
27// specific goals in mind:
38// * Convert "errno"-style error codes into Zig errors.
......@@ -296,6 +301,7 @@ pub const ReadError = error{
296301 BrokenPipe,
297302 ConnectionResetByPeer,
298303 ConnectionTimedOut,
304 NotOpenForReading,
299305
300306 /// This error occurs when no global event loop is configured,
301307 /// and reading from the file descriptor would block.
......@@ -332,7 +338,7 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize {
332338 wasi.EINVAL => unreachable,
333339 wasi.EFAULT => unreachable,
334340 wasi.EAGAIN => unreachable,
335 wasi.EBADF => unreachable, // Always a race condition.
341 wasi.EBADF => return error.NotOpenForReading, // Can be a race condition.
336342 wasi.EIO => return error.InputOutput,
337343 wasi.EISDIR => return error.IsDir,
338344 wasi.ENOBUFS => return error.SystemResources,
......@@ -364,7 +370,7 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize {
364370 } else {
365371 return error.WouldBlock;
366372 },
367 EBADF => unreachable, // Always a race condition.
373 EBADF => return error.NotOpenForReading, // Can be a race condition.
368374 EIO => return error.InputOutput,
369375 EISDIR => return error.IsDir,
370376 ENOBUFS => return error.SystemResources,
......@@ -402,7 +408,7 @@ pub fn readv(fd: fd_t, iov: []const iovec) ReadError!usize {
402408 wasi.EINVAL => unreachable,
403409 wasi.EFAULT => unreachable,
404410 wasi.EAGAIN => unreachable, // currently not support in WASI
405 wasi.EBADF => unreachable, // always a race condition
411 wasi.EBADF => return error.NotOpenForReading, // can be a race condition
406412 wasi.EIO => return error.InputOutput,
407413 wasi.EISDIR => return error.IsDir,
408414 wasi.ENOBUFS => return error.SystemResources,
......@@ -426,7 +432,7 @@ pub fn readv(fd: fd_t, iov: []const iovec) ReadError!usize {
426432 } else {
427433 return error.WouldBlock;
428434 },
429 EBADF => unreachable, // always a race condition
435 EBADF => return error.NotOpenForReading, // can be a race condition
430436 EIO => return error.InputOutput,
431437 EISDIR => return error.IsDir,
432438 ENOBUFS => return error.SystemResources,
......@@ -463,7 +469,7 @@ pub fn pread(fd: fd_t, buf: []u8, offset: u64) PReadError!usize {
463469 wasi.EINVAL => unreachable,
464470 wasi.EFAULT => unreachable,
465471 wasi.EAGAIN => unreachable,
466 wasi.EBADF => unreachable, // Always a race condition.
472 wasi.EBADF => return error.NotOpenForReading, // Can be a race condition.
467473 wasi.EIO => return error.InputOutput,
468474 wasi.EISDIR => return error.IsDir,
469475 wasi.ENOBUFS => return error.SystemResources,
......@@ -490,7 +496,7 @@ pub fn pread(fd: fd_t, buf: []u8, offset: u64) PReadError!usize {
490496 } else {
491497 return error.WouldBlock;
492498 },
493 EBADF => unreachable, // Always a race condition.
499 EBADF => return error.NotOpenForReading, // Can be a race condition.
494500 EIO => return error.InputOutput,
495501 EISDIR => return error.IsDir,
496502 ENOBUFS => return error.SystemResources,
......@@ -607,7 +613,7 @@ pub fn preadv(fd: fd_t, iov: []const iovec, offset: u64) PReadError!usize {
607613 wasi.EINVAL => unreachable,
608614 wasi.EFAULT => unreachable,
609615 wasi.EAGAIN => unreachable,
610 wasi.EBADF => unreachable, // always a race condition
616 wasi.EBADF => return error.NotOpenForReading, // can be a race condition
611617 wasi.EIO => return error.InputOutput,
612618 wasi.EISDIR => return error.IsDir,
613619 wasi.ENOBUFS => return error.SystemResources,
......@@ -635,7 +641,7 @@ pub fn preadv(fd: fd_t, iov: []const iovec, offset: u64) PReadError!usize {
635641 } else {
636642 return error.WouldBlock;
637643 },
638 EBADF => unreachable, // always a race condition
644 EBADF => return error.NotOpenForReading, // can be a race condition
639645 EIO => return error.InputOutput,
640646 EISDIR => return error.IsDir,
641647 ENOBUFS => return error.SystemResources,
......@@ -660,6 +666,7 @@ pub const WriteError = error{
660666 BrokenPipe,
661667 SystemResources,
662668 OperationAborted,
669 NotOpenForWriting,
663670
664671 /// This error occurs when no global event loop is configured,
665672 /// and reading from the file descriptor would block.
......@@ -704,7 +711,7 @@ pub fn write(fd: fd_t, bytes: []const u8) WriteError!usize {
704711 wasi.EINVAL => unreachable,
705712 wasi.EFAULT => unreachable,
706713 wasi.EAGAIN => unreachable,
707 wasi.EBADF => unreachable, // Always a race condition.
714 wasi.EBADF => return error.NotOpenForWriting, // can be a race condition.
708715 wasi.EDESTADDRREQ => unreachable, // `connect` was never called.
709716 wasi.EDQUOT => return error.DiskQuota,
710717 wasi.EFBIG => return error.FileTooBig,
......@@ -736,7 +743,7 @@ pub fn write(fd: fd_t, bytes: []const u8) WriteError!usize {
736743 } else {
737744 return error.WouldBlock;
738745 },
739 EBADF => unreachable, // Always a race condition.
746 EBADF => return error.NotOpenForWriting, // can be a race condition.
740747 EDESTADDRREQ => unreachable, // `connect` was never called.
741748 EDQUOT => return error.DiskQuota,
742749 EFBIG => return error.FileTooBig,
......@@ -782,7 +789,7 @@ pub fn writev(fd: fd_t, iov: []const iovec_const) WriteError!usize {
782789 wasi.EINVAL => unreachable,
783790 wasi.EFAULT => unreachable,
784791 wasi.EAGAIN => unreachable,
785 wasi.EBADF => unreachable, // Always a race condition.
792 wasi.EBADF => return error.NotOpenForWriting, // can be a race condition.
786793 wasi.EDESTADDRREQ => unreachable, // `connect` was never called.
787794 wasi.EDQUOT => return error.DiskQuota,
788795 wasi.EFBIG => return error.FileTooBig,
......@@ -809,7 +816,7 @@ pub fn writev(fd: fd_t, iov: []const iovec_const) WriteError!usize {
809816 } else {
810817 return error.WouldBlock;
811818 },
812 EBADF => unreachable, // Always a race condition.
819 EBADF => return error.NotOpenForWriting, // Can be a race condition.
813820 EDESTADDRREQ => unreachable, // `connect` was never called.
814821 EDQUOT => return error.DiskQuota,
815822 EFBIG => return error.FileTooBig,
......@@ -862,7 +869,7 @@ pub fn pwrite(fd: fd_t, bytes: []const u8, offset: u64) PWriteError!usize {
862869 wasi.EINVAL => unreachable,
863870 wasi.EFAULT => unreachable,
864871 wasi.EAGAIN => unreachable,
865 wasi.EBADF => unreachable, // Always a race condition.
872 wasi.EBADF => return error.NotOpenForWriting, // can be a race condition.
866873 wasi.EDESTADDRREQ => unreachable, // `connect` was never called.
867874 wasi.EDQUOT => return error.DiskQuota,
868875 wasi.EFBIG => return error.FileTooBig,
......@@ -898,7 +905,7 @@ pub fn pwrite(fd: fd_t, bytes: []const u8, offset: u64) PWriteError!usize {
898905 } else {
899906 return error.WouldBlock;
900907 },
901 EBADF => unreachable, // Always a race condition.
908 EBADF => return error.NotOpenForWriting, // Can be a race condition.
902909 EDESTADDRREQ => unreachable, // `connect` was never called.
903910 EDQUOT => return error.DiskQuota,
904911 EFBIG => return error.FileTooBig,
......@@ -956,7 +963,7 @@ pub fn pwritev(fd: fd_t, iov: []const iovec_const, offset: u64) PWriteError!usiz
956963 wasi.EINVAL => unreachable,
957964 wasi.EFAULT => unreachable,
958965 wasi.EAGAIN => unreachable,
959 wasi.EBADF => unreachable, // Always a race condition.
966 wasi.EBADF => return error.NotOpenForWriting, // Can be a race condition.
960967 wasi.EDESTADDRREQ => unreachable, // `connect` was never called.
961968 wasi.EDQUOT => return error.DiskQuota,
962969 wasi.EFBIG => return error.FileTooBig,
......@@ -986,7 +993,7 @@ pub fn pwritev(fd: fd_t, iov: []const iovec_const, offset: u64) PWriteError!usiz
986993 } else {
987994 return error.WouldBlock;
988995 },
989 EBADF => unreachable, // Always a race condition.
996 EBADF => return error.NotOpenForWriting, // Can be a race condition.
990997 EDESTADDRREQ => unreachable, // `connect` was never called.
991998 EDQUOT => return error.DiskQuota,
992999 EFBIG => return error.FileTooBig,
......@@ -1251,7 +1258,7 @@ pub fn dup2(old_fd: fd_t, new_fd: fd_t) !void {
12511258 EBUSY, EINTR => continue,
12521259 EMFILE => return error.ProcessFdQuotaExceeded,
12531260 EINVAL => unreachable, // invalid parameters passed to dup2
1254 EBADF => unreachable, // always a race condition
1261 EBADF => unreachable, // invalid file descriptor
12551262 else => |err| return unexpectedErrno(err),
12561263 }
12571264 }
lib/std/os/bits.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16//! Platform-dependent types and values that are used along with OS-specific APIs.
27//! These are imported into `std.c`, `std.os`, and `std.os.linux`.
38//! 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// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../../std.zig");
27const assert = std.debug.assert;
38const maxInt = std.math.maxInt;
lib/std/os/bits/dragonfly.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../../std.zig");
27const maxInt = std.math.maxInt;
38
lib/std/os/bits/freebsd.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../../std.zig");
27const maxInt = std.math.maxInt;
38
lib/std/os/bits/linux.zig+9-1
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const builtin = @import("builtin");
27const std = @import("../../std.zig");
38const maxInt = std.math.maxInt;
......@@ -19,7 +24,7 @@ pub usingnamespace switch (builtin.arch) {
1924};
2025
2126pub usingnamespace @import("linux/netlink.zig");
22pub const bpf = @import("linux/bpf.zig");
27pub const BPF = @import("linux/bpf.zig");
2328
2429const is_mips = builtin.arch.isMIPS();
2530
......@@ -770,6 +775,9 @@ pub fn S_ISSOCK(m: u32) bool {
770775 return m & S_IFMT == S_IFSOCK;
771776}
772777
778pub const UTIME_NOW = 0x3fffffff;
779pub const UTIME_OMIT = 0x3ffffffe;
780
773781pub const TFD_NONBLOCK = O_NONBLOCK;
774782pub const TFD_CLOEXEC = O_CLOEXEC;
775783
lib/std/os/bits/linux/arm-eabi.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// arm-eabi-specific declarations that are intended to be imported into the POSIX namespace.
27const std = @import("../../../std.zig");
38const linux = std.os.linux;
lib/std/os/bits/linux/arm64.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// arm64-specific declarations that are intended to be imported into the POSIX namespace.
27// This does include Linux-only APIs.
38
lib/std/os/bits/linux/bpf.zig+387-18
......@@ -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.
16usingnamespace std.os;
27const 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
464// instruction classes
565/// jmp mode in word width
......@@ -8,8 +68,6 @@ pub const JMP32 = 0x06;
868pub const ALU64 = 0x07;
969
1070// ld/ldx fields
11/// double word (64-bit)
12pub const DW = 0x18;
1371/// exclusive add
1472pub const XADD = 0xc0;
1573
......@@ -148,6 +206,130 @@ pub const BPF_F_CLONE = 0x200;
148206/// flag for BPF_MAP_CREATE command. Enable memory-mapping BPF map
149207pub 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
151333/// a single BPF instruction
152334pub const Insn = packed struct {
153335 code: u8,
......@@ -158,32 +340,168 @@ pub const Insn = packed struct {
158340
159341 /// r0 - r9 are general purpose 64-bit registers, r10 points to the stack
160342 /// frame
161 pub const Reg = enum(u4) {
162 r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10
343 pub const Reg = packed enum(u4) { r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10 };
344 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,
163358 };
164359
165 const alu = 0x04;
166 const jmp = 0x05;
167 const mov = 0xb0;
168 const k = 0;
169 const exit_code = 0x90;
360 pub const Size = packed enum(u8) {
361 byte = B,
362 half_word = H,
363 word = W,
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 instructions
172 /// load immediate value into a register
173 pub fn load_imm(dst: Reg, imm: i32) Insn {
416 pub fn mov(dst: Reg, src: anytype) Insn {
417 return alu(64, .mov, dst, src);
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 {
174433 return Insn{
175 .code = alu | mov | k,
434 .code = STX | @enumToInt(size) | MEM,
176435 .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,
177457 .src = 0,
178458 .off = 0,
179459 .imm = imm,
180460 };
181461 }
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
183501 /// exit BPF program
184502 pub fn exit() Insn {
185503 return Insn{
186 .code = jmp | exit_code,
504 .code = JMP | EXIT,
187505 .dst = 0,
188506 .src = 0,
189507 .off = 0,
......@@ -192,6 +510,61 @@ pub const Insn = packed struct {
192510 }
193511};
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
195568pub const Cmd = extern enum(usize) {
196569 map_create,
197570 map_lookup_elem,
......@@ -600,7 +973,3 @@ pub const Attr = extern union {
600973 enable_stats: EnableStatsAttr,
601974 iter_create: IterCreateAttr,
602975};
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// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16/// Operation not permitted
27pub const EPERM = 1;
38
lib/std/os/bits/linux/errno-mips.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16pub const EPERM = 1;
27pub const ENOENT = 2;
38pub const ESRCH = 3;
lib/std/os/bits/linux/i386.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// i386-specific declarations that are intended to be imported into the POSIX namespace.
27// This does include Linux-only APIs.
38
lib/std/os/bits/linux/mips.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../../../std.zig");
27const linux = std.os.linux;
38const socklen_t = linux.socklen_t;
lib/std/os/bits/linux/netlink.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16usingnamespace @import("../linux.zig");
27
38/// Routing/device hook
lib/std/os/bits/linux/riscv64.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// riscv64-specific declarations that are intended to be imported into the POSIX namespace.
27const std = @import("../../../std.zig");
38const uid_t = std.os.linux.uid_t;
lib/std/os/bits/linux/x86_64.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// x86-64-specific declarations that are intended to be imported into the POSIX namespace.
27const std = @import("../../../std.zig");
38const pid_t = linux.pid_t;
lib/std/os/bits/netbsd.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../../std.zig");
27const builtin = std.builtin;
38const maxInt = std.math.maxInt;
lib/std/os/bits/wasi.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Convenience types and consts used by std.os module
27pub const STDIN_FILENO = 0;
38pub const STDOUT_FILENO = 1;
lib/std/os/bits/windows.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// The reference for these types and values is Microsoft Windows's ucrt (Universal C RunTime).
27
38usingnamespace @import("../windows/bits.zig");
lib/std/os/darwin.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const builtin = @import("builtin");
27const std = @import("../std.zig");
38pub usingnamespace std.c;
lib/std/os/dragonfly.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27pub usingnamespace std.c;
38pub usingnamespace @import("bits.zig");
lib/std/os/freebsd.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27pub usingnamespace std.c;
38pub usingnamespace @import("bits.zig");
lib/std/os/linux.zig+9
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// This file provides the system interface functions for Linux matching those
27// that are provided by libc, whether or not libc is linked. The following
38// 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,
12161221 );
12171222}
12181223
1224pub fn bpf(cmd: BPF.Cmd, attr: *BPF.Attr, size: u32) usize {
1225 return syscall3(.bpf, @enumToInt(cmd), @ptrToInt(attr), size);
1226}
1227
12191228test "" {
12201229 if (builtin.os.tag == .linux) {
12211230 _ = @import("linux/test.zig");
lib/std/os/linux/arm-eabi.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16usingnamespace @import("../bits.zig");
27
38pub fn syscall0(number: SYS) usize {
lib/std/os/linux/arm64.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16usingnamespace @import("../bits.zig");
27
38pub fn syscall0(number: SYS) usize {
lib/std/os/linux/i386.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16usingnamespace @import("../bits.zig");
27
38pub fn syscall0(number: SYS) usize {
lib/std/os/linux/mips.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16usingnamespace @import("../bits.zig");
27
38pub fn syscall0(number: SYS) usize {
lib/std/os/linux/riscv64.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16usingnamespace @import("../bits.zig");
27
38pub fn syscall0(number: SYS) usize {
lib/std/os/linux/test.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../../std.zig");
27const builtin = @import("builtin");
38const linux = std.os.linux;
lib/std/os/linux/tls.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std");
27const builtin = std.builtin;
38const os = std.os;
lib/std/os/linux/vdso.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../../std.zig");
27const elf = std.elf;
38const linux = std.os.linux;
lib/std/os/linux/x86_64.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16usingnamespace @import("../bits.zig");
27
38pub fn syscall0(number: SYS) usize {
lib/std/os/netbsd.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27pub usingnamespace std.c;
38pub usingnamespace @import("bits.zig");
lib/std/os/test.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const os = std.os;
38const testing = std.testing;
lib/std/os/uefi.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16/// A protocol is an interface identified by a GUID.
27pub const protocols = @import("uefi/protocols.zig");
38
lib/std/os/uefi/protocols.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16pub const LoadedImageProtocol = @import("protocols/loaded_image_protocol.zig").LoadedImageProtocol;
27pub 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// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const uefi = @import("std").os.uefi;
27const Event = uefi.Event;
38const Guid = uefi.Guid;
lib/std/os/uefi/protocols/device_path_protocol.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const uefi = @import("std").os.uefi;
27const Guid = uefi.Guid;
38
lib/std/os/uefi/protocols/edid_active_protocol.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const uefi = @import("std").os.uefi;
27const Guid = uefi.Guid;
38
lib/std/os/uefi/protocols/edid_discovered_protocol.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const uefi = @import("std").os.uefi;
27const Guid = uefi.Guid;
38
lib/std/os/uefi/protocols/edid_override_protocol.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const uefi = @import("std").os.uefi;
27const Guid = uefi.Guid;
38const Handle = uefi.Handle;
lib/std/os/uefi/protocols/file_protocol.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const uefi = @import("std").os.uefi;
27const Guid = uefi.Guid;
38const Time = uefi.Time;
lib/std/os/uefi/protocols/graphics_output_protocol.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const uefi = @import("std").os.uefi;
27const Guid = uefi.Guid;
38const Status = uefi.Status;
lib/std/os/uefi/protocols/hii.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const uefi = @import("std").os.uefi;
27const Guid = uefi.Guid;
38
lib/std/os/uefi/protocols/hii_database_protocol.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const uefi = @import("std").os.uefi;
27const Guid = uefi.Guid;
38const Status = uefi.Status;
lib/std/os/uefi/protocols/hii_popup_protocol.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const uefi = @import("std").os.uefi;
27const Guid = uefi.Guid;
38const Status = uefi.Status;
lib/std/os/uefi/protocols/ip6_config_protocol.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const uefi = @import("std").os.uefi;
27const Guid = uefi.Guid;
38const Event = uefi.Event;
lib/std/os/uefi/protocols/ip6_protocol.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const uefi = @import("std").os.uefi;
27const Guid = uefi.Guid;
38const Event = uefi.Event;
lib/std/os/uefi/protocols/ip6_service_binding_protocol.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const uefi = @import("std").os.uefi;
27const Handle = uefi.Handle;
38const Guid = uefi.Guid;
lib/std/os/uefi/protocols/loaded_image_protocol.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const uefi = @import("std").os.uefi;
27const Guid = uefi.Guid;
38const Handle = uefi.Handle;
lib/std/os/uefi/protocols/managed_network_protocol.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const uefi = @import("std").os.uefi;
27const Guid = uefi.Guid;
38const Event = uefi.Event;
lib/std/os/uefi/protocols/managed_network_service_binding_protocol.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const uefi = @import("std").os.uefi;
27const Handle = uefi.Handle;
38const Guid = uefi.Guid;
lib/std/os/uefi/protocols/rng_protocol.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const uefi = @import("std").os.uefi;
27const Guid = uefi.Guid;
38const Status = uefi.Status;
lib/std/os/uefi/protocols/shell_parameters_protocol.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const uefi = @import("std").os.uefi;
27const Guid = uefi.Guid;
38const FileHandle = uefi.FileHandle;
lib/std/os/uefi/protocols/simple_file_system_protocol.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const uefi = @import("std").os.uefi;
27const Guid = uefi.Guid;
38const FileProtocol = uefi.protocols.FileProtocol;
lib/std/os/uefi/protocols/simple_network_protocol.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const uefi = @import("std").os.uefi;
27const Event = uefi.Event;
38const Guid = uefi.Guid;
lib/std/os/uefi/protocols/simple_pointer_protocol.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const uefi = @import("std").os.uefi;
27const Event = uefi.Event;
38const Guid = uefi.Guid;
lib/std/os/uefi/protocols/simple_text_input_ex_protocol.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const uefi = @import("std").os.uefi;
27const Event = uefi.Event;
38const Guid = uefi.Guid;
lib/std/os/uefi/protocols/simple_text_input_protocol.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const uefi = @import("std").os.uefi;
27const Event = uefi.Event;
38const Guid = uefi.Guid;
lib/std/os/uefi/protocols/simple_text_output_protocol.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const uefi = @import("std").os.uefi;
27const Guid = uefi.Guid;
38const Status = uefi.Status;
lib/std/os/uefi/protocols/udp6_protocol.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const uefi = @import("std").os.uefi;
27const Guid = uefi.Guid;
38const Event = uefi.Event;
lib/std/os/uefi/protocols/udp6_service_binding_protocol.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const uefi = @import("std").os.uefi;
27const Handle = uefi.Handle;
38const Guid = uefi.Guid;
lib/std/os/uefi/status.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const high_bit = 1 << @typeInfo(usize).Int.bits - 1;
27
38pub const Status = extern enum(usize) {
lib/std/os/uefi/tables.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16pub const AllocateType = @import("tables/boot_services.zig").AllocateType;
27pub const BootServices = @import("tables/boot_services.zig").BootServices;
38pub const ConfigurationTable = @import("tables/configuration_table.zig").ConfigurationTable;
lib/std/os/uefi/tables/boot_services.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const uefi = @import("std").os.uefi;
27const Event = uefi.Event;
38const Guid = uefi.Guid;
lib/std/os/uefi/tables/configuration_table.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const uefi = @import("std").os.uefi;
27const Guid = uefi.Guid;
38
lib/std/os/uefi/tables/runtime_services.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const uefi = @import("std").os.uefi;
27const Guid = uefi.Guid;
38const TableHeader = uefi.tables.TableHeader;
lib/std/os/uefi/tables/system_table.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const uefi = @import("std").os.uefi;
27const BootServices = uefi.tables.BootServices;
38const ConfigurationTable = uefi.tables.ConfigurationTable;
lib/std/os/uefi/tables/table_header.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16pub const TableHeader = extern struct {
27 signature: u64,
38 revision: u32,
lib/std/os/wasi.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// wasi_snapshot_preview1 spec available (in witx format) here:
27// * typenames -- https://github.com/WebAssembly/WASI/blob/master/phases/snapshot/witx/typenames.witx
38// * 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// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// This file contains thin wrappers around Windows-specific APIs, with these
27// specific goals in mind:
38// * Convert "errno"-style error codes into Zig errors.
......@@ -469,6 +474,7 @@ pub const WriteFileError = error{
469474 SystemResources,
470475 OperationAborted,
471476 BrokenPipe,
477 NotOpenForWriting,
472478 Unexpected,
473479};
474480
......@@ -542,6 +548,7 @@ pub fn WriteFile(
542548 .NOT_ENOUGH_QUOTA => return error.SystemResources,
543549 .IO_PENDING => unreachable,
544550 .BROKEN_PIPE => return error.BrokenPipe,
551 .INVALID_HANDLE => return error.NotOpenForWriting,
545552 else => |err| return unexpectedError(err),
546553 }
547554 }
lib/std/os/windows/advapi32.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16usingnamespace @import("bits.zig");
27
38pub extern "advapi32" fn RegOpenKeyExW(
lib/std/os/windows/bits.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Platform-dependent types and values that are used along with OS-specific APIs.
27
38const builtin = @import("builtin");
lib/std/os/windows/gdi32.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16usingnamespace @import("bits.zig");
27
38pub const PIXELFORMATDESCRIPTOR = extern struct {
lib/std/os/windows/kernel32.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16usingnamespace @import("bits.zig");
27
38pub 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// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16pub const NEUTRAL = 0x00;
27pub const INVARIANT = 0x7f;
38pub const AFRIKAANS = 0x36;
lib/std/os/windows/ntdll.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16usingnamespace @import("bits.zig");
27
38pub extern "NtDll" fn RtlGetVersion(
lib/std/os/windows/ntstatus.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// NTSTATUS codes from https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/596a1078-e883-4972-9bbc-49e60bebca55?
27pub const NTSTATUS = extern enum(u32) {
38 /// The operation completed successfully.
lib/std/os/windows/ole32.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16usingnamespace @import("bits.zig");
27
38pub extern "ole32" fn CoTaskMemFree(pv: LPVOID) callconv(.Stdcall) void;
lib/std/os/windows/psapi.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16usingnamespace @import("bits.zig");
27
38pub extern "psapi" fn EmptyWorkingSet(hProcess: HANDLE) callconv(.Stdcall) BOOL;
lib/std/os/windows/shell32.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16usingnamespace @import("bits.zig");
27
38pub 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// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16pub const NEUTRAL = 0x00;
27pub const DEFAULT = 0x01;
38pub const SYS_DEFAULT = 0x02;
lib/std/os/windows/user32.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16usingnamespace @import("bits.zig");
27
38// PM
lib/std/os/windows/win32error.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Codes are from https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/18d8fbe8-a967-4f1c-ae50-99ca8e491d2d
27pub const Win32Error = extern enum(u16) {
38 /// The operation completed successfully.
lib/std/os/windows/ws2_32.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16usingnamespace @import("bits.zig");
27
38pub const SOCKET = *@Type(.Opaque);
lib/std/packed_int_array.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std");
27const builtin = @import("builtin");
38const debug = std.debug;
lib/std/pdb.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const builtin = @import("builtin");
27const std = @import("std.zig");
38const io = std.io;
lib/std/priority_queue.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std.zig");
27const Allocator = std.mem.Allocator;
38const assert = std.debug.assert;
lib/std/process.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std.zig");
27const builtin = std.builtin;
38const os = std.os;
lib/std/progress.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std");
27const windows = std.os.windows;
38const testing = std.testing;
lib/std/rand.zig+7-2
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// The engines provided here should be initialized from an external source. For now, randomBytes
27// from the crypto package is the most suitable. Be sure to use a CSPRNG when required, otherwise using
38// a normal PRNG will be faster and use substantially less stack space.
......@@ -732,12 +737,12 @@ test "xoroshiro sequence" {
732737// CSPRNG
733738pub const Gimli = struct {
734739 random: Random,
735 state: std.crypto.gimli.State,
740 state: std.crypto.core.Gimli,
736741
737742 pub fn init(init_s: u64) Gimli {
738743 var self = Gimli{
739744 .random = Random{ .fillFn = fill },
740 .state = std.crypto.gimli.State{
745 .state = std.crypto.core.Gimli{
741746 .data = [_]u32{0} ** (std.crypto.gimli.State.BLOCKBYTES / 4),
742747 },
743748 };
lib/std/rand/ziggurat.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Implements ZIGNOR [1].
27//
38// [1]: Jurgen A. Doornik (2005). [*An Improved Ziggurat Method to Generate Normal Random Samples*]
lib/std/rb.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std");
27const assert = std.debug.assert;
38const testing = std.testing;
lib/std/reset_event.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std.zig");
27const builtin = @import("builtin");
38const testing = std.testing;
lib/std/segmented_list.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std.zig");
27const assert = std.debug.assert;
38const testing = std.testing;
lib/std/sort.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std.zig");
27const assert = std.debug.assert;
38const testing = std.testing;
lib/std/special/build_runner.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const root = @import("@build");
27const std = @import("std");
38const builtin = @import("builtin");
lib/std/special/c.zig+6-1
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// This is Zig's multi-target implementation of libc.
27// When builtin.link_libc is true, we need to export all the functions and
38// provide an entire C API.
......@@ -35,7 +40,7 @@ comptime {
3540 }
3641}
3742
38extern var _fltused: c_int = 1;
43var _fltused: c_int = 1;
3944
4045extern fn main(argc: c_int, argv: [*:null]?[*:0]u8) c_int;
4146fn wasm_start() callconv(.C) void {
lib/std/special/compiler_rt.zig+6-1
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std");
27const builtin = std.builtin;
38const is_test = builtin.is_test;
......@@ -335,7 +340,7 @@ fn __stack_chk_fail() callconv(.C) noreturn {
335340 @panic("stack smashing detected");
336341}
337342
338extern var __stack_chk_guard: usize = blk: {
343var __stack_chk_guard: usize = blk: {
339344 var buf = [1]u8{0} ** @sizeOf(usize);
340345 buf[@sizeOf(usize) - 1] = 255;
341346 buf[@sizeOf(usize) - 2] = '\n';
lib/std/special/compiler_rt/addXf3.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Ported from:
27//
38// 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// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Ported from:
27//
38// 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// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// ARM specific builtins
27const builtin = @import("builtin");
38
lib/std/special/compiler_rt/ashldi3_test.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const __ashldi3 = @import("shift.zig").__ashldi3;
27const testing = @import("std").testing;
38
lib/std/special/compiler_rt/ashlti3_test.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const __ashlti3 = @import("shift.zig").__ashlti3;
27const testing = @import("std").testing;
38
lib/std/special/compiler_rt/ashrdi3_test.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const __ashrdi3 = @import("shift.zig").__ashrdi3;
27const testing = @import("std").testing;
38
lib/std/special/compiler_rt/ashrti3_test.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const __ashrti3 = @import("shift.zig").__ashrti3;
27const testing = @import("std").testing;
38
lib/std/special/compiler_rt/atomics.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std");
27const builtin = std.builtin;
38
lib/std/special/compiler_rt/aulldiv.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const builtin = @import("builtin");
27
38pub fn _alldiv(a: i64, b: i64) callconv(.Stdcall) i64 {
lib/std/special/compiler_rt/aullrem.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const builtin = @import("builtin");
27
38pub fn _allrem(a: i64, b: i64) callconv(.Stdcall) i64 {
lib/std/special/compiler_rt/clear_cache.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std");
27const arch = std.builtin.cpu.arch;
38const os = std.builtin.os.tag;
lib/std/special/compiler_rt/clzsi2.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const builtin = @import("builtin");
27
38fn __clzsi2_generic(a: i32) callconv(.C) i32 {
lib/std/special/compiler_rt/clzsi2_test.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const clzsi2 = @import("clzsi2.zig");
27const testing = @import("std").testing;
38
lib/std/special/compiler_rt/compareXf2.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Ported from:
27//
38// 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// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Ported from:
27//
38// 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// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Ported from:
27//
38// 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// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Ported from:
27//
38// 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// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Ported from:
27//
38// 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// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Ported from:
27//
38// 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// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Ported from:
27//
38// 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// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std");
27const builtin = @import("builtin");
38
lib/std/special/compiler_rt/divtf3_test.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std");
27const math = std.math;
38const testing = std.testing;
lib/std/special/compiler_rt/divti3.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const udivmod = @import("udivmod.zig").udivmod;
27const builtin = @import("builtin");
38
lib/std/special/compiler_rt/divti3_test.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const __divti3 = @import("divti3.zig").__divti3;
27const testing = @import("std").testing;
38
lib/std/special/compiler_rt/extendXfYf2.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std");
27const builtin = @import("builtin");
38const is_test = builtin.is_test;
lib/std/special/compiler_rt/extendXfYf2_test.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const builtin = @import("builtin");
27const __extenddftf2 = @import("extendXfYf2.zig").__extenddftf2;
38const __extendhfsf2 = @import("extendXfYf2.zig").__extendhfsf2;
lib/std/special/compiler_rt/fixdfdi.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const fixint = @import("fixint.zig").fixint;
27const builtin = @import("builtin");
38
lib/std/special/compiler_rt/fixdfdi_test.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const __fixdfdi = @import("fixdfdi.zig").__fixdfdi;
27const std = @import("std");
38const math = std.math;
lib/std/special/compiler_rt/fixdfsi.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const fixint = @import("fixint.zig").fixint;
27const builtin = @import("builtin");
38
lib/std/special/compiler_rt/fixdfsi_test.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const __fixdfsi = @import("fixdfsi.zig").__fixdfsi;
27const std = @import("std");
38const math = std.math;
lib/std/special/compiler_rt/fixdfti.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const fixint = @import("fixint.zig").fixint;
27const builtin = @import("builtin");
38
lib/std/special/compiler_rt/fixdfti_test.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const __fixdfti = @import("fixdfti.zig").__fixdfti;
27const std = @import("std");
38const math = std.math;
lib/std/special/compiler_rt/fixint.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const is_test = @import("builtin").is_test;
27const std = @import("std");
38const math = std.math;
lib/std/special/compiler_rt/fixint_test.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const is_test = @import("builtin").is_test;
27const std = @import("std");
38const math = std.math;
lib/std/special/compiler_rt/fixsfdi.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const fixint = @import("fixint.zig").fixint;
27const builtin = @import("builtin");
38
lib/std/special/compiler_rt/fixsfdi_test.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const __fixsfdi = @import("fixsfdi.zig").__fixsfdi;
27const std = @import("std");
38const math = std.math;
lib/std/special/compiler_rt/fixsfsi.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const fixint = @import("fixint.zig").fixint;
27const builtin = @import("builtin");
38
lib/std/special/compiler_rt/fixsfsi_test.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const __fixsfsi = @import("fixsfsi.zig").__fixsfsi;
27const std = @import("std");
38const math = std.math;
lib/std/special/compiler_rt/fixsfti.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const fixint = @import("fixint.zig").fixint;
27const builtin = @import("builtin");
38
lib/std/special/compiler_rt/fixsfti_test.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const __fixsfti = @import("fixsfti.zig").__fixsfti;
27const std = @import("std");
38const math = std.math;
lib/std/special/compiler_rt/fixtfdi.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const fixint = @import("fixint.zig").fixint;
27const builtin = @import("builtin");
38
lib/std/special/compiler_rt/fixtfdi_test.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const __fixtfdi = @import("fixtfdi.zig").__fixtfdi;
27const std = @import("std");
38const math = std.math;
lib/std/special/compiler_rt/fixtfsi.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const fixint = @import("fixint.zig").fixint;
27const builtin = @import("builtin");
38
lib/std/special/compiler_rt/fixtfsi_test.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const __fixtfsi = @import("fixtfsi.zig").__fixtfsi;
27const std = @import("std");
38const math = std.math;
lib/std/special/compiler_rt/fixtfti.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const fixint = @import("fixint.zig").fixint;
27const builtin = @import("builtin");
38
lib/std/special/compiler_rt/fixtfti_test.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const __fixtfti = @import("fixtfti.zig").__fixtfti;
27const std = @import("std");
38const math = std.math;
lib/std/special/compiler_rt/fixuint.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const is_test = @import("builtin").is_test;
27const Log2Int = @import("std").math.Log2Int;
38
lib/std/special/compiler_rt/fixunsdfdi.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const fixuint = @import("fixuint.zig").fixuint;
27const builtin = @import("builtin");
38
lib/std/special/compiler_rt/fixunsdfdi_test.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const __fixunsdfdi = @import("fixunsdfdi.zig").__fixunsdfdi;
27const testing = @import("std").testing;
38
lib/std/special/compiler_rt/fixunsdfsi.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const fixuint = @import("fixuint.zig").fixuint;
27const builtin = @import("builtin");
38
lib/std/special/compiler_rt/fixunsdfsi_test.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const __fixunsdfsi = @import("fixunsdfsi.zig").__fixunsdfsi;
27const testing = @import("std").testing;
38
lib/std/special/compiler_rt/fixunsdfti.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const fixuint = @import("fixuint.zig").fixuint;
27const builtin = @import("builtin");
38
lib/std/special/compiler_rt/fixunsdfti_test.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const __fixunsdfti = @import("fixunsdfti.zig").__fixunsdfti;
27const testing = @import("std").testing;
38
lib/std/special/compiler_rt/fixunssfdi.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const fixuint = @import("fixuint.zig").fixuint;
27const builtin = @import("builtin");
38
lib/std/special/compiler_rt/fixunssfdi_test.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const __fixunssfdi = @import("fixunssfdi.zig").__fixunssfdi;
27const testing = @import("std").testing;
38
lib/std/special/compiler_rt/fixunssfsi.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const fixuint = @import("fixuint.zig").fixuint;
27const builtin = @import("builtin");
38
lib/std/special/compiler_rt/fixunssfsi_test.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const __fixunssfsi = @import("fixunssfsi.zig").__fixunssfsi;
27const testing = @import("std").testing;
38
lib/std/special/compiler_rt/fixunssfti.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const fixuint = @import("fixuint.zig").fixuint;
27const builtin = @import("builtin");
38
lib/std/special/compiler_rt/fixunssfti_test.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const __fixunssfti = @import("fixunssfti.zig").__fixunssfti;
27const testing = @import("std").testing;
38
lib/std/special/compiler_rt/fixunstfdi.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const fixuint = @import("fixuint.zig").fixuint;
27const builtin = @import("builtin");
38
lib/std/special/compiler_rt/fixunstfdi_test.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const __fixunstfdi = @import("fixunstfdi.zig").__fixunstfdi;
27const testing = @import("std").testing;
38
lib/std/special/compiler_rt/fixunstfsi.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const fixuint = @import("fixuint.zig").fixuint;
27const builtin = @import("builtin");
38
lib/std/special/compiler_rt/fixunstfsi_test.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const __fixunstfsi = @import("fixunstfsi.zig").__fixunstfsi;
27const testing = @import("std").testing;
38
lib/std/special/compiler_rt/fixunstfti.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const fixuint = @import("fixuint.zig").fixuint;
27const builtin = @import("builtin");
38
lib/std/special/compiler_rt/fixunstfti_test.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const __fixunstfti = @import("fixunstfti.zig").__fixunstfti;
27const testing = @import("std").testing;
38
lib/std/special/compiler_rt/floatdidf.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const builtin = @import("builtin");
27const std = @import("std");
38
lib/std/special/compiler_rt/floatdidf_test.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const __floatdidf = @import("floatdidf.zig").__floatdidf;
27const testing = @import("std").testing;
38
lib/std/special/compiler_rt/floatditf.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const builtin = @import("builtin");
27const is_test = builtin.is_test;
38const std = @import("std");
lib/std/special/compiler_rt/floatditf_test.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const __floatditf = @import("floatditf.zig").__floatditf;
27const testing = @import("std").testing;
38
lib/std/special/compiler_rt/floatsiXf.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const builtin = @import("builtin");
27const std = @import("std");
38const maxInt = std.math.maxInt;
lib/std/special/compiler_rt/floattidf.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const builtin = @import("builtin");
27const is_test = builtin.is_test;
38const std = @import("std");
lib/std/special/compiler_rt/floattidf_test.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const __floattidf = @import("floattidf.zig").__floattidf;
27const testing = @import("std").testing;
38
lib/std/special/compiler_rt/floattisf.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const builtin = @import("builtin");
27const is_test = builtin.is_test;
38const std = @import("std");
lib/std/special/compiler_rt/floattisf_test.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const __floattisf = @import("floattisf.zig").__floattisf;
27const testing = @import("std").testing;
38
lib/std/special/compiler_rt/floattitf.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const builtin = @import("builtin");
27const is_test = builtin.is_test;
38const std = @import("std");
lib/std/special/compiler_rt/floattitf_test.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const __floattitf = @import("floattitf.zig").__floattitf;
27const testing = @import("std").testing;
38
lib/std/special/compiler_rt/floatundidf.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const builtin = @import("builtin");
27const std = @import("std");
38
lib/std/special/compiler_rt/floatundidf_test.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const __floatundidf = @import("floatundidf.zig").__floatundidf;
27const testing = @import("std").testing;
38
lib/std/special/compiler_rt/floatundisf.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const builtin = @import("builtin");
27const std = @import("std");
38const maxInt = std.math.maxInt;
lib/std/special/compiler_rt/floatunditf.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const builtin = @import("builtin");
27const is_test = builtin.is_test;
38const std = @import("std");
lib/std/special/compiler_rt/floatunditf_test.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const __floatunditf = @import("floatunditf.zig").__floatunditf;
27
38fn test__floatunditf(a: u64, expected_hi: u64, expected_lo: u64) void {
lib/std/special/compiler_rt/floatunsidf.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const builtin = @import("builtin");
27const std = @import("std");
38const maxInt = std.math.maxInt;
lib/std/special/compiler_rt/floatunsisf.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const builtin = @import("builtin");
27const std = @import("std");
38const maxInt = std.math.maxInt;
lib/std/special/compiler_rt/floatunsitf.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const builtin = @import("builtin");
27const is_test = builtin.is_test;
38const std = @import("std");
lib/std/special/compiler_rt/floatunsitf_test.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const __floatunsitf = @import("floatunsitf.zig").__floatunsitf;
27
38fn test__floatunsitf(a: u64, expected_hi: u64, expected_lo: u64) void {
lib/std/special/compiler_rt/floatuntidf.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const builtin = @import("builtin");
27const is_test = builtin.is_test;
38const std = @import("std");
lib/std/special/compiler_rt/floatuntidf_test.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const __floatuntidf = @import("floatuntidf.zig").__floatuntidf;
27const testing = @import("std").testing;
38
lib/std/special/compiler_rt/floatuntisf.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const builtin = @import("builtin");
27const is_test = builtin.is_test;
38const std = @import("std");
lib/std/special/compiler_rt/floatuntisf_test.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const __floatuntisf = @import("floatuntisf.zig").__floatuntisf;
27const testing = @import("std").testing;
38
lib/std/special/compiler_rt/floatuntitf.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const builtin = @import("builtin");
27const is_test = builtin.is_test;
38const std = @import("std");
lib/std/special/compiler_rt/floatuntitf_test.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const __floatuntitf = @import("floatuntitf.zig").__floatuntitf;
27const testing = @import("std").testing;
38
lib/std/special/compiler_rt/int.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Builtin functions that operate on integer types
27const builtin = @import("builtin");
38const testing = @import("std").testing;
lib/std/special/compiler_rt/lshrdi3_test.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const __lshrdi3 = @import("shift.zig").__lshrdi3;
27const testing = @import("std").testing;
38
lib/std/special/compiler_rt/lshrti3_test.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const __lshrti3 = @import("shift.zig").__lshrti3;
27const testing = @import("std").testing;
38
lib/std/special/compiler_rt/modti3.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Ported from:
27//
38// 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// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const __modti3 = @import("modti3.zig").__modti3;
27const testing = @import("std").testing;
38
lib/std/special/compiler_rt/mulXf3.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Ported from:
27//
38// 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// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Ported from:
27//
38// 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// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const builtin = @import("builtin");
27
38// Ported from
lib/std/special/compiler_rt/muldi3_test.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const __muldi3 = @import("muldi3.zig").__muldi3;
27const testing = @import("std").testing;
38
lib/std/special/compiler_rt/mulodi4.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const builtin = @import("builtin");
27const compiler_rt = @import("../compiler_rt.zig");
38const maxInt = std.math.maxInt;
lib/std/special/compiler_rt/mulodi4_test.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const __mulodi4 = @import("mulodi4.zig").__mulodi4;
27const testing = @import("std").testing;
38
lib/std/special/compiler_rt/muloti4.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const builtin = @import("builtin");
27const compiler_rt = @import("../compiler_rt.zig");
38
lib/std/special/compiler_rt/muloti4_test.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const __muloti4 = @import("muloti4.zig").__muloti4;
27const testing = @import("std").testing;
38
lib/std/special/compiler_rt/multi3.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const builtin = @import("builtin");
27const compiler_rt = @import("../compiler_rt.zig");
38
lib/std/special/compiler_rt/multi3_test.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const __multi3 = @import("multi3.zig").__multi3;
27const testing = @import("std").testing;
38
lib/std/special/compiler_rt/negXf2.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std");
27
38pub fn __negsf2(a: f32) callconv(.C) f32 {
lib/std/special/compiler_rt/popcountdi2.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const builtin = @import("builtin");
27const compiler_rt = @import("../compiler_rt.zig");
38
lib/std/special/compiler_rt/popcountdi2_test.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const __popcountdi2 = @import("popcountdi2.zig").__popcountdi2;
27const testing = @import("std").testing;
38
lib/std/special/compiler_rt/shift.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std");
27const builtin = std.builtin;
38const Log2Int = std.math.Log2Int;
lib/std/special/compiler_rt/stack_probe.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const builtin = @import("builtin");
27
38// 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// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std");
27
38pub fn __truncsfhf2(a: f32) callconv(.C) u16 {
lib/std/special/compiler_rt/truncXfYf2_test.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const __truncsfhf2 = @import("truncXfYf2.zig").__truncsfhf2;
27
38fn test__truncsfhf2(a: u32, expected: u16) void {
lib/std/special/compiler_rt/udivmod.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const builtin = @import("builtin");
27const is_test = builtin.is_test;
38
lib/std/special/compiler_rt/udivmoddi4_test.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Disable formatting to avoid unnecessary source repository bloat.
27// zig fmt: off
38const __udivmoddi4 = @import("int.zig").__udivmoddi4;
lib/std/special/compiler_rt/udivmodti4.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const udivmod = @import("udivmod.zig").udivmod;
27const builtin = @import("builtin");
38const compiler_rt = @import("../compiler_rt.zig");
lib/std/special/compiler_rt/udivmodti4_test.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// Disable formatting to avoid unnecessary source repository bloat.
27// zig fmt: off
38const __udivmodti4 = @import("udivmodti4.zig").__udivmodti4;
lib/std/special/compiler_rt/udivti3.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const udivmodti4 = @import("udivmodti4.zig");
27const builtin = @import("builtin");
38
lib/std/special/compiler_rt/umodti3.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const udivmodti4 = @import("udivmodti4.zig");
27const builtin = @import("builtin");
38const compiler_rt = @import("../compiler_rt.zig");
lib/std/special/init-exe/build.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const Builder = @import("std").build.Builder;
27
38pub fn build(b: *Builder) void {
lib/std/special/init-exe/src/main.zig+6-1
......@@ -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.
16const std = @import("std");
27
38pub 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.", .{});
510}
lib/std/special/init-lib/build.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const Builder = @import("std").build.Builder;
27
38pub fn build(b: *Builder) void {
lib/std/special/init-lib/src/main.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std");
27const testing = std.testing;
38
lib/std/special/test_runner.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std");
27const io = std.io;
38const builtin = @import("builtin");
lib/std/spinlock.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std.zig");
27const builtin = @import("builtin");
38
lib/std/start.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16// This file is included in the compilation unit when exporting an executable.
27
38const root = @import("root");
lib/std/start_windows_tls.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std");
27const builtin = std.builtin;
38
lib/std/std.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16pub const ArrayList = @import("array_list.zig").ArrayList;
27pub const ArrayListAligned = @import("array_list.zig").ArrayListAligned;
38pub const ArrayListAlignedUnmanaged = @import("array_list.zig").ArrayListAlignedUnmanaged;
lib/std/target.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std.zig");
27const mem = std.mem;
38const builtin = std.builtin;
lib/std/target/aarch64.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const CpuFeature = std.Target.Cpu.Feature;
38const CpuModel = std.Target.Cpu.Model;
lib/std/target/amdgpu.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const CpuFeature = std.Target.Cpu.Feature;
38const CpuModel = std.Target.Cpu.Model;
lib/std/target/arm.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const CpuFeature = std.Target.Cpu.Feature;
38const CpuModel = std.Target.Cpu.Model;
lib/std/target/avr.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const CpuFeature = std.Target.Cpu.Feature;
38const CpuModel = std.Target.Cpu.Model;
lib/std/target/bpf.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const CpuFeature = std.Target.Cpu.Feature;
38const CpuModel = std.Target.Cpu.Model;
lib/std/target/hexagon.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const CpuFeature = std.Target.Cpu.Feature;
38const CpuModel = std.Target.Cpu.Model;
lib/std/target/mips.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const CpuFeature = std.Target.Cpu.Feature;
38const CpuModel = std.Target.Cpu.Model;
lib/std/target/msp430.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const CpuFeature = std.Target.Cpu.Feature;
38const CpuModel = std.Target.Cpu.Model;
lib/std/target/nvptx.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const CpuFeature = std.Target.Cpu.Feature;
38const CpuModel = std.Target.Cpu.Model;
lib/std/target/powerpc.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const CpuFeature = std.Target.Cpu.Feature;
38const CpuModel = std.Target.Cpu.Model;
lib/std/target/riscv.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const CpuFeature = std.Target.Cpu.Feature;
38const CpuModel = std.Target.Cpu.Model;
lib/std/target/sparc.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const CpuFeature = std.Target.Cpu.Feature;
38const CpuModel = std.Target.Cpu.Model;
lib/std/target/systemz.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const CpuFeature = std.Target.Cpu.Feature;
38const CpuModel = std.Target.Cpu.Model;
lib/std/target/wasm.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const CpuFeature = std.Target.Cpu.Feature;
38const CpuModel = std.Target.Cpu.Model;
lib/std/target/x86.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const CpuFeature = std.Target.Cpu.Feature;
38const CpuModel = std.Target.Cpu.Model;
lib/std/testing.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std.zig");
27const print = std.debug.print;
38
lib/std/testing/failing_allocator.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const mem = std.mem;
38
lib/std/thread.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std.zig");
27const builtin = std.builtin;
38const os = std.os;
lib/std/time.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std.zig");
27const builtin = std.builtin;
38const assert = std.debug.assert;
lib/std/time/epoch.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16//! Epoch reference times in terms of their difference from
27//! UTC 1970-01-01 in seconds.
38
lib/std/unicode.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("./std.zig");
27const builtin = @import("builtin");
38const assert = std.debug.assert;
lib/std/unicode/throughput_test.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const builtin = @import("builtin");
27const std = @import("std");
38
lib/std/valgrind.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const builtin = @import("builtin");
27const std = @import("std.zig");
38const math = std.math;
lib/std/valgrind/callgrind.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const valgrind = std.valgrind;
38
lib/std/valgrind/memcheck.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const testing = std.testing;
38const valgrind = std.valgrind;
lib/std/zig.zig+115-1
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std.zig");
27const tokenizer = @import("zig/tokenizer.zig");
38
......@@ -21,7 +26,7 @@ pub fn hashSrc(src: []const u8) SrcHash {
2126 std.mem.copy(u8, &out, src);
2227 std.mem.set(u8, out[src.len..], 0);
2328 } else {
24 std.crypto.Blake3.hash(src, &out);
29 std.crypto.hash.Blake3.hash(src, &out, .{});
2530 }
2631 return out;
2732}
......@@ -80,6 +85,115 @@ pub fn binNameAlloc(
8085 }
8186}
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
83197test "" {
84198 @import("std").meta.refAllDecls(@This());
85199}
lib/std/zig/ast.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const assert = std.debug.assert;
38const testing = std.testing;
lib/std/zig/cross_target.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const assert = std.debug.assert;
38const Target = std.Target;
lib/std/zig/parse.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const assert = std.debug.assert;
38const Allocator = std.mem.Allocator;
lib/std/zig/parser_test.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16test "zig fmt: convert var to anytype" {
27 // TODO remove in next release cycle
38 try testTransform(
lib/std/zig/perf_test.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std");
27const mem = std.mem;
38const warn = std.debug.warn;
lib/std/zig/render.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const assert = std.debug.assert;
38const mem = std.mem;
lib/std/zig/string_literal.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const assert = std.debug.assert;
38
lib/std/zig/system.zig+6
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const elf = std.elf;
38const mem = std.mem;
......@@ -857,6 +862,7 @@ pub const NativeTargetInfo = struct {
857862 const len = file.pread(buf[i .. buf.len - i], offset + i) catch |err| switch (err) {
858863 error.OperationAborted => unreachable, // Windows-only
859864 error.WouldBlock => unreachable, // Did not request blocking mode
865 error.NotOpenForReading => unreachable,
860866 error.SystemResources => return error.SystemResources,
861867 error.IsDir => return error.UnableToReadElfFile,
862868 error.BrokenPipe => return error.UnableToReadElfFile,
lib/std/zig/system/macos.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std");
27
38pub fn version_from_build(build: []const u8) !std.builtin.Version {
lib/std/zig/system/x86.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("std");
27const Target = std.Target;
38const CrossTarget = std.zig.CrossTarget;
lib/std/zig/tokenizer.zig+5
......@@ -1,3 +1,8 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
16const std = @import("../std.zig");
27const mem = std.mem;
38
src-self-hosted/Module.zig+412-14
......@@ -170,6 +170,9 @@ pub const Decl = struct {
170170 /// This flag is set when this Decl is added to a check_for_deletion set, and cleared
171171 /// when removed.
172172 deletion_flag: bool,
173 /// Whether the corresponding AST decl has a `pub` keyword.
174 is_pub: bool,
175
173176 /// An integer that can be checked against the corresponding incrementing
174177 /// generation field of Module. This is used to determine whether `complete` status
175178 /// represents pre- or post- re-analysis.
......@@ -320,6 +323,16 @@ pub const Fn = struct {
320323 }
321324};
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
323336pub const Scope = struct {
324337 tag: Tag,
325338
......@@ -1235,6 +1248,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
12351248 };
12361249 defer fn_type_scope.instructions.deinit(self.gpa);
12371250
1251 decl.is_pub = fn_proto.getTrailer("visib_token") != null;
12381252 const body_node = fn_proto.getTrailer("body_node") orelse
12391253 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 {
14191433 }
14201434 return type_changed;
14211435 },
1422 .VarDecl => @panic("TODO var decl"),
1423 .Comptime => @panic("TODO comptime decl"),
1436 .VarDecl => {
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 },
14241643 .Use => @panic("TODO usingnamespace decl"),
14251644 else => unreachable,
14261645 }
......@@ -1583,11 +1802,53 @@ fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void {
15831802 }
15841803 }
15851804 }
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", .{});
15861849 } else {
1587 std.debug.panic("TODO: analyzeRootSrcFile {}", .{src_decl.tag});
1850 unreachable;
15881851 }
1589 // TODO also look for global variable declarations
1590 // TODO also look for comptime blocks and exported globals
15911852 }
15921853 // Handle explicitly deleted decls from the source code. Not to be confused
15931854 // with when we delete decls because they are no longer referenced.
......@@ -1790,6 +2051,7 @@ fn allocateNewDecl(
17902051 .wasm => .{ .wasm = null },
17912052 },
17922053 .generation = 0,
2054 .is_pub = false,
17932055 };
17942056 return new_decl;
17952057}
......@@ -2209,20 +2471,46 @@ pub fn analyzeDeclRef(self: *Module, scope: *Scope, src: usize, decl: *Decl) Inn
22092471 };
22102472
22112473 const decl_tv = try decl.typedValue();
2212 const ty_payload = try scope.arena().create(Type.Payload.Pointer);
2213 ty_payload.* = .{
2214 .base = .{ .tag = .single_const_pointer },
2215 .pointee_type = decl_tv.ty,
2216 };
2474 if (decl_tv.val.tag() == .variable) {
2475 return self.analyzeVarRef(scope, src, decl_tv);
2476 }
2477 const ty = try self.simplePtrType(scope, src, decl_tv.ty, false, .One);
22172478 const val_payload = try scope.arena().create(Value.Payload.DeclRef);
22182479 val_payload.* = .{ .decl = decl };
22192480
22202481 return self.constInst(scope, src, .{
2221 .ty = Type.initPayload(&ty_payload.base),
2482 .ty = ty,
22222483 .val = Value.initPayload(&val_payload.base),
22232484 });
22242485}
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
22262514pub fn analyzeDeref(self: *Module, scope: *Scope, src: usize, ptr: *Inst, ptr_src: usize) InnerError!*Inst {
22272515 const elem_ty = switch (ptr.ty.zigTypeTag()) {
22282516 .Pointer => ptr.ty.elemType(),
......@@ -2523,7 +2811,7 @@ pub fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst
25232811
25242812 // T to ?T
25252813 if (dest_type.zigTypeTag() == .Optional) {
2526 var buf: Type.Payload.Pointer = undefined;
2814 var buf: Type.Payload.PointerSimple = undefined;
25272815 const child_type = dest_type.optionalChild(&buf);
25282816 if (child_type.eql(inst.ty)) {
25292817 return self.wrapOptional(scope, dest_type, inst);
......@@ -2902,15 +3190,125 @@ pub fn floatSub(self: *Module, scope: *Scope, float_type: Type, src: usize, lhs:
29023190 return Value.initPayload(val_payload);
29033191}
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
29063232 const type_payload = try scope.arena().create(Type.Payload.Pointer);
29073233 type_payload.* = .{
2908 .base = .{ .tag = if (mutable) .single_mut_pointer else .single_const_pointer },
29093234 .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,
29103243 };
29113244 return Type.initPayload(&type_payload.base);
29123245}
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
29143312pub fn dumpInst(self: *Module, scope: *Scope, inst: *Inst) void {
29153313 const zir_module = scope.namespace();
29163314 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) {
2020 /// The expression must generate a pointer rather than a value. For example, the left hand side
2121 /// of an assignment uses an "LValue" result location.
2222 lvalue,
23 /// The expression must generate a pointer
24 ref,
2325 /// The expression will be type coerced into this type, but it will be evaluated as an rvalue.
2426 ty: *zir.Inst,
2527 /// 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
4648
4749/// Turn Zig AST into untyped ZIR istructions.
4850pub 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 }
49177 switch (node.tag) {
50178 .Root => unreachable, // Top-level declaration.
51179 .Use => unreachable, // Top-level declaration.
......@@ -60,6 +188,7 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr
60188 .PointerIndexPayload => unreachable, // Handled explicitly.
61189 .ErrorTag => unreachable, // Handled explicitly.
62190 .FieldInitializer => unreachable, // Handled explicitly.
191 .ContainerField => unreachable, // Handled explicitly.
63192
64193 .Assign => return rlWrapVoid(mod, scope, rl, node, try assign(mod, scope, node.castTag(.Assign).?)),
65194 .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
100229 .ArrayCat => return simpleBinOp(mod, scope, rl, node.castTag(.ArrayCat).?, .array_cat),
101230 .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
103235 .Identifier => return try identifier(mod, scope, rl, node.castTag(.Identifier).?),
104236 .Asm => return rlWrap(mod, scope, rl, try assembly(mod, scope, node.castTag(.Asm).?)),
105237 .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
124256 .LabeledBlock => return labeledBlockExpr(mod, scope, rl, node.castTag(.LabeledBlock).?),
125257 .Break => return rlWrap(mod, scope, rl, try breakExpr(mod, scope, node.castTag(.Break).?)),
126258 .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
128267 .Defer => return mod.failNode(scope, node, "TODO implement astgen.expr for .Defer", .{}),
129268 .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", .{}),
132269 .ErrorUnion => return mod.failNode(scope, node, "TODO implement astgen.expr for .ErrorUnion", .{}),
133270 .MergeErrorSets => return mod.failNode(scope, node, "TODO implement astgen.expr for .MergeErrorSets", .{}),
134271 .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
139276 .NegationWrap => return mod.failNode(scope, node, "TODO implement astgen.expr for .NegationWrap", .{}),
140277 .Resume => return mod.failNode(scope, node, "TODO implement astgen.expr for .Resume", .{}),
141278 .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", .{}),
145279 .Slice => return mod.failNode(scope, node, "TODO implement astgen.expr for .Slice", .{}),
146280 .ArrayAccess => return mod.failNode(scope, node, "TODO implement astgen.expr for .ArrayAccess", .{}),
147281 .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
156290 .ErrorType => return mod.failNode(scope, node, "TODO implement astgen.expr for .ErrorType", .{}),
157291 .FnProto => return mod.failNode(scope, node, "TODO implement astgen.expr for .FnProto", .{}),
158292 .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", .{}),
163293 .ErrorSetDecl => return mod.failNode(scope, node, "TODO implement astgen.expr for .ErrorSetDecl", .{}),
164294 .ContainerDecl => return mod.failNode(scope, node, "TODO implement astgen.expr for .ContainerDecl", .{}),
165295 .Comptime => return mod.failNode(scope, node, "TODO implement astgen.expr for .Comptime", .{}),
166296 .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", .{}),
168297 }
169298}
170299
......@@ -187,7 +316,7 @@ fn breakExpr(mod: *Module, parent_scope: *Scope, node: *ast.Node.ControlFlowExpr
187316 // proper type inference requires peer type resolution on the block's
188317 // break operand expressions.
189318 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,
191320 .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = label.block_inst },
192321 };
193322 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
426555}
427556
428557fn 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);
430559}
431560
432561fn 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
440569 return addZIRUnOp(mod, scope, src, .optional_type, operand);
441570}
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
443578fn ptrType(mod: *Module, scope: *Scope, node: *ast.Node.PtrType) InnerError!*zir.Inst {
444579 const tree = scope.tree();
445580 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 {
446593 const meta_type = try addZIRInstConst(mod, scope, src, .{
447594 .ty = Type.initTag(.type),
448595 .val = Value.initTag(.type_type),
449596 });
450597
451 const simple = node.ptr_info.allowzero_token == null and
452 node.ptr_info.align_info == null and
453 node.ptr_info.volatile_token == null and
454 node.ptr_info.sentinel == null;
598 const simple = ptr_info.allowzero_token == null and
599 ptr_info.align_info == null and
600 ptr_info.volatile_token == null and
601 ptr_info.sentinel == null;
455602
456603 if (simple) {
457 const child_type = try expr(mod, scope, .{ .ty = meta_type }, node.rhs);
458 return addZIRUnOp(mod, scope, src, if (node.ptr_info.const_token == null)
459 .single_mut_ptr_type
460 else
461 .single_const_ptr_type, child_type);
604 const child_type = try expr(mod, scope, .{ .ty = meta_type }, rhs);
605 const mutable = ptr_info.const_token == null;
606 // TODO stage1 type inference bug
607 const T = zir.Inst.Tag;
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);
462614 }
463615
464616 var kw_args: std.meta.fieldInfo(zir.Inst.PtrType, "kw_args").field_type = .{};
465 kw_args.@"allowzero" = node.ptr_info.allowzero_token != null;
466 if (node.ptr_info.align_info) |some| {
617 kw_args.size = size;
618 kw_args.@"allowzero" = ptr_info.allowzero_token != null;
619 if (ptr_info.align_info) |some| {
467620 kw_args.@"align" = try expr(mod, scope, .none, some.node);
468621 if (some.bit_range) |bit_range| {
469622 kw_args.align_bit_start = try expr(mod, scope, .none, bit_range.start);
470623 kw_args.align_bit_end = try expr(mod, scope, .none, bit_range.end);
471624 }
472625 }
473 kw_args.@"const" = node.ptr_info.const_token != null;
474 kw_args.@"volatile" = node.ptr_info.volatile_token != null;
475 if (node.ptr_info.sentinel) |some| {
626 kw_args.mutable = ptr_info.const_token == null;
627 kw_args.@"volatile" = ptr_info.volatile_token != null;
628 if (ptr_info.sentinel) |some| {
476629 kw_args.sentinel = try expr(mod, scope, .none, some);
477630 }
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);
480633 if (kw_args.sentinel) |some| {
481634 kw_args.sentinel = try addZIRBinOp(mod, scope, some.src, .as, child_type, some);
482635 }
......@@ -484,13 +637,65 @@ fn ptrType(mod: *Module, scope: *Scope, node: *ast.Node.PtrType) InnerError!*zir
484637 return addZIRInst(mod, scope, src, zir.Inst.PtrType, .{ .child_type = child_type }, kw_args);
485638}
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
487692fn unwrapOptional(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.SimpleSuffixOp) InnerError!*zir.Inst {
488693 const tree = scope.tree();
489694 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);
492697 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
495700 return rlWrap(mod, scope, rl, try addZIRUnOp(mod, scope, src, .deref, unwrapped_ptr));
496701}
......@@ -568,6 +773,88 @@ fn simpleBinOp(
568773 return rlWrap(mod, scope, rl, result);
569774}
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
571858const CondKind = union(enum) {
572859 bool,
573860 optional: ?*zir.Inst,
......@@ -583,13 +870,13 @@ const CondKind = union(enum) {
583870 return try expr(mod, &block_scope.base, .{ .ty = bool_type }, cond_node);
584871 },
585872 .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);
587874 self.* = .{ .optional = cond_ptr };
588875 const result = try addZIRUnOp(mod, &block_scope.base, src, .deref, cond_ptr);
589876 return try addZIRUnOp(mod, &block_scope.base, src, .isnonnull, result);
590877 },
591878 .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);
593880 self.* = .{ .err_union = err_ptr };
594881 const result = try addZIRUnOp(mod, &block_scope.base, src, .deref, err_ptr);
595882 return try addZIRUnOp(mod, &block_scope.base, src, .iserr, result);
......@@ -600,7 +887,11 @@ const CondKind = union(enum) {
600887 fn thenSubScope(self: CondKind, mod: *Module, then_scope: *Scope.GenZIR, src: usize, payload_node: ?*ast.Node) !*Scope {
601888 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 };
604895 const is_ptr = payload.ptr_token != null;
605896 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
680971 // proper type inference requires peer type resolution on the if's
681972 // branches.
682973 const branch_rl: ResultLoc = switch (rl) {
683 .discard, .none, .ty, .ptr, .lvalue => rl,
974 .discard, .none, .ty, .ptr, .lvalue, .ref => rl,
684975 .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = block },
685976 };
686977
......@@ -810,7 +1101,7 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W
8101101 // proper type inference requires peer type resolution on the while's
8111102 // branches.
8121103 const branch_rl: ResultLoc = switch (rl) {
813 .discard, .none, .ty, .ptr, .lvalue => rl,
1104 .discard, .none, .ty, .ptr, .lvalue, .ref => rl,
8141105 .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = while_block },
8151106 };
8161107
......@@ -941,7 +1232,7 @@ fn identifier(mod: *Module, scope: *Scope, rl: ResultLoc, ident: *ast.Node.OneTo
9411232 .local_ptr => {
9421233 const local_ptr = s.cast(Scope.LocalPtr).?;
9431234 if (mem.eql(u8, local_ptr.name, ident_name)) {
944 if (rl == .lvalue) {
1235 if (rl == .lvalue or rl == .ref) {
9451236 return local_ptr.ptr;
9461237 } else {
9471238 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
9561247 }
9571248
9581249 if (mod.lookupDeclName(scope, ident_name)) |decl| {
959 // TODO handle lvalues
9601250 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));
9621254 }
9631255
9641256 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
9831275 return addZIRInst(mod, scope, src, zir.Inst.Str, .{ .bytes = bytes }, .{});
9841276}
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
9861326fn integerLiteral(mod: *Module, scope: *Scope, int_lit: *ast.Node.OneToken) InnerError!*zir.Inst {
9871327 const arena = scope.arena();
9881328 const tree = scope.tree();
......@@ -1158,7 +1498,8 @@ fn as(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.BuiltinCall) I
11581498 _ = try addZIRUnOp(mod, scope, result.src, .ensure_result_non_error, result);
11591499 return result;
11601500 },
1161 .lvalue => {
1501 .lvalue => unreachable,
1502 .ref => {
11621503 const result = try expr(mod, scope, .{ .ty = dest_type }, params[1]);
11631504 return addZIRUnOp(mod, scope, result.src, .ref, result);
11641505 },
......@@ -1209,9 +1550,10 @@ fn bitCast(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.BuiltinCa
12091550 _ = try addZIRUnOp(mod, scope, result.src, .ensure_result_non_error, result);
12101551 return result;
12111552 },
1212 .lvalue => {
1213 const operand = try expr(mod, scope, .lvalue, params[1]);
1214 const result = try addZIRBinOp(mod, scope, src, .bitcast_lvalue, dest_type, operand);
1553 .lvalue => unreachable,
1554 .ref => {
1555 const operand = try expr(mod, scope, .ref, params[1]);
1556 const result = try addZIRBinOp(mod, scope, src, .bitcast_ref, dest_type, operand);
12151557 return result;
12161558 },
12171559 .ty => |result_ty| {
......@@ -1476,7 +1818,7 @@ fn rlWrap(mod: *Module, scope: *Scope, rl: ResultLoc, result: *zir.Inst) InnerEr
14761818 _ = try addZIRUnOp(mod, scope, result.src, .ensure_result_non_error, result);
14771819 return result;
14781820 },
1479 .lvalue => {
1821 .lvalue, .ref => {
14801822 // We need a pointer but we have a value.
14811823 return addZIRUnOp(mod, scope, result.src, .ref, result);
14821824 },
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{
5959};
6060
6161pub fn generateSymbol(
62 bin_file: *link.File.Elf,
62 bin_file: *link.File,
6363 src: usize,
6464 typed_value: TypedValue,
6565 code: *std.ArrayList(u8),
6666 dbg_line: *std.ArrayList(u8),
6767 dbg_info: *std.ArrayList(u8),
68 dbg_info_type_relocs: *link.File.Elf.DbgInfoTypeRelocsTable,
68 dbg_info_type_relocs: *link.File.DbgInfoTypeRelocsTable,
6969) GenerateSymbolError!Result {
7070 const tracy = trace(@src());
7171 defer tracy.end();
7272
7373 switch (typed_value.ty.zigTypeTag()) {
7474 .Fn => {
75 switch (bin_file.base.options.target.cpu.arch) {
75 switch (bin_file.options.target.cpu.arch) {
7676 .wasm32 => unreachable, // has its own code path
7777 .wasm64 => unreachable, // has its own code path
7878 //.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(
151151 }
152152 return Result{
153153 .fail = try ErrorMsg.create(
154 bin_file.base.allocator,
154 bin_file.allocator,
155155 src,
156156 "TODO implement generateSymbol for more kinds of arrays",
157157 .{},
......@@ -164,12 +164,11 @@ pub fn generateSymbol(
164164 if (typed_value.val.cast(Value.Payload.DeclRef)) |payload| {
165165 const decl = payload.decl;
166166 if (decl.analysis != .complete) return error.AnalysisFail;
167 assert(decl.link.elf.local_sym_index != 0);
168167 // TODO handle the dependency of this symbol on the decl's vaddr.
169168 // 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;
171 const endian = bin_file.base.options.target.cpu.arch.endian();
172 switch (bin_file.base.options.target.cpu.arch.ptrBitWidth()) {
169 const vaddr = bin_file.getDeclVAddr(decl);
170 const endian = bin_file.options.target.cpu.arch.endian();
171 switch (bin_file.options.target.cpu.arch.ptrBitWidth()) {
173172 16 => {
174173 try code.resize(2);
175174 mem.writeInt(u16, code.items[0..2], @intCast(u16, vaddr), endian);
......@@ -188,7 +187,7 @@ pub fn generateSymbol(
188187 }
189188 return Result{
190189 .fail = try ErrorMsg.create(
191 bin_file.base.allocator,
190 bin_file.allocator,
192191 src,
193192 "TODO implement generateSymbol for pointer {}",
194193 .{typed_value.val},
......@@ -198,7 +197,7 @@ pub fn generateSymbol(
198197 .Int => {
199198 // 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);
202201 if (info.bits == 8 and !info.signed) {
203202 const x = typed_value.val.toUnsignedInt();
204203 try code.append(@intCast(u8, x));
......@@ -206,7 +205,7 @@ pub fn generateSymbol(
206205 }
207206 return Result{
208207 .fail = try ErrorMsg.create(
209 bin_file.base.allocator,
208 bin_file.allocator,
210209 src,
211210 "TODO implement generateSymbol for int type '{}'",
212211 .{typed_value.ty},
......@@ -216,7 +215,7 @@ pub fn generateSymbol(
216215 else => |t| {
217216 return Result{
218217 .fail = try ErrorMsg.create(
219 bin_file.base.allocator,
218 bin_file.allocator,
220219 src,
221220 "TODO implement generateSymbol for type '{}'",
222221 .{@tagName(t)},
......@@ -234,13 +233,13 @@ const InnerError = error{
234233fn Function(comptime arch: std.Target.Cpu.Arch) type {
235234 return struct {
236235 gpa: *Allocator,
237 bin_file: *link.File.Elf,
236 bin_file: *link.File,
238237 target: *const std.Target,
239238 mod_fn: *const Module.Fn,
240239 code: *std.ArrayList(u8),
241240 dbg_line: *std.ArrayList(u8),
242241 dbg_info: *std.ArrayList(u8),
243 dbg_info_type_relocs: *link.File.Elf.DbgInfoTypeRelocsTable,
242 dbg_info_type_relocs: *link.File.DbgInfoTypeRelocsTable,
244243 err_msg: ?*ErrorMsg,
245244 args: []MCValue,
246245 ret_mcv: MCValue,
......@@ -405,22 +404,22 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
405404 const Self = @This();
406405
407406 fn generateSymbol(
408 bin_file: *link.File.Elf,
407 bin_file: *link.File,
409408 src: usize,
410409 typed_value: TypedValue,
411410 code: *std.ArrayList(u8),
412411 dbg_line: *std.ArrayList(u8),
413412 dbg_info: *std.ArrayList(u8),
414 dbg_info_type_relocs: *link.File.Elf.DbgInfoTypeRelocsTable,
413 dbg_info_type_relocs: *link.File.DbgInfoTypeRelocsTable,
415414 ) GenerateSymbolError!Result {
416415 const module_fn = typed_value.val.cast(Value.Payload.Function).?.func;
417416
418417 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);
421420 defer {
422421 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);
424423 branch_stack.deinit();
425424 }
426425 const branch = try branch_stack.addOne();
......@@ -443,8 +442,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
443442 };
444443
445444 var function = Self{
446 .gpa = bin_file.base.allocator,
447 .target = &bin_file.base.options.target,
445 .gpa = bin_file.allocator,
446 .target = &bin_file.options.target,
448447 .bin_file = bin_file,
449448 .mod_fn = module_fn,
450449 .code = code,
......@@ -464,7 +463,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
464463 .rbrace_src = src_data.rbrace_src,
465464 .source = src_data.source,
466465 };
467 defer function.exitlude_jump_relocs.deinit(bin_file.base.allocator);
466 defer function.exitlude_jump_relocs.deinit(bin_file.allocator);
468467
469468 var call_info = function.resolveCallingConventionValues(src, fn_type) catch |err| switch (err) {
470469 error.CodegenFail => return Result{ .fail = function.err_msg.? },
......@@ -684,6 +683,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
684683 .unreach => return MCValue{ .unreach = {} },
685684 .unwrap_optional => return self.genUnwrapOptional(inst.castTag(.unwrap_optional).?),
686685 .wrap_optional => return self.genWrapOptional(inst.castTag(.wrap_optional).?),
686 .varptr => return self.genVarPtr(inst.castTag(.varptr).?),
687687 }
688688 }
689689
......@@ -858,6 +858,26 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
858858 }
859859 }
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
861881 fn genLoad(self: *Self, inst: *ir.Inst.UnOp) !MCValue {
862882 const elem_ty = inst.base.ty;
863883 if (!elem_ty.hasCodeGenBits())
......@@ -867,9 +887,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
867887 if (inst.base.isUnused() and !is_volatile)
868888 return MCValue.dead;
869889 const dst_mcv: MCValue = blk: {
870 if (inst.base.operandDies(0) and ptr.isMutable()) {
890 if (reuseOperand(&inst.base, 0, ptr)) {
871891 // The MCValue that holds the pointer can be re-used as the value.
872 // TODO track this in the register/stack allocation metadata.
873892 break :blk ptr;
874893 } else {
875894 break :blk try self.allocRegOrMem(&inst.base);
......@@ -966,7 +985,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
966985 var dst_mcv: MCValue = undefined;
967986 var src_mcv: MCValue = undefined;
968987 var src_inst: *ir.Inst = undefined;
969 if (inst.operandDies(0) and lhs.isMutable()) {
988 if (reuseOperand(inst, 0, lhs)) {
970989 // LHS dies; use it as the destination.
971990 // Both operands cannot be memory.
972991 src_inst = op_rhs;
......@@ -977,7 +996,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
977996 dst_mcv = lhs;
978997 src_mcv = rhs;
979998 }
980 } else if (inst.operandDies(1) and rhs.isMutable()) {
999 } else if (reuseOperand(inst, 1, rhs)) {
9811000 // RHS dies; use it as the destination.
9821001 // Both operands cannot be memory.
9831002 src_inst = op_lhs;
......@@ -1124,80 +1143,88 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
11241143 var info = try self.resolveCallingConventionValues(inst.base.src, inst.func.ty);
11251144 defer info.deinit(self);
11261145
1127 switch (arch) {
1128 .x86_64 => {
1129 for (info.args) |mc_arg, arg_i| {
1130 const arg = inst.args[arg_i];
1131 const arg_mcv = try self.resolveInst(inst.args[arg_i]);
1132 // Here we do not use setRegOrMem even though the logic is similar, because
1133 // the function call will move the stack pointer, so the offsets are different.
1134 switch (mc_arg) {
1135 .none => continue,
1136 .register => |reg| {
1137 try self.genSetReg(arg.src, reg, arg_mcv);
1138 // TODO interact with the register allocator to mark the instruction as moved.
1139 },
1140 .stack_offset => {
1141 // Here we need to emit instructions like this:
1142 // mov qword ptr [rsp + stack_offset], x
1143 return self.fail(inst.base.src, "TODO implement calling with parameters in memory", .{});
1144 },
1145 .ptr_stack_offset => {
1146 return self.fail(inst.base.src, "TODO implement calling with MCValue.ptr_stack_offset arg", .{});
1147 },
1148 .ptr_embedded_in_code => {
1149 return self.fail(inst.base.src, "TODO implement calling with MCValue.ptr_embedded_in_code arg", .{});
1150 },
1151 .undef => unreachable,
1152 .immediate => unreachable,
1153 .unreach => unreachable,
1154 .dead => unreachable,
1155 .embedded_in_code => unreachable,
1156 .memory => unreachable,
1157 .compare_flags_signed => unreachable,
1158 .compare_flags_unsigned => unreachable,
1146 // Due to incremental compilation, how function calls are generated depends
1147 // on linking.
1148 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
1149 switch (arch) {
1150 .x86_64 => {
1151 for (info.args) |mc_arg, arg_i| {
1152 const arg = inst.args[arg_i];
1153 const arg_mcv = try self.resolveInst(inst.args[arg_i]);
1154 // Here we do not use setRegOrMem even though the logic is similar, because
1155 // the function call will move the stack pointer, so the offsets are different.
1156 switch (mc_arg) {
1157 .none => continue,
1158 .register => |reg| {
1159 try self.genSetReg(arg.src, reg, arg_mcv);
1160 // TODO interact with the register allocator to mark the instruction as moved.
1161 },
1162 .stack_offset => {
1163 // Here we need to emit instructions like this:
1164 // mov qword ptr [rsp + stack_offset], x
1165 return self.fail(inst.base.src, "TODO implement calling with parameters in memory", .{});
1166 },
1167 .ptr_stack_offset => {
1168 return self.fail(inst.base.src, "TODO implement calling with MCValue.ptr_stack_offset arg", .{});
1169 },
1170 .ptr_embedded_in_code => {
1171 return self.fail(inst.base.src, "TODO implement calling with MCValue.ptr_embedded_in_code arg", .{});
1172 },
1173 .undef => unreachable,
1174 .immediate => unreachable,
1175 .unreach => unreachable,
1176 .dead => unreachable,
1177 .embedded_in_code => unreachable,
1178 .memory => unreachable,
1179 .compare_flags_signed => unreachable,
1180 .compare_flags_unsigned => unreachable,
1181 }
11591182 }
1160 }
11611183
1162 if (inst.func.cast(ir.Inst.Constant)) |func_inst| {
1163 if (func_inst.val.cast(Value.Payload.Function)) |func_val| {
1164 const func = func_val.func;
1165 const got = &self.bin_file.program_headers.items[self.bin_file.phdr_got_index.?];
1166 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
1167 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);
1169 // ff 14 25 xx xx xx xx call [addr]
1170 try self.code.ensureCapacity(self.code.items.len + 7);
1171 self.code.appendSliceAssumeCapacity(&[3]u8{ 0xff, 0x14, 0x25 });
1172 mem.writeIntLittle(u32, self.code.addManyAsArrayAssumeCapacity(4), got_addr);
1184 if (inst.func.cast(ir.Inst.Constant)) |func_inst| {
1185 if (func_inst.val.cast(Value.Payload.Function)) |func_val| {
1186 const func = func_val.func;
1187 const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];
1188 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
1189 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
1190 const got_addr = @intCast(u32, got.p_vaddr + func.owner_decl.link.elf.offset_table_index * ptr_bytes);
1191 // ff 14 25 xx xx xx xx call [addr]
1192 try self.code.ensureCapacity(self.code.items.len + 7);
1193 self.code.appendSliceAssumeCapacity(&[3]u8{ 0xff, 0x14, 0x25 });
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 }
11731198 } 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", .{});
11751200 }
1176 } else {
1177 return self.fail(inst.base.src, "TODO implement calling runtime known function pointer", .{});
1178 }
1179 },
1180 .riscv64 => {
1181 if (info.args.len > 0) return self.fail(inst.base.src, "TODO implement fn args for {}", .{self.target.cpu.arch});
1182
1183 if (inst.func.cast(ir.Inst.Constant)) |func_inst| {
1184 if (func_inst.val.cast(Value.Payload.Function)) |func_val| {
1185 const func = func_val.func;
1186 const got = &self.bin_file.program_headers.items[self.bin_file.phdr_got_index.?];
1187 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
1188 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
1189 const got_addr = @intCast(u32, got.p_vaddr + func.owner_decl.link.elf.offset_table_index * ptr_bytes);
1190
1191 try self.genSetReg(inst.base.src, .ra, .{ .memory = got_addr });
1192 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.jalr(.ra, 0, .ra).toU32());
1201 },
1202 .riscv64 => {
1203 if (info.args.len > 0) return self.fail(inst.base.src, "TODO implement fn args for {}", .{self.target.cpu.arch});
1204
1205 if (inst.func.cast(ir.Inst.Constant)) |func_inst| {
1206 if (func_inst.val.cast(Value.Payload.Function)) |func_val| {
1207 const func = func_val.func;
1208 const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];
1209 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
1210 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
1211 const got_addr = @intCast(u32, got.p_vaddr + func.owner_decl.link.elf.offset_table_index * ptr_bytes);
1212
1213 try self.genSetReg(inst.base.src, .ra, .{ .memory = got_addr });
1214 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.jalr(.ra, 0, .ra).toU32());
1215 } else {
1216 return self.fail(inst.base.src, "TODO implement calling bitcasted functions", .{});
1217 }
11931218 } 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", .{});
11951220 }
1196 } else {
1197 return self.fail(inst.base.src, "TODO implement calling runtime known function pointer", .{});
1198 }
1199 },
1200 else => return self.fail(inst.base.src, "TODO implement call for {}", .{self.target.cpu.arch}),
1221 },
1222 else => return self.fail(inst.base.src, "TODO implement call for {}", .{self.target.cpu.arch}),
1223 }
1224 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
1225 return self.fail(inst.base.src, "TODO implement codegen for call when linking with MachO", .{});
1226 } else {
1227 unreachable;
12011228 }
12021229
12031230 return info.return_value;
......@@ -2016,10 +2043,14 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
20162043 switch (typed_value.ty.zigTypeTag()) {
20172044 .Pointer => {
20182045 if (typed_value.val.cast(Value.Payload.DeclRef)) |payload| {
2019 const got = &self.bin_file.program_headers.items[self.bin_file.phdr_got_index.?];
2020 const decl = payload.decl;
2021 const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes;
2022 return MCValue{ .memory = got_addr };
2046 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
2047 const decl = payload.decl;
2048 const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];
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 }
20232054 }
20242055 return self.fail(src, "TODO codegen more kinds of const pointers", .{});
20252056 },
......@@ -2040,7 +2071,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
20402071 if (typed_value.val.isNull())
20412072 return MCValue{ .immediate = 0 };
20422073
2043 var buf: Type.Payload.Pointer = undefined;
2074 var buf: Type.Payload.PointerSimple = undefined;
20442075 return self.genTypedValue(src, .{
20452076 .ty = typed_value.ty.optionalChild(&buf),
20462077 .val = typed_value.val,
......@@ -2147,7 +2178,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
21472178
21482179 /// TODO support scope overrides. Also note this logic is duplicated with `Module.wantSafety`.
21492180 fn wantSafety(self: *Self) bool {
2150 return switch (self.bin_file.base.options.optimize_mode) {
2181 return switch (self.bin_file.options.optimize_mode) {
21512182 .Debug => true,
21522183 .ReleaseSafe => true,
21532184 .ReleaseFast => false,
......@@ -2158,7 +2189,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
21582189 fn fail(self: *Self, src: usize, comptime format: []const u8, args: anytype) InnerError {
21592190 @setCold(true);
21602191 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);
21622193 return error.CodegenFail;
21632194 }
21642195
src-self-hosted/codegen/wasm.zig+59-37
......@@ -62,58 +62,80 @@ pub fn genCode(buf: *ArrayList(u8), decl: *Decl) !void {
6262 // TODO: check for and handle death of instructions
6363 const tv = decl.typed_value.most_recent.typed_value;
6464 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
6767 // Write 'end' opcode
6868 try writer.writeByte(0x0B);
6969
7070 // Fill in the size of the generated code to the reserved space at the
7171 // 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));
7374}
7475
75fn genInst(writer: ArrayList(u8).Writer, inst: *Inst) !void {
76fn genInst(buf: *ArrayList(u8), decl: *Decl, inst: *Inst) !void {
7677 return switch (inst.tag) {
78 .call => genCall(buf, decl, inst.castTag(.call).?),
79 .constant => genConstant(buf, decl, inst.castTag(.constant).?),
7780 .dbg_stmt => {},
78 .ret => genRet(writer, inst.castTag(.ret).?),
81 .ret => genRet(buf, decl, inst.castTag(.ret).?),
82 .retvoid => {},
7983 else => error.TODOImplementMoreWasmCodegen,
8084 };
8185}
8286
83fn genRet(writer: ArrayList(u8).Writer, inst: *Inst.UnOp) !void {
84 switch (inst.operand.tag) {
85 .constant => {
86 const constant = inst.operand.castTag(.constant).?;
87 switch (inst.operand.ty.tag()) {
88 .u32 => {
89 try writer.writeByte(0x41); // i32.const
90 try leb.writeILEB128(writer, constant.val.toUnsignedInt());
91 },
92 .i32 => {
93 try writer.writeByte(0x41); // i32.const
94 try leb.writeILEB128(writer, constant.val.toSignedInt());
95 },
96 .u64 => {
97 try writer.writeByte(0x42); // i64.const
98 try leb.writeILEB128(writer, constant.val.toUnsignedInt());
99 },
100 .i64 => {
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 }
87fn genConstant(buf: *ArrayList(u8), decl: *Decl, inst: *Inst.Constant) !void {
88 const writer = buf.writer();
89 switch (inst.base.ty.tag()) {
90 .u32 => {
91 try writer.writeByte(0x41); // i32.const
92 try leb.writeILEB128(writer, inst.val.toUnsignedInt());
93 },
94 .i32 => {
95 try writer.writeByte(0x41); // i32.const
96 try leb.writeILEB128(writer, inst.val.toSignedInt());
97 },
98 .u64 => {
99 try writer.writeByte(0x42); // i64.const
100 try leb.writeILEB128(writer, inst.val.toUnsignedInt());
101 },
102 .i64 => {
103 try writer.writeByte(0x42); // i64.const
104 try leb.writeILEB128(writer, inst.val.toSignedInt());
116105 },
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 => {},
117117 else => return error.TODOImplementMoreWasmCodegen,
118118 }
119119}
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 {
8787 return fs.getAppDataDir(allocator, appname);
8888}
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
9097var compiler_id_mutex = std.Mutex{};
9198var compiler_id: [16]u8 = undefined;
9299var compiler_id_computed = false;
......@@ -99,11 +106,7 @@ pub fn resolveCompilerId(gpa: *mem.Allocator) ![16]u8 {
99106 return compiler_id;
100107 compiler_id_computed = true;
101108
102 const global_cache_dir = try resolveGlobalCacheDir(gpa);
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, .{});
109 var cache_dir = try openGlobalCacheDir();
107110 defer cache_dir.close();
108111
109112 var ch = try CacheHash.init(gpa, cache_dir, "exe");
src-self-hosted/ir.zig+21
......@@ -42,6 +42,11 @@ pub const Inst = struct {
4242 return @truncate(u1, self.deaths >> index) != 0;
4343 }
4444
45 pub fn clearOperandDeath(self: *Inst, index: DeathsBitIndex) void {
46 assert(index < deaths_bits);
47 self.deaths &= ~(@as(DeathsInt, 1) << index);
48 }
49
4550 pub fn specialOperandDeaths(self: Inst) bool {
4651 return (self.deaths & (1 << deaths_bits)) != 0;
4752 }
......@@ -76,6 +81,7 @@ pub const Inst = struct {
7681 ref,
7782 ret,
7883 retvoid,
84 varptr,
7985 /// Write a value to a pointer. LHS is pointer, RHS is value.
8086 store,
8187 sub,
......@@ -130,6 +136,7 @@ pub const Inst = struct {
130136 .condbr => CondBr,
131137 .constant => Constant,
132138 .loop => Loop,
139 .varptr => VarPtr,
133140 };
134141 }
135142
......@@ -429,6 +436,20 @@ pub const Inst = struct {
429436 return null;
430437 }
431438 };
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 };
432453};
433454
434455pub const Body = struct {
src-self-hosted/link.zig+36-2686
......@@ -1,28 +1,10 @@
11const std = @import("std");
2const mem = std.mem;
3const assert = std.debug.assert;
42const Allocator = std.mem.Allocator;
5const ir = @import("ir.zig");
63const Module = @import("Module.zig");
74const 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;
135const trace = @import("tracy.zig").trace;
14const leb128 = std.debug.leb;
156const Package = @import("Package.zig");
16const Value = @import("value.zig").Value;
177const 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
279pub const Options = struct {
2810 target: std.Target,
......@@ -40,8 +22,12 @@ pub const Options = struct {
4022 program_code_size_hint: u64 = 256 * 1024,
4123};
4224
43
4425pub const File = struct {
26 tag: Tag,
27 options: Options,
28 file: ?fs.File,
29 allocator: *Allocator,
30
4531 pub const LinkBlock = union {
4632 elf: Elf.TextBlock,
4733 macho: MachO.TextBlock,
......@@ -56,16 +42,24 @@ pub const File = struct {
5642 wasm: ?Wasm.FnData,
5743 };
5844
59 tag: Tag,
60 options: Options,
61 file: ?fs.File,
62 allocator: *Allocator,
45 /// For DWARF .debug_info.
46 pub const DbgInfoTypeRelocsTable = std.HashMapUnmanaged(Type, DbgInfoTypeReloc, Type.hash, Type.eql, true);
47
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
6458 /// Attempts incremental linking, if the file already exists. If
6559 /// incremental linking fails, falls back to truncating the file and
6660 /// rewriting it. A malicious file is detected as incremental link failure
6761 /// 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 {
6963 switch (options.object_format) {
7064 .unknown => unreachable,
7165 .coff => return error.TODOImplementCoff,
......@@ -110,6 +104,8 @@ pub const File = struct {
110104 }
111105 }
112106
107 /// May be called before or after updateDeclExports but must be called
108 /// after allocateDeclIndexes for any given Decl.
113109 pub fn updateDecl(base: *File, module: *Module, decl: *Module.Decl) !void {
114110 switch (base.tag) {
115111 .elf => return @fieldParentPtr(Elf, "base", base).updateDecl(module, decl),
......@@ -127,6 +123,8 @@ pub const File = struct {
127123 }
128124 }
129125
126 /// Must be called before any call to updateDecl or updateDeclExports for
127 /// any given Decl.
130128 pub fn allocateDeclIndexes(base: *File, decl: *Module.Decl) !void {
131129 switch (base.tag) {
132130 .elf => return @fieldParentPtr(Elf, "base", base).allocateDeclIndexes(decl),
......@@ -200,7 +198,8 @@ pub const File = struct {
200198 };
201199 }
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.
204203 pub fn updateDeclExports(
205204 base: *File,
206205 module: *Module,
......@@ -215,6 +214,15 @@ pub const File = struct {
215214 }
216215 }
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
218226 pub const Tag = enum {
219227 elf,
220228 macho,
......@@ -226,2670 +234,12 @@ pub const File = struct {
226234 no_entry_point_found: bool = false,
227235 };
228236
229 pub const C = struct {
230 pub const base_tag: Tag = .c;
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
237 pub const C = @import("link/C.zig");
238 pub const Elf = @import("link/Elf.zig");
2851239 pub const MachO = @import("link/MachO.zig");
2852 const Wasm = @import("link/Wasm.zig");
240 pub const Wasm = @import("link/Wasm.zig");
2853241};
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
2893243pub fn determineMode(options: Options) fs.File.Mode {
2894244 // On common systems with a 0o022 umask, 0o777 will still result in a file created
2895245 // 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");
44const Allocator = std.mem.Allocator;
55const assert = std.debug.assert;
66const fs = std.fs;
7const log = std.log.scoped(.link);
8const macho = std.macho;
9const math = std.math;
10const mem = std.mem;
711
812const Module = @import("../Module.zig");
913const link = @import("../link.zig");
1014const File = link.File;
1115
12pub const base_tag: Tag = File.Tag.macho;
16pub const base_tag: File.Tag = File.Tag.macho;
1317
1418base: 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
1630error_flags: File.ErrorFlags = File.ErrorFlags{},
1731
1832pub const TextBlock = struct {
......@@ -67,15 +81,120 @@ fn openFile(allocator: *Allocator, file: fs.File, options: link.Options) !MachO
6781/// Returns an error if `file` is not already open with +read +write +seek abilities.
6882fn createFile(allocator: *Allocator, file: fs.File, options: link.Options) !MachO {
6983 switch (options.output_mode) {
70 .Exe => return error.TODOImplementWritingMachOExeFiles,
71 .Obj => return error.TODOImplementWritingMachOObjFiles,
84 .Exe => {},
85 .Obj => {},
7286 .Lib => return error.TODOImplementWritingLibFiles,
7387 }
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);
74169}
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
80199pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void {}
81200
......@@ -91,3 +210,7 @@ pub fn updateDeclExports(
91210) !void {}
92211
93212pub 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 {
3232pub const base_tag = link.File.Tag.wasm;
3333
3434pub 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 }) = .{},
3642};
3743
3844base: link.File,
3945
40types: Types,
41funcs: Funcs,
42exports: Exports,
43
44/// Array over the section structs used in the various sections above to
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,
46/// List of all function Decls to be written to the output file. The index of
47/// each Decl in this list at the time of writing the binary is used as the
48/// function index.
49/// TODO: can/should we access some data structure in Module directly?
50funcs: std.ArrayListUnmanaged(*Module.Decl) = .{},
4851
4952pub fn openPath(allocator: *Allocator, dir: fs.Dir, sub_path: []const u8, options: link.Options) !*link.File {
5053 assert(options.object_format == .wasm);
......@@ -58,10 +61,6 @@ pub fn openPath(allocator: *Allocator, dir: fs.Dir, sub_path: []const u8, option
5861
5962 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
6564 wasm.* = .{
6665 .base = .{
6766 .tag = .wasm,
......@@ -69,52 +68,42 @@ pub fn openPath(allocator: *Allocator, dir: fs.Dir, sub_path: []const u8, option
6968 .file = file,
7069 .allocator = allocator,
7170 },
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 },
8471 };
8572
86 try file.setEndPos(offset + 4 * size);
87
8873 return &wasm.base;
8974}
9075
9176pub fn deinit(self: *Wasm) void {
92 self.types.deinit();
93 self.funcs.deinit();
77 for (self.funcs.items) |decl| {
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);
9483}
9584
85// Generate code for the Decl, storing it in memory to be later written to
86// the file on flush().
9687pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void {
9788 if (decl.typed_value.most_recent.typed_value.ty.zigTypeTag() != .Fn)
9889 return error.TODOImplementNonFnDeclsForWasm;
9990
100 if (decl.fn_link.wasm) |fn_data| {
101 self.funcs.free(fn_data.funcidx);
102 }
103
104 var buf = std.ArrayList(u8).init(self.base.allocator);
105 defer buf.deinit();
106
107 try codegen.genFunctype(&buf, decl);
108 const typeidx = try self.types.new(buf.items);
109 buf.items.len = 0;
110
111 try codegen.genCode(&buf, decl);
112 const funcidx = try self.funcs.new(typeidx, buf.items);
113
114 decl.fn_link.wasm = .{ .funcidx = funcidx };
115
116 // TODO: we should be more smart and set this only when needed
117 self.exports.dirty = true;
91 if (decl.fn_link.wasm) |*fn_data| {
92 fn_data.functype.items.len = 0;
93 fn_data.code.items.len = 0;
94 fn_data.idx_refs.items.len = 0;
95 } else {
96 decl.fn_link.wasm = .{};
97 try self.funcs.append(self.base.allocator, decl);
98 }
99 const fn_data = &decl.fn_link.wasm.?;
100
101 var managed_functype = fn_data.functype.toManaged(self.base.allocator);
102 var managed_code = fn_data.code.toManaged(self.base.allocator);
103 try codegen.genFunctype(&managed_functype, decl);
104 try codegen.genCode(&managed_code, decl);
105 fn_data.functype = managed_functype.toUnmanaged();
106 fn_data.code = managed_code.toUnmanaged();
118107}
119108
120109pub fn updateDeclExports(
......@@ -122,332 +111,141 @@ pub fn updateDeclExports(
122111 module: *Module,
123112 decl: *const Module.Decl,
124113 exports: []const *Module.Export,
125) !void {
126 self.exports.dirty = true;
127}
114) !void {}
128115
129116pub fn freeDecl(self: *Wasm, decl: *Module.Decl) void {
130117 // TODO: remove this assert when non-function Decls are implemented
131118 assert(decl.typed_value.most_recent.typed_value.ty.zigTypeTag() == .Fn);
132 if (decl.fn_link.wasm) |fn_data| {
133 self.funcs.free(fn_data.funcidx);
134 decl.fn_link.wasm = null;
135 }
119 _ = self.funcs.swapRemove(self.getFuncidx(decl).?);
120 decl.fn_link.wasm.?.functype.deinit(self.base.allocator);
121 decl.fn_link.wasm.?.code.deinit(self.base.allocator);
122 decl.fn_link.wasm.?.idx_refs.deinit(self.base.allocator);
123 decl.fn_link.wasm = null;
136124}
137125
138126pub fn flush(self: *Wasm, module: *Module) !void {
139 if (self.exports.dirty) try self.exports.writeAll(module);
140}
141
142/// This struct describes the location of a named section + custom section
143/// padding in the output file. This is all the data we need to allow for
144/// shifting sections around when padding runs out.
145const Section = struct {
146 /// The size of a section header: 1 byte section id + 5 bytes
147 /// for the fixed-width ULEB128 encoded contents size.
148 const header_size = 1 + 5;
149 /// Offset of the section id byte from the start of the file.
150 offset: u64,
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 }
127 const file = self.base.file.?;
128 const header_size = 5 + 1;
129
130 // No need to rewrite the magic/version header
131 try file.setEndPos(@sizeOf(@TypeOf(spec.magic ++ spec.version)));
132 try file.seekTo(@sizeOf(@TypeOf(spec.magic ++ spec.version)));
133
134 // Type section
135 {
136 const header_offset = try reserveVecSectionHeader(file);
137 for (self.funcs.items) |decl| {
138 try file.writeAll(decl.fn_link.wasm.?.functype.items);
246139 }
247
248 // TODO: We can be more efficient if we special-case one or
249 // more consecutive dead entries at the end of the vector.
250
251 // We failed to find a dead entry to reuse, so write the new
252 // entry to the end of the section.
253 try self.section.resize(file, self.contents_size, self.contents_size + @intCast(u32, data.len));
254 try file.pwriteAll(data, self.section.offset + Section.header_size + self.contents_size);
255 try self.entries.append(allocator, .{
256 .offset = self.contents_size,
257 .size = @intCast(u32, data.len),
258 });
259 self.contents_size += @intCast(u32, data.len);
260 // Make sure the dead list always has enough space to store all free'd
261 // entries. This makes it so that delEntry() cannot fail.
262 // TODO: figure out a better way that doesn't waste as much memory
263 try self.dead_list.ensureCapacity(allocator, self.entries.items.len);
264
265 // Update the size in the section header and the item count of
266 // the contents vector.
267 var size_and_count: [10]u8 = undefined;
268 leb.writeUnsignedFixed(5, size_and_count[0..5], self.contents_size);
269 leb.writeUnsignedFixed(5, size_and_count[5..], @intCast(u32, self.entries.items.len));
270 try file.pwriteAll(&size_and_count, self.section.offset + 1);
271
272 return @intCast(u32, self.entries.items.len - 1);
273 }
274
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;
140 try writeVecSectionHeader(
141 file,
142 header_offset,
143 spec.types_id,
144 @intCast(u32, (try file.getPos()) - header_offset - header_size),
145 @intCast(u32, self.funcs.items.len),
146 );
147 }
148
149 // Function section
150 {
151 const header_offset = try reserveVecSectionHeader(file);
152 const writer = file.writer();
153 for (self.funcs.items) |_, typeidx| try leb.writeULEB128(writer, @intCast(u32, typeidx));
154 try writeVecSectionHeader(
155 file,
156 header_offset,
157 spec.funcs_id,
158 @intCast(u32, (try file.getPos()) - header_offset - header_size),
159 @intCast(u32, self.funcs.items.len),
160 );
161 }
162
163 // Export section
164 {
165 const header_offset = try reserveVecSectionHeader(file);
166 const writer = file.writer();
167 var count: u32 = 0;
398168 for (module.decl_exports.entries.items) |entry| {
399 for (entry.value) |e| {
400 export_count += 1;
401 new_contents_size += calcSize(e);
169 for (entry.value) |exprt| {
170 // Export name length + name
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;
402185 }
403186 }
404 if (new_contents_size != self.contents_size) {
405 try self.exportsec.resize(file, self.contents_size, new_contents_size);
406 leb.writeUnsignedFixed(5, &buf, new_contents_size);
407 try file.pwriteAll(&buf, self.exportsec.offset + 1);
408 }
409
410 try file.seekTo(self.exportsec.offset + Section.header_size);
187 try writeVecSectionHeader(
188 file,
189 header_offset,
190 spec.exports_id,
191 @intCast(u32, (try file.getPos()) - header_offset - header_size),
192 count,
193 );
194 }
195
196 // Code section
197 {
198 const header_offset = try reserveVecSectionHeader(file);
411199 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 vec
414 leb.writeUnsignedFixed(5, &buf, export_count);
415 try writer.writeAll(&buf);
416
417 for (module.decl_exports.entries.items) |entry|
418 for (entry.value) |e| try writeExport(writer, e);
419
420 self.dirty = false;
216 try writer.writeAll(fn_data.code.items[current..]);
217 }
218 try writeVecSectionHeader(
219 file,
220 header_offset,
221 spec.code_id,
222 @intCast(u32, (try file.getPos()) - header_offset - header_size),
223 @intCast(u32, self.funcs.items.len),
224 );
421225 }
226}
422227
423 /// Return the total number of bytes an export will take.
424 /// TODO: fixed-width LEB128 is currently used for simplicity, but should
425 /// be replaced with proper variable-length LEB128 as it is inefficient.
426 fn calcSize(e: *Module.Export) u32 {
427 // LEB128 name length + name bytes + export type + LEB128 index
428 return 5 + @intCast(u32, e.options.name.len) + 1 + 5;
429 }
228/// Get the current index of a given Decl in the function list
229/// TODO: we could maintain a hash map to potentially make this
230fn getFuncidx(self: Wasm, decl: *Module.Decl) ?u32 {
231 return for (self.funcs.items) |func, idx| {
232 if (func == decl) break @intCast(u32, idx);
233 } else null;
234}
430235
431 /// Write the data for a single export to the given file at a given offset.
432 /// TODO: fixed-width LEB128 is currently used for simplicity, but should
433 /// be replaced with proper variable-length LEB128 as it is inefficient.
434 fn writeExport(writer: anytype, e: *Module.Export) !void {
435 var buf: [5]u8 = undefined;
436
437 // Export name length + name
438 leb.writeUnsignedFixed(5, &buf, @intCast(u32, e.options.name.len));
439 try writer.writeAll(&buf);
440 try writer.writeAll(e.options.name);
441
442 switch (e.exported_decl.typed_value.most_recent.typed_value.ty.zigTypeTag()) {
443 .Fn => {
444 // Type of the export
445 try writer.writeByte(0x00);
446 // Exported function index
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};
236fn reserveVecSectionHeader(file: fs.File) !u64 {
237 // section id + fixed leb contents size + fixed leb vector length
238 const header_size = 1 + 5 + 5;
239 // TODO: this should be a single lseek(2) call, but fs.File does not
240 // currently provide a way to do this.
241 try file.seekBy(header_size);
242 return (try file.getPos()) - header_size;
243}
244
245fn writeVecSectionHeader(file: fs.File, offset: u64, section: u8, size: u32, items: u32) !void {
246 var buf: [1 + 5 + 5]u8 = undefined;
247 buf[0] = section;
248 leb.writeUnsignedFixed(5, buf[1..6], size);
249 leb.writeUnsignedFixed(5, buf[6..], items);
250 try file.pwriteAll(&buf, offset);
251}
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{
742742 LinkQuotaExceeded,
743743 FileBusy,
744744 EndOfStream,
745 NotOpenForWriting,
745746} || fs.File.OpenError;
746747
747748fn 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(
807808 const source_code = source_file.readAllAlloc(fmt.gpa, stat.size, max_src_size) catch |err| switch (err) {
808809 error.ConnectionResetByPeer => unreachable,
809810 error.ConnectionTimedOut => unreachable,
811 error.NotOpenForReading => unreachable,
810812 else => |e| return e,
811813 };
812814 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 {
153153 const c_out_stream = std.io.cOutStream(output_file);
154154 _ = std.zig.render(std.heap.c_allocator, c_out_stream, tree) catch |e| switch (e) {
155155 error.WouldBlock => unreachable, // stage1 opens stuff in exclusively blocking mode
156 error.NotOpenForWriting => unreachable,
156157 error.SystemResources => return .SystemResources,
157158 error.OperationAborted => return .OperationAborted,
158159 error.BrokenPipe => return .BrokenPipe,
......@@ -611,6 +612,8 @@ export fn stage2_libc_parse(stage1_libc: *Stage2LibCInstallation, libc_file_z: [
611612 error.SystemResources => return .SystemResources,
612613 error.OperationAborted => return .OperationAborted,
613614 error.WouldBlock => unreachable,
615 error.NotOpenForWriting => unreachable,
616 error.NotOpenForReading => unreachable,
614617 error.Unexpected => return .Unexpected,
615618 error.EndOfStream => return .EndOfFile,
616619 error.IsDir => return .IsDir,
......@@ -666,6 +669,7 @@ export fn stage2_libc_render(stage1_libc: *Stage2LibCInstallation, output_file:
666669 const c_out_stream = std.io.cOutStream(output_file);
667670 libc.render(c_out_stream) catch |err| switch (err) {
668671 error.WouldBlock => unreachable, // stage1 opens stuff in exclusively blocking mode
672 error.NotOpenForWriting => unreachable,
669673 error.SystemResources => return .SystemResources,
670674 error.OperationAborted => return .OperationAborted,
671675 error.BrokenPipe => return .BrokenPipe,
src-self-hosted/test.zig+1-1
......@@ -10,7 +10,7 @@ const enable_wine: bool = build_options.enable_wine;
1010const enable_wasmtime: bool = build_options.enable_wasmtime;
1111const 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
1515test "self-hosted" {
1616 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 {
498498 _ = try transRecordDecl(c, @ptrCast(*const ZigClangRecordDecl, decl));
499499 },
500500 .Var => {
501 return visitVarDecl(c, @ptrCast(*const ZigClangVarDecl, decl));
501 return visitVarDecl(c, @ptrCast(*const ZigClangVarDecl, decl), null);
502502 },
503503 .Empty => {
504504 // Do nothing
......@@ -679,12 +679,13 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void {
679679 return addTopLevelDecl(c, fn_name, &proto_node.base);
680680}
681681
682fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {
683 const var_name = try c.str(ZigClangNamedDecl_getName_bytes_begin(@ptrCast(*const ZigClangNamedDecl, var_decl)));
682/// if mangled_name is not null, this var decl was declared in a block scope.
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)));
684685 if (c.global_scope.sym_table.contains(var_name))
685686 return; // Avoid processing this decl twice
686687 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
689690 const thread_local_token = if (ZigClangVarDecl_getTLSKind(var_decl) == .None)
690691 null
......@@ -701,8 +702,14 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {
701702 const qual_type = ZigClangVarDecl_getTypeSourceInfo_getType(var_decl);
702703 const storage_class = ZigClangVarDecl_getStorageClass(var_decl);
703704 const is_const = ZigClangQualType_isConstQualified(qual_type);
704
705 const extern_tok = if (storage_class == .Extern)
705 const has_init = ZigClangVarDecl_hasInit(var_decl);
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)
706713 try appendToken(c, .Keyword_extern, "extern")
707714 else if (storage_class != .Static)
708715 try appendToken(c, .Keyword_export, "export")
......@@ -730,7 +737,7 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {
730737 // If the initialization expression is not present, initialize with undefined.
731738 // If it is an integer literal, we can skip the @as since it will be redundant
732739 // with the variable type.
733 if (ZigClangVarDecl_hasInit(var_decl)) {
740 if (has_init) {
734741 eq_tok = try appendToken(c, .Equal, "=");
735742 init_node = if (ZigClangVarDecl_getInit(var_decl)) |expr|
736743 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 {
745752 try transCreateNodeUndefinedLiteral(c);
746753 } else if (storage_class != .Extern) {
747754 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;
749771 }
750772
751773 const linksection_expr = blk: {
......@@ -1561,15 +1583,22 @@ fn transDeclStmtOne(
15611583 .Var => {
15621584 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");
15681586 const qual_type = ZigClangVarDecl_getTypeSourceInfo_getType(var_decl);
15691587 const name = try c.str(ZigClangNamedDecl_getName_bytes_begin(
15701588 @ptrCast(*const ZigClangNamedDecl, var_decl),
15711589 ));
15721590 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
15731602 const mut_tok = if (ZigClangQualType_isConstQualified(qual_type))
15741603 try appendToken(c, .Keyword_const, "const")
15751604 else
......@@ -1597,7 +1626,6 @@ fn transDeclStmtOne(
15971626 .mut_token = mut_tok,
15981627 .semicolon_token = semicolon_token,
15991628 }, .{
1600 .thread_local_token = thread_local_token,
16011629 .eq_token = eq_token,
16021630 .type_node = type_node,
16031631 .init_node = init_node,
src-self-hosted/type.zig+516-55
......@@ -65,16 +65,25 @@ pub const Type = extern union {
6565 .fn_ccc_void_no_args => return .Fn,
6666 .function => return .Fn,
6767
68 .array, .array_u8_sentinel_0 => return .Array,
69 .single_const_pointer => return .Pointer,
70 .single_mut_pointer => return .Pointer,
71 .single_const_pointer_to_comptime_int => return .Pointer,
72 .const_slice_u8 => return .Pointer,
68 .array, .array_u8_sentinel_0, .array_u8, .array_sentinel => return .Array,
69 .single_const_pointer_to_comptime_int,
70 .const_slice_u8,
71 .single_const_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
7482 .optional,
7583 .optional_single_const_pointer,
7684 .optional_single_mut_pointer,
7785 => return .Optional,
86 .enum_literal => return .EnumLiteral,
7887 }
7988 }
8089
......@@ -107,13 +116,19 @@ pub const Type = extern union {
107116 return @fieldParentPtr(T, "base", self.ptr_otherwise);
108117 }
109118
110 pub fn castPointer(self: Type) ?*Payload.Pointer {
119 pub fn castPointer(self: Type) ?*Payload.PointerSimple {
111120 return switch (self.tag()) {
112121 .single_const_pointer,
113122 .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,
114129 .optional_single_const_pointer,
115130 .optional_single_mut_pointer,
116 => @fieldParentPtr(Payload.Pointer, "base", self.ptr_otherwise),
131 => @fieldParentPtr(Payload.PointerSimple, "base", self.ptr_otherwise),
117132 else => null,
118133 };
119134 }
......@@ -127,6 +142,7 @@ pub const Type = extern union {
127142 if (zig_tag_a != zig_tag_b)
128143 return false;
129144 switch (zig_tag_a) {
145 .EnumLiteral => return true,
130146 .Type => return true,
131147 .Void => return true,
132148 .Bool => return true,
......@@ -196,8 +212,8 @@ pub const Type = extern union {
196212 return true;
197213 },
198214 .Optional => {
199 var buf_a: Payload.Pointer = undefined;
200 var buf_b: Payload.Pointer = undefined;
215 var buf_a: Payload.PointerSimple = undefined;
216 var buf_b: Payload.PointerSimple = undefined;
201217 return a.optionalChild(&buf_a).eql(b.optionalChild(&buf_b));
202218 },
203219 .Float,
......@@ -211,7 +227,6 @@ pub const Type = extern union {
211227 .Frame,
212228 .AnyFrame,
213229 .Vector,
214 .EnumLiteral,
215230 => std.debug.panic("TODO implement Type equality comparison of {} and {}", .{ a, b }),
216231 }
217232 }
......@@ -262,7 +277,7 @@ pub const Type = extern union {
262277 }
263278 },
264279 .Optional => {
265 var buf: Payload.Pointer = undefined;
280 var buf: Payload.PointerSimple = undefined;
266281 std.hash.autoHash(&hasher, self.optionalChild(&buf).hash());
267282 },
268283 .Float,
......@@ -327,9 +342,11 @@ pub const Type = extern union {
327342 .fn_ccc_void_no_args,
328343 .single_const_pointer_to_comptime_int,
329344 .const_slice_u8,
345 .enum_literal,
330346 => unreachable,
331347
332348 .array_u8_sentinel_0 => return self.copyPayloadShallow(allocator, Payload.Array_u8_Sentinel0),
349 .array_u8 => return self.copyPayloadShallow(allocator, Payload.Array_u8),
333350 .array => {
334351 const payload = @fieldParentPtr(Payload.Array, "base", self.ptr_otherwise);
335352 const new_payload = try allocator.create(Payload.Array);
......@@ -340,6 +357,17 @@ pub const Type = extern union {
340357 };
341358 return Type{ .ptr_otherwise = &new_payload.base };
342359 },
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 },
343371 .int_signed => return self.copyPayloadShallow(allocator, Payload.IntSigned),
344372 .int_unsigned => return self.copyPayloadShallow(allocator, Payload.IntUnsigned),
345373 .function => {
......@@ -360,9 +388,34 @@ pub const Type = extern union {
360388 .optional => return self.copyPayloadSingleField(allocator, Payload.Optional, "child_type"),
361389 .single_const_pointer,
362390 .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,
363397 .optional_single_mut_pointer,
364398 .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 },
366419 }
367420 }
368421
......@@ -425,6 +478,7 @@ pub const Type = extern union {
425478 .noreturn,
426479 => return out_stream.writeAll(@tagName(t)),
427480
481 .enum_literal => return out_stream.writeAll("@TypeOf(.EnumLiteral)"),
428482 .@"null" => return out_stream.writeAll("@TypeOf(null)"),
429483 .@"undefined" => return out_stream.writeAll("@TypeOf(undefined)"),
430484
......@@ -442,9 +496,14 @@ pub const Type = extern union {
442496 try param_type.format("", .{}, out_stream);
443497 }
444498 try out_stream.writeAll(") ");
445 try payload.return_type.format("", .{}, out_stream);
499 ty = payload.return_type;
500 continue;
446501 },
447502
503 .array_u8 => {
504 const payload = @fieldParentPtr(Payload.Array_u8, "base", ty.ptr_otherwise);
505 return out_stream.print("[{}]u8", .{payload.len});
506 },
448507 .array_u8_sentinel_0 => {
449508 const payload = @fieldParentPtr(Payload.Array_u8_Sentinel0, "base", ty.ptr_otherwise);
450509 return out_stream.print("[{}:0]u8", .{payload.len});
......@@ -455,18 +514,60 @@ pub const Type = extern union {
455514 ty = payload.elem_type;
456515 continue;
457516 },
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 },
458523 .single_const_pointer => {
459 const payload = @fieldParentPtr(Payload.Pointer, "base", ty.ptr_otherwise);
524 const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise);
460525 try out_stream.writeAll("*const ");
461526 ty = payload.pointee_type;
462527 continue;
463528 },
464529 .single_mut_pointer => {
465 const payload = @fieldParentPtr(Payload.Pointer, "base", ty.ptr_otherwise);
530 const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise);
466531 try out_stream.writeAll("*");
467532 ty = payload.pointee_type;
468533 continue;
469534 },
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 },
470571 .int_signed => {
471572 const payload = @fieldParentPtr(Payload.IntSigned, "base", ty.ptr_otherwise);
472573 return out_stream.print("i{}", .{payload.bits});
......@@ -482,17 +583,45 @@ pub const Type = extern union {
482583 continue;
483584 },
484585 .optional_single_const_pointer => {
485 const payload = @fieldParentPtr(Payload.Pointer, "base", ty.ptr_otherwise);
586 const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise);
486587 try out_stream.writeAll("?*const ");
487588 ty = payload.pointee_type;
488589 continue;
489590 },
490591 .optional_single_mut_pointer => {
491 const payload = @fieldParentPtr(Payload.Pointer, "base", ty.ptr_otherwise);
592 const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise);
492593 try out_stream.writeAll("?*");
493594 ty = payload.pointee_type;
494595 continue;
495596 },
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 },
496625 }
497626 unreachable;
498627 }
......@@ -539,6 +668,7 @@ pub const Type = extern union {
539668 .fn_ccc_void_no_args => return Value.initTag(.fn_ccc_void_no_args_type),
540669 .single_const_pointer_to_comptime_int => return Value.initTag(.single_const_pointer_to_comptime_int_type),
541670 .const_slice_u8 => return Value.initTag(.const_slice_u8_type),
671 .enum_literal => return Value.initTag(.enum_literal_type),
542672 else => {
543673 const ty_payload = try allocator.create(Value.Payload.Ty);
544674 ty_payload.* = .{ .ty = self };
......@@ -588,8 +718,8 @@ pub const Type = extern union {
588718 => true,
589719 // TODO lazy types
590720 .array => self.elemType().hasCodeGenBits() and self.arrayLen() != 0,
591 .single_const_pointer => self.elemType().hasCodeGenBits(),
592 .single_mut_pointer => self.elemType().hasCodeGenBits(),
721 .array_u8 => self.arrayLen() != 0,
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(),
593723 .int_signed => self.cast(Payload.IntSigned).?.bits == 0,
594724 .int_unsigned => self.cast(Payload.IntUnsigned).?.bits == 0,
595725
......@@ -601,6 +731,7 @@ pub const Type = extern union {
601731 .noreturn,
602732 .@"null",
603733 .@"undefined",
734 .enum_literal,
604735 => false,
605736 };
606737 }
......@@ -616,6 +747,7 @@ pub const Type = extern union {
616747 .i8,
617748 .bool,
618749 .array_u8_sentinel_0,
750 .array_u8,
619751 => return 1,
620752
621753 .fn_noreturn_no_args, // represents machine code; not a pointer
......@@ -638,10 +770,23 @@ pub const Type = extern union {
638770 .const_slice_u8,
639771 .single_const_pointer,
640772 .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,
641779 .optional_single_const_pointer,
642780 .optional_single_mut_pointer,
643781 => 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
645790 .c_short => return @divExact(CType.short.sizeInBits(target), 8),
646791 .c_ushort => return @divExact(CType.ushort.sizeInBits(target), 8),
647792 .c_int => return @divExact(CType.int.sizeInBits(target), 8),
......@@ -659,7 +804,7 @@ pub const Type = extern union {
659804
660805 .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
664809 .int_signed, .int_unsigned => {
665810 const bits: u16 = if (self.cast(Payload.IntSigned)) |pl|
......@@ -673,7 +818,7 @@ pub const Type = extern union {
673818 },
674819
675820 .optional => {
676 var buf: Payload.Pointer = undefined;
821 var buf: Payload.PointerSimple = undefined;
677822 const child_type = self.optionalChild(&buf);
678823 if (!child_type.hasCodeGenBits()) return 1;
679824
......@@ -691,6 +836,7 @@ pub const Type = extern union {
691836 .noreturn,
692837 .@"null",
693838 .@"undefined",
839 .enum_literal,
694840 => unreachable,
695841 };
696842 }
......@@ -711,31 +857,55 @@ pub const Type = extern union {
711857 .noreturn => unreachable,
712858 .@"null" => unreachable,
713859 .@"undefined" => unreachable,
860 .enum_literal => unreachable,
861 .single_const_pointer_to_comptime_int => unreachable,
714862
715863 .u8,
716864 .i8,
717865 .bool,
718866 => 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,
721870 .array => {
722871 const payload = @fieldParentPtr(Payload.Array, "base", self.ptr_otherwise);
723872 const elem_size = std.math.max(payload.elem_type.abiAlignment(target), payload.elem_type.abiSize(target));
724873 return payload.len * elem_size;
725874 },
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 },
726880 .i16, .u16 => return 2,
727881 .i32, .u32 => return 4,
728882 .i64, .u64 => return 8,
729883
730 .isize,
731 .usize,
732 .single_const_pointer_to_comptime_int,
884 .isize, .usize => return @divExact(target.cpu.arch.ptrBitWidth(), 8),
885
886 .const_slice,
887 .mut_slice,
733888 .const_slice_u8,
734 .single_const_pointer,
735 .single_mut_pointer,
889 => return @divExact(target.cpu.arch.ptrBitWidth(), 8) * 2,
890
736891 .optional_single_const_pointer,
737892 .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
740910 .c_short => return @divExact(CType.short.sizeInBits(target), 8),
741911 .c_ushort => return @divExact(CType.ushort.sizeInBits(target), 8),
......@@ -766,7 +936,7 @@ pub const Type = extern union {
766936 },
767937
768938 .optional => {
769 var buf: Payload.Pointer = undefined;
939 var buf: Payload.PointerSimple = undefined;
770940 const child_type = self.optionalChild(&buf);
771941 if (!child_type.hasCodeGenBits()) return 1;
772942
......@@ -818,6 +988,8 @@ pub const Type = extern union {
818988 .@"null",
819989 .@"undefined",
820990 .array,
991 .array_sentinel,
992 .array_u8,
821993 .array_u8_sentinel_0,
822994 .const_slice_u8,
823995 .fn_noreturn_no_args,
......@@ -830,12 +1002,21 @@ pub const Type = extern union {
8301002 .optional,
8311003 .optional_single_mut_pointer,
8321004 .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,
8331012 => false,
8341013
8351014 .single_const_pointer,
8361015 .single_mut_pointer,
8371016 .single_const_pointer_to_comptime_int,
8381017 => true,
1018
1019 .pointer => self.cast(Payload.Pointer).?.size == .One,
8391020 };
8401021 }
8411022
......@@ -875,9 +1056,15 @@ pub const Type = extern union {
8751056 .@"null",
8761057 .@"undefined",
8771058 .array,
1059 .array_sentinel,
1060 .array_u8,
8781061 .array_u8_sentinel_0,
8791062 .single_const_pointer,
8801063 .single_mut_pointer,
1064 .many_const_pointer,
1065 .many_mut_pointer,
1066 .c_const_pointer,
1067 .c_mut_pointer,
8811068 .single_const_pointer_to_comptime_int,
8821069 .fn_noreturn_no_args,
8831070 .fn_void_no_args,
......@@ -889,9 +1076,15 @@ pub const Type = extern union {
8891076 .optional,
8901077 .optional_single_mut_pointer,
8911078 .optional_single_const_pointer,
1079 .enum_literal,
8921080 => 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,
8951088 };
8961089 }
8971090
......@@ -931,6 +1124,8 @@ pub const Type = extern union {
9311124 .@"null",
9321125 .@"undefined",
9331126 .array,
1127 .array_sentinel,
1128 .array_u8,
9341129 .array_u8_sentinel_0,
9351130 .fn_noreturn_no_args,
9361131 .fn_void_no_args,
......@@ -940,15 +1135,24 @@ pub const Type = extern union {
9401135 .int_unsigned,
9411136 .int_signed,
9421137 .single_mut_pointer,
1138 .many_mut_pointer,
1139 .c_mut_pointer,
9431140 .optional,
9441141 .optional_single_mut_pointer,
9451142 .optional_single_const_pointer,
1143 .enum_literal,
1144 .mut_slice,
9461145 => false,
9471146
9481147 .single_const_pointer,
1148 .many_const_pointer,
1149 .c_const_pointer,
9491150 .single_const_pointer_to_comptime_int,
9501151 .const_slice_u8,
1152 .const_slice,
9511153 => true,
1154
1155 .pointer => !self.cast(Payload.Pointer).?.mutable,
9521156 };
9531157 }
9541158
......@@ -988,6 +1192,8 @@ pub const Type = extern union {
9881192 .@"null",
9891193 .@"undefined",
9901194 .array,
1195 .array_sentinel,
1196 .array_u8,
9911197 .array_u8_sentinel_0,
9921198 .fn_noreturn_no_args,
9931199 .fn_void_no_args,
......@@ -998,12 +1204,24 @@ pub const Type = extern union {
9981204 .int_signed,
9991205 .single_mut_pointer,
10001206 .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,
10011213 .single_const_pointer_to_comptime_int,
10021214 .const_slice_u8,
10031215 .optional,
10041216 .optional_single_mut_pointer,
10051217 .optional_single_const_pointer,
1218 .enum_literal,
10061219 => false,
1220
1221 .pointer => {
1222 const payload = @fieldParentPtr(Payload.Pointer, "base", self.ptr_otherwise);
1223 return payload.@"volatile";
1224 },
10071225 };
10081226 }
10091227
......@@ -1012,7 +1230,7 @@ pub const Type = extern union {
10121230 switch (self.tag()) {
10131231 .optional_single_const_pointer, .optional_single_mut_pointer => return true,
10141232 .optional => {
1015 var buf: Payload.Pointer = undefined;
1233 var buf: Payload.PointerSimple = undefined;
10161234 const child_type = self.optionalChild(&buf);
10171235 // optionals of zero sized pointers behave like bools
10181236 if (!child_type.hasCodeGenBits()) return false;
......@@ -1023,6 +1241,45 @@ pub const Type = extern union {
10231241 }
10241242 }
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
10261283 /// Asserts the type is a pointer or array type.
10271284 pub fn elemType(self: Type) Type {
10281285 return switch (self.tag()) {
......@@ -1069,18 +1326,28 @@ pub const Type = extern union {
10691326 .optional,
10701327 .optional_single_const_pointer,
10711328 .optional_single_mut_pointer,
1329 .enum_literal,
10721330 => unreachable,
10731331
10741332 .array => self.cast(Payload.Array).?.elem_type,
1075 .single_const_pointer => self.castPointer().?.pointee_type,
1076 .single_mut_pointer => self.castPointer().?.pointee_type,
1077 .array_u8_sentinel_0, .const_slice_u8 => Type.initTag(.u8),
1333 .array_sentinel => self.cast(Payload.ArraySentinel).?.elem_type,
1334 .single_const_pointer,
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),
10781344 .single_const_pointer_to_comptime_int => Type.initTag(.comptime_int),
1345 .pointer => self.cast(Payload.Pointer).?.pointee_type,
10791346 };
10801347 }
10811348
10821349 /// 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 {
10841351 return switch (self.tag()) {
10851352 .optional => self.cast(Payload.Optional).?.child_type,
10861353 .optional_single_mut_pointer => {
......@@ -1107,7 +1374,7 @@ pub const Type = extern union {
11071374 return switch (self.tag()) {
11081375 .optional => self.cast(Payload.Optional).?.child_type,
11091376 .optional_single_mut_pointer, .optional_single_const_pointer => {
1110 const payload = try allocator.create(Payload.Pointer);
1377 const payload = try allocator.create(Payload.PointerSimple);
11111378 payload.* = .{
11121379 .base = .{
11131380 .tag = if (self.tag() == .optional_single_const_pointer)
......@@ -1164,8 +1431,15 @@ pub const Type = extern union {
11641431 .fn_naked_noreturn_no_args,
11651432 .fn_ccc_void_no_args,
11661433 .function,
1434 .pointer,
11671435 .single_const_pointer,
11681436 .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,
11691443 .single_const_pointer_to_comptime_int,
11701444 .const_slice_u8,
11711445 .int_unsigned,
......@@ -1173,9 +1447,12 @@ pub const Type = extern union {
11731447 .optional,
11741448 .optional_single_mut_pointer,
11751449 .optional_single_const_pointer,
1450 .enum_literal,
11761451 => unreachable,
11771452
11781453 .array => self.cast(Payload.Array).?.len,
1454 .array_sentinel => self.cast(Payload.ArraySentinel).?.len,
1455 .array_u8 => self.cast(Payload.Array_u8).?.len,
11791456 .array_u8_sentinel_0 => self.cast(Payload.Array_u8_Sentinel0).?.len,
11801457 };
11811458 }
......@@ -1221,8 +1498,15 @@ pub const Type = extern union {
12211498 .fn_naked_noreturn_no_args,
12221499 .fn_ccc_void_no_args,
12231500 .function,
1501 .pointer,
12241502 .single_const_pointer,
12251503 .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,
12261510 .single_const_pointer_to_comptime_int,
12271511 .const_slice_u8,
12281512 .int_unsigned,
......@@ -1230,9 +1514,11 @@ pub const Type = extern union {
12301514 .optional,
12311515 .optional_single_mut_pointer,
12321516 .optional_single_const_pointer,
1517 .enum_literal,
12331518 => unreachable,
12341519
1235 .array => return null,
1520 .array, .array_u8 => return null,
1521 .array_sentinel => return self.cast(Payload.ArraySentinel).?.sentinel,
12361522 .array_u8_sentinel_0 => return Value.initTag(.zero),
12371523 };
12381524 }
......@@ -1266,10 +1552,19 @@ pub const Type = extern union {
12661552 .fn_ccc_void_no_args,
12671553 .function,
12681554 .array,
1555 .array_sentinel,
1556 .array_u8,
1557 .array_u8_sentinel_0,
1558 .pointer,
12691559 .single_const_pointer,
12701560 .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,
12711567 .single_const_pointer_to_comptime_int,
1272 .array_u8_sentinel_0,
12731568 .const_slice_u8,
12741569 .int_unsigned,
12751570 .u8,
......@@ -1284,6 +1579,7 @@ pub const Type = extern union {
12841579 .optional,
12851580 .optional_single_mut_pointer,
12861581 .optional_single_const_pointer,
1582 .enum_literal,
12871583 => false,
12881584
12891585 .int_signed,
......@@ -1324,10 +1620,19 @@ pub const Type = extern union {
13241620 .fn_ccc_void_no_args,
13251621 .function,
13261622 .array,
1623 .array_sentinel,
1624 .array_u8,
1625 .array_u8_sentinel_0,
1626 .pointer,
13271627 .single_const_pointer,
13281628 .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,
13291635 .single_const_pointer_to_comptime_int,
1330 .array_u8_sentinel_0,
13311636 .const_slice_u8,
13321637 .int_signed,
13331638 .i8,
......@@ -1342,6 +1647,7 @@ pub const Type = extern union {
13421647 .optional,
13431648 .optional_single_mut_pointer,
13441649 .optional_single_const_pointer,
1650 .enum_literal,
13451651 => false,
13461652
13471653 .int_unsigned,
......@@ -1382,14 +1688,24 @@ pub const Type = extern union {
13821688 .fn_ccc_void_no_args,
13831689 .function,
13841690 .array,
1691 .array_sentinel,
1692 .array_u8,
1693 .array_u8_sentinel_0,
1694 .pointer,
13851695 .single_const_pointer,
13861696 .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,
13871703 .single_const_pointer_to_comptime_int,
1388 .array_u8_sentinel_0,
13891704 .const_slice_u8,
13901705 .optional,
13911706 .optional_single_mut_pointer,
13921707 .optional_single_const_pointer,
1708 .enum_literal,
13931709 => unreachable,
13941710
13951711 .int_unsigned => .{ .signed = false, .bits = self.cast(Payload.IntUnsigned).?.bits },
......@@ -1438,10 +1754,19 @@ pub const Type = extern union {
14381754 .fn_ccc_void_no_args,
14391755 .function,
14401756 .array,
1757 .array_sentinel,
1758 .array_u8,
1759 .array_u8_sentinel_0,
1760 .pointer,
14411761 .single_const_pointer,
14421762 .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,
14431769 .single_const_pointer_to_comptime_int,
1444 .array_u8_sentinel_0,
14451770 .const_slice_u8,
14461771 .int_unsigned,
14471772 .int_signed,
......@@ -1456,6 +1781,7 @@ pub const Type = extern union {
14561781 .optional,
14571782 .optional_single_mut_pointer,
14581783 .optional_single_const_pointer,
1784 .enum_literal,
14591785 => false,
14601786
14611787 .usize,
......@@ -1523,10 +1849,19 @@ pub const Type = extern union {
15231849 .@"null",
15241850 .@"undefined",
15251851 .array,
1852 .array_sentinel,
1853 .array_u8,
1854 .array_u8_sentinel_0,
1855 .pointer,
15261856 .single_const_pointer,
15271857 .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,
15281864 .single_const_pointer_to_comptime_int,
1529 .array_u8_sentinel_0,
15301865 .const_slice_u8,
15311866 .u8,
15321867 .i8,
......@@ -1551,6 +1886,7 @@ pub const Type = extern union {
15511886 .optional,
15521887 .optional_single_mut_pointer,
15531888 .optional_single_const_pointer,
1889 .enum_literal,
15541890 => unreachable,
15551891 };
15561892 }
......@@ -1584,10 +1920,19 @@ pub const Type = extern union {
15841920 .@"null",
15851921 .@"undefined",
15861922 .array,
1923 .array_sentinel,
1924 .array_u8,
1925 .array_u8_sentinel_0,
1926 .pointer,
15871927 .single_const_pointer,
15881928 .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,
15891935 .single_const_pointer_to_comptime_int,
1590 .array_u8_sentinel_0,
15911936 .const_slice_u8,
15921937 .u8,
15931938 .i8,
......@@ -1612,6 +1957,7 @@ pub const Type = extern union {
16121957 .optional,
16131958 .optional_single_mut_pointer,
16141959 .optional_single_const_pointer,
1960 .enum_literal,
16151961 => unreachable,
16161962 }
16171963 }
......@@ -1644,10 +1990,19 @@ pub const Type = extern union {
16441990 .@"null",
16451991 .@"undefined",
16461992 .array,
1993 .array_sentinel,
1994 .array_u8,
1995 .array_u8_sentinel_0,
1996 .pointer,
16471997 .single_const_pointer,
16481998 .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,
16492005 .single_const_pointer_to_comptime_int,
1650 .array_u8_sentinel_0,
16512006 .const_slice_u8,
16522007 .u8,
16532008 .i8,
......@@ -1672,6 +2027,7 @@ pub const Type = extern union {
16722027 .optional,
16732028 .optional_single_mut_pointer,
16742029 .optional_single_const_pointer,
2030 .enum_literal,
16752031 => unreachable,
16762032 }
16772033 }
......@@ -1704,10 +2060,19 @@ pub const Type = extern union {
17042060 .@"null",
17052061 .@"undefined",
17062062 .array,
2063 .array_sentinel,
2064 .array_u8,
2065 .array_u8_sentinel_0,
2066 .pointer,
17072067 .single_const_pointer,
17082068 .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,
17092075 .single_const_pointer_to_comptime_int,
1710 .array_u8_sentinel_0,
17112076 .const_slice_u8,
17122077 .u8,
17132078 .i8,
......@@ -1732,6 +2097,7 @@ pub const Type = extern union {
17322097 .optional,
17332098 .optional_single_mut_pointer,
17342099 .optional_single_const_pointer,
2100 .enum_literal,
17352101 => unreachable,
17362102 };
17372103 }
......@@ -1761,10 +2127,19 @@ pub const Type = extern union {
17612127 .@"null",
17622128 .@"undefined",
17632129 .array,
2130 .array_sentinel,
2131 .array_u8,
2132 .array_u8_sentinel_0,
2133 .pointer,
17642134 .single_const_pointer,
17652135 .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,
17662142 .single_const_pointer_to_comptime_int,
1767 .array_u8_sentinel_0,
17682143 .const_slice_u8,
17692144 .u8,
17702145 .i8,
......@@ -1789,6 +2164,7 @@ pub const Type = extern union {
17892164 .optional,
17902165 .optional_single_mut_pointer,
17912166 .optional_single_const_pointer,
2167 .enum_literal,
17922168 => unreachable,
17932169 };
17942170 }
......@@ -1818,10 +2194,19 @@ pub const Type = extern union {
18182194 .@"null",
18192195 .@"undefined",
18202196 .array,
2197 .array_sentinel,
2198 .array_u8,
2199 .array_u8_sentinel_0,
2200 .pointer,
18212201 .single_const_pointer,
18222202 .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,
18232209 .single_const_pointer_to_comptime_int,
1824 .array_u8_sentinel_0,
18252210 .const_slice_u8,
18262211 .u8,
18272212 .i8,
......@@ -1846,6 +2231,7 @@ pub const Type = extern union {
18462231 .optional,
18472232 .optional_single_mut_pointer,
18482233 .optional_single_const_pointer,
2234 .enum_literal,
18492235 => unreachable,
18502236 };
18512237 }
......@@ -1895,14 +2281,24 @@ pub const Type = extern union {
18952281 .fn_ccc_void_no_args,
18962282 .function,
18972283 .array,
2284 .array_sentinel,
2285 .array_u8,
2286 .array_u8_sentinel_0,
2287 .pointer,
18982288 .single_const_pointer,
18992289 .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,
19002296 .single_const_pointer_to_comptime_int,
1901 .array_u8_sentinel_0,
19022297 .const_slice_u8,
19032298 .optional,
19042299 .optional_single_mut_pointer,
19052300 .optional_single_const_pointer,
2301 .enum_literal,
19062302 => false,
19072303 };
19082304 }
......@@ -1944,12 +2340,16 @@ pub const Type = extern union {
19442340 .fn_ccc_void_no_args,
19452341 .function,
19462342 .single_const_pointer_to_comptime_int,
2343 .array_sentinel,
19472344 .array_u8_sentinel_0,
19482345 .const_slice_u8,
2346 .const_slice,
2347 .mut_slice,
19492348 .c_void,
19502349 .optional,
19512350 .optional_single_mut_pointer,
19522351 .optional_single_const_pointer,
2352 .enum_literal,
19532353 => return null,
19542354
19552355 .void => return Value.initTag(.void_value),
......@@ -1971,18 +2371,27 @@ pub const Type = extern union {
19712371 return null;
19722372 }
19732373 },
1974 .array => {
1975 const array = ty.cast(Payload.Array).?;
1976 if (array.len == 0)
2374 .array, .array_u8 => {
2375 if (ty.arrayLen() == 0)
19772376 return Value.initTag(.empty_array);
1978 ty = array.elem_type;
2377 ty = ty.elemType();
19792378 continue;
19802379 },
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 => {
19822387 const ptr = ty.castPointer().?;
19832388 ty = ptr.pointee_type;
19842389 continue;
19852390 },
2391 .pointer => {
2392 ty = ty.cast(Payload.Pointer).?.pointee_type;
2393 continue;
2394 },
19862395 };
19872396 }
19882397
......@@ -2022,7 +2431,6 @@ pub const Type = extern union {
20222431 .fn_ccc_void_no_args,
20232432 .function,
20242433 .single_const_pointer_to_comptime_int,
2025 .array_u8_sentinel_0,
20262434 .const_slice_u8,
20272435 .c_void,
20282436 .void,
......@@ -2032,12 +2440,26 @@ pub const Type = extern union {
20322440 .int_unsigned,
20332441 .int_signed,
20342442 .array,
2443 .array_sentinel,
2444 .array_u8,
2445 .array_u8_sentinel_0,
20352446 .single_const_pointer,
20362447 .single_mut_pointer,
2448 .many_const_pointer,
2449 .many_mut_pointer,
2450 .const_slice,
2451 .mut_slice,
20372452 .optional,
20382453 .optional_single_mut_pointer,
20392454 .optional_single_const_pointer,
2455 .enum_literal,
20402456 => return false,
2457
2458 .c_const_pointer,
2459 .c_mut_pointer,
2460 => return true,
2461
2462 .pointer => self.cast(Payload.Pointer).?.size == .C,
20412463 };
20422464 }
20432465
......@@ -2080,6 +2502,7 @@ pub const Type = extern union {
20802502 comptime_int,
20812503 comptime_float,
20822504 noreturn,
2505 enum_literal,
20832506 @"null",
20842507 @"undefined",
20852508 fn_noreturn_no_args,
......@@ -2090,10 +2513,19 @@ pub const Type = extern union {
20902513 const_slice_u8, // See last_no_payload_tag below.
20912514 // After this, the tag requires a payload.
20922515
2516 array_u8,
20932517 array_u8_sentinel_0,
20942518 array,
2519 array_sentinel,
2520 pointer,
20952521 single_const_pointer,
20962522 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,
20972529 int_signed,
20982530 int_unsigned,
20992531 function,
......@@ -2114,14 +2546,28 @@ pub const Type = extern union {
21142546 len: u64,
21152547 };
21162548
2549 pub const Array_u8 = struct {
2550 base: Payload = Payload{ .tag = .array_u8 },
2551
2552 len: u64,
2553 };
2554
21172555 pub const Array = struct {
21182556 base: Payload = Payload{ .tag = .array },
21192557
2558 len: u64,
21202559 elem_type: Type,
2560 };
2561
2562 pub const ArraySentinel = struct {
2563 base: Payload = Payload{ .tag = .array_sentinel },
2564
21212565 len: u64,
2566 sentinel: Value,
2567 elem_type: Type,
21222568 };
21232569
2124 pub const Pointer = struct {
2570 pub const PointerSimple = struct {
21252571 base: Payload,
21262572
21272573 pointee_type: Type,
......@@ -2152,6 +2598,21 @@ pub const Type = extern union {
21522598
21532599 child_type: Type,
21542600 };
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 };
21552616 };
21562617};
21572618
src-self-hosted/value.zig+60-1
......@@ -60,6 +60,7 @@ pub const Value = extern union {
6060 fn_ccc_void_no_args_type,
6161 single_const_pointer_to_comptime_int_type,
6262 const_slice_u8_type,
63 enum_literal_type,
6364
6465 undef,
6566 zero,
......@@ -78,6 +79,7 @@ pub const Value = extern union {
7879 int_big_positive,
7980 int_big_negative,
8081 function,
82 variable,
8183 ref_val,
8284 decl_ref,
8385 elem_ptr,
......@@ -87,6 +89,7 @@ pub const Value = extern union {
8789 float_32,
8890 float_64,
8991 float_128,
92 enum_literal,
9093
9194 pub const last_no_payload_tag = Tag.bool_false;
9295 pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;
......@@ -164,6 +167,7 @@ pub const Value = extern union {
164167 .fn_ccc_void_no_args_type,
165168 .single_const_pointer_to_comptime_int_type,
166169 .const_slice_u8_type,
170 .enum_literal_type,
167171 .undef,
168172 .zero,
169173 .void_value,
......@@ -193,6 +197,7 @@ pub const Value = extern union {
193197 @panic("TODO implement copying of big ints");
194198 },
195199 .function => return self.copyPayloadShallow(allocator, Payload.Function),
200 .variable => return self.copyPayloadShallow(allocator, Payload.Variable),
196201 .ref_val => {
197202 const payload = @fieldParentPtr(Payload.RefVal, "base", self.ptr_otherwise);
198203 const new_payload = try allocator.create(Payload.RefVal);
......@@ -227,6 +232,15 @@ pub const Value = extern union {
227232 .float_32 => return self.copyPayloadShallow(allocator, Payload.Float_32),
228233 .float_64 => return self.copyPayloadShallow(allocator, Payload.Float_64),
229234 .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 },
230244 }
231245 }
232246
......@@ -285,6 +299,7 @@ pub const Value = extern union {
285299 .fn_ccc_void_no_args_type => return out_stream.writeAll("fn() callconv(.C) void"),
286300 .single_const_pointer_to_comptime_int_type => return out_stream.writeAll("*const comptime_int"),
287301 .const_slice_u8_type => return out_stream.writeAll("[]const u8"),
302 .enum_literal_type => return out_stream.writeAll("@TypeOf(.EnumLiteral)"),
288303
289304 .null_value => return out_stream.writeAll("null"),
290305 .undef => return out_stream.writeAll("undefined"),
......@@ -306,6 +321,7 @@ pub const Value = extern union {
306321 .int_big_positive => return out_stream.print("{}", .{val.cast(Payload.IntBigPositive).?.asBigInt()}),
307322 .int_big_negative => return out_stream.print("{}", .{val.cast(Payload.IntBigNegative).?.asBigInt()}),
308323 .function => return out_stream.writeAll("(function)"),
324 .variable => return out_stream.writeAll("(variable)"),
309325 .ref_val => {
310326 const ref_val = val.cast(Payload.RefVal).?;
311327 try out_stream.writeAll("&const ");
......@@ -318,7 +334,7 @@ pub const Value = extern union {
318334 val = elem_ptr.array_ptr;
319335 },
320336 .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),
322338 .repeated => {
323339 try out_stream.writeAll("(repeated) ");
324340 val = val.cast(Payload.Repeated).?.val;
......@@ -391,6 +407,7 @@ pub const Value = extern union {
391407 .fn_ccc_void_no_args_type => Type.initTag(.fn_ccc_void_no_args),
392408 .single_const_pointer_to_comptime_int_type => Type.initTag(.single_const_pointer_to_comptime_int),
393409 .const_slice_u8_type => Type.initTag(.const_slice_u8),
410 .enum_literal_type => Type.initTag(.enum_literal),
394411
395412 .undef,
396413 .zero,
......@@ -405,6 +422,7 @@ pub const Value = extern union {
405422 .int_big_positive,
406423 .int_big_negative,
407424 .function,
425 .variable,
408426 .ref_val,
409427 .decl_ref,
410428 .elem_ptr,
......@@ -414,6 +432,7 @@ pub const Value = extern union {
414432 .float_32,
415433 .float_64,
416434 .float_128,
435 .enum_literal,
417436 => unreachable,
418437 };
419438 }
......@@ -462,8 +481,10 @@ pub const Value = extern union {
462481 .fn_ccc_void_no_args_type,
463482 .single_const_pointer_to_comptime_int_type,
464483 .const_slice_u8_type,
484 .enum_literal_type,
465485 .null_value,
466486 .function,
487 .variable,
467488 .ref_val,
468489 .decl_ref,
469490 .elem_ptr,
......@@ -476,6 +497,7 @@ pub const Value = extern union {
476497 .void_value,
477498 .unreachable_value,
478499 .empty_array,
500 .enum_literal,
479501 => unreachable,
480502
481503 .undef => unreachable,
......@@ -537,8 +559,10 @@ pub const Value = extern union {
537559 .fn_ccc_void_no_args_type,
538560 .single_const_pointer_to_comptime_int_type,
539561 .const_slice_u8_type,
562 .enum_literal_type,
540563 .null_value,
541564 .function,
565 .variable,
542566 .ref_val,
543567 .decl_ref,
544568 .elem_ptr,
......@@ -551,6 +575,7 @@ pub const Value = extern union {
551575 .void_value,
552576 .unreachable_value,
553577 .empty_array,
578 .enum_literal,
554579 => unreachable,
555580
556581 .undef => unreachable,
......@@ -612,8 +637,10 @@ pub const Value = extern union {
612637 .fn_ccc_void_no_args_type,
613638 .single_const_pointer_to_comptime_int_type,
614639 .const_slice_u8_type,
640 .enum_literal_type,
615641 .null_value,
616642 .function,
643 .variable,
617644 .ref_val,
618645 .decl_ref,
619646 .elem_ptr,
......@@ -626,6 +653,7 @@ pub const Value = extern union {
626653 .void_value,
627654 .unreachable_value,
628655 .empty_array,
656 .enum_literal,
629657 => unreachable,
630658
631659 .undef => unreachable,
......@@ -713,8 +741,10 @@ pub const Value = extern union {
713741 .fn_ccc_void_no_args_type,
714742 .single_const_pointer_to_comptime_int_type,
715743 .const_slice_u8_type,
744 .enum_literal_type,
716745 .null_value,
717746 .function,
747 .variable,
718748 .ref_val,
719749 .decl_ref,
720750 .elem_ptr,
......@@ -728,6 +758,7 @@ pub const Value = extern union {
728758 .void_value,
729759 .unreachable_value,
730760 .empty_array,
761 .enum_literal,
731762 => unreachable,
732763
733764 .zero,
......@@ -793,8 +824,10 @@ pub const Value = extern union {
793824 .fn_ccc_void_no_args_type,
794825 .single_const_pointer_to_comptime_int_type,
795826 .const_slice_u8_type,
827 .enum_literal_type,
796828 .null_value,
797829 .function,
830 .variable,
798831 .ref_val,
799832 .decl_ref,
800833 .elem_ptr,
......@@ -807,6 +840,7 @@ pub const Value = extern union {
807840 .void_value,
808841 .unreachable_value,
809842 .empty_array,
843 .enum_literal,
810844 => unreachable,
811845
812846 .zero,
......@@ -953,10 +987,12 @@ pub const Value = extern union {
953987 .fn_ccc_void_no_args_type,
954988 .single_const_pointer_to_comptime_int_type,
955989 .const_slice_u8_type,
990 .enum_literal_type,
956991 .bool_true,
957992 .bool_false,
958993 .null_value,
959994 .function,
995 .variable,
960996 .ref_val,
961997 .decl_ref,
962998 .elem_ptr,
......@@ -970,6 +1006,7 @@ pub const Value = extern union {
9701006 .empty_array,
9711007 .void_value,
9721008 .unreachable_value,
1009 .enum_literal,
9731010 => unreachable,
9741011
9751012 .zero => false,
......@@ -1025,8 +1062,10 @@ pub const Value = extern union {
10251062 .fn_ccc_void_no_args_type,
10261063 .single_const_pointer_to_comptime_int_type,
10271064 .const_slice_u8_type,
1065 .enum_literal_type,
10281066 .null_value,
10291067 .function,
1068 .variable,
10301069 .ref_val,
10311070 .decl_ref,
10321071 .elem_ptr,
......@@ -1036,6 +1075,7 @@ pub const Value = extern union {
10361075 .void_value,
10371076 .unreachable_value,
10381077 .empty_array,
1078 .enum_literal,
10391079 => unreachable,
10401080
10411081 .zero,
......@@ -1102,6 +1142,11 @@ pub const Value = extern union {
11021142 }
11031143
11041144 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 }
11051150 // TODO non numerical comparisons
11061151 return compare(a, .eq, b);
11071152 }
......@@ -1151,11 +1196,13 @@ pub const Value = extern union {
11511196 .fn_ccc_void_no_args_type,
11521197 .single_const_pointer_to_comptime_int_type,
11531198 .const_slice_u8_type,
1199 .enum_literal_type,
11541200 .zero,
11551201 .bool_true,
11561202 .bool_false,
11571203 .null_value,
11581204 .function,
1205 .variable,
11591206 .int_u64,
11601207 .int_i64,
11611208 .int_big_positive,
......@@ -1170,6 +1217,7 @@ pub const Value = extern union {
11701217 .void_value,
11711218 .unreachable_value,
11721219 .empty_array,
1220 .enum_literal,
11731221 => unreachable,
11741222
11751223 .ref_val => self.cast(Payload.RefVal).?.val,
......@@ -1227,11 +1275,13 @@ pub const Value = extern union {
12271275 .fn_ccc_void_no_args_type,
12281276 .single_const_pointer_to_comptime_int_type,
12291277 .const_slice_u8_type,
1278 .enum_literal_type,
12301279 .zero,
12311280 .bool_true,
12321281 .bool_false,
12331282 .null_value,
12341283 .function,
1284 .variable,
12351285 .int_u64,
12361286 .int_i64,
12371287 .int_big_positive,
......@@ -1246,6 +1296,7 @@ pub const Value = extern union {
12461296 .float_128,
12471297 .void_value,
12481298 .unreachable_value,
1299 .enum_literal,
12491300 => unreachable,
12501301
12511302 .empty_array => unreachable, // out of bounds array index
......@@ -1320,11 +1371,13 @@ pub const Value = extern union {
13201371 .fn_ccc_void_no_args_type,
13211372 .single_const_pointer_to_comptime_int_type,
13221373 .const_slice_u8_type,
1374 .enum_literal_type,
13231375 .zero,
13241376 .empty_array,
13251377 .bool_true,
13261378 .bool_false,
13271379 .function,
1380 .variable,
13281381 .int_u64,
13291382 .int_i64,
13301383 .int_big_positive,
......@@ -1339,6 +1392,7 @@ pub const Value = extern union {
13391392 .float_64,
13401393 .float_128,
13411394 .void_value,
1395 .enum_literal,
13421396 => false,
13431397
13441398 .undef => unreachable,
......@@ -1398,6 +1452,11 @@ pub const Value = extern union {
13981452 func: *Module.Fn,
13991453 };
14001454
1455 pub const Variable = struct {
1456 base: Payload = Payload{ .tag = .variable },
1457 variable: *Module.Var,
1458 };
1459
14011460 pub const ArraySentinel0_u8_Type = struct {
14021461 base: Payload = Payload{ .tag = .array_sentinel_0_u8_type },
14031462 len: u64,
src-self-hosted/zir.zig+146-9
......@@ -47,6 +47,10 @@ pub const Inst = struct {
4747 array_cat,
4848 /// Array multiplication `a ** b`
4949 array_mul,
50 /// Create an array type
51 array_type,
52 /// Create an array type with sentinel
53 array_type_sentinel,
5054 /// Function parameter value. These must be first in a function's main block,
5155 /// in respective order with the parameters.
5256 arg,
......@@ -58,11 +62,11 @@ pub const Inst = struct {
5862 bitand,
5963 /// TODO delete this instruction, it has no purpose.
6064 bitcast,
61 /// An arbitrary typed pointer, which is to be used as an L-Value, is pointer-casted
62 /// to a new L-Value. The destination type is given by LHS. The cast is to be evaluated
65 /// An arbitrary typed pointer is pointer-casted to a new Pointer.
66 /// The destination type is given by LHS. The cast is to be evaluated
6367 /// as if it were a bit-cast operation from the operand pointer element type to the
6468 /// provided destination type.
65 bitcast_lvalue,
69 bitcast_ref,
6670 /// A typed result location pointer is bitcasted to a new result location pointer.
6771 /// The new result location pointer has an inferred type.
6872 bitcast_result_ptr,
......@@ -190,10 +194,22 @@ pub const Inst = struct {
190194 shl,
191195 /// Integer shift-right. Arithmetic or logical depending on the signedness of the integer type.
192196 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`
194198 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`
196200 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,
197213 /// Create a pointer type with attributes
198214 ptr_type,
199215 /// Write a value to a pointer. For loading, see `deref`.
......@@ -225,6 +241,10 @@ pub const Inst = struct {
225241 unwrap_err_safe,
226242 /// Same as previous, but without safety checks. Used for orelse, if and while
227243 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
229249 pub fn Type(tag: Tag) type {
230250 return switch (tag) {
......@@ -250,21 +270,29 @@ pub const Inst = struct {
250270 .ensure_result_non_error,
251271 .bitcast_result_ptr,
252272 .ref,
253 .bitcast_lvalue,
273 .bitcast_ref,
254274 .typeof,
255275 .single_const_ptr_type,
256276 .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,
257283 .optional_type,
258284 .unwrap_optional_safe,
259285 .unwrap_optional_unsafe,
260286 .unwrap_err_safe,
261287 .unwrap_err_unsafe,
288 .ensure_err_payload_void,
262289 => UnOp,
263290
264291 .add,
265292 .addwrap,
266293 .array_cat,
267294 .array_mul,
295 .array_type,
268296 .bitand,
269297 .bitor,
270298 .div,
......@@ -291,6 +319,7 @@ pub const Inst = struct {
291319 => BinOp,
292320
293321 .arg => Arg,
322 .array_type_sentinel => ArrayTypeSentinel,
294323 .block => Block,
295324 .@"break" => Break,
296325 .breakvoid => BreakVoid,
......@@ -317,6 +346,7 @@ pub const Inst = struct {
317346 .elemptr => ElemPtr,
318347 .condbr => CondBr,
319348 .ptr_type => PtrType,
349 .enum_literal => EnumLiteral,
320350 };
321351 }
322352
......@@ -330,12 +360,14 @@ pub const Inst = struct {
330360 .alloc_inferred,
331361 .array_cat,
332362 .array_mul,
363 .array_type,
364 .array_type_sentinel,
333365 .arg,
334366 .as,
335367 .@"asm",
336368 .bitand,
337369 .bitcast,
338 .bitcast_lvalue,
370 .bitcast_ref,
339371 .bitcast_result_ptr,
340372 .bitor,
341373 .block,
......@@ -386,6 +418,12 @@ pub const Inst = struct {
386418 .shr,
387419 .single_const_ptr_type,
388420 .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,
389427 .store,
390428 .str,
391429 .sub,
......@@ -398,6 +436,8 @@ pub const Inst = struct {
398436 .unwrap_err_safe,
399437 .unwrap_err_unsafe,
400438 .ptr_type,
439 .ensure_err_payload_void,
440 .enum_literal,
401441 => false,
402442
403443 .@"break",
......@@ -840,11 +880,34 @@ pub const Inst = struct {
840880 @"align": ?*Inst = null,
841881 align_bit_start: ?*Inst = null,
842882 align_bit_end: ?*Inst = null,
843 @"const": bool = true,
883 mutable: bool = true,
844884 @"volatile": bool = false,
845885 sentinel: ?*Inst = null,
886 size: std.builtin.TypeInfo.Pointer.Size = .One,
846887 },
847888 };
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 };
848911};
849912
850913pub const ErrorMsg = struct {
......@@ -1714,6 +1777,9 @@ const EmitZIR = struct {
17141777 const decl_ref = try self.emitDeclRef(inst.src, declref.decl);
17151778 try new_body.instructions.append(decl_ref);
17161779 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));
17171783 } else blk: {
17181784 break :blk (try self.emitTypedValue(inst.src, .{ .ty = inst.ty, .val = const_inst.val })).inst;
17191785 };
......@@ -1837,6 +1903,11 @@ const EmitZIR = struct {
18371903 if (typed_value.val.cast(Value.Payload.DeclRef)) |decl_ref| {
18381904 const decl = decl_ref.decl;
18391905 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 });
18401911 }
18411912 if (typed_value.val.isUndef()) {
18421913 const as_inst = try self.arena.allocator.create(Inst.BinOp);
......@@ -1922,6 +1993,25 @@ const EmitZIR = struct {
19221993 return self.emitUnnamedDecl(&str_inst.base);
19231994 },
19241995 .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 },
19252015 else => |t| std.debug.panic("TODO implement emitTypedValue for {}", .{@tagName(t)}),
19262016 }
19272017 }
......@@ -2269,6 +2359,8 @@ const EmitZIR = struct {
22692359 };
22702360 break :blk &new_inst.base;
22712361 },
2362
2363 .varptr => @panic("TODO"),
22722364 };
22732365 try self.metadata.put(new_inst, .{ .deaths = inst.deaths });
22742366 try instructions.append(new_inst);
......@@ -2376,7 +2468,7 @@ const EmitZIR = struct {
23762468 }
23772469 },
23782470 .Optional => {
2379 var buf: Type.Payload.Pointer = undefined;
2471 var buf: Type.Payload.PointerSimple = undefined;
23802472 const inst = try self.arena.allocator.create(Inst.UnOp);
23812473 inst.* = .{
23822474 .base = .{
......@@ -2390,6 +2482,51 @@ const EmitZIR = struct {
23902482 };
23912483 return self.emitUnnamedDecl(&inst.base);
23922484 },
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 },
23932530 else => std.debug.panic("TODO implement emitType for {}", .{ty}),
23942531 },
23952532 }
src-self-hosted/zir_sema.zig+112-46
......@@ -29,7 +29,7 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!
2929 .alloc => return analyzeInstAlloc(mod, scope, old_inst.castTag(.alloc).?),
3030 .alloc_inferred => return analyzeInstAllocInferred(mod, scope, old_inst.castTag(.alloc_inferred).?),
3131 .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).?),
3333 .bitcast_result_ptr => return analyzeInstBitCastResultPtr(mod, scope, old_inst.castTag(.bitcast_result_ptr).?),
3434 .block => return analyzeInstBlock(mod, scope, old_inst.castTag(.block).?),
3535 .@"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!
5151 .ref => return analyzeInstRef(mod, scope, old_inst.castTag(.ref).?),
5252 .ret_ptr => return analyzeInstRetPtr(mod, scope, old_inst.castTag(.ret_ptr).?),
5353 .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).?),
55 .single_mut_ptr_type => return analyzeInstSingleMutPtrType(mod, scope, old_inst.castTag(.single_mut_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 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),
5662 .ptr_type => return analyzeInstPtrType(mod, scope, old_inst.castTag(.ptr_type).?),
5763 .store => return analyzeInstStore(mod, scope, old_inst.castTag(.store).?),
5864 .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!
112118 .unwrap_optional_unsafe => return analyzeInstUnwrapOptional(mod, scope, old_inst.castTag(.unwrap_optional_unsafe).?, false),
113119 .unwrap_err_safe => return analyzeInstUnwrapErr(mod, scope, old_inst.castTag(.unwrap_err_safe).?, true),
114120 .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).?),
115125 }
116126}
117127
......@@ -263,6 +273,14 @@ fn resolveType(mod: *Module, scope: *Scope, old_inst: *zir.Inst) !Type {
263273 return val.toType();
264274}
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
266284pub fn resolveInstConst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!TypedValue {
267285 const new_inst = try resolveInst(mod, scope, old_inst);
268286 const val = try mod.resolveConstValue(scope, new_inst);
......@@ -295,8 +313,8 @@ fn analyzeInstCoerceResultBlockPtr(
295313 return mod.fail(scope, inst.base.src, "TODO implement analyzeInstCoerceResultBlockPtr", .{});
296314}
297315
298fn analyzeInstBitCastLValue(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
299 return mod.fail(scope, inst.base.src, "TODO implement analyzeInstBitCastLValue", .{});
316fn analyzeInstBitCastRef(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
317 return mod.fail(scope, inst.base.src, "TODO implement analyzeInstBitCastRef", .{});
300318}
301319
302320fn 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
320338
321339fn analyzeInstRef(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
322340 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
325343 if (operand.value()) |val| {
326344 const ref_payload = try scope.arena().create(Value.Payload.RefVal);
......@@ -361,7 +379,11 @@ fn analyzeInstEnsureResultNonError(mod: *Module, scope: *Scope, inst: *zir.Inst.
361379
362380fn analyzeInstAlloc(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
363381 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);
365387 const b = try mod.requireRuntimeBlock(scope, inst.base.src);
366388 return mod.addNoOp(b, inst.base.src, ptr_type, .alloc);
367389}
......@@ -573,8 +595,7 @@ fn analyzeInstDeclVal(mod: *Module, scope: *Scope, inst: *zir.Inst.DeclVal) Inne
573595
574596fn analyzeInstDeclValInModule(mod: *Module, scope: *Scope, inst: *zir.Inst.DeclValInModule) InnerError!*Inst {
575597 const decl = inst.positionals.decl;
576 const ptr = try mod.analyzeDeclRef(scope, inst.base.src, decl);
577 return mod.analyzeDeref(scope, inst.base.src, ptr, inst.base.src);
598 return mod.analyzeDeclRef(scope, inst.base.src, decl);
578599}
579600
580601fn 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
675696fn analyzeInstOptionalType(mod: *Module, scope: *Scope, optional: *zir.Inst.UnOp) InnerError!*Inst {
676697 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()) {
679 .single_const_pointer => blk: {
680 const payload = try scope.arena().create(Type.Payload.Pointer);
681 payload.* = .{
682 .base = .{ .tag = .optional_single_const_pointer },
683 .pointee_type = child_type.elemType(),
684 };
685 break :blk &payload.base;
686 },
687 .single_mut_pointer => blk: {
688 const payload = try scope.arena().create(Type.Payload.Pointer);
689 payload.* = .{
690 .base = .{ .tag = .optional_single_mut_pointer },
691 .pointee_type = child_type.elemType(),
692 };
693 break :blk &payload.base;
694 },
695 else => blk: {
696 const payload = try scope.arena().create(Type.Payload.Optional);
697 payload.* = .{
698 .child_type = child_type,
699 };
700 break :blk &payload.base;
701 },
702 }));
699 return mod.constType(scope, optional.base.src, try mod.optionalType(scope, child_type));
700}
701
702fn analyzeInstArrayType(mod: *Module, scope: *Scope, array: *zir.Inst.BinOp) InnerError!*Inst {
703 // TODO these should be lazily evaluated
704 const len = try resolveInstConst(mod, scope, array.positionals.lhs);
705 const elem_type = try resolveType(mod, scope, array.positionals.rhs);
706
707 return mod.constType(scope, array.base.src, try mod.arrayType(scope, len.val.toUnsignedInt(), null, elem_type));
708}
709
710fn analyzeInstArrayTypeSentinel(mod: *Module, scope: *Scope, array: *zir.Inst.ArrayTypeSentinel) InnerError!*Inst {
711 // TODO these should be lazily evaluated
712 const len = try resolveInstConst(mod, scope, array.positionals.len);
713 const sentinel = try resolveInstConst(mod, scope, array.positionals.sentinel);
714 const elem_type = try resolveType(mod, scope, array.positionals.elem_type);
715
716 return mod.constType(scope, array.base.src, try mod.arrayType(scope, len.val.toUnsignedInt(), sentinel.val, elem_type));
717}
718
719fn analyzeInstEnumLiteral(mod: *Module, scope: *Scope, inst: *zir.Inst.EnumLiteral) InnerError!*Inst {
720 const payload = try scope.arena().create(Value.Payload.Bytes);
721 payload.* = .{
722 .base = .{ .tag = .enum_literal },
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 });
703729}
704730
705731fn 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
711737 }
712738
713739 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
716742 if (operand.value()) |val| {
717743 if (val.isNull()) {
......@@ -735,6 +761,10 @@ fn analyzeInstUnwrapErr(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp, saf
735761 return mod.fail(scope, unwrap.base.src, "TODO implement analyzeInstUnwrapErr", .{});
736762}
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
738768fn analyzeInstFnType(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnType) InnerError!*Inst {
739769 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
760790 const arena = scope.arena();
761791 const param_types = try arena.alloc(Type, fntype.positionals.param_types.len);
762792 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;
764799 }
765800
766801 const payload = try arena.create(Type.Payload.Function);
......@@ -919,7 +954,7 @@ fn analyzeInstElemPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.ElemPtr) Inne
919954 // required a larger index.
920955 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);
923958 type_payload.* = .{
924959 .base = .{ .tag = .single_const_pointer },
925960 .pointee_type = array_ptr.ty.elemType().elemType(),
......@@ -1290,18 +1325,49 @@ fn analyzeDeclVal(mod: *Module, scope: *Scope, inst: *zir.Inst.DeclVal) InnerErr
12901325 return decl;
12911326}
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 {
12941329 const elem_type = try resolveType(mod, scope, inst.positionals.operand);
1295 const ty = try mod.singlePtrType(scope, inst.base.src, false, elem_type);
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);
1330 const ty = try mod.simplePtrType(scope, inst.base.src, elem_type, mutable, size);
13021331 return mod.constType(scope, inst.base.src, ty);
13031332}
13041333
13051334fn 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);
13071373}
src/all_types.hpp+1
......@@ -1420,6 +1420,7 @@ struct ZigTypeStruct {
14201420 bool requires_comptime;
14211421 bool resolve_loop_flag_zero_bits;
14221422 bool resolve_loop_flag_other;
1423 bool created_by_at_type;
14231424};
14241425
14251426struct ZigTypeOptional {
src/analyze.cpp+5-5
......@@ -138,7 +138,7 @@ void init_scope(CodeGen *g, Scope *dest, ScopeId id, AstNode *source_node, Scope
138138 dest->parent = parent;
139139}
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,
142142 ZigType *import, Buf *bare_name)
143143{
144144 ScopeDecls *scope = heap::c_allocator.create<ScopeDecls>();
......@@ -2821,7 +2821,7 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) {
28212821
28222822 src_assert(struct_type->data.structure.fields == nullptr, decl_node);
28232823 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) {
28252825 field_count = struct_type->data.structure.src_field_count;
28262826
28272827 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) {
28562856 struct_type->data.structure.resolve_status = ResolveStatusInvalid;
28572857 return ErrorSemanticAnalyzeFail;
28582858 }
2859 } else if (is_anon_container(struct_type)) {
2859 } else if (is_anon_container(struct_type) || struct_type->data.structure.created_by_at_type) {
28602860 field_node = type_struct_field->decl_node;
28612861
28622862 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) {
28832883 type_struct_field->type_val = field_type_val;
28842884 if (struct_type->data.structure.resolve_status == ResolveStatusInvalid)
28852885 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) {
28872887 field_type_val = type_struct_field->type_val;
28882888 } else zig_unreachable();
28892889
......@@ -8331,7 +8331,7 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS
83318331 ZigLLVMDIFile *di_file;
83328332 ZigLLVMDIScope *di_scope;
83338333 unsigned line;
8334 if (decl_node != nullptr) {
8334 if (decl_node != nullptr && !struct_type->data.structure.created_by_at_type) {
83358335 Scope *scope = &struct_type->data.structure.decls_scope->base;
83368336 ZigType *import = get_scope_import(scope);
83378337 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
116116
117117void 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);
119120ScopeBlock *create_block_scope(CodeGen *g, AstNode *node, Scope *parent);
120121ScopeDefer *create_defer_scope(CodeGen *g, AstNode *node, Scope *parent);
121122ScopeDeferExpr *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) {
293293 }
294294}
295295
296static LLVMLinkage to_llvm_linkage(GlobalLinkageId id) {
296static LLVMLinkage to_llvm_linkage(GlobalLinkageId id, bool is_extern) {
297297 switch (id) {
298298 case GlobalLinkageIdInternal:
299299 return LLVMInternalLinkage;
300300 case GlobalLinkageIdStrong:
301301 return LLVMExternalLinkage;
302302 case GlobalLinkageIdWeak:
303 if (is_extern) return LLVMExternalWeakLinkage;
303304 return LLVMWeakODRLinkage;
304305 case GlobalLinkageIdLinkOnce:
305306 return LLVMLinkOnceODRLinkage;
......@@ -522,7 +523,7 @@ static LLVMValueRef make_fn_llvm_value(CodeGen *g, ZigFn *fn) {
522523 }
523524
524525
525 LLVMSetLinkage(llvm_fn, to_llvm_linkage(linkage));
526 LLVMSetLinkage(llvm_fn, to_llvm_linkage(linkage, fn->body_node == nullptr));
526527
527528 if (linkage == GlobalLinkageIdInternal) {
528529 LLVMSetUnnamedAddr(llvm_fn, true);
......@@ -7963,7 +7964,7 @@ static void do_code_gen(CodeGen *g) {
79637964 global_value = LLVMAddGlobal(g->module, get_llvm_type(g, var->var_type), symbol_name);
79647965 // 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));
79677968 maybe_import_dll(g, global_value, GlobalLinkageIdStrong);
79687969 LLVMSetAlignment(global_value, var->align_bytes);
79697970 LLVMSetGlobalConstant(global_value, var->gen_is_const);
......@@ -7976,7 +7977,7 @@ static void do_code_gen(CodeGen *g) {
79767977 global_value = var->const_value->llvm_global;
79777978
79787979 if (exported) {
7979 LLVMSetLinkage(global_value, to_llvm_linkage(linkage));
7980 LLVMSetLinkage(global_value, to_llvm_linkage(linkage, false));
79807981 maybe_export_dll(g, global_value, GlobalLinkageIdStrong);
79817982 }
79827983 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
2567925679 struct_field_val->type = type_info_struct_field_type;
2568025680
2568125681 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;
25701 inner_fields[2]->type = ira->codegen->builtin_types.entry_type;
25702 inner_fields[2]->data.x_type = struct_field->type_entry;
25683 inner_fields[1]->special = ConstValSpecialStatic;
25684 inner_fields[1]->type = ira->codegen->builtin_types.entry_type;
25685 inner_fields[1]->data.x_type = struct_field->type_entry;
2570325686
2570425687 // default_value: anytype
25705 inner_fields[3]->special = ConstValSpecialStatic;
25706 inner_fields[3]->type = get_optional_type2(ira->codegen, struct_field->type_entry);
25707 if (inner_fields[3]->type == nullptr) return ErrorSemanticAnalyzeFail;
25688 inner_fields[2]->special = ConstValSpecialStatic;
25689 inner_fields[2]->type = get_optional_type2(ira->codegen, struct_field->type_entry);
25690 if (inner_fields[2]->type == nullptr) return ErrorSemanticAnalyzeFail;
2570825691 memoize_field_init_val(ira->codegen, type_entry, struct_field);
2570925692 if(struct_field->init_val != nullptr && type_is_invalid(struct_field->init_val->type)){
2571025693 return ErrorSemanticAnalyzeFail;
2571125694 }
25712 set_optional_payload(inner_fields[3], struct_field->init_val);
25695 set_optional_payload(inner_fields[2], struct_field->init_val);
2571325696
2571425697 ZigValue *name = create_const_str_lit(ira->codegen, struct_field->name)->data.x_ptr.data.ref.pointee;
2571525698 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
2596025943 return value->data.x_optional->data.x_type;
2596125944}
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
2596325976static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeId tagTypeId, ZigValue *payload) {
2596425977 Error err;
2596525978 switch (tagTypeId) {
......@@ -26163,30 +26176,9 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeI
2616326176 assert(error->type == ir_type_info_get_type(ira, "Error", nullptr));
2616426177 ErrorTableEntry *err_entry = heap::c_allocator.create<ErrorTableEntry>();
2616526178 err_entry->decl_node = source_instr->source_node;
26166 ZigValue *name_slice = get_const_field(ira, source_instr->source_node, error, "name", 0);
26167 ZigValue *name_ptr = name_slice->data.x_struct.fields[slice_ptr_index];
26168 ZigValue *name_len = name_slice->data.x_struct.fields[slice_len_index];
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 }
26179 Error err;
26180 if ((err = get_const_field_buf(ira, source_instr->source_node, error, "name", 0, &err_entry->name)))
26181 return ira->codegen->invalid_inst_gen->value->type;
2619026182 auto existing_entry = ira->codegen->error_table.put_unique(&err_entry->name, err_entry);
2619126183 if (existing_entry) {
2619226184 err_entry->value = existing_entry->value->value;
......@@ -26206,14 +26198,92 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeI
2620626198 }
2620726199 return err_set_type;
2620826200 }
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 }
2620926280 case ZigTypeIdEnum:
26281 case ZigTypeIdUnion:
2621026282 ir_add_error(ira, source_instr, buf_sprintf(
2621126283 "TODO implement @Type for 'TypeInfo.%s': see https://github.com/ziglang/zig/issues/2907", type_id_name(tagTypeId)));
2621226284 return ira->codegen->invalid_inst_gen->value->type;
26213 case ZigTypeIdUnion:
2621426285 case ZigTypeIdFn:
2621526286 case ZigTypeIdBoundFn:
26216 case ZigTypeIdStruct:
2621726287 ir_add_error(ira, source_instr, buf_sprintf(
2621826288 "@Type not available for 'TypeInfo.%s'", type_id_name(tagTypeId)));
2621926289 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
680680 AstNode *var_decl = ast_parse_var_decl(pc);
681681 if (var_decl != nullptr) {
682682 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 }
683686 var_decl->line = first->start_line;
684687 var_decl->column = first->start_column;
685688 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");
22const std = @import("std");
33
44pub 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
511 cases.addTest("duplicate/unused labels",
612 \\comptime {
713 \\ blk: { blk: while (false) {} }
......@@ -1395,12 +1401,12 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
13951401 "tmp.zig:3:36: error: expected type 'std.builtin.TypeInfo', found 'std.builtin.Int'",
13961402 });
13971403
1398 cases.add("Struct unavailable for @Type",
1404 cases.add("struct with declarations unavailable for @Type",
13991405 \\export fn entry() void {
1400 \\ _ = @Type(@typeInfo(struct { }));
1406 \\ _ = @Type(@typeInfo(struct { const foo = 1; }));
14011407 \\}
14021408 , &[_][]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",
14041410 });
14051411
14061412 cases.add("wrong type for argument tuple to @asyncCall",
test/run_translated_c.zig+14
......@@ -3,6 +3,20 @@ const tests = @import("tests.zig");
33const nl = std.cstr.line_sep;
44
55pub 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
620 cases.add("array initializer",
721 \\#include <stdlib.h>
822 \\int main(int argc, char **argv) {
test/stack_traces.zig+3-3
......@@ -282,10 +282,10 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
282282 \\source.zig:10:8: [address] in main (test)
283283 \\ foo();
284284 \\ ^
285 \\start.zig:249:29: [address] in std.start.posixCallMainAndExit (test)
285 \\start.zig:254:29: [address] in std.start.posixCallMainAndExit (test)
286286 \\ return root.main();
287287 \\ ^
288 \\start.zig:123:5: [address] in std.start._start (test)
288 \\start.zig:128:5: [address] in std.start._start (test)
289289 \\ @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});
290290 \\ ^
291291 \\
......@@ -294,7 +294,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
294294 switch (std.Target.current.cpu.arch) {
295295 .aarch64 => "", // TODO disabled; results in segfault
296296 else =>
297 \\start.zig:123:5: [address] in std.start._start (test)
297 \\start.zig:128:5: [address] in std.start._start (test)
298298 \\ @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});
299299 \\ ^
300300 \\
test/stage1/behavior/type.zig+44
......@@ -236,3 +236,47 @@ test "Type.ErrorSet" {
236236 _ = @Type(@typeInfo(error{A}));
237237 _ = @Type(@typeInfo(error{ A, B, C }));
238238}
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 {
238238 expect(struct_info == .Struct);
239239 expect(struct_info.Struct.layout == .Packed);
240240 expect(struct_info.Struct.fields.len == 4);
241 expect(struct_info.Struct.fields[1].offset == null);
242241 expect(struct_info.Struct.fields[2].field_type == *TestStruct);
243242 expect(struct_info.Struct.fields[2].default_value == null);
244243 expect(struct_info.Struct.fields[3].default_value.? == 4);
......@@ -320,16 +319,6 @@ fn testAnyFrame() void {
320319 }
321320}
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
333322test "type info: pass to function" {
334323 _ = passTypeInfo(@typeInfo(void));
335324 _ = 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 @@
1const std = @import("std");
12const 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
326pub fn addCases(ctx: *TestContext) !void {
4 try @import("compile_errors.zig").addCases(ctx);
5 try @import("compare_output.zig").addCases(ctx);
627 try @import("zir.zig").addCases(ctx);
728 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"});
8736}
test/standalone/global_linkage/obj1.zig+2-2
......@@ -1,5 +1,5 @@
1extern var internal_integer: usize = 1;
2extern var obj1_integer: usize = 421;
1var internal_integer: usize = 1;
2var obj1_integer: usize = 421;
33
44comptime {
55 @export(internal_integer, .{ .name = "internal_integer", .linkage = .Internal });
test/standalone/global_linkage/obj2.zig+2-2
......@@ -1,5 +1,5 @@
1extern var internal_integer: usize = 2;
2extern var obj2_integer: usize = 422;
1var internal_integer: usize = 2;
2var obj2_integer: usize = 422;
33
44comptime {
55 @export(internal_integer, .{ .name = "internal_integer", .linkage = .Internal });
test/translate_c.zig+18-3
......@@ -3,6 +3,20 @@ const std = @import("std");
33const CrossTarget = std.zig.CrossTarget;
44
55pub 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
620 cases.add("missing return stmt",
721 \\int foo() {}
822 \\int bar() {
......@@ -466,7 +480,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
466480 , &[_][]const u8{
467481 \\pub extern var extern_var: c_int;
468482 \\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);
470484 });
471485
472486 cases.add("const ptr initializer",
......@@ -480,8 +494,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
480494 \\ static const char v2[] = "2.2.2";
481495 \\}
482496 , &[_][]const u8{
497 \\const v2: [*c]const u8 = "2.2.2";
483498 \\pub export fn foo() void {
484 \\ const v2: [*c]const u8 = "2.2.2";
499 \\ _ = v2;
485500 \\}
486501 });
487502
......@@ -1327,7 +1342,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
13271342 \\static char arr1[] = "hello";
13281343 \\char arr2[] = "hello";
13291344 , &[_][]const u8{
1330 \\pub extern var arr0: [*c]u8 = "hello";
1345 \\pub export var arr0: [*c]u8 = "hello";
13311346 \\pub var arr1: [*c]u8 = "hello";
13321347 \\pub export var arr2: [*c]u8 = "hello";
13331348 });
tools/process_headers.zig+1-1
......@@ -313,7 +313,7 @@ pub fn main() !void {
313313 var max_bytes_saved: usize = 0;
314314 var total_bytes: usize = 0;
315315
316 var hasher = std.crypto.Sha256.init();
316 var hasher = std.crypto.hash.sha2.Sha256.init(.{});
317317
318318 for (libc_targets) |libc_target| {
319319 const dest_target = DestTarget{