From f47c6d3c6b5325ae682e50950765d352b2929126 Mon Sep 17 00:00:00 2001 From: Luna Date: Sun, 28 Jun 2020 17:38:24 -0300 Subject: [PATCH 01/66] std.os: make EBADF return error for read and write --- lib/std/elf.zig | 1 + lib/std/os.zig | 20 +++++++++++--------- lib/std/zig/system.zig | 1 + src-self-hosted/main.zig | 2 ++ src-self-hosted/stage2.zig | 4 ++++ 5 files changed, 19 insertions(+), 9 deletions(-) diff --git a/lib/std/elf.zig b/lib/std/elf.zig index dd22a42304..3b0d749a66 100644 --- a/lib/std/elf.zig +++ b/lib/std/elf.zig @@ -551,6 +551,7 @@ fn preadNoEof(file: std.fs.File, buf: []u8, offset: u64) !void { error.InputOutput => return error.FileSystem, error.Unexpected => return error.Unexpected, error.WouldBlock => return error.Unexpected, + error.NotOpenForReading => return error.Unexpected, }; if (len == 0) return error.UnexpectedEndOfFile; i += len; diff --git a/lib/std/os.zig b/lib/std/os.zig index 99d66db2bb..0dcece611c 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -296,6 +296,7 @@ pub const ReadError = error{ BrokenPipe, ConnectionResetByPeer, ConnectionTimedOut, + NotOpenForReading, /// This error occurs when no global event loop is configured, /// and reading from the file descriptor would block. @@ -359,7 +360,7 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize { } else { return error.WouldBlock; }, - EBADF => unreachable, // Always a race condition. + EBADF => return error.NotOpenForReading, // Can be a race condition. EIO => return error.InputOutput, EISDIR => return error.IsDir, ENOBUFS => return error.SystemResources, @@ -420,7 +421,7 @@ pub fn readv(fd: fd_t, iov: []const iovec) ReadError!usize { } else { return error.WouldBlock; }, - EBADF => unreachable, // always a race condition + EBADF => return error.NotOpenForReading, // can be a race condition EIO => return error.InputOutput, EISDIR => return error.IsDir, ENOBUFS => return error.SystemResources, @@ -483,7 +484,7 @@ pub fn pread(fd: fd_t, buf: []u8, offset: u64) PReadError!usize { } else { return error.WouldBlock; }, - EBADF => unreachable, // Always a race condition. + EBADF => return error.NotOpenForReading, // Can be a race condition. EIO => return error.InputOutput, EISDIR => return error.IsDir, ENOBUFS => return error.SystemResources, @@ -623,7 +624,7 @@ pub fn preadv(fd: fd_t, iov: []const iovec, offset: u64) PReadError!usize { } else { return error.WouldBlock; }, - EBADF => unreachable, // always a race condition + EBADF => return error.NotOpenForReading, // can be a race condition EIO => return error.InputOutput, EISDIR => return error.IsDir, ENOBUFS => return error.SystemResources, @@ -645,6 +646,7 @@ pub const WriteError = error{ BrokenPipe, SystemResources, OperationAborted, + NotOpenForWriting, /// This error occurs when no global event loop is configured, /// and reading from the file descriptor would block. @@ -720,7 +722,7 @@ pub fn write(fd: fd_t, bytes: []const u8) WriteError!usize { } else { return error.WouldBlock; }, - EBADF => unreachable, // Always a race condition. + EBADF => return error.NotOpenForWriting, // can be a race condition. EDESTADDRREQ => unreachable, // `connect` was never called. EDQUOT => return error.DiskQuota, EFBIG => return error.FileTooBig, @@ -792,7 +794,7 @@ pub fn writev(fd: fd_t, iov: []const iovec_const) WriteError!usize { } else { return error.WouldBlock; }, - EBADF => unreachable, // Always a race condition. + EBADF => return error.NotOpenForWriting, // Can be a race condition. EDESTADDRREQ => unreachable, // `connect` was never called. EDQUOT => return error.DiskQuota, EFBIG => return error.FileTooBig, @@ -880,7 +882,7 @@ pub fn pwrite(fd: fd_t, bytes: []const u8, offset: u64) PWriteError!usize { } else { return error.WouldBlock; }, - EBADF => unreachable, // Always a race condition. + EBADF => return error.NotOpenForWriting, // Can be a race condition. EDESTADDRREQ => unreachable, // `connect` was never called. EDQUOT => return error.DiskQuota, EFBIG => return error.FileTooBig, @@ -967,7 +969,7 @@ pub fn pwritev(fd: fd_t, iov: []const iovec_const, offset: u64) PWriteError!usiz } else { return error.WouldBlock; }, - EBADF => unreachable, // Always a race condition. + EBADF => return error.NotOpenForWriting, // Can be a race condition. EDESTADDRREQ => unreachable, // `connect` was never called. EDQUOT => return error.DiskQuota, EFBIG => return error.FileTooBig, @@ -1162,7 +1164,7 @@ pub fn dup2(old_fd: fd_t, new_fd: fd_t) !void { EBUSY, EINTR => continue, EMFILE => return error.ProcessFdQuotaExceeded, EINVAL => unreachable, // invalid parameters passed to dup2 - EBADF => unreachable, // always a race condition + EBADF => unreachable, // invalid file descriptor else => |err| return unexpectedErrno(err), } } diff --git a/lib/std/zig/system.zig b/lib/std/zig/system.zig index 64c9401dbc..8a2c1dfc87 100644 --- a/lib/std/zig/system.zig +++ b/lib/std/zig/system.zig @@ -851,6 +851,7 @@ pub const NativeTargetInfo = struct { const len = file.pread(buf[i .. buf.len - i], offset + i) catch |err| switch (err) { error.OperationAborted => unreachable, // Windows-only error.WouldBlock => unreachable, // Did not request blocking mode + error.NotOpenForReading => unreachable, error.SystemResources => return error.SystemResources, error.IsDir => return error.UnableToReadElfFile, error.BrokenPipe => return error.UnableToReadElfFile, diff --git a/src-self-hosted/main.zig b/src-self-hosted/main.zig index 3743b4f334..be1e941992 100644 --- a/src-self-hosted/main.zig +++ b/src-self-hosted/main.zig @@ -696,6 +696,7 @@ const FmtError = error{ LinkQuotaExceeded, FileBusy, EndOfStream, + NotOpenForWriting, } || fs.File.OpenError; fn fmtPath(fmt: *Fmt, file_path: []const u8, check_mode: bool, dir: fs.Dir, sub_path: []const u8) FmtError!void { @@ -761,6 +762,7 @@ fn fmtPathFile( const source_code = source_file.readAllAlloc(fmt.gpa, stat.size, max_src_size) catch |err| switch (err) { error.ConnectionResetByPeer => unreachable, error.ConnectionTimedOut => unreachable, + error.NotOpenForReading => unreachable, else => |e| return e, }; source_file.close(); diff --git a/src-self-hosted/stage2.zig b/src-self-hosted/stage2.zig index bd24ffb399..33e9200902 100644 --- a/src-self-hosted/stage2.zig +++ b/src-self-hosted/stage2.zig @@ -153,6 +153,7 @@ export fn stage2_render_ast(tree: *ast.Tree, output_file: *FILE) Error { const c_out_stream = std.io.cOutStream(output_file); _ = std.zig.render(std.heap.c_allocator, c_out_stream, tree) catch |e| switch (e) { error.WouldBlock => unreachable, // stage1 opens stuff in exclusively blocking mode + error.NotOpenForWriting => unreachable, error.SystemResources => return .SystemResources, error.OperationAborted => return .OperationAborted, error.BrokenPipe => return .BrokenPipe, @@ -585,6 +586,8 @@ export fn stage2_libc_parse(stage1_libc: *Stage2LibCInstallation, libc_file_z: [ error.SystemResources => return .SystemResources, error.OperationAborted => return .OperationAborted, error.WouldBlock => unreachable, + error.NotOpenForWriting => unreachable, + error.NotOpenForReading => unreachable, error.Unexpected => return .Unexpected, error.EndOfStream => return .EndOfFile, error.IsDir => return .IsDir, @@ -640,6 +643,7 @@ export fn stage2_libc_render(stage1_libc: *Stage2LibCInstallation, output_file: const c_out_stream = std.io.cOutStream(output_file); libc.render(c_out_stream) catch |err| switch (err) { error.WouldBlock => unreachable, // stage1 opens stuff in exclusively blocking mode + error.NotOpenForWriting => unreachable, error.SystemResources => return .SystemResources, error.OperationAborted => return .OperationAborted, error.BrokenPipe => return .BrokenPipe, From 3f5b2d6c51b983ae66ad20124924378c2291cd67 Mon Sep 17 00:00:00 2001 From: Luna Date: Mon, 29 Jun 2020 16:23:58 -0300 Subject: [PATCH 02/66] std.os: map EBADF to errors on WASI read/write syscalls --- lib/std/os.zig | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/std/os.zig b/lib/std/os.zig index 0dcece611c..5677ab5e30 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -329,7 +329,7 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize { wasi.EINVAL => unreachable, wasi.EFAULT => unreachable, wasi.EAGAIN => unreachable, - wasi.EBADF => unreachable, // Always a race condition. + wasi.EBADF => return error.NotOpenForReading, // Can be a race condition. wasi.EIO => return error.InputOutput, wasi.EISDIR => return error.IsDir, wasi.ENOBUFS => return error.SystemResources, @@ -398,7 +398,7 @@ pub fn readv(fd: fd_t, iov: []const iovec) ReadError!usize { wasi.EINVAL => unreachable, wasi.EFAULT => unreachable, wasi.EAGAIN => unreachable, // currently not support in WASI - wasi.EBADF => unreachable, // always a race condition + wasi.EBADF => return error.NotOpenForReading, // can be a race condition wasi.EIO => return error.InputOutput, wasi.EISDIR => return error.IsDir, wasi.ENOBUFS => return error.SystemResources, @@ -458,7 +458,7 @@ pub fn pread(fd: fd_t, buf: []u8, offset: u64) PReadError!usize { wasi.EINVAL => unreachable, wasi.EFAULT => unreachable, wasi.EAGAIN => unreachable, - wasi.EBADF => unreachable, // Always a race condition. + wasi.EBADF => return error.NotOpenForReading, // Can be a race condition. wasi.EIO => return error.InputOutput, wasi.EISDIR => return error.IsDir, wasi.ENOBUFS => return error.SystemResources, @@ -597,7 +597,7 @@ pub fn preadv(fd: fd_t, iov: []const iovec, offset: u64) PReadError!usize { wasi.EINVAL => unreachable, wasi.EFAULT => unreachable, wasi.EAGAIN => unreachable, - wasi.EBADF => unreachable, // always a race condition + wasi.EBADF => return error.NotOpenForReading, // can be a race condition wasi.EIO => return error.InputOutput, wasi.EISDIR => return error.IsDir, wasi.ENOBUFS => return error.SystemResources, @@ -691,7 +691,7 @@ pub fn write(fd: fd_t, bytes: []const u8) WriteError!usize { wasi.EINVAL => unreachable, wasi.EFAULT => unreachable, wasi.EAGAIN => unreachable, - wasi.EBADF => unreachable, // Always a race condition. + wasi.EBADF => return error.NotOpenForWriting, // can be a race condition. wasi.EDESTADDRREQ => unreachable, // `connect` was never called. wasi.EDQUOT => return error.DiskQuota, wasi.EFBIG => return error.FileTooBig, @@ -768,7 +768,7 @@ pub fn writev(fd: fd_t, iov: []const iovec_const) WriteError!usize { wasi.EINVAL => unreachable, wasi.EFAULT => unreachable, wasi.EAGAIN => unreachable, - wasi.EBADF => unreachable, // Always a race condition. + wasi.EBADF => return error.NotOpenForWriting, // can be a race condition. wasi.EDESTADDRREQ => unreachable, // `connect` was never called. wasi.EDQUOT => return error.DiskQuota, wasi.EFBIG => return error.FileTooBig, @@ -847,7 +847,7 @@ pub fn pwrite(fd: fd_t, bytes: []const u8, offset: u64) PWriteError!usize { wasi.EINVAL => unreachable, wasi.EFAULT => unreachable, wasi.EAGAIN => unreachable, - wasi.EBADF => unreachable, // Always a race condition. + wasi.EBADF => return error.NotOpenForWriting, // can be a race condition. wasi.EDESTADDRREQ => unreachable, // `connect` was never called. wasi.EDQUOT => return error.DiskQuota, wasi.EFBIG => return error.FileTooBig, @@ -940,7 +940,7 @@ pub fn pwritev(fd: fd_t, iov: []const iovec_const, offset: u64) PWriteError!usiz wasi.EINVAL => unreachable, wasi.EFAULT => unreachable, wasi.EAGAIN => unreachable, - wasi.EBADF => unreachable, // Always a race condition. + wasi.EBADF => return error.NotOpenForWriting, // Can be a race condition. wasi.EDESTADDRREQ => unreachable, // `connect` was never called. wasi.EDQUOT => return error.DiskQuota, wasi.EFBIG => return error.FileTooBig, From 0977e4140768447e57474792ff42d056a8f2e0ed Mon Sep 17 00:00:00 2001 From: Vexu Date: Tue, 18 Aug 2020 10:36:57 +0300 Subject: [PATCH 03/66] stage2: ensure discarded error union payload is void --- src-self-hosted/astgen.zig | 6 +++++- src-self-hosted/zir.zig | 4 ++++ src-self-hosted/zir_sema.zig | 5 +++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src-self-hosted/astgen.zig b/src-self-hosted/astgen.zig index 3a9c7e6c59..b521e1543a 100644 --- a/src-self-hosted/astgen.zig +++ b/src-self-hosted/astgen.zig @@ -600,7 +600,11 @@ const CondKind = union(enum) { fn thenSubScope(self: CondKind, mod: *Module, then_scope: *Scope.GenZIR, src: usize, payload_node: ?*ast.Node) !*Scope { if (self == .bool) return &then_scope.base; - const payload = payload_node.?.castTag(.PointerPayload).?; + const payload = payload_node.?.castTag(.PointerPayload) orelse { + // condition is error union and payload is not explicitly ignored + _ = try addZIRUnOp(mod, &then_scope.base, src, .ensure_err_payload_void, self.err_union.?); + return &then_scope.base; + }; const is_ptr = payload.ptr_token != null; const ident_node = payload.value_symbol.castTag(.Identifier).?; diff --git a/src-self-hosted/zir.zig b/src-self-hosted/zir.zig index 276db6d522..ebc491c943 100644 --- a/src-self-hosted/zir.zig +++ b/src-self-hosted/zir.zig @@ -225,6 +225,8 @@ pub const Inst = struct { unwrap_err_safe, /// Same as previous, but without safety checks. Used for orelse, if and while unwrap_err_unsafe, + /// Takes a *E!T and raises a compiler error if T != void + ensure_err_payload_void, pub fn Type(tag: Tag) type { return switch (tag) { @@ -259,6 +261,7 @@ pub const Inst = struct { .unwrap_optional_unsafe, .unwrap_err_safe, .unwrap_err_unsafe, + .ensure_err_payload_void, => UnOp, .add, @@ -398,6 +401,7 @@ pub const Inst = struct { .unwrap_err_safe, .unwrap_err_unsafe, .ptr_type, + .ensure_err_payload_void, => false, .@"break", diff --git a/src-self-hosted/zir_sema.zig b/src-self-hosted/zir_sema.zig index 94c3a19677..d51d0d0f7f 100644 --- a/src-self-hosted/zir_sema.zig +++ b/src-self-hosted/zir_sema.zig @@ -112,6 +112,7 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError! .unwrap_optional_unsafe => return analyzeInstUnwrapOptional(mod, scope, old_inst.castTag(.unwrap_optional_unsafe).?, false), .unwrap_err_safe => return analyzeInstUnwrapErr(mod, scope, old_inst.castTag(.unwrap_err_safe).?, true), .unwrap_err_unsafe => return analyzeInstUnwrapErr(mod, scope, old_inst.castTag(.unwrap_err_unsafe).?, false), + .ensure_err_payload_void => return analyzeInstEnsureErrPayloadVoid(mod, scope, old_inst.castTag(.ensure_err_payload_void).?), } } @@ -735,6 +736,10 @@ fn analyzeInstUnwrapErr(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp, saf return mod.fail(scope, unwrap.base.src, "TODO implement analyzeInstUnwrapErr", .{}); } +fn analyzeInstEnsureErrPayloadVoid(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp) InnerError!*Inst { + return mod.fail(scope, unwrap.base.src, "TODO implement analyzeInstEnsureErrPayloadVoid", .{}); +} + fn analyzeInstFnType(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnType) InnerError!*Inst { const return_type = try resolveType(mod, scope, fntype.positionals.return_type); From 3eb8f7be1018cef3043bfb56a0e2c3ff323e91d5 Mon Sep 17 00:00:00 2001 From: Vexu Date: Tue, 18 Aug 2020 11:38:56 +0300 Subject: [PATCH 04/66] stage2: astgen bool and/or --- src-self-hosted/astgen.zig | 89 ++++++++++++++++++++++++++++++++++++-- src-self-hosted/zir.zig | 4 ++ 2 files changed, 90 insertions(+), 3 deletions(-) diff --git a/src-self-hosted/astgen.zig b/src-self-hosted/astgen.zig index b521e1543a..b8860d7df6 100644 --- a/src-self-hosted/astgen.zig +++ b/src-self-hosted/astgen.zig @@ -100,6 +100,9 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr .ArrayCat => return simpleBinOp(mod, scope, rl, node.castTag(.ArrayCat).?, .array_cat), .ArrayMult => return simpleBinOp(mod, scope, rl, node.castTag(.ArrayMult).?, .array_mul), + .BoolAnd => return boolBinOp(mod, scope, rl, node.castTag(.BoolAnd).?), + .BoolOr => return boolBinOp(mod, scope, rl, node.castTag(.BoolOr).?), + .Identifier => return try identifier(mod, scope, rl, node.castTag(.Identifier).?), .Asm => return rlWrap(mod, scope, rl, try assembly(mod, scope, node.castTag(.Asm).?)), .StringLiteral => return rlWrap(mod, scope, rl, try stringLiteral(mod, scope, node.castTag(.StringLiteral).?)), @@ -124,11 +127,10 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr .LabeledBlock => return labeledBlockExpr(mod, scope, rl, node.castTag(.LabeledBlock).?), .Break => return rlWrap(mod, scope, rl, try breakExpr(mod, scope, node.castTag(.Break).?)), .PtrType => return rlWrap(mod, scope, rl, try ptrType(mod, scope, node.castTag(.PtrType).?)), + .GroupedExpression => return expr(mod, scope, rl, node.castTag(.GroupedExpression).?.expr), .Defer => return mod.failNode(scope, node, "TODO implement astgen.expr for .Defer", .{}), .Catch => return mod.failNode(scope, node, "TODO implement astgen.expr for .Catch", .{}), - .BoolAnd => return mod.failNode(scope, node, "TODO implement astgen.expr for .BoolAnd", .{}), - .BoolOr => return mod.failNode(scope, node, "TODO implement astgen.expr for .BoolOr", .{}), .ErrorUnion => return mod.failNode(scope, node, "TODO implement astgen.expr for .ErrorUnion", .{}), .MergeErrorSets => return mod.failNode(scope, node, "TODO implement astgen.expr for .MergeErrorSets", .{}), .Range => return mod.failNode(scope, node, "TODO implement astgen.expr for .Range", .{}), @@ -159,7 +161,6 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr .EnumLiteral => return mod.failNode(scope, node, "TODO implement astgen.expr for .EnumLiteral", .{}), .MultilineStringLiteral => return mod.failNode(scope, node, "TODO implement astgen.expr for .MultilineStringLiteral", .{}), .CharLiteral => return mod.failNode(scope, node, "TODO implement astgen.expr for .CharLiteral", .{}), - .GroupedExpression => return mod.failNode(scope, node, "TODO implement astgen.expr for .GroupedExpression", .{}), .ErrorSetDecl => return mod.failNode(scope, node, "TODO implement astgen.expr for .ErrorSetDecl", .{}), .ContainerDecl => return mod.failNode(scope, node, "TODO implement astgen.expr for .ContainerDecl", .{}), .Comptime => return mod.failNode(scope, node, "TODO implement astgen.expr for .Comptime", .{}), @@ -568,6 +569,88 @@ fn simpleBinOp( return rlWrap(mod, scope, rl, result); } +fn boolBinOp( + mod: *Module, + scope: *Scope, + rl: ResultLoc, + infix_node: *ast.Node.SimpleInfixOp, +) InnerError!*zir.Inst { + const tree = scope.tree(); + const src = tree.token_locs[infix_node.op_token].start; + const bool_type = try addZIRInstConst(mod, scope, src, .{ + .ty = Type.initTag(.type), + .val = Value.initTag(.bool_type), + }); + + var block_scope: Scope.GenZIR = .{ + .parent = scope, + .decl = scope.decl().?, + .arena = scope.arena(), + .instructions = .{}, + }; + defer block_scope.instructions.deinit(mod.gpa); + + const lhs = try expr(mod, scope, .{ .ty = bool_type }, infix_node.lhs); + const condbr = try addZIRInstSpecial(mod, &block_scope.base, src, zir.Inst.CondBr, .{ + .condition = lhs, + .then_body = undefined, // populated below + .else_body = undefined, // populated below + }, .{}); + + const block = try addZIRInstBlock(mod, scope, src, .{ + .instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items), + }); + + var rhs_scope: Scope.GenZIR = .{ + .parent = scope, + .decl = block_scope.decl, + .arena = block_scope.arena, + .instructions = .{}, + }; + defer rhs_scope.instructions.deinit(mod.gpa); + + const rhs = try expr(mod, &rhs_scope.base, .{ .ty = bool_type }, infix_node.rhs); + _ = try addZIRInst(mod, &rhs_scope.base, src, zir.Inst.Break, .{ + .block = block, + .operand = rhs, + }, .{}); + + var const_scope: Scope.GenZIR = .{ + .parent = scope, + .decl = block_scope.decl, + .arena = block_scope.arena, + .instructions = .{}, + }; + defer const_scope.instructions.deinit(mod.gpa); + + const is_bool_and = infix_node.base.tag == .BoolAnd; + _ = try addZIRInst(mod, &const_scope.base, src, zir.Inst.Break, .{ + .block = block, + .operand = try addZIRInstConst(mod, &const_scope.base, src, .{ + .ty = Type.initTag(.bool), + .val = if (is_bool_and) Value.initTag(.bool_false) else Value.initTag(.bool_true), + }), + }, .{}); + + if (is_bool_and) { + // if lhs // AND + // break rhs + // else + // break false + condbr.positionals.then_body = .{ .instructions = try rhs_scope.arena.dupe(*zir.Inst, rhs_scope.instructions.items) }; + condbr.positionals.else_body = .{ .instructions = try const_scope.arena.dupe(*zir.Inst, const_scope.instructions.items) }; + } else { + // if lhs // OR + // break true + // else + // break rhs + condbr.positionals.then_body = .{ .instructions = try const_scope.arena.dupe(*zir.Inst, const_scope.instructions.items) }; + condbr.positionals.else_body = .{ .instructions = try rhs_scope.arena.dupe(*zir.Inst, rhs_scope.instructions.items) }; + } + + return rlWrap(mod, scope, rl, &block.base); +} + const CondKind = union(enum) { bool, optional: ?*zir.Inst, diff --git a/src-self-hosted/zir.zig b/src-self-hosted/zir.zig index ebc491c943..3e8400dca7 100644 --- a/src-self-hosted/zir.zig +++ b/src-self-hosted/zir.zig @@ -1924,6 +1924,10 @@ const EmitZIR = struct { return self.emitUnnamedDecl(&str_inst.base); }, .Void => return self.emitPrimitive(src, .void_value), + .Bool => if (typed_value.val.toBool()) + return self.emitPrimitive(src, .@"true") + else + return self.emitPrimitive(src, .@"false"), else => |t| std.debug.panic("TODO implement emitTypedValue for {}", .{@tagName(t)}), } } From 7c15c9428e9df26c8699f034704796b03cf839b9 Mon Sep 17 00:00:00 2001 From: Vexu Date: Tue, 18 Aug 2020 12:24:23 +0300 Subject: [PATCH 05/66] stage2: array types --- src-self-hosted/Module.zig | 67 +++++++++++++++++- src-self-hosted/astgen.zig | 46 ++++++++++++- src-self-hosted/type.zig | 127 +++++++++++++++++++++++++++++------ src-self-hosted/zir.zig | 20 ++++++ src-self-hosted/zir_sema.zig | 45 ++++++------- 5 files changed, 255 insertions(+), 50 deletions(-) diff --git a/src-self-hosted/Module.zig b/src-self-hosted/Module.zig index 6e33101e76..3c31c7da44 100644 --- a/src-self-hosted/Module.zig +++ b/src-self-hosted/Module.zig @@ -2902,7 +2902,7 @@ pub fn floatSub(self: *Module, scope: *Scope, float_type: Type, src: usize, lhs: return Value.initPayload(val_payload); } -pub fn singlePtrType(self: *Module, scope: *Scope, src: usize, mutable: bool, elem_ty: Type) error{OutOfMemory}!Type { +pub fn singlePtrType(self: *Module, scope: *Scope, src: usize, mutable: bool, elem_ty: Type) Allocator.Error!Type { const type_payload = try scope.arena().create(Type.Payload.Pointer); type_payload.* = .{ .base = .{ .tag = if (mutable) .single_mut_pointer else .single_const_pointer }, @@ -2911,6 +2911,71 @@ pub fn singlePtrType(self: *Module, scope: *Scope, src: usize, mutable: bool, el return Type.initPayload(&type_payload.base); } +pub fn optionalType(self: *Module, scope: *Scope, child_type: Type) Allocator.Error!Type { + return Type.initPayload(switch (child_type.tag()) { + .single_const_pointer => blk: { + const payload = try scope.arena().create(Type.Payload.Pointer); + payload.* = .{ + .base = .{ .tag = .optional_single_const_pointer }, + .pointee_type = child_type.elemType(), + }; + break :blk &payload.base; + }, + .single_mut_pointer => blk: { + const payload = try scope.arena().create(Type.Payload.Pointer); + payload.* = .{ + .base = .{ .tag = .optional_single_mut_pointer }, + .pointee_type = child_type.elemType(), + }; + break :blk &payload.base; + }, + else => blk: { + const payload = try scope.arena().create(Type.Payload.Optional); + payload.* = .{ + .child_type = child_type, + }; + break :blk &payload.base; + }, + }); +} + +pub fn arrayType(self: *Module, scope: *Scope, len: u64, sentinel: ?Value, elem_type: Type) Allocator.Error!Type { + if (elem_type.eql(Type.initTag(.u8))) { + if (sentinel) |some| { + if (some.eql(Value.initTag(.zero))) { + const payload = try scope.arena().create(Type.Payload.Array_u8_Sentinel0); + payload.* = .{ + .len = len, + }; + return Type.initPayload(&payload.base); + } + } else { + const payload = try scope.arena().create(Type.Payload.Array_u8); + payload.* = .{ + .len = len, + }; + return Type.initPayload(&payload.base); + } + } + + if (sentinel) |some| { + const payload = try scope.arena().create(Type.Payload.ArraySentinel); + payload.* = .{ + .len = len, + .sentinel = some, + .elem_type = elem_type, + }; + return Type.initPayload(&payload.base); + } + + const payload = try scope.arena().create(Type.Payload.Array); + payload.* = .{ + .len = len, + .elem_type = elem_type, + }; + return Type.initPayload(&payload.base); +} + pub fn dumpInst(self: *Module, scope: *Scope, inst: *Inst) void { const zir_module = scope.namespace(); const source = zir_module.getSource(self) catch @panic("dumpInst failed to get source"); diff --git a/src-self-hosted/astgen.zig b/src-self-hosted/astgen.zig index b8860d7df6..46ccde10f1 100644 --- a/src-self-hosted/astgen.zig +++ b/src-self-hosted/astgen.zig @@ -128,6 +128,8 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr .Break => return rlWrap(mod, scope, rl, try breakExpr(mod, scope, node.castTag(.Break).?)), .PtrType => return rlWrap(mod, scope, rl, try ptrType(mod, scope, node.castTag(.PtrType).?)), .GroupedExpression => return expr(mod, scope, rl, node.castTag(.GroupedExpression).?.expr), + .ArrayType => return rlWrap(mod, scope, rl, try arrayType(mod, scope, node.castTag(.ArrayType).?)), + .ArrayTypeSentinel => return rlWrap(mod, scope, rl, try arrayTypeSentinel(mod, scope, node.castTag(.ArrayTypeSentinel).?)), .Defer => return mod.failNode(scope, node, "TODO implement astgen.expr for .Defer", .{}), .Catch => return mod.failNode(scope, node, "TODO implement astgen.expr for .Catch", .{}), @@ -141,8 +143,6 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr .NegationWrap => return mod.failNode(scope, node, "TODO implement astgen.expr for .NegationWrap", .{}), .Resume => return mod.failNode(scope, node, "TODO implement astgen.expr for .Resume", .{}), .Try => return mod.failNode(scope, node, "TODO implement astgen.expr for .Try", .{}), - .ArrayType => return mod.failNode(scope, node, "TODO implement astgen.expr for .ArrayType", .{}), - .ArrayTypeSentinel => return mod.failNode(scope, node, "TODO implement astgen.expr for .ArrayTypeSentinel", .{}), .SliceType => return mod.failNode(scope, node, "TODO implement astgen.expr for .SliceType", .{}), .Slice => return mod.failNode(scope, node, "TODO implement astgen.expr for .Slice", .{}), .ArrayAccess => return mod.failNode(scope, node, "TODO implement astgen.expr for .ArrayAccess", .{}), @@ -485,6 +485,48 @@ fn ptrType(mod: *Module, scope: *Scope, node: *ast.Node.PtrType) InnerError!*zir return addZIRInst(mod, scope, src, zir.Inst.PtrType, .{ .child_type = child_type }, kw_args); } +fn arrayType(mod: *Module, scope: *Scope, node: *ast.Node.ArrayType) !*zir.Inst { + const tree = scope.tree(); + const src = tree.token_locs[node.op_token].start; + const meta_type = try addZIRInstConst(mod, scope, src, .{ + .ty = Type.initTag(.type), + .val = Value.initTag(.type_type), + }); + const usize_type = try addZIRInstConst(mod, scope, src, .{ + .ty = Type.initTag(.type), + .val = Value.initTag(.usize_type), + }); + + const len = try expr(mod, scope, .{ .ty = usize_type }, node.len_expr); + const child_type = try expr(mod, scope, .{ .ty = meta_type }, node.rhs); + + return addZIRBinOp(mod, scope, src, .array_type, len, child_type); +} + +fn arrayTypeSentinel(mod: *Module, scope: *Scope, node: *ast.Node.ArrayTypeSentinel) !*zir.Inst { + const tree = scope.tree(); + const src = tree.token_locs[node.op_token].start; + const meta_type = try addZIRInstConst(mod, scope, src, .{ + .ty = Type.initTag(.type), + .val = Value.initTag(.type_type), + }); + const usize_type = try addZIRInstConst(mod, scope, src, .{ + .ty = Type.initTag(.type), + .val = Value.initTag(.usize_type), + }); + + const len = try expr(mod, scope, .{ .ty = usize_type }, node.len_expr); + const sentinel_uncasted = try expr(mod, scope, .none, node.sentinel); + const elem_type = try expr(mod, scope, .{ .ty = meta_type }, node.rhs); + const sentinel = try addZIRBinOp(mod, scope, src, .as, elem_type, sentinel_uncasted); + + return addZIRInst(mod, scope, src, zir.Inst.ArrayTypeSentinel, .{ + .len = len, + .sentinel = sentinel, + .elem_type = elem_type, + }, .{}); +} + fn unwrapOptional(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.SimpleSuffixOp) InnerError!*zir.Inst { const tree = scope.tree(); const src = tree.token_locs[node.rtoken].start; diff --git a/src-self-hosted/type.zig b/src-self-hosted/type.zig index faba784f90..5329841d4b 100644 --- a/src-self-hosted/type.zig +++ b/src-self-hosted/type.zig @@ -65,7 +65,7 @@ pub const Type = extern union { .fn_ccc_void_no_args => return .Fn, .function => return .Fn, - .array, .array_u8_sentinel_0 => return .Array, + .array, .array_u8_sentinel_0, .array_u8, .array_sentinel => return .Array, .single_const_pointer => return .Pointer, .single_mut_pointer => return .Pointer, .single_const_pointer_to_comptime_int => return .Pointer, @@ -330,6 +330,7 @@ pub const Type = extern union { => unreachable, .array_u8_sentinel_0 => return self.copyPayloadShallow(allocator, Payload.Array_u8_Sentinel0), + .array_u8 => return self.copyPayloadShallow(allocator, Payload.Array_u8), .array => { const payload = @fieldParentPtr(Payload.Array, "base", self.ptr_otherwise); const new_payload = try allocator.create(Payload.Array); @@ -340,6 +341,17 @@ pub const Type = extern union { }; return Type{ .ptr_otherwise = &new_payload.base }; }, + .array_sentinel => { + const payload = @fieldParentPtr(Payload.ArraySentinel, "base", self.ptr_otherwise); + const new_payload = try allocator.create(Payload.ArraySentinel); + new_payload.* = .{ + .base = payload.base, + .len = payload.len, + .sentinel = try payload.sentinel.copy(allocator), + .elem_type = try payload.elem_type.copy(allocator), + }; + return Type{ .ptr_otherwise = &new_payload.base }; + }, .int_signed => return self.copyPayloadShallow(allocator, Payload.IntSigned), .int_unsigned => return self.copyPayloadShallow(allocator, Payload.IntUnsigned), .function => { @@ -445,6 +457,10 @@ pub const Type = extern union { try payload.return_type.format("", .{}, out_stream); }, + .array_u8 => { + const payload = @fieldParentPtr(Payload.Array_u8, "base", ty.ptr_otherwise); + return out_stream.print("[{}]u8", .{payload.len}); + }, .array_u8_sentinel_0 => { const payload = @fieldParentPtr(Payload.Array_u8_Sentinel0, "base", ty.ptr_otherwise); return out_stream.print("[{}:0]u8", .{payload.len}); @@ -455,6 +471,12 @@ pub const Type = extern union { ty = payload.elem_type; continue; }, + .array_sentinel => { + const payload = @fieldParentPtr(Payload.ArraySentinel, "base", ty.ptr_otherwise); + try out_stream.print("[{}:{}]", .{ payload.len, payload.sentinel }); + ty = payload.elem_type; + continue; + }, .single_const_pointer => { const payload = @fieldParentPtr(Payload.Pointer, "base", ty.ptr_otherwise); try out_stream.writeAll("*const "); @@ -588,6 +610,8 @@ pub const Type = extern union { => true, // TODO lazy types .array => self.elemType().hasCodeGenBits() and self.arrayLen() != 0, + .array_u8 => self.arrayLen() != 0, + .array_sentinel => self.elemType().hasCodeGenBits(), .single_const_pointer => self.elemType().hasCodeGenBits(), .single_mut_pointer => self.elemType().hasCodeGenBits(), .int_signed => self.cast(Payload.IntSigned).?.bits == 0, @@ -616,6 +640,7 @@ pub const Type = extern union { .i8, .bool, .array_u8_sentinel_0, + .array_u8, => return 1, .fn_noreturn_no_args, // represents machine code; not a pointer @@ -659,7 +684,7 @@ pub const Type = extern union { .anyerror => return 2, // TODO revisit this when we have the concept of the error tag type - .array => return self.cast(Payload.Array).?.elem_type.abiAlignment(target), + .array, .array_sentinel => return self.elemType().abiAlignment(target), .int_signed, .int_unsigned => { const bits: u16 = if (self.cast(Payload.IntSigned)) |pl| @@ -717,12 +742,18 @@ pub const Type = extern union { .bool, => return 1, - .array_u8_sentinel_0 => @fieldParentPtr(Payload.Array_u8_Sentinel0, "base", self.ptr_otherwise).len, + .array_u8 => @fieldParentPtr(Payload.Array_u8_Sentinel0, "base", self.ptr_otherwise).len, + .array_u8_sentinel_0 => @fieldParentPtr(Payload.Array_u8_Sentinel0, "base", self.ptr_otherwise).len + 1, .array => { const payload = @fieldParentPtr(Payload.Array, "base", self.ptr_otherwise); const elem_size = std.math.max(payload.elem_type.abiAlignment(target), payload.elem_type.abiSize(target)); return payload.len * elem_size; }, + .array_sentinel => { + const payload = @fieldParentPtr(Payload.ArraySentinel, "base", self.ptr_otherwise); + const elem_size = std.math.max(payload.elem_type.abiAlignment(target), payload.elem_type.abiSize(target)); + return (payload.len + 1) * elem_size; + }, .i16, .u16 => return 2, .i32, .u32 => return 4, .i64, .u64 => return 8, @@ -818,6 +849,8 @@ pub const Type = extern union { .@"null", .@"undefined", .array, + .array_sentinel, + .array_u8, .array_u8_sentinel_0, .const_slice_u8, .fn_noreturn_no_args, @@ -875,6 +908,8 @@ pub const Type = extern union { .@"null", .@"undefined", .array, + .array_sentinel, + .array_u8, .array_u8_sentinel_0, .single_const_pointer, .single_mut_pointer, @@ -931,6 +966,8 @@ pub const Type = extern union { .@"null", .@"undefined", .array, + .array_sentinel, + .array_u8, .array_u8_sentinel_0, .fn_noreturn_no_args, .fn_void_no_args, @@ -988,6 +1025,8 @@ pub const Type = extern union { .@"null", .@"undefined", .array, + .array_sentinel, + .array_u8, .array_u8_sentinel_0, .fn_noreturn_no_args, .fn_void_no_args, @@ -1072,9 +1111,10 @@ pub const Type = extern union { => unreachable, .array => self.cast(Payload.Array).?.elem_type, + .array_sentinel => self.cast(Payload.ArraySentinel).?.elem_type, .single_const_pointer => self.castPointer().?.pointee_type, .single_mut_pointer => self.castPointer().?.pointee_type, - .array_u8_sentinel_0, .const_slice_u8 => Type.initTag(.u8), + .array_u8, .array_u8_sentinel_0, .const_slice_u8 => Type.initTag(.u8), .single_const_pointer_to_comptime_int => Type.initTag(.comptime_int), }; } @@ -1176,6 +1216,8 @@ pub const Type = extern union { => unreachable, .array => self.cast(Payload.Array).?.len, + .array_sentinel => self.cast(Payload.ArraySentinel).?.len, + .array_u8 => self.cast(Payload.Array_u8).?.len, .array_u8_sentinel_0 => self.cast(Payload.Array_u8_Sentinel0).?.len, }; } @@ -1232,7 +1274,8 @@ pub const Type = extern union { .optional_single_const_pointer, => unreachable, - .array => return null, + .array, .array_u8 => return null, + .array_sentinel => return self.cast(Payload.ArraySentinel).?.sentinel, .array_u8_sentinel_0 => return Value.initTag(.zero), }; } @@ -1266,10 +1309,12 @@ pub const Type = extern union { .fn_ccc_void_no_args, .function, .array, + .array_sentinel, + .array_u8, + .array_u8_sentinel_0, .single_const_pointer, .single_mut_pointer, .single_const_pointer_to_comptime_int, - .array_u8_sentinel_0, .const_slice_u8, .int_unsigned, .u8, @@ -1324,10 +1369,12 @@ pub const Type = extern union { .fn_ccc_void_no_args, .function, .array, + .array_sentinel, + .array_u8, + .array_u8_sentinel_0, .single_const_pointer, .single_mut_pointer, .single_const_pointer_to_comptime_int, - .array_u8_sentinel_0, .const_slice_u8, .int_signed, .i8, @@ -1382,10 +1429,12 @@ pub const Type = extern union { .fn_ccc_void_no_args, .function, .array, + .array_sentinel, + .array_u8, + .array_u8_sentinel_0, .single_const_pointer, .single_mut_pointer, .single_const_pointer_to_comptime_int, - .array_u8_sentinel_0, .const_slice_u8, .optional, .optional_single_mut_pointer, @@ -1438,10 +1487,12 @@ pub const Type = extern union { .fn_ccc_void_no_args, .function, .array, + .array_sentinel, + .array_u8, + .array_u8_sentinel_0, .single_const_pointer, .single_mut_pointer, .single_const_pointer_to_comptime_int, - .array_u8_sentinel_0, .const_slice_u8, .int_unsigned, .int_signed, @@ -1523,10 +1574,12 @@ pub const Type = extern union { .@"null", .@"undefined", .array, + .array_sentinel, + .array_u8, + .array_u8_sentinel_0, .single_const_pointer, .single_mut_pointer, .single_const_pointer_to_comptime_int, - .array_u8_sentinel_0, .const_slice_u8, .u8, .i8, @@ -1584,10 +1637,12 @@ pub const Type = extern union { .@"null", .@"undefined", .array, + .array_sentinel, + .array_u8, + .array_u8_sentinel_0, .single_const_pointer, .single_mut_pointer, .single_const_pointer_to_comptime_int, - .array_u8_sentinel_0, .const_slice_u8, .u8, .i8, @@ -1644,10 +1699,12 @@ pub const Type = extern union { .@"null", .@"undefined", .array, + .array_sentinel, + .array_u8, + .array_u8_sentinel_0, .single_const_pointer, .single_mut_pointer, .single_const_pointer_to_comptime_int, - .array_u8_sentinel_0, .const_slice_u8, .u8, .i8, @@ -1704,10 +1761,12 @@ pub const Type = extern union { .@"null", .@"undefined", .array, + .array_sentinel, + .array_u8, + .array_u8_sentinel_0, .single_const_pointer, .single_mut_pointer, .single_const_pointer_to_comptime_int, - .array_u8_sentinel_0, .const_slice_u8, .u8, .i8, @@ -1761,10 +1820,12 @@ pub const Type = extern union { .@"null", .@"undefined", .array, + .array_sentinel, + .array_u8, + .array_u8_sentinel_0, .single_const_pointer, .single_mut_pointer, .single_const_pointer_to_comptime_int, - .array_u8_sentinel_0, .const_slice_u8, .u8, .i8, @@ -1818,10 +1879,12 @@ pub const Type = extern union { .@"null", .@"undefined", .array, + .array_sentinel, + .array_u8, + .array_u8_sentinel_0, .single_const_pointer, .single_mut_pointer, .single_const_pointer_to_comptime_int, - .array_u8_sentinel_0, .const_slice_u8, .u8, .i8, @@ -1895,10 +1958,12 @@ pub const Type = extern union { .fn_ccc_void_no_args, .function, .array, + .array_sentinel, + .array_u8, + .array_u8_sentinel_0, .single_const_pointer, .single_mut_pointer, .single_const_pointer_to_comptime_int, - .array_u8_sentinel_0, .const_slice_u8, .optional, .optional_single_mut_pointer, @@ -1944,6 +2009,7 @@ pub const Type = extern union { .fn_ccc_void_no_args, .function, .single_const_pointer_to_comptime_int, + .array_sentinel, .array_u8_sentinel_0, .const_slice_u8, .c_void, @@ -1971,11 +2037,10 @@ pub const Type = extern union { return null; } }, - .array => { - const array = ty.cast(Payload.Array).?; - if (array.len == 0) + .array, .array_u8 => { + if (ty.arrayLen() == 0) return Value.initTag(.empty_array); - ty = array.elem_type; + ty = ty.elemType(); continue; }, .single_const_pointer, .single_mut_pointer => { @@ -2022,7 +2087,6 @@ pub const Type = extern union { .fn_ccc_void_no_args, .function, .single_const_pointer_to_comptime_int, - .array_u8_sentinel_0, .const_slice_u8, .c_void, .void, @@ -2032,6 +2096,9 @@ pub const Type = extern union { .int_unsigned, .int_signed, .array, + .array_sentinel, + .array_u8, + .array_u8_sentinel_0, .single_const_pointer, .single_mut_pointer, .optional, @@ -2090,8 +2157,10 @@ pub const Type = extern union { const_slice_u8, // See last_no_payload_tag below. // After this, the tag requires a payload. + array_u8, array_u8_sentinel_0, array, + array_sentinel, single_const_pointer, single_mut_pointer, int_signed, @@ -2114,11 +2183,25 @@ pub const Type = extern union { len: u64, }; + pub const Array_u8 = struct { + base: Payload = Payload{ .tag = .array_u8 }, + + len: u64, + }; + pub const Array = struct { base: Payload = Payload{ .tag = .array }, - elem_type: Type, len: u64, + elem_type: Type, + }; + + pub const ArraySentinel = struct { + base: Payload = Payload{ .tag = .array_sentinel }, + + len: u64, + sentinel: Value, + elem_type: Type, }; pub const Pointer = struct { diff --git a/src-self-hosted/zir.zig b/src-self-hosted/zir.zig index 3e8400dca7..a38c1b8373 100644 --- a/src-self-hosted/zir.zig +++ b/src-self-hosted/zir.zig @@ -47,6 +47,10 @@ pub const Inst = struct { array_cat, /// Array multiplication `a ** b` array_mul, + /// Create an array type + array_type, + /// Create an array type with sentinel + array_type_sentinel, /// Function parameter value. These must be first in a function's main block, /// in respective order with the parameters. arg, @@ -268,6 +272,7 @@ pub const Inst = struct { .addwrap, .array_cat, .array_mul, + .array_type, .bitand, .bitor, .div, @@ -294,6 +299,7 @@ pub const Inst = struct { => BinOp, .arg => Arg, + .array_type_sentinel => ArrayTypeSentinel, .block => Block, .@"break" => Break, .breakvoid => BreakVoid, @@ -333,6 +339,8 @@ pub const Inst = struct { .alloc_inferred, .array_cat, .array_mul, + .array_type, + .array_type_sentinel, .arg, .as, .@"asm", @@ -849,6 +857,18 @@ pub const Inst = struct { sentinel: ?*Inst = null, }, }; + + pub const ArrayTypeSentinel = struct { + pub const base_tag = Tag.array_type_sentinel; + base: Inst, + + positionals: struct { + len: *Inst, + sentinel: *Inst, + elem_type: *Inst, + }, + kw_args: struct {}, + }; }; pub const ErrorMsg = struct { diff --git a/src-self-hosted/zir_sema.zig b/src-self-hosted/zir_sema.zig index d51d0d0f7f..593330f782 100644 --- a/src-self-hosted/zir_sema.zig +++ b/src-self-hosted/zir_sema.zig @@ -113,6 +113,8 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError! .unwrap_err_safe => return analyzeInstUnwrapErr(mod, scope, old_inst.castTag(.unwrap_err_safe).?, true), .unwrap_err_unsafe => return analyzeInstUnwrapErr(mod, scope, old_inst.castTag(.unwrap_err_unsafe).?, false), .ensure_err_payload_void => return analyzeInstEnsureErrPayloadVoid(mod, scope, old_inst.castTag(.ensure_err_payload_void).?), + .array_type => return analyzeInstArrayType(mod, scope, old_inst.castTag(.array_type).?), + .array_type_sentinel => return analyzeInstArrayTypeSentinel(mod, scope, old_inst.castTag(.array_type_sentinel).?), } } @@ -676,31 +678,24 @@ fn analyzeInstIntType(mod: *Module, scope: *Scope, inttype: *zir.Inst.IntType) I fn analyzeInstOptionalType(mod: *Module, scope: *Scope, optional: *zir.Inst.UnOp) InnerError!*Inst { const child_type = try resolveType(mod, scope, optional.positionals.operand); - return mod.constType(scope, optional.base.src, Type.initPayload(switch (child_type.tag()) { - .single_const_pointer => blk: { - const payload = try scope.arena().create(Type.Payload.Pointer); - payload.* = .{ - .base = .{ .tag = .optional_single_const_pointer }, - .pointee_type = child_type.elemType(), - }; - break :blk &payload.base; - }, - .single_mut_pointer => blk: { - const payload = try scope.arena().create(Type.Payload.Pointer); - payload.* = .{ - .base = .{ .tag = .optional_single_mut_pointer }, - .pointee_type = child_type.elemType(), - }; - break :blk &payload.base; - }, - else => blk: { - const payload = try scope.arena().create(Type.Payload.Optional); - payload.* = .{ - .child_type = child_type, - }; - break :blk &payload.base; - }, - })); + return mod.constType(scope, optional.base.src, try mod.optionalType(scope, child_type)); +} + +fn analyzeInstArrayType(mod: *Module, scope: *Scope, array: *zir.Inst.BinOp) InnerError!*Inst { + // TODO these should be lazily evaluated + const len = try resolveInstConst(mod, scope, array.positionals.lhs); + const elem_type = try resolveType(mod, scope, array.positionals.rhs); + + return mod.constType(scope, array.base.src, try mod.arrayType(scope, len.val.toUnsignedInt(), null, elem_type)); +} + +fn analyzeInstArrayTypeSentinel(mod: *Module, scope: *Scope, array: *zir.Inst.ArrayTypeSentinel) InnerError!*Inst { + // TODO these should be lazily evaluated + const len = try resolveInstConst(mod, scope, array.positionals.len); + const sentinel = try resolveInstConst(mod, scope, array.positionals.sentinel); + const elem_type = try resolveType(mod, scope, array.positionals.elem_type); + + return mod.constType(scope, array.base.src, try mod.arrayType(scope, len.val.toUnsignedInt(), sentinel.val, elem_type)); } fn analyzeInstUnwrapOptional(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp, safety_check: bool) InnerError!*Inst { From 31d8efc6b32a6b60b7ab292ac50e0f6c02bc140e Mon Sep 17 00:00:00 2001 From: Vexu Date: Tue, 18 Aug 2020 13:57:09 +0300 Subject: [PATCH 06/66] stage2: validate param and variable types --- src-self-hosted/type.zig | 39 ++++++++++++++++++++++++++++++++++++ src-self-hosted/zir_sema.zig | 10 ++++++++- 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/src-self-hosted/type.zig b/src-self-hosted/type.zig index 5329841d4b..25f0be16f9 100644 --- a/src-self-hosted/type.zig +++ b/src-self-hosted/type.zig @@ -1062,6 +1062,45 @@ pub const Type = extern union { } } + /// Returns if type can be used for a runtime variable + pub fn isValidVarType(self: Type) bool { + var ty = self; + while (true) switch (ty.zigTypeTag()) { + .Bool, + .Int, + .Float, + .ErrorSet, + .Enum, + .Frame, + .AnyFrame, + .Vector, + => return true, + + .BoundFn, + .ComptimeFloat, + .ComptimeInt, + .EnumLiteral, + .NoReturn, + .Type, + .Void, + .Undefined, + .Null, + .Opaque, + => return false, + + .Optional => { + var buf: Payload.Pointer = undefined; + return ty.optionalChild(&buf).isValidVarType(); + }, + .Pointer, .Array => ty = ty.elemType(), + + .ErrorUnion => @panic("TODO fn isValidVarType"), + .Fn => @panic("TODO fn isValidVarType"), + .Struct => @panic("TODO struct isValidVarType"), + .Union => @panic("TODO union isValidVarType"), + }; + } + /// Asserts the type is a pointer or array type. pub fn elemType(self: Type) Type { return switch (self.tag()) { diff --git a/src-self-hosted/zir_sema.zig b/src-self-hosted/zir_sema.zig index 593330f782..49009d8dec 100644 --- a/src-self-hosted/zir_sema.zig +++ b/src-self-hosted/zir_sema.zig @@ -364,6 +364,9 @@ fn analyzeInstEnsureResultNonError(mod: *Module, scope: *Scope, inst: *zir.Inst. fn analyzeInstAlloc(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { const var_type = try resolveType(mod, scope, inst.positionals.operand); + if (!var_type.isValidVarType()) { + return mod.fail(scope, inst.base.src, "variable of type '{}' must be const or comptime", .{var_type}); + } const ptr_type = try mod.singlePtrType(scope, inst.base.src, true, var_type); const b = try mod.requireRuntimeBlock(scope, inst.base.src); return mod.addNoOp(b, inst.base.src, ptr_type, .alloc); @@ -760,7 +763,12 @@ fn analyzeInstFnType(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnType) Inne const arena = scope.arena(); const param_types = try arena.alloc(Type, fntype.positionals.param_types.len); for (fntype.positionals.param_types) |param_type, i| { - param_types[i] = try resolveType(mod, scope, param_type); + const resolved = try resolveType(mod, scope, param_type); + // TODO skip for comptime params + if (!resolved.isValidVarType()) { + return mod.fail(scope, param_type.src, "parameter of type '{}' must be declared comptime", .{resolved}); + } + param_types[i] = resolved; } const payload = try arena.create(Type.Payload.Function); From e0b01bd4a98e2605f197a04f84e0c281ccc90f81 Mon Sep 17 00:00:00 2001 From: Vexu Date: Tue, 18 Aug 2020 14:28:33 +0300 Subject: [PATCH 07/66] stage2: enum literals --- src-self-hosted/astgen.zig | 10 +++++++++- src-self-hosted/type.zig | 30 +++++++++++++++++++++++++++++- src-self-hosted/value.zig | 35 +++++++++++++++++++++++++++++++++-- src-self-hosted/zir.zig | 14 ++++++++++++++ src-self-hosted/zir_sema.zig | 13 +++++++++++++ 5 files changed, 98 insertions(+), 4 deletions(-) diff --git a/src-self-hosted/astgen.zig b/src-self-hosted/astgen.zig index 46ccde10f1..87f69e053a 100644 --- a/src-self-hosted/astgen.zig +++ b/src-self-hosted/astgen.zig @@ -130,6 +130,7 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr .GroupedExpression => return expr(mod, scope, rl, node.castTag(.GroupedExpression).?.expr), .ArrayType => return rlWrap(mod, scope, rl, try arrayType(mod, scope, node.castTag(.ArrayType).?)), .ArrayTypeSentinel => return rlWrap(mod, scope, rl, try arrayTypeSentinel(mod, scope, node.castTag(.ArrayTypeSentinel).?)), + .EnumLiteral => return rlWrap(mod, scope, rl, try enumLiteral(mod, scope, node.castTag(.EnumLiteral).?)), .Defer => return mod.failNode(scope, node, "TODO implement astgen.expr for .Defer", .{}), .Catch => return mod.failNode(scope, node, "TODO implement astgen.expr for .Catch", .{}), @@ -158,7 +159,6 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr .ErrorType => return mod.failNode(scope, node, "TODO implement astgen.expr for .ErrorType", .{}), .FnProto => return mod.failNode(scope, node, "TODO implement astgen.expr for .FnProto", .{}), .AnyFrameType => return mod.failNode(scope, node, "TODO implement astgen.expr for .AnyFrameType", .{}), - .EnumLiteral => return mod.failNode(scope, node, "TODO implement astgen.expr for .EnumLiteral", .{}), .MultilineStringLiteral => return mod.failNode(scope, node, "TODO implement astgen.expr for .MultilineStringLiteral", .{}), .CharLiteral => return mod.failNode(scope, node, "TODO implement astgen.expr for .CharLiteral", .{}), .ErrorSetDecl => return mod.failNode(scope, node, "TODO implement astgen.expr for .ErrorSetDecl", .{}), @@ -527,6 +527,14 @@ fn arrayTypeSentinel(mod: *Module, scope: *Scope, node: *ast.Node.ArrayTypeSenti }, .{}); } +fn enumLiteral(mod: *Module, scope: *Scope, node: *ast.Node.EnumLiteral) !*zir.Inst { + const tree = scope.tree(); + const src = tree.token_locs[node.name].start; + const name = try identifierTokenString(mod, scope, node.name); + + return addZIRInst(mod, scope, src, zir.Inst.EnumLiteral, .{ .name = name }, .{}); +} + fn unwrapOptional(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.SimpleSuffixOp) InnerError!*zir.Inst { const tree = scope.tree(); const src = tree.token_locs[node.rtoken].start; diff --git a/src-self-hosted/type.zig b/src-self-hosted/type.zig index 25f0be16f9..a6ec90a35b 100644 --- a/src-self-hosted/type.zig +++ b/src-self-hosted/type.zig @@ -75,6 +75,7 @@ pub const Type = extern union { .optional_single_const_pointer, .optional_single_mut_pointer, => return .Optional, + .enum_literal => return .EnumLiteral, } } @@ -127,6 +128,7 @@ pub const Type = extern union { if (zig_tag_a != zig_tag_b) return false; switch (zig_tag_a) { + .EnumLiteral => return true, .Type => return true, .Void => return true, .Bool => return true, @@ -211,7 +213,6 @@ pub const Type = extern union { .Frame, .AnyFrame, .Vector, - .EnumLiteral, => std.debug.panic("TODO implement Type equality comparison of {} and {}", .{ a, b }), } } @@ -327,6 +328,7 @@ pub const Type = extern union { .fn_ccc_void_no_args, .single_const_pointer_to_comptime_int, .const_slice_u8, + .enum_literal, => unreachable, .array_u8_sentinel_0 => return self.copyPayloadShallow(allocator, Payload.Array_u8_Sentinel0), @@ -437,6 +439,7 @@ pub const Type = extern union { .noreturn, => return out_stream.writeAll(@tagName(t)), + .enum_literal => return out_stream.writeAll("@TypeOf(.EnumLiteral)"), .@"null" => return out_stream.writeAll("@TypeOf(null)"), .@"undefined" => return out_stream.writeAll("@TypeOf(undefined)"), @@ -561,6 +564,7 @@ pub const Type = extern union { .fn_ccc_void_no_args => return Value.initTag(.fn_ccc_void_no_args_type), .single_const_pointer_to_comptime_int => return Value.initTag(.single_const_pointer_to_comptime_int_type), .const_slice_u8 => return Value.initTag(.const_slice_u8_type), + .enum_literal => return Value.initTag(.enum_literal_type), else => { const ty_payload = try allocator.create(Value.Payload.Ty); ty_payload.* = .{ .ty = self }; @@ -625,6 +629,7 @@ pub const Type = extern union { .noreturn, .@"null", .@"undefined", + .enum_literal, => false, }; } @@ -716,6 +721,7 @@ pub const Type = extern union { .noreturn, .@"null", .@"undefined", + .enum_literal, => unreachable, }; } @@ -736,6 +742,7 @@ pub const Type = extern union { .noreturn => unreachable, .@"null" => unreachable, .@"undefined" => unreachable, + .enum_literal => unreachable, .u8, .i8, @@ -863,6 +870,7 @@ pub const Type = extern union { .optional, .optional_single_mut_pointer, .optional_single_const_pointer, + .enum_literal, => false, .single_const_pointer, @@ -924,6 +932,7 @@ pub const Type = extern union { .optional, .optional_single_mut_pointer, .optional_single_const_pointer, + .enum_literal, => false, .const_slice_u8 => true, @@ -980,6 +989,7 @@ pub const Type = extern union { .optional, .optional_single_mut_pointer, .optional_single_const_pointer, + .enum_literal, => false, .single_const_pointer, @@ -1042,6 +1052,7 @@ pub const Type = extern union { .optional, .optional_single_mut_pointer, .optional_single_const_pointer, + .enum_literal, => false, }; } @@ -1147,6 +1158,7 @@ pub const Type = extern union { .optional, .optional_single_const_pointer, .optional_single_mut_pointer, + .enum_literal, => unreachable, .array => self.cast(Payload.Array).?.elem_type, @@ -1252,6 +1264,7 @@ pub const Type = extern union { .optional, .optional_single_mut_pointer, .optional_single_const_pointer, + .enum_literal, => unreachable, .array => self.cast(Payload.Array).?.len, @@ -1311,6 +1324,7 @@ pub const Type = extern union { .optional, .optional_single_mut_pointer, .optional_single_const_pointer, + .enum_literal, => unreachable, .array, .array_u8 => return null, @@ -1368,6 +1382,7 @@ pub const Type = extern union { .optional, .optional_single_mut_pointer, .optional_single_const_pointer, + .enum_literal, => false, .int_signed, @@ -1428,6 +1443,7 @@ pub const Type = extern union { .optional, .optional_single_mut_pointer, .optional_single_const_pointer, + .enum_literal, => false, .int_unsigned, @@ -1478,6 +1494,7 @@ pub const Type = extern union { .optional, .optional_single_mut_pointer, .optional_single_const_pointer, + .enum_literal, => unreachable, .int_unsigned => .{ .signed = false, .bits = self.cast(Payload.IntUnsigned).?.bits }, @@ -1546,6 +1563,7 @@ pub const Type = extern union { .optional, .optional_single_mut_pointer, .optional_single_const_pointer, + .enum_literal, => false, .usize, @@ -1643,6 +1661,7 @@ pub const Type = extern union { .optional, .optional_single_mut_pointer, .optional_single_const_pointer, + .enum_literal, => unreachable, }; } @@ -1706,6 +1725,7 @@ pub const Type = extern union { .optional, .optional_single_mut_pointer, .optional_single_const_pointer, + .enum_literal, => unreachable, } } @@ -1768,6 +1788,7 @@ pub const Type = extern union { .optional, .optional_single_mut_pointer, .optional_single_const_pointer, + .enum_literal, => unreachable, } } @@ -1830,6 +1851,7 @@ pub const Type = extern union { .optional, .optional_single_mut_pointer, .optional_single_const_pointer, + .enum_literal, => unreachable, }; } @@ -1889,6 +1911,7 @@ pub const Type = extern union { .optional, .optional_single_mut_pointer, .optional_single_const_pointer, + .enum_literal, => unreachable, }; } @@ -1948,6 +1971,7 @@ pub const Type = extern union { .optional, .optional_single_mut_pointer, .optional_single_const_pointer, + .enum_literal, => unreachable, }; } @@ -2007,6 +2031,7 @@ pub const Type = extern union { .optional, .optional_single_mut_pointer, .optional_single_const_pointer, + .enum_literal, => false, }; } @@ -2055,6 +2080,7 @@ pub const Type = extern union { .optional, .optional_single_mut_pointer, .optional_single_const_pointer, + .enum_literal, => return null, .void => return Value.initTag(.void_value), @@ -2143,6 +2169,7 @@ pub const Type = extern union { .optional, .optional_single_mut_pointer, .optional_single_const_pointer, + .enum_literal, => return false, }; } @@ -2186,6 +2213,7 @@ pub const Type = extern union { comptime_int, comptime_float, noreturn, + enum_literal, @"null", @"undefined", fn_noreturn_no_args, diff --git a/src-self-hosted/value.zig b/src-self-hosted/value.zig index c8af4716a6..b6356d9b17 100644 --- a/src-self-hosted/value.zig +++ b/src-self-hosted/value.zig @@ -60,6 +60,7 @@ pub const Value = extern union { fn_ccc_void_no_args_type, single_const_pointer_to_comptime_int_type, const_slice_u8_type, + enum_literal_type, undef, zero, @@ -87,6 +88,7 @@ pub const Value = extern union { float_32, float_64, float_128, + enum_literal, pub const last_no_payload_tag = Tag.bool_false; pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1; @@ -164,6 +166,7 @@ pub const Value = extern union { .fn_ccc_void_no_args_type, .single_const_pointer_to_comptime_int_type, .const_slice_u8_type, + .enum_literal_type, .undef, .zero, .void_value, @@ -213,7 +216,7 @@ pub const Value = extern union { }; return Value{ .ptr_otherwise = &new_payload.base }; }, - .bytes => return self.copyPayloadShallow(allocator, Payload.Bytes), + .enum_literal, .bytes => return self.copyPayloadShallow(allocator, Payload.Bytes), .repeated => { const payload = @fieldParentPtr(Payload.Repeated, "base", self.ptr_otherwise); const new_payload = try allocator.create(Payload.Repeated); @@ -285,6 +288,7 @@ pub const Value = extern union { .fn_ccc_void_no_args_type => return out_stream.writeAll("fn() callconv(.C) void"), .single_const_pointer_to_comptime_int_type => return out_stream.writeAll("*const comptime_int"), .const_slice_u8_type => return out_stream.writeAll("[]const u8"), + .enum_literal_type => return out_stream.writeAll("@TypeOf(.EnumLiteral)"), .null_value => return out_stream.writeAll("null"), .undef => return out_stream.writeAll("undefined"), @@ -318,7 +322,7 @@ pub const Value = extern union { val = elem_ptr.array_ptr; }, .empty_array => return out_stream.writeAll(".{}"), - .bytes => return std.zig.renderStringLiteral(self.cast(Payload.Bytes).?.data, out_stream), + .enum_literal, .bytes => return std.zig.renderStringLiteral(self.cast(Payload.Bytes).?.data, out_stream), .repeated => { try out_stream.writeAll("(repeated) "); val = val.cast(Payload.Repeated).?.val; @@ -391,6 +395,7 @@ pub const Value = extern union { .fn_ccc_void_no_args_type => Type.initTag(.fn_ccc_void_no_args), .single_const_pointer_to_comptime_int_type => Type.initTag(.single_const_pointer_to_comptime_int), .const_slice_u8_type => Type.initTag(.const_slice_u8), + .enum_literal_type => Type.initTag(.enum_literal), .undef, .zero, @@ -414,6 +419,7 @@ pub const Value = extern union { .float_32, .float_64, .float_128, + .enum_literal, => unreachable, }; } @@ -462,6 +468,7 @@ pub const Value = extern union { .fn_ccc_void_no_args_type, .single_const_pointer_to_comptime_int_type, .const_slice_u8_type, + .enum_literal_type, .null_value, .function, .ref_val, @@ -476,6 +483,7 @@ pub const Value = extern union { .void_value, .unreachable_value, .empty_array, + .enum_literal, => unreachable, .undef => unreachable, @@ -537,6 +545,7 @@ pub const Value = extern union { .fn_ccc_void_no_args_type, .single_const_pointer_to_comptime_int_type, .const_slice_u8_type, + .enum_literal_type, .null_value, .function, .ref_val, @@ -551,6 +560,7 @@ pub const Value = extern union { .void_value, .unreachable_value, .empty_array, + .enum_literal, => unreachable, .undef => unreachable, @@ -612,6 +622,7 @@ pub const Value = extern union { .fn_ccc_void_no_args_type, .single_const_pointer_to_comptime_int_type, .const_slice_u8_type, + .enum_literal_type, .null_value, .function, .ref_val, @@ -626,6 +637,7 @@ pub const Value = extern union { .void_value, .unreachable_value, .empty_array, + .enum_literal, => unreachable, .undef => unreachable, @@ -713,6 +725,7 @@ pub const Value = extern union { .fn_ccc_void_no_args_type, .single_const_pointer_to_comptime_int_type, .const_slice_u8_type, + .enum_literal_type, .null_value, .function, .ref_val, @@ -728,6 +741,7 @@ pub const Value = extern union { .void_value, .unreachable_value, .empty_array, + .enum_literal, => unreachable, .zero, @@ -793,6 +807,7 @@ pub const Value = extern union { .fn_ccc_void_no_args_type, .single_const_pointer_to_comptime_int_type, .const_slice_u8_type, + .enum_literal_type, .null_value, .function, .ref_val, @@ -807,6 +822,7 @@ pub const Value = extern union { .void_value, .unreachable_value, .empty_array, + .enum_literal, => unreachable, .zero, @@ -953,6 +969,7 @@ pub const Value = extern union { .fn_ccc_void_no_args_type, .single_const_pointer_to_comptime_int_type, .const_slice_u8_type, + .enum_literal_type, .bool_true, .bool_false, .null_value, @@ -970,6 +987,7 @@ pub const Value = extern union { .empty_array, .void_value, .unreachable_value, + .enum_literal, => unreachable, .zero => false, @@ -1025,6 +1043,7 @@ pub const Value = extern union { .fn_ccc_void_no_args_type, .single_const_pointer_to_comptime_int_type, .const_slice_u8_type, + .enum_literal_type, .null_value, .function, .ref_val, @@ -1036,6 +1055,7 @@ pub const Value = extern union { .void_value, .unreachable_value, .empty_array, + .enum_literal, => unreachable, .zero, @@ -1102,6 +1122,11 @@ pub const Value = extern union { } pub fn eql(a: Value, b: Value) bool { + if (a.tag() == b.tag() and a.tag() == .enum_literal) { + const a_name = @fieldParentPtr(Payload.Bytes, "base", a.ptr_otherwise).data; + const b_name = @fieldParentPtr(Payload.Bytes, "base", b.ptr_otherwise).data; + return std.mem.eql(u8, a_name, b_name); + } // TODO non numerical comparisons return compare(a, .eq, b); } @@ -1151,6 +1176,7 @@ pub const Value = extern union { .fn_ccc_void_no_args_type, .single_const_pointer_to_comptime_int_type, .const_slice_u8_type, + .enum_literal_type, .zero, .bool_true, .bool_false, @@ -1170,6 +1196,7 @@ pub const Value = extern union { .void_value, .unreachable_value, .empty_array, + .enum_literal, => unreachable, .ref_val => self.cast(Payload.RefVal).?.val, @@ -1227,6 +1254,7 @@ pub const Value = extern union { .fn_ccc_void_no_args_type, .single_const_pointer_to_comptime_int_type, .const_slice_u8_type, + .enum_literal_type, .zero, .bool_true, .bool_false, @@ -1246,6 +1274,7 @@ pub const Value = extern union { .float_128, .void_value, .unreachable_value, + .enum_literal, => unreachable, .empty_array => unreachable, // out of bounds array index @@ -1320,6 +1349,7 @@ pub const Value = extern union { .fn_ccc_void_no_args_type, .single_const_pointer_to_comptime_int_type, .const_slice_u8_type, + .enum_literal_type, .zero, .empty_array, .bool_true, @@ -1339,6 +1369,7 @@ pub const Value = extern union { .float_64, .float_128, .void_value, + .enum_literal, => false, .undef => unreachable, diff --git a/src-self-hosted/zir.zig b/src-self-hosted/zir.zig index a38c1b8373..235a4c931b 100644 --- a/src-self-hosted/zir.zig +++ b/src-self-hosted/zir.zig @@ -231,6 +231,8 @@ pub const Inst = struct { unwrap_err_unsafe, /// Takes a *E!T and raises a compiler error if T != void ensure_err_payload_void, + /// Enum literal + enum_literal, pub fn Type(tag: Tag) type { return switch (tag) { @@ -326,6 +328,7 @@ pub const Inst = struct { .elemptr => ElemPtr, .condbr => CondBr, .ptr_type => PtrType, + .enum_literal => EnumLiteral, }; } @@ -410,6 +413,7 @@ pub const Inst = struct { .unwrap_err_unsafe, .ptr_type, .ensure_err_payload_void, + .enum_literal, => false, .@"break", @@ -869,6 +873,16 @@ pub const Inst = struct { }, kw_args: struct {}, }; + + pub const EnumLiteral = struct { + pub const base_tag = Tag.enum_literal; + base: Inst, + + positionals: struct { + name: []const u8, + }, + kw_args: struct {}, + }; }; pub const ErrorMsg = struct { diff --git a/src-self-hosted/zir_sema.zig b/src-self-hosted/zir_sema.zig index 49009d8dec..5c473494fb 100644 --- a/src-self-hosted/zir_sema.zig +++ b/src-self-hosted/zir_sema.zig @@ -115,6 +115,7 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError! .ensure_err_payload_void => return analyzeInstEnsureErrPayloadVoid(mod, scope, old_inst.castTag(.ensure_err_payload_void).?), .array_type => return analyzeInstArrayType(mod, scope, old_inst.castTag(.array_type).?), .array_type_sentinel => return analyzeInstArrayTypeSentinel(mod, scope, old_inst.castTag(.array_type_sentinel).?), + .enum_literal => return analyzeInstEnumLiteral(mod, scope, old_inst.castTag(.enum_literal).?), } } @@ -701,6 +702,18 @@ fn analyzeInstArrayTypeSentinel(mod: *Module, scope: *Scope, array: *zir.Inst.Ar return mod.constType(scope, array.base.src, try mod.arrayType(scope, len.val.toUnsignedInt(), sentinel.val, elem_type)); } +fn analyzeInstEnumLiteral(mod: *Module, scope: *Scope, inst: *zir.Inst.EnumLiteral) InnerError!*Inst { + const payload = try scope.arena().create(Value.Payload.Bytes); + payload.* = .{ + .base = .{ .tag = .enum_literal }, + .data = try scope.arena().dupe(u8, inst.positionals.name), + }; + return mod.constInst(scope, inst.base.src, .{ + .ty = Type.initTag(.enum_literal), + .val = Value.initPayload(&payload.base), + }); +} + fn analyzeInstUnwrapOptional(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp, safety_check: bool) InnerError!*Inst { const operand = try resolveInst(mod, scope, unwrap.positionals.operand); assert(operand.ty.zigTypeTag() == .Pointer); From 2b45e23477605e15fecec3566b3dc90b71e2f7a7 Mon Sep 17 00:00:00 2001 From: Vexu Date: Tue, 18 Aug 2020 15:33:11 +0300 Subject: [PATCH 08/66] stage2: character literals and multiline strings --- lib/std/zig.zig | 101 +++++++++++++++++++++++++++++++++ src-self-hosted/astgen.zig | 53 ++++++++++++++++- src-self-hosted/zir_sema.zig | 1 + test/stage2/compare_output.zig | 32 +++++++++++ 4 files changed, 185 insertions(+), 2 deletions(-) diff --git a/lib/std/zig.zig b/lib/std/zig.zig index b070fbdcd5..36dfe74086 100644 --- a/lib/std/zig.zig +++ b/lib/std/zig.zig @@ -80,6 +80,107 @@ pub fn binNameAlloc( } } +/// Only validates escape sequence characters. +/// Slice must be valid utf8 starting and ending with "'" and exactly one codepoint in between. +pub fn parseCharLiteral( + slice: []const u8, + bad_index: *usize, // populated if error.InvalidCharacter is returned) +) error{InvalidCharacter}!u32 { + std.debug.assert(slice.len >= 3 and slice[0] == '\'' and slice[slice.len - 1] == '\''); + + if (slice[1] == '\\') { + switch (slice[2]) { + 'n' => return '\n', + 'r' => return '\r', + '\\' => return '\\', + 't' => return '\t', + '\'' => return '\'', + '"' => return '"', + 'x' => { + if (slice.len != 6) { + bad_index.* = slice.len - 2; + return error.InvalidCharacter; + } + + var value: u32 = 0; + for (slice[3..5]) |c, i| { + switch (slice[3]) { + '0'...'9' => { + value *= 16; + value += c - '0'; + }, + 'a'...'f' => { + value *= 16; + value += c - 'a'; + }, + 'A'...'F' => { + value *= 16; + value += c - 'a'; + }, + else => { + bad_index.* = i; + return error.InvalidCharacter; + }, + } + } + return value; + }, + 'u' => { + if (slice.len < 6 or slice[3] != '{') { + bad_index.* = 2; + return error.InvalidCharacter; + } + var value: u32 = 0; + for (slice[4..]) |c, i| { + if (value > 0x10ffff) { + bad_index.* = i; + return error.InvalidCharacter; + } + switch (c) { + '0'...'9' => { + value *= 16; + value += c - '0'; + }, + 'a'...'f' => { + value *= 16; + value += c - 'a'; + }, + 'A'...'F' => { + value *= 16; + value += c - 'A'; + }, + '}' => break, + else => { + bad_index.* = i; + return error.InvalidCharacter; + }, + } + } + return value; + }, + else => { + bad_index.* = 2; + return error.InvalidCharacter; + } + } + } + return std.unicode.utf8Decode(slice[1 .. slice.len - 1]) catch unreachable; +} + +test "parseCharLiteral" { + var bad_index: usize = undefined; + std.testing.expectEqual(try parseCharLiteral("'a'", &bad_index), 'a'); + std.testing.expectEqual(try parseCharLiteral("'ä'", &bad_index), 'ä'); + std.testing.expectEqual(try parseCharLiteral("'\\x00'", &bad_index), 0); + std.testing.expectEqual(try parseCharLiteral("'ぁ'", &bad_index), 0x3041); + std.testing.expectEqual(try parseCharLiteral("'\\u{3041}'", &bad_index), 0x3041); + + std.testing.expectError(error.InvalidCharacter, parseCharLiteral("'\\x0'", &bad_index)); + std.testing.expectError(error.InvalidCharacter, parseCharLiteral("'\\y'", &bad_index)); + std.testing.expectError(error.InvalidCharacter, parseCharLiteral("'\\u'", &bad_index)); + std.testing.expectError(error.InvalidCharacter, parseCharLiteral("'\\u{FFFFFF}'", &bad_index)); +} + test "" { @import("std").meta.refAllDecls(@This()); } diff --git a/src-self-hosted/astgen.zig b/src-self-hosted/astgen.zig index 87f69e053a..f05020f6df 100644 --- a/src-self-hosted/astgen.zig +++ b/src-self-hosted/astgen.zig @@ -131,6 +131,8 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr .ArrayType => return rlWrap(mod, scope, rl, try arrayType(mod, scope, node.castTag(.ArrayType).?)), .ArrayTypeSentinel => return rlWrap(mod, scope, rl, try arrayTypeSentinel(mod, scope, node.castTag(.ArrayTypeSentinel).?)), .EnumLiteral => return rlWrap(mod, scope, rl, try enumLiteral(mod, scope, node.castTag(.EnumLiteral).?)), + .MultilineStringLiteral => return rlWrap(mod, scope, rl, try multilineStrLiteral(mod, scope, node.castTag(.MultilineStringLiteral).?)), + .CharLiteral => return rlWrap(mod, scope, rl, try charLiteral(mod, scope, node.castTag(.CharLiteral).?)), .Defer => return mod.failNode(scope, node, "TODO implement astgen.expr for .Defer", .{}), .Catch => return mod.failNode(scope, node, "TODO implement astgen.expr for .Catch", .{}), @@ -159,8 +161,6 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr .ErrorType => return mod.failNode(scope, node, "TODO implement astgen.expr for .ErrorType", .{}), .FnProto => return mod.failNode(scope, node, "TODO implement astgen.expr for .FnProto", .{}), .AnyFrameType => return mod.failNode(scope, node, "TODO implement astgen.expr for .AnyFrameType", .{}), - .MultilineStringLiteral => return mod.failNode(scope, node, "TODO implement astgen.expr for .MultilineStringLiteral", .{}), - .CharLiteral => return mod.failNode(scope, node, "TODO implement astgen.expr for .CharLiteral", .{}), .ErrorSetDecl => return mod.failNode(scope, node, "TODO implement astgen.expr for .ErrorSetDecl", .{}), .ContainerDecl => return mod.failNode(scope, node, "TODO implement astgen.expr for .ContainerDecl", .{}), .Comptime => return mod.failNode(scope, node, "TODO implement astgen.expr for .Comptime", .{}), @@ -497,6 +497,7 @@ fn arrayType(mod: *Module, scope: *Scope, node: *ast.Node.ArrayType) !*zir.Inst .val = Value.initTag(.usize_type), }); + // TODO check for [_]T const len = try expr(mod, scope, .{ .ty = usize_type }, node.len_expr); const child_type = try expr(mod, scope, .{ .ty = meta_type }, node.rhs); @@ -515,6 +516,7 @@ fn arrayTypeSentinel(mod: *Module, scope: *Scope, node: *ast.Node.ArrayTypeSenti .val = Value.initTag(.usize_type), }); + // TODO check for [_]T const len = try expr(mod, scope, .{ .ty = usize_type }, node.len_expr); const sentinel_uncasted = try expr(mod, scope, .none, node.sentinel); const elem_type = try expr(mod, scope, .{ .ty = meta_type }, node.rhs); @@ -1120,6 +1122,53 @@ fn stringLiteral(mod: *Module, scope: *Scope, str_lit: *ast.Node.OneToken) Inner return addZIRInst(mod, scope, src, zir.Inst.Str, .{ .bytes = bytes }, .{}); } +fn multilineStrLiteral(mod: *Module, scope: *Scope, node: *ast.Node.MultilineStringLiteral) !*zir.Inst { + const tree = scope.tree(); + const lines = node.linesConst(); + const src = tree.token_locs[lines[0]].start; + + // line lengths and new lines + var len = lines.len - 1; + for (lines) |line| { + len += tree.tokenSlice(line).len - 2; + } + + const bytes = try scope.arena().alloc(u8, len); + var i: usize = 0; + for (lines) |line, line_i| { + if (line_i != 0) { + bytes[i] = '\n'; + i += 1; + } + const slice = tree.tokenSlice(line)[2..]; + mem.copy(u8, bytes[i..], slice); + i += slice.len; + } + + return addZIRInst(mod, scope, src, zir.Inst.Str, .{ .bytes = bytes }, .{}); +} + +fn charLiteral(mod: *Module, scope: *Scope, node: *ast.Node.OneToken) !*zir.Inst { + const tree = scope.tree(); + const src = tree.token_locs[node.token].start; + const slice = tree.tokenSlice(node.token); + + var bad_index: usize = undefined; + const value = std.zig.parseCharLiteral(slice, &bad_index) catch |err| switch (err) { + error.InvalidCharacter => { + const bad_byte = slice[bad_index]; + return mod.fail(scope, src + bad_index, "invalid character: '{c}'\n", .{bad_byte}); + }, + }; + + const int_payload = try scope.arena().create(Value.Payload.Int_u64); + int_payload.* = .{ .int = value }; + return addZIRInstConst(mod, scope, src, .{ + .ty = Type.initTag(.comptime_int), + .val = Value.initPayload(&int_payload.base), + }); +} + fn integerLiteral(mod: *Module, scope: *Scope, int_lit: *ast.Node.OneToken) InnerError!*zir.Inst { const arena = scope.arena(); const tree = scope.tree(); diff --git a/src-self-hosted/zir_sema.zig b/src-self-hosted/zir_sema.zig index 5c473494fb..3a2a593539 100644 --- a/src-self-hosted/zir_sema.zig +++ b/src-self-hosted/zir_sema.zig @@ -365,6 +365,7 @@ fn analyzeInstEnsureResultNonError(mod: *Module, scope: *Scope, inst: *zir.Inst. fn analyzeInstAlloc(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { const var_type = try resolveType(mod, scope, inst.positionals.operand); + // TODO this should happen only for var allocs if (!var_type.isValidVarType()) { return mod.fail(scope, inst.base.src, "variable of type '{}' must be const or comptime", .{var_type}); } diff --git a/test/stage2/compare_output.zig b/test/stage2/compare_output.zig index 4208cc3911..8b92674e9c 100644 --- a/test/stage2/compare_output.zig +++ b/test/stage2/compare_output.zig @@ -543,6 +543,38 @@ pub fn addCases(ctx: *TestContext) !void { , "", ); + + case.addCompareOutput( + \\export fn _start() noreturn { + \\ const ignore = + \\ \\ cool thx + \\ \\ + \\ ; + \\ add('ぁ', '\x03'); + \\ + \\ exit(); + \\} + \\ + \\fn add(a: u32, b: u32) void { + \\ assert(a + b == 12356); + \\} + \\ + \\pub fn assert(ok: bool) void { + \\ if (!ok) unreachable; // assertion failure + \\} + \\ + \\fn exit() noreturn { + \\ asm volatile ("syscall" + \\ : + \\ : [number] "{rax}" (231), + \\ [arg1] "{rdi}" (0) + \\ : "rcx", "r11", "memory" + \\ ); + \\ unreachable; + \\} + , + "", + ); } { From e4aefc6d0f9b08a98f566cb8280a6195c08f7a82 Mon Sep 17 00:00:00 2001 From: Vexu Date: Tue, 18 Aug 2020 22:42:35 +0300 Subject: [PATCH 09/66] stage2: split ref from lvalue and add compile error for invalid assignments --- src-self-hosted/astgen.zig | 160 +++++++++++++++++++++++++++++++---- src-self-hosted/zir.zig | 10 +-- src-self-hosted/zir_sema.zig | 6 +- 3 files changed, 153 insertions(+), 23 deletions(-) diff --git a/src-self-hosted/astgen.zig b/src-self-hosted/astgen.zig index f05020f6df..9d40c7899a 100644 --- a/src-self-hosted/astgen.zig +++ b/src-self-hosted/astgen.zig @@ -20,6 +20,8 @@ pub const ResultLoc = union(enum) { /// The expression must generate a pointer rather than a value. For example, the left hand side /// of an assignment uses an "LValue" result location. lvalue, + /// The expression must generate a pointer + ref, /// The expression will be type coerced into this type, but it will be evaluated as an rvalue. ty: *zir.Inst, /// 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 /// Turn Zig AST into untyped ZIR istructions. pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerError!*zir.Inst { + if (rl == .lvalue) { + switch (node.tag) { + .Root => unreachable, + .Use => unreachable, + .TestDecl => unreachable, + .DocComment => unreachable, + .VarDecl => unreachable, + .SwitchCase => unreachable, + .SwitchElse => unreachable, + .Else => unreachable, + .Payload => unreachable, + .PointerPayload => unreachable, + .PointerIndexPayload => unreachable, + .ErrorTag => unreachable, + .FieldInitializer => unreachable, + .ContainerField => unreachable, + + .Assign, + .AssignBitAnd, + .AssignBitOr, + .AssignBitShiftLeft, + .AssignBitShiftRight, + .AssignBitXor, + .AssignDiv, + .AssignSub, + .AssignSubWrap, + .AssignMod, + .AssignAdd, + .AssignAddWrap, + .AssignMul, + .AssignMulWrap, + .Add, + .AddWrap, + .Sub, + .SubWrap, + .Mul, + .MulWrap, + .Div, + .Mod, + .BitAnd, + .BitOr, + .BitShiftLeft, + .BitShiftRight, + .BitXor, + .BangEqual, + .EqualEqual, + .GreaterThan, + .GreaterOrEqual, + .LessThan, + .LessOrEqual, + .ArrayCat, + .ArrayMult, + .BoolAnd, + .BoolOr, + .Asm, + .StringLiteral, + .IntegerLiteral, + .Call, + .Unreachable, + .Return, + .If, + .While, + .BoolNot, + .AddressOf, + .FloatLiteral, + .UndefinedLiteral, + .BoolLiteral, + .NullLiteral, + .OptionalType, + .Block, + .LabeledBlock, + .Break, + .PtrType, + .GroupedExpression, + .ArrayType, + .ArrayTypeSentinel, + .EnumLiteral, + .MultilineStringLiteral, + .CharLiteral, + .Defer, + .Catch, + .ErrorUnion, + .MergeErrorSets, + .Range, + .OrElse, + .Await, + .BitNot, + .Negation, + .NegationWrap, + .Resume, + .Try, + .SliceType, + .Slice, + .ArrayInitializer, + .ArrayInitializerDot, + .StructInitializer, + .StructInitializerDot, + .Switch, + .For, + .Suspend, + .Continue, + .AnyType, + .ErrorType, + .FnProto, + .AnyFrameType, + .ErrorSetDecl, + .ContainerDecl, + .Comptime, + .Nosuspend, + => return mod.failNode(scope, node, "invalid left-hand side to assignment", .{}), + + // @field can be assigned to + .BuiltinCall => { + const call = node.castTag(.BuiltinCall).?; + const tree = scope.tree(); + const builtin_name = tree.tokenSlice(call.builtin_token); + + if (!mem.eql(u8, builtin_name, "@field")) { + return mod.failNode(scope, node, "invalid left-hand side to assignment", .{}); + } + }, + + // can be assigned to + .UnwrapOptional, .Deref, .Period, .ArrayAccess, .Identifier => {}, + } + } switch (node.tag) { .Root => unreachable, // Top-level declaration. .Use => unreachable, // Top-level declaration. @@ -60,6 +188,7 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr .PointerIndexPayload => unreachable, // Handled explicitly. .ErrorTag => unreachable, // Handled explicitly. .FieldInitializer => unreachable, // Handled explicitly. + .ContainerField => unreachable, // Handled explicitly. .Assign => return rlWrapVoid(mod, scope, rl, node, try assign(mod, scope, node.castTag(.Assign).?)), .AssignBitAnd => return rlWrapVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignBitAnd).?, .bitand)), @@ -165,7 +294,6 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr .ContainerDecl => return mod.failNode(scope, node, "TODO implement astgen.expr for .ContainerDecl", .{}), .Comptime => return mod.failNode(scope, node, "TODO implement astgen.expr for .Comptime", .{}), .Nosuspend => return mod.failNode(scope, node, "TODO implement astgen.expr for .Nosuspend", .{}), - .ContainerField => return mod.failNode(scope, node, "TODO implement astgen.expr for .ContainerField", .{}), } } @@ -188,7 +316,7 @@ fn breakExpr(mod: *Module, parent_scope: *Scope, node: *ast.Node.ControlFlowExpr // proper type inference requires peer type resolution on the block's // break operand expressions. const branch_rl: ResultLoc = switch (label.result_loc) { - .discard, .none, .ty, .ptr, .lvalue => label.result_loc, + .discard, .none, .ty, .ptr, .lvalue, .ref => label.result_loc, .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = label.block_inst }, }; const operand = try expr(mod, parent_scope, branch_rl, rhs); @@ -427,7 +555,7 @@ fn boolNot(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerErr } fn addressOf(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerError!*zir.Inst { - return expr(mod, scope, .lvalue, node.rhs); + return expr(mod, scope, .ref, node.rhs); } fn optionalType(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerError!*zir.Inst { @@ -541,9 +669,9 @@ fn unwrapOptional(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Si const tree = scope.tree(); const src = tree.token_locs[node.rtoken].start; - const operand = try expr(mod, scope, .lvalue, node.lhs); + const operand = try expr(mod, scope, .ref, node.lhs); const unwrapped_ptr = try addZIRUnOp(mod, scope, src, .unwrap_optional_safe, operand); - if (rl == .lvalue) return unwrapped_ptr; + if (rl == .lvalue or rl == .ref) return unwrapped_ptr; return rlWrap(mod, scope, rl, try addZIRUnOp(mod, scope, src, .deref, unwrapped_ptr)); } @@ -718,13 +846,13 @@ const CondKind = union(enum) { return try expr(mod, &block_scope.base, .{ .ty = bool_type }, cond_node); }, .optional => { - const cond_ptr = try expr(mod, &block_scope.base, .lvalue, cond_node); + const cond_ptr = try expr(mod, &block_scope.base, .ref, cond_node); self.* = .{ .optional = cond_ptr }; const result = try addZIRUnOp(mod, &block_scope.base, src, .deref, cond_ptr); return try addZIRUnOp(mod, &block_scope.base, src, .isnonnull, result); }, .err_union => { - const err_ptr = try expr(mod, &block_scope.base, .lvalue, cond_node); + const err_ptr = try expr(mod, &block_scope.base, .ref, cond_node); self.* = .{ .err_union = err_ptr }; const result = try addZIRUnOp(mod, &block_scope.base, src, .deref, err_ptr); return try addZIRUnOp(mod, &block_scope.base, src, .iserr, result); @@ -819,7 +947,7 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn // proper type inference requires peer type resolution on the if's // branches. const branch_rl: ResultLoc = switch (rl) { - .discard, .none, .ty, .ptr, .lvalue => rl, + .discard, .none, .ty, .ptr, .lvalue, .ref => rl, .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = block }, }; @@ -949,7 +1077,7 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W // proper type inference requires peer type resolution on the while's // branches. const branch_rl: ResultLoc = switch (rl) { - .discard, .none, .ty, .ptr, .lvalue => rl, + .discard, .none, .ty, .ptr, .lvalue, .ref => rl, .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = while_block }, }; @@ -1080,7 +1208,7 @@ fn identifier(mod: *Module, scope: *Scope, rl: ResultLoc, ident: *ast.Node.OneTo .local_ptr => { const local_ptr = s.cast(Scope.LocalPtr).?; if (mem.eql(u8, local_ptr.name, ident_name)) { - if (rl == .lvalue) { + if (rl == .lvalue or rl == .ref) { return local_ptr.ptr; } else { const result = try addZIRUnOp(mod, scope, src, .deref, local_ptr.ptr); @@ -1344,7 +1472,8 @@ fn as(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.BuiltinCall) I _ = try addZIRUnOp(mod, scope, result.src, .ensure_result_non_error, result); return result; }, - .lvalue => { + .lvalue => unreachable, + .ref => { const result = try expr(mod, scope, .{ .ty = dest_type }, params[1]); return addZIRUnOp(mod, scope, result.src, .ref, result); }, @@ -1395,9 +1524,10 @@ fn bitCast(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.BuiltinCa _ = try addZIRUnOp(mod, scope, result.src, .ensure_result_non_error, result); return result; }, - .lvalue => { - const operand = try expr(mod, scope, .lvalue, params[1]); - const result = try addZIRBinOp(mod, scope, src, .bitcast_lvalue, dest_type, operand); + .lvalue => unreachable, + .ref => { + const operand = try expr(mod, scope, .ref, params[1]); + const result = try addZIRBinOp(mod, scope, src, .bitcast_ref, dest_type, operand); return result; }, .ty => |result_ty| { @@ -1662,7 +1792,7 @@ fn rlWrap(mod: *Module, scope: *Scope, rl: ResultLoc, result: *zir.Inst) InnerEr _ = try addZIRUnOp(mod, scope, result.src, .ensure_result_non_error, result); return result; }, - .lvalue => { + .lvalue, .ref => { // We need a pointer but we have a value. return addZIRUnOp(mod, scope, result.src, .ref, result); }, diff --git a/src-self-hosted/zir.zig b/src-self-hosted/zir.zig index 235a4c931b..e8e21e5365 100644 --- a/src-self-hosted/zir.zig +++ b/src-self-hosted/zir.zig @@ -62,11 +62,11 @@ pub const Inst = struct { bitand, /// TODO delete this instruction, it has no purpose. bitcast, - /// An arbitrary typed pointer, which is to be used as an L-Value, is pointer-casted - /// to a new L-Value. The destination type is given by LHS. The cast is to be evaluated + /// An arbitrary typed pointer is pointer-casted to a new Pointer. + /// The destination type is given by LHS. The cast is to be evaluated /// as if it were a bit-cast operation from the operand pointer element type to the /// provided destination type. - bitcast_lvalue, + bitcast_ref, /// A typed result location pointer is bitcasted to a new result location pointer. /// The new result location pointer has an inferred type. bitcast_result_ptr, @@ -258,7 +258,7 @@ pub const Inst = struct { .ensure_result_non_error, .bitcast_result_ptr, .ref, - .bitcast_lvalue, + .bitcast_ref, .typeof, .single_const_ptr_type, .single_mut_ptr_type, @@ -349,7 +349,7 @@ pub const Inst = struct { .@"asm", .bitand, .bitcast, - .bitcast_lvalue, + .bitcast_ref, .bitcast_result_ptr, .bitor, .block, diff --git a/src-self-hosted/zir_sema.zig b/src-self-hosted/zir_sema.zig index 3a2a593539..fb39a1e077 100644 --- a/src-self-hosted/zir_sema.zig +++ b/src-self-hosted/zir_sema.zig @@ -29,7 +29,7 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError! .alloc => return analyzeInstAlloc(mod, scope, old_inst.castTag(.alloc).?), .alloc_inferred => return analyzeInstAllocInferred(mod, scope, old_inst.castTag(.alloc_inferred).?), .arg => return analyzeInstArg(mod, scope, old_inst.castTag(.arg).?), - .bitcast_lvalue => return analyzeInstBitCastLValue(mod, scope, old_inst.castTag(.bitcast_lvalue).?), + .bitcast_ref => return analyzeInstBitCastRef(mod, scope, old_inst.castTag(.bitcast_ref).?), .bitcast_result_ptr => return analyzeInstBitCastResultPtr(mod, scope, old_inst.castTag(.bitcast_result_ptr).?), .block => return analyzeInstBlock(mod, scope, old_inst.castTag(.block).?), .@"break" => return analyzeInstBreak(mod, scope, old_inst.castTag(.@"break").?), @@ -299,8 +299,8 @@ fn analyzeInstCoerceResultBlockPtr( return mod.fail(scope, inst.base.src, "TODO implement analyzeInstCoerceResultBlockPtr", .{}); } -fn analyzeInstBitCastLValue(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { - return mod.fail(scope, inst.base.src, "TODO implement analyzeInstBitCastLValue", .{}); +fn analyzeInstBitCastRef(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { + return mod.fail(scope, inst.base.src, "TODO implement analyzeInstBitCastRef", .{}); } fn analyzeInstBitCastResultPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { From e4b3da27203e0117ac29cceb03d7fe396f3931a7 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Tue, 18 Aug 2020 17:45:04 +0200 Subject: [PATCH 10/66] Write out Mach-O header This commit write out Mach-O header in the linker's `flush` method. The header currently only populates the magic number, filetype, and cpu info. Signed-off-by: Jakub Konka --- lib/std/macho.zig | 12 ++++++ src-self-hosted/link.zig | 1 - src-self-hosted/link/MachO.zig | 74 ++++++++++++++++++++++++++++++++-- 3 files changed, 83 insertions(+), 4 deletions(-) diff --git a/lib/std/macho.zig b/lib/std/macho.zig index a499a93675..950283b59f 100644 --- a/lib/std/macho.zig +++ b/lib/std/macho.zig @@ -703,3 +703,15 @@ pub const cpu_type_t = integer_t; pub const cpu_subtype_t = integer_t; pub const integer_t = c_int; pub const vm_prot_t = c_int; + +/// CPU type targeting 64-bit Intel-based Macs +pub const CPU_TYPE_X86_64: cpu_type_t = 0x01000007; + +/// CPU type targeting 64-bit ARM-based Macs +pub const CPU_TYPE_ARM64: cpu_type_t = 0x0100000C; + +/// All Intel-based Macs +pub const CPU_SUBTYPE_X86_64_ALL: cpu_subtype_t = 0x3; + +/// All ARM-based Macs +pub const CPU_SUBTYPE_ARM_ALL: cpu_subtype_t = 0x0; diff --git a/src-self-hosted/link.zig b/src-self-hosted/link.zig index cbc376f7ab..506efa85cc 100644 --- a/src-self-hosted/link.zig +++ b/src-self-hosted/link.zig @@ -40,7 +40,6 @@ pub const Options = struct { program_code_size_hint: u64 = 256 * 1024, }; - pub const File = struct { pub const LinkBlock = union { elf: Elf.TextBlock, diff --git a/src-self-hosted/link/MachO.zig b/src-self-hosted/link/MachO.zig index 49e365d203..e7b0a68c81 100644 --- a/src-self-hosted/link/MachO.zig +++ b/src-self-hosted/link/MachO.zig @@ -4,6 +4,8 @@ const std = @import("std"); const Allocator = std.mem.Allocator; const assert = std.debug.assert; const fs = std.fs; +const log = std.log; +const macho = std.macho; const Module = @import("../Module.zig"); const link = @import("../link.zig"); @@ -13,6 +15,8 @@ pub const base_tag: Tag = File.Tag.macho; base: File, +entry_addr: ?u64 = null, + error_flags: File.ErrorFlags = File.ErrorFlags{}, pub const TextBlock = struct { @@ -67,13 +71,77 @@ fn openFile(allocator: *Allocator, file: fs.File, options: link.Options) !MachO /// Returns an error if `file` is not already open with +read +write +seek abilities. fn createFile(allocator: *Allocator, file: fs.File, options: link.Options) !MachO { switch (options.output_mode) { - .Exe => return error.TODOImplementWritingMachOExeFiles, - .Obj => return error.TODOImplementWritingMachOObjFiles, + .Exe => {}, + .Obj => {}, .Lib => return error.TODOImplementWritingLibFiles, } + + var self: MachO = .{ + .base = .{ + .file = file, + .tag = .macho, + .options = options, + .allocator = allocator, + }, + }; + errdefer self.deinit(); + + return self; } -pub fn flush(self: *MachO, module: *Module) !void {} +fn writeMachOHeader(self: *MachO) !void { + var hdr: macho.mach_header_64 = undefined; + hdr.magic = macho.MH_MAGIC_64; + + const CpuInfo = struct { + cpu_type: macho.cpu_type_t, + cpu_subtype: macho.cpu_subtype_t, + }; + + const cpu_info: CpuInfo = switch (self.base.options.target.cpu.arch) { + .aarch64 => .{ + .cpu_type = macho.CPU_TYPE_ARM64, + .cpu_subtype = macho.CPU_SUBTYPE_ARM_ALL, + }, + .x86_64 => .{ + .cpu_type = macho.CPU_TYPE_X86_64, + .cpu_subtype = macho.CPU_SUBTYPE_X86_64_ALL, + }, + else => return error.UnsupportedMachOArchitecture, + }; + hdr.cputype = cpu_info.cpu_type; + hdr.cpusubtype = cpu_info.cpu_subtype; + + const filetype: u32 = switch (self.base.options.output_mode) { + .Exe => macho.MH_EXECUTE, + .Obj => macho.MH_OBJECT, + .Lib => switch (self.base.options.link_mode) { + .Static => return error.TODOStaticLibMachOType, + .Dynamic => macho.MH_DYLIB, + }, + }; + hdr.filetype = filetype; + + // TODO the rest of the header + hdr.ncmds = 0; + hdr.sizeofcmds = 0; + hdr.flags = 0; + hdr.reserved = 0; + + try self.base.file.?.pwriteAll(@ptrCast([*]const u8, &hdr)[0..@sizeOf(macho.mach_header_64)], 0); +} + +pub fn flush(self: *MachO, module: *Module) !void { + // TODO implement flush + if (self.entry_addr == null and self.base.options.output_mode == .Exe) { + log.debug(.link, "flushing. no_entry_point_found = true\n", .{}); + self.error_flags.no_entry_point_found = true; + } else { + log.debug(.link, "flushing. no_entry_point_found = false\n", .{}); + self.error_flags.no_entry_point_found = false; + try self.writeMachOHeader(); + } +} pub fn deinit(self: *MachO) void {} From 34e628a0a0239eb7da4ee9c69dae62c16dd93a55 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Tue, 18 Aug 2020 22:37:25 +0200 Subject: [PATCH 11/66] Fix compile error Signed-off-by: Jakub Konka --- src-self-hosted/link/MachO.zig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src-self-hosted/link/MachO.zig b/src-self-hosted/link/MachO.zig index e7b0a68c81..e83b2314d8 100644 --- a/src-self-hosted/link/MachO.zig +++ b/src-self-hosted/link/MachO.zig @@ -134,10 +134,10 @@ fn writeMachOHeader(self: *MachO) !void { pub fn flush(self: *MachO, module: *Module) !void { // TODO implement flush if (self.entry_addr == null and self.base.options.output_mode == .Exe) { - log.debug(.link, "flushing. no_entry_point_found = true\n", .{}); + log.debug("flushing. no_entry_point_found = true\n", .{}); self.error_flags.no_entry_point_found = true; } else { - log.debug(.link, "flushing. no_entry_point_found = false\n", .{}); + log.debug("flushing. no_entry_point_found = false\n", .{}); self.error_flags.no_entry_point_found = false; try self.writeMachOHeader(); } From 741fb8d30675f85316f7df100801e7cf8c2b3194 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Tue, 18 Aug 2020 10:54:54 +0200 Subject: [PATCH 12/66] stage2/link: clarify comments on calling order --- src-self-hosted/link.zig | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src-self-hosted/link.zig b/src-self-hosted/link.zig index cbc376f7ab..2f786609b7 100644 --- a/src-self-hosted/link.zig +++ b/src-self-hosted/link.zig @@ -110,6 +110,8 @@ pub const File = struct { } } + /// May be called before or after updateDeclExports but must be called + /// after allocateDeclIndexes for any given Decl. pub fn updateDecl(base: *File, module: *Module, decl: *Module.Decl) !void { switch (base.tag) { .elf => return @fieldParentPtr(Elf, "base", base).updateDecl(module, decl), @@ -127,6 +129,8 @@ pub const File = struct { } } + /// Must be called before any call to updateDecl or updateDeclExports for + /// any given Decl. pub fn allocateDeclIndexes(base: *File, decl: *Module.Decl) !void { switch (base.tag) { .elf => return @fieldParentPtr(Elf, "base", base).allocateDeclIndexes(decl), @@ -200,7 +204,8 @@ pub const File = struct { }; } - /// Must be called only after a successful call to `updateDecl`. + /// May be called before or after updateDecl, but must be called after + /// allocateDeclIndexes for any given Decl. pub fn updateDeclExports( base: *File, module: *Module, From fe3aa4ccd0bc157e1dd9d84b7c57b0cb2f0a77a9 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Tue, 18 Aug 2020 18:30:48 +0200 Subject: [PATCH 13/66] stage2/wasm: do incremental compilation in-memory Before this commit the wasm backend worked similarly to elf. As functions were generated they were written directly to the output file and existing code was shifted around in the file as necessary. This approach had several disadvantages: - Large amounts of padding in the output were necessary to avoid expensive copying of data within the file. - Function/type/global/etc indexes were required to be known at the time of preforming codegen, which severely limited the flexibility of where code could be placed in the binary - Significant complexity to track the state of the output file through incremental updates This commit takes things in a different direction. Code is incrementally compiled into in-memory buffers and the entire binary is rewritten using these buffers on flush. This has several advantages: - Significantly smaller resulting binaries - More performant resulting binaries due to lack of indirection - Significantly simpler compiler code - Indexes no longer need to be known before codegen. We can track where Decls must be referenced by index insert the proper indexes while writing the code in the flush() function. This is not yet implemented but is planned for the next commit. The main disadvantage is of course increased memory usage in order to store these buffers of generated code. --- src-self-hosted/link/Wasm.zig | 500 ++++++++++------------------------ 1 file changed, 137 insertions(+), 363 deletions(-) diff --git a/src-self-hosted/link/Wasm.zig b/src-self-hosted/link/Wasm.zig index a381cfad57..434c17372b 100644 --- a/src-self-hosted/link/Wasm.zig +++ b/src-self-hosted/link/Wasm.zig @@ -32,19 +32,19 @@ const spec = struct { pub const base_tag = link.File.Tag.wasm; pub const FnData = struct { - funcidx: u32, + /// Generated code for the type of the function + functype: std.ArrayListUnmanaged(u8) = .{}, + /// Generated code for the body of the function + code: std.ArrayListUnmanaged(u8) = .{}, }; base: link.File, -types: Types, -funcs: Funcs, -exports: Exports, - -/// Array over the section structs used in the various sections above to -/// allow iteration when shifting sections to make space. -/// TODO: this should eventually be size 11 when we use all the sections. -sections: [4]*Section, +/// List of all function Decls to be written to the output file. The index of +/// each Decl in this list at the time of writing the binary is used as the +/// function index. +/// TODO: can/should we access some data structure in Module directly? +funcs: std.ArrayListUnmanaged(*Module.Decl) = .{}, pub fn openPath(allocator: *Allocator, dir: fs.Dir, sub_path: []const u8, options: link.Options) !*link.File { assert(options.object_format == .wasm); @@ -58,10 +58,6 @@ pub fn openPath(allocator: *Allocator, dir: fs.Dir, sub_path: []const u8, option try file.writeAll(&(spec.magic ++ spec.version)); - // TODO: this should vary depending on the section and be less arbitrary - const size = 1024; - const offset = @sizeOf(@TypeOf(spec.magic ++ spec.version)); - wasm.* = .{ .base = .{ .tag = .wasm, @@ -69,52 +65,40 @@ pub fn openPath(allocator: *Allocator, dir: fs.Dir, sub_path: []const u8, option .file = file, .allocator = allocator, }, - - .types = try Types.init(file, offset, size), - .funcs = try Funcs.init(file, offset + size, size, offset + 3 * size, size), - .exports = try Exports.init(file, offset + 2 * size, size), - - // These must be ordered as they will appear in the output file - .sections = [_]*Section{ - &wasm.types.typesec.section, - &wasm.funcs.funcsec, - &wasm.exports.exportsec, - &wasm.funcs.codesec.section, - }, }; - try file.setEndPos(offset + 4 * size); - return &wasm.base; } pub fn deinit(self: *Wasm) void { - self.types.deinit(); - self.funcs.deinit(); + for (self.funcs.items) |decl| { + decl.fn_link.wasm.?.functype.deinit(self.base.allocator); + decl.fn_link.wasm.?.code.deinit(self.base.allocator); + } + self.funcs.deinit(self.base.allocator); } +// Generate code for the Decl, storing it in memory to be later written to +// the file on flush(). pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void { if (decl.typed_value.most_recent.typed_value.ty.zigTypeTag() != .Fn) return error.TODOImplementNonFnDeclsForWasm; - if (decl.fn_link.wasm) |fn_data| { - self.funcs.free(fn_data.funcidx); + if (decl.fn_link.wasm) |*fn_data| { + fn_data.functype.items.len = 0; + fn_data.code.items.len = 0; + } else { + decl.fn_link.wasm = .{}; + try self.funcs.append(self.base.allocator, decl); } + const fn_data = &decl.fn_link.wasm.?; - var buf = std.ArrayList(u8).init(self.base.allocator); - defer buf.deinit(); - - try codegen.genFunctype(&buf, decl); - const typeidx = try self.types.new(buf.items); - buf.items.len = 0; - - try codegen.genCode(&buf, decl); - const funcidx = try self.funcs.new(typeidx, buf.items); - - decl.fn_link.wasm = .{ .funcidx = funcidx }; - - // TODO: we should be more smart and set this only when needed - self.exports.dirty = true; + var managed_functype = fn_data.functype.toManaged(self.base.allocator); + var managed_code = fn_data.code.toManaged(self.base.allocator); + try codegen.genFunctype(&managed_functype, decl); + try codegen.genCode(&managed_code, decl); + fn_data.functype = managed_functype.toUnmanaged(); + fn_data.code = managed_code.toUnmanaged(); } pub fn updateDeclExports( @@ -122,332 +106,122 @@ pub fn updateDeclExports( module: *Module, decl: *const Module.Decl, exports: []const *Module.Export, -) !void { - self.exports.dirty = true; -} +) !void {} pub fn freeDecl(self: *Wasm, decl: *Module.Decl) void { // TODO: remove this assert when non-function Decls are implemented assert(decl.typed_value.most_recent.typed_value.ty.zigTypeTag() == .Fn); - if (decl.fn_link.wasm) |fn_data| { - self.funcs.free(fn_data.funcidx); - decl.fn_link.wasm = null; - } + _ = self.funcs.swapRemove(self.getFuncidx(decl).?); + decl.fn_link.wasm.?.functype.deinit(self.base.allocator); + decl.fn_link.wasm.?.code.deinit(self.base.allocator); + decl.fn_link.wasm = null; } pub fn flush(self: *Wasm, module: *Module) !void { - if (self.exports.dirty) try self.exports.writeAll(module); + const file = self.base.file.?; + const header_size = 5 + 1; + + // No need to rewrite the magic/version header + try file.setEndPos(@sizeOf(@TypeOf(spec.magic ++ spec.version))); + try file.seekTo(@sizeOf(@TypeOf(spec.magic ++ spec.version))); + + // Type section + { + const header_offset = try reserveVecSectionHeader(file); + for (self.funcs.items) |decl| { + try file.writeAll(decl.fn_link.wasm.?.functype.items); + } + try writeVecSectionHeader( + file, + header_offset, + spec.types_id, + @intCast(u32, (try file.getPos()) - header_offset - header_size), + @intCast(u32, self.funcs.items.len), + ); + } + + // Function section + { + const header_offset = try reserveVecSectionHeader(file); + const writer = file.writer(); + for (self.funcs.items) |_, typeidx| try leb.writeULEB128(writer, @intCast(u32, typeidx)); + try writeVecSectionHeader( + file, + header_offset, + spec.funcs_id, + @intCast(u32, (try file.getPos()) - header_offset - header_size), + @intCast(u32, self.funcs.items.len), + ); + } + + // Export section + { + const header_offset = try reserveVecSectionHeader(file); + const writer = file.writer(); + var count: u32 = 0; + for (module.decl_exports.entries.items) |entry| { + for (entry.value) |exprt| { + // Export name length + name + try leb.writeULEB128(writer, @intCast(u32, exprt.options.name.len)); + try writer.writeAll(exprt.options.name); + + switch (exprt.exported_decl.typed_value.most_recent.typed_value.ty.zigTypeTag()) { + .Fn => { + // Type of the export + try writer.writeByte(0x00); + // Exported function index + try leb.writeULEB128(writer, self.getFuncidx(exprt.exported_decl).?); + }, + else => return error.TODOImplementNonFnDeclsForWasm, + } + + count += 1; + } + } + try writeVecSectionHeader( + file, + header_offset, + spec.exports_id, + @intCast(u32, (try file.getPos()) - header_offset - header_size), + count, + ); + } + + // Code section + { + const header_offset = try reserveVecSectionHeader(file); + for (self.funcs.items) |decl| try file.writeAll(decl.fn_link.wasm.?.code.items); + try writeVecSectionHeader( + file, + header_offset, + spec.code_id, + @intCast(u32, (try file.getPos()) - header_offset - header_size), + @intCast(u32, self.funcs.items.len), + ); + } } -/// This struct describes the location of a named section + custom section -/// padding in the output file. This is all the data we need to allow for -/// shifting sections around when padding runs out. -const Section = struct { - /// The size of a section header: 1 byte section id + 5 bytes - /// for the fixed-width ULEB128 encoded contents size. - const header_size = 1 + 5; - /// Offset of the section id byte from the start of the file. - offset: u64, - /// Size of the section, including the header and directly - /// following custom section used for padding if any. - size: u64, +/// Get the current index of a given Decl in the function list +/// TODO: we could maintain a hash map to potentially make this +fn getFuncidx(self: Wasm, decl: *Module.Decl) ?u32 { + return for (self.funcs.items) |func, idx| { + if (func == decl) break @intCast(u32, idx); + } else null; +} - /// Resize the usable part of the section, handling the following custom - /// section used for padding. If there is not enough padding left, shift - /// all following sections to make space. Takes the current and target - /// contents sizes of the section as arguments. - fn resize(self: *Section, file: fs.File, current: u32, target: u32) !void { - // Section header + target contents size + custom section header - // + custom section name + empty custom section > owned chunk of the file - if (header_size + target + header_size + 1 + 0 > self.size) - return error.TODOImplementSectionShifting; +fn reserveVecSectionHeader(file: fs.File) !u64 { + // section id + fixed leb contents size + fixed leb vector length + const header_size = 1 + 5 + 5; + // TODO: this should be a single lseek(2) call, but fs.File does not + // currently provide a way to do this. + try file.seekBy(header_size); + return (try file.getPos()) - header_size; +} - const new_custom_start = self.offset + header_size + target; - const new_custom_contents_size = self.size - target - 2 * header_size; - assert(new_custom_contents_size >= 1); - // +1 for the name of the custom section, which we set to an empty string - var custom_header: [header_size + 1]u8 = undefined; - custom_header[0] = spec.custom_id; - leb.writeUnsignedFixed(5, custom_header[1..header_size], @intCast(u32, new_custom_contents_size)); - custom_header[header_size] = 0; - try file.pwriteAll(&custom_header, new_custom_start); - } -}; - -/// This can be used to manage the contents of any section which uses a vector -/// of contents. This interface maintains index stability while allowing for -/// reuse of "dead" indexes. -const VecSection = struct { - /// Represents a single entry in the vector (e.g. a type in the type section) - const Entry = struct { - /// Offset from the start of the section contents in bytes - offset: u32, - /// Size in bytes of the entry - size: u32, - }; - section: Section, - /// Size in bytes of the contents of the section. Does not include - /// the "header" containing the section id and this value. - contents_size: u32, - /// List of all entries in the contents of the section. - entries: std.ArrayListUnmanaged(Entry) = std.ArrayListUnmanaged(Entry){}, - /// List of indexes of unreferenced entries which may be - /// overwritten and reused. - dead_list: std.ArrayListUnmanaged(u32) = std.ArrayListUnmanaged(u32){}, - - /// Write the headers of the section and custom padding section - fn init(comptime section_id: u8, file: fs.File, offset: u64, initial_size: u64) !VecSection { - // section id, section size, empty vector, custom section id, - // custom section size, empty custom section name - var initial_data: [1 + 5 + 5 + 1 + 5 + 1]u8 = undefined; - - assert(initial_size >= initial_data.len); - - comptime var i = 0; - initial_data[i] = section_id; - i += 1; - leb.writeUnsignedFixed(5, initial_data[i..(i + 5)], 5); - i += 5; - leb.writeUnsignedFixed(5, initial_data[i..(i + 5)], 0); - i += 5; - initial_data[i] = spec.custom_id; - i += 1; - leb.writeUnsignedFixed(5, initial_data[i..(i + 5)], @intCast(u32, initial_size - @sizeOf(@TypeOf(initial_data)))); - i += 5; - initial_data[i] = 0; - - try file.pwriteAll(&initial_data, offset); - - return VecSection{ - .section = .{ - .offset = offset, - .size = initial_size, - }, - .contents_size = 5, - }; - } - - fn deinit(self: *VecSection, allocator: *Allocator) void { - self.entries.deinit(allocator); - self.dead_list.deinit(allocator); - } - - /// Write a new entry into the file, returning the index used. - fn addEntry(self: *VecSection, file: fs.File, allocator: *Allocator, data: []const u8) !u32 { - // First look for a dead entry we can reuse - for (self.dead_list.items) |dead_idx, i| { - const dead_entry = &self.entries.items[dead_idx]; - if (dead_entry.size == data.len) { - // Found a dead entry of the right length, overwrite it - try file.pwriteAll(data, self.section.offset + Section.header_size + dead_entry.offset); - _ = self.dead_list.swapRemove(i); - return dead_idx; - } - } - - // TODO: We can be more efficient if we special-case one or - // more consecutive dead entries at the end of the vector. - - // We failed to find a dead entry to reuse, so write the new - // entry to the end of the section. - try self.section.resize(file, self.contents_size, self.contents_size + @intCast(u32, data.len)); - try file.pwriteAll(data, self.section.offset + Section.header_size + self.contents_size); - try self.entries.append(allocator, .{ - .offset = self.contents_size, - .size = @intCast(u32, data.len), - }); - self.contents_size += @intCast(u32, data.len); - // Make sure the dead list always has enough space to store all free'd - // entries. This makes it so that delEntry() cannot fail. - // TODO: figure out a better way that doesn't waste as much memory - try self.dead_list.ensureCapacity(allocator, self.entries.items.len); - - // Update the size in the section header and the item count of - // the contents vector. - var size_and_count: [10]u8 = undefined; - leb.writeUnsignedFixed(5, size_and_count[0..5], self.contents_size); - leb.writeUnsignedFixed(5, size_and_count[5..], @intCast(u32, self.entries.items.len)); - try file.pwriteAll(&size_and_count, self.section.offset + 1); - - return @intCast(u32, self.entries.items.len - 1); - } - - /// Mark the type referenced by the given index as dead. - fn delEntry(self: *VecSection, index: u32) void { - self.dead_list.appendAssumeCapacity(index); - } -}; - -const Types = struct { - typesec: VecSection, - - fn init(file: fs.File, offset: u64, initial_size: u64) !Types { - return Types{ .typesec = try VecSection.init(spec.types_id, file, offset, initial_size) }; - } - - fn deinit(self: *Types) void { - const wasm = @fieldParentPtr(Wasm, "types", self); - self.typesec.deinit(wasm.base.allocator); - } - - fn new(self: *Types, data: []const u8) !u32 { - const wasm = @fieldParentPtr(Wasm, "types", self); - return self.typesec.addEntry(wasm.base.file.?, wasm.base.allocator, data); - } - - fn free(self: *Types, typeidx: u32) void { - self.typesec.delEntry(typeidx); - } -}; - -const Funcs = struct { - /// This section needs special handling to keep the indexes matching with - /// the codesec, so we cant just use a VecSection. - funcsec: Section, - /// The typeidx stored for each function, indexed by funcidx. - func_types: std.ArrayListUnmanaged(u32) = std.ArrayListUnmanaged(u32){}, - codesec: VecSection, - - fn init(file: fs.File, funcs_offset: u64, funcs_size: u64, code_offset: u64, code_size: u64) !Funcs { - return Funcs{ - .funcsec = (try VecSection.init(spec.funcs_id, file, funcs_offset, funcs_size)).section, - .codesec = try VecSection.init(spec.code_id, file, code_offset, code_size), - }; - } - - fn deinit(self: *Funcs) void { - const wasm = @fieldParentPtr(Wasm, "funcs", self); - self.func_types.deinit(wasm.base.allocator); - self.codesec.deinit(wasm.base.allocator); - } - - /// Add a new function to the binary, first finding space for and writing - /// the code then writing the typeidx to the corresponding index in the - /// funcsec. Returns the function index used. - fn new(self: *Funcs, typeidx: u32, code: []const u8) !u32 { - const wasm = @fieldParentPtr(Wasm, "funcs", self); - const file = wasm.base.file.?; - const allocator = wasm.base.allocator; - - assert(self.func_types.items.len == self.codesec.entries.items.len); - - // TODO: consider nop-padding the code if there is a close but not perfect fit - const funcidx = try self.codesec.addEntry(file, allocator, code); - - if (self.func_types.items.len < self.codesec.entries.items.len) { - // u32 vector length + funcs_count u32s in the vector - const current = 5 + @intCast(u32, self.func_types.items.len) * 5; - try self.funcsec.resize(file, current, current + 5); - try self.func_types.append(allocator, typeidx); - - // Update the size in the section header and the item count of - // the contents vector. - const count = @intCast(u32, self.func_types.items.len); - var size_and_count: [10]u8 = undefined; - leb.writeUnsignedFixed(5, size_and_count[0..5], 5 + count * 5); - leb.writeUnsignedFixed(5, size_and_count[5..], count); - try file.pwriteAll(&size_and_count, self.funcsec.offset + 1); - } else { - // We are overwriting a dead function and may now free the type - wasm.types.free(self.func_types.items[funcidx]); - } - - assert(self.func_types.items.len == self.codesec.entries.items.len); - - var typeidx_leb: [5]u8 = undefined; - leb.writeUnsignedFixed(5, &typeidx_leb, typeidx); - try file.pwriteAll(&typeidx_leb, self.funcsec.offset + Section.header_size + 5 + funcidx * 5); - - return funcidx; - } - - fn free(self: *Funcs, funcidx: u32) void { - self.codesec.delEntry(funcidx); - } -}; - -/// Exports are tricky. We can't leave dead entries in the binary as they -/// would obviously be visible from the execution environment. The simplest -/// way to work around this is to re-emit the export section whenever -/// something changes. This also makes it easier to ensure exported function -/// and global indexes are updated as they change. -const Exports = struct { - exportsec: Section, - /// Size in bytes of the contents of the section. Does not include - /// the "header" containing the section id and this value. - contents_size: u32, - /// If this is true, then exports will be rewritten on flush() - dirty: bool, - - fn init(file: fs.File, offset: u64, initial_size: u64) !Exports { - return Exports{ - .exportsec = (try VecSection.init(spec.exports_id, file, offset, initial_size)).section, - .contents_size = 5, - .dirty = false, - }; - } - - fn writeAll(self: *Exports, module: *Module) !void { - const wasm = @fieldParentPtr(Wasm, "exports", self); - const file = wasm.base.file.?; - var buf: [5]u8 = undefined; - - // First ensure the section is the right size - var export_count: u32 = 0; - var new_contents_size: u32 = 5; - for (module.decl_exports.entries.items) |entry| { - for (entry.value) |e| { - export_count += 1; - new_contents_size += calcSize(e); - } - } - if (new_contents_size != self.contents_size) { - try self.exportsec.resize(file, self.contents_size, new_contents_size); - leb.writeUnsignedFixed(5, &buf, new_contents_size); - try file.pwriteAll(&buf, self.exportsec.offset + 1); - } - - try file.seekTo(self.exportsec.offset + Section.header_size); - const writer = file.writer(); - - // Length of the exports vec - leb.writeUnsignedFixed(5, &buf, export_count); - try writer.writeAll(&buf); - - for (module.decl_exports.entries.items) |entry| - for (entry.value) |e| try writeExport(writer, e); - - self.dirty = false; - } - - /// Return the total number of bytes an export will take. - /// TODO: fixed-width LEB128 is currently used for simplicity, but should - /// be replaced with proper variable-length LEB128 as it is inefficient. - fn calcSize(e: *Module.Export) u32 { - // LEB128 name length + name bytes + export type + LEB128 index - return 5 + @intCast(u32, e.options.name.len) + 1 + 5; - } - - /// Write the data for a single export to the given file at a given offset. - /// TODO: fixed-width LEB128 is currently used for simplicity, but should - /// be replaced with proper variable-length LEB128 as it is inefficient. - fn writeExport(writer: anytype, e: *Module.Export) !void { - var buf: [5]u8 = undefined; - - // Export name length + name - leb.writeUnsignedFixed(5, &buf, @intCast(u32, e.options.name.len)); - try writer.writeAll(&buf); - try writer.writeAll(e.options.name); - - switch (e.exported_decl.typed_value.most_recent.typed_value.ty.zigTypeTag()) { - .Fn => { - // Type of the export - try writer.writeByte(0x00); - // Exported function index - leb.writeUnsignedFixed(5, &buf, e.exported_decl.fn_link.wasm.?.funcidx); - try writer.writeAll(&buf); - }, - else => return error.TODOImplementNonFnDeclsForWasm, - } - } -}; +fn writeVecSectionHeader(file: fs.File, offset: u64, section: u8, size: u32, items: u32) !void { + var buf: [1 + 5 + 5]u8 = undefined; + buf[0] = section; + leb.writeUnsignedFixed(5, buf[1..6], size); + leb.writeUnsignedFixed(5, buf[6..], items); + try file.pwriteAll(&buf, offset); +} From 6242ae35f37a6e67d9da514fa7a3508843515667 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Wed, 19 Aug 2020 01:48:09 +0200 Subject: [PATCH 14/66] stage2/wasm: implement function calls During codegen we do not yet know the indexes that will be used for called functions. Therefore, we store the offset into the in-memory code where the index is needed with a pointer to the Decl and use this data to insert the proper indexes while writing the binary in the flush function. --- src-self-hosted/codegen/wasm.zig | 96 ++++++++++++++++++++------------ src-self-hosted/link/Wasm.zig | 26 ++++++++- test/stage2/compare_output.zig | 27 ++++++++- 3 files changed, 110 insertions(+), 39 deletions(-) diff --git a/src-self-hosted/codegen/wasm.zig b/src-self-hosted/codegen/wasm.zig index 57eb002e82..e55e904934 100644 --- a/src-self-hosted/codegen/wasm.zig +++ b/src-self-hosted/codegen/wasm.zig @@ -62,58 +62,80 @@ pub fn genCode(buf: *ArrayList(u8), decl: *Decl) !void { // TODO: check for and handle death of instructions const tv = decl.typed_value.most_recent.typed_value; const mod_fn = tv.val.cast(Value.Payload.Function).?.func; - for (mod_fn.analysis.success.instructions) |inst| try genInst(writer, inst); + for (mod_fn.analysis.success.instructions) |inst| try genInst(buf, decl, inst); // Write 'end' opcode try writer.writeByte(0x0B); // Fill in the size of the generated code to the reserved space at the // beginning of the buffer. - leb.writeUnsignedFixed(5, buf.items[0..5], @intCast(u32, buf.items.len - 5)); + const size = buf.items.len - 5 + decl.fn_link.wasm.?.idx_refs.items.len * 5; + leb.writeUnsignedFixed(5, buf.items[0..5], @intCast(u32, size)); } -fn genInst(writer: ArrayList(u8).Writer, inst: *Inst) !void { +fn genInst(buf: *ArrayList(u8), decl: *Decl, inst: *Inst) !void { return switch (inst.tag) { + .call => genCall(buf, decl, inst.castTag(.call).?), + .constant => genConstant(buf, decl, inst.castTag(.constant).?), .dbg_stmt => {}, - .ret => genRet(writer, inst.castTag(.ret).?), + .ret => genRet(buf, decl, inst.castTag(.ret).?), + .retvoid => {}, else => error.TODOImplementMoreWasmCodegen, }; } -fn genRet(writer: ArrayList(u8).Writer, inst: *Inst.UnOp) !void { - switch (inst.operand.tag) { - .constant => { - const constant = inst.operand.castTag(.constant).?; - switch (inst.operand.ty.tag()) { - .u32 => { - try writer.writeByte(0x41); // i32.const - try leb.writeILEB128(writer, constant.val.toUnsignedInt()); - }, - .i32 => { - try writer.writeByte(0x41); // i32.const - try leb.writeILEB128(writer, constant.val.toSignedInt()); - }, - .u64 => { - try writer.writeByte(0x42); // i64.const - try leb.writeILEB128(writer, constant.val.toUnsignedInt()); - }, - .i64 => { - try writer.writeByte(0x42); // i64.const - try leb.writeILEB128(writer, constant.val.toSignedInt()); - }, - .f32 => { - try writer.writeByte(0x43); // f32.const - // TODO: enforce LE byte order - try writer.writeAll(mem.asBytes(&constant.val.toFloat(f32))); - }, - .f64 => { - try writer.writeByte(0x44); // f64.const - // TODO: enforce LE byte order - try writer.writeAll(mem.asBytes(&constant.val.toFloat(f64))); - }, - else => return error.TODOImplementMoreWasmCodegen, - } +fn genConstant(buf: *ArrayList(u8), decl: *Decl, inst: *Inst.Constant) !void { + const writer = buf.writer(); + switch (inst.base.ty.tag()) { + .u32 => { + try writer.writeByte(0x41); // i32.const + try leb.writeILEB128(writer, inst.val.toUnsignedInt()); }, + .i32 => { + try writer.writeByte(0x41); // i32.const + try leb.writeILEB128(writer, inst.val.toSignedInt()); + }, + .u64 => { + try writer.writeByte(0x42); // i64.const + try leb.writeILEB128(writer, inst.val.toUnsignedInt()); + }, + .i64 => { + try writer.writeByte(0x42); // i64.const + try leb.writeILEB128(writer, inst.val.toSignedInt()); + }, + .f32 => { + try writer.writeByte(0x43); // f32.const + // TODO: enforce LE byte order + try writer.writeAll(mem.asBytes(&inst.val.toFloat(f32))); + }, + .f64 => { + try writer.writeByte(0x44); // f64.const + // TODO: enforce LE byte order + try writer.writeAll(mem.asBytes(&inst.val.toFloat(f64))); + }, + .void => {}, else => return error.TODOImplementMoreWasmCodegen, } } + +fn genRet(buf: *ArrayList(u8), decl: *Decl, inst: *Inst.UnOp) !void { + try genInst(buf, decl, inst.operand); +} + +fn genCall(buf: *ArrayList(u8), decl: *Decl, inst: *Inst.Call) !void { + const func_inst = inst.func.castTag(.constant).?; + const func_val = func_inst.val.cast(Value.Payload.Function).?; + const target = func_val.func.owner_decl; + const target_ty = target.typed_value.most_recent.typed_value.ty; + + if (inst.args.len != 0) return error.TODOImplementMoreWasmCodegen; + + try buf.append(0x10); // call + + // The function index immediate argument will be filled in using this data + // in link.Wasm.flush(). + try decl.fn_link.wasm.?.idx_refs.append(buf.allocator, .{ + .offset = @intCast(u32, buf.items.len), + .decl = target, + }); +} diff --git a/src-self-hosted/link/Wasm.zig b/src-self-hosted/link/Wasm.zig index 434c17372b..d8f172f584 100644 --- a/src-self-hosted/link/Wasm.zig +++ b/src-self-hosted/link/Wasm.zig @@ -36,6 +36,9 @@ pub const FnData = struct { functype: std.ArrayListUnmanaged(u8) = .{}, /// Generated code for the body of the function code: std.ArrayListUnmanaged(u8) = .{}, + /// Locations in the generated code where function indexes must be filled in. + /// This must be kept ordered by offset. + idx_refs: std.ArrayListUnmanaged(struct { offset: u32, decl: *Module.Decl }) = .{}, }; base: link.File, @@ -74,6 +77,7 @@ pub fn deinit(self: *Wasm) void { for (self.funcs.items) |decl| { decl.fn_link.wasm.?.functype.deinit(self.base.allocator); decl.fn_link.wasm.?.code.deinit(self.base.allocator); + decl.fn_link.wasm.?.idx_refs.deinit(self.base.allocator); } self.funcs.deinit(self.base.allocator); } @@ -87,6 +91,7 @@ pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void { if (decl.fn_link.wasm) |*fn_data| { fn_data.functype.items.len = 0; fn_data.code.items.len = 0; + fn_data.idx_refs.items.len = 0; } else { decl.fn_link.wasm = .{}; try self.funcs.append(self.base.allocator, decl); @@ -114,6 +119,7 @@ pub fn freeDecl(self: *Wasm, decl: *Module.Decl) void { _ = self.funcs.swapRemove(self.getFuncidx(decl).?); decl.fn_link.wasm.?.functype.deinit(self.base.allocator); decl.fn_link.wasm.?.code.deinit(self.base.allocator); + decl.fn_link.wasm.?.idx_refs.deinit(self.base.allocator); decl.fn_link.wasm = null; } @@ -190,7 +196,25 @@ pub fn flush(self: *Wasm, module: *Module) !void { // Code section { const header_offset = try reserveVecSectionHeader(file); - for (self.funcs.items) |decl| try file.writeAll(decl.fn_link.wasm.?.code.items); + const writer = file.writer(); + for (self.funcs.items) |decl| { + const fn_data = &decl.fn_link.wasm.?; + + // Write the already generated code to the file, inserting + // function indexes where required. + var current: u32 = 0; + for (fn_data.idx_refs.items) |idx_ref| { + try writer.writeAll(fn_data.code.items[current..idx_ref.offset]); + current = idx_ref.offset; + // Use a fixed width here to make calculating the code size + // in codegen.wasm.genCode() simpler. + var buf: [5]u8 = undefined; + leb.writeUnsignedFixed(5, &buf, self.getFuncidx(idx_ref.decl).?); + try writer.writeAll(&buf); + } + + try writer.writeAll(fn_data.code.items[current..]); + } try writeVecSectionHeader( file, header_offset, diff --git a/test/stage2/compare_output.zig b/test/stage2/compare_output.zig index 4208cc3911..34e8f5e159 100644 --- a/test/stage2/compare_output.zig +++ b/test/stage2/compare_output.zig @@ -546,28 +546,53 @@ pub fn addCases(ctx: *TestContext) !void { } { - var case = ctx.exe("wasm returns", wasi); + var case = ctx.exe("wasm function calls", wasi); case.addCompareOutput( \\export fn _start() u32 { + \\ foo(); + \\ bar(); \\ return 42; \\} + \\fn foo() void { + \\ bar(); + \\ bar(); + \\} + \\fn bar() void {} , "42\n", ); case.addCompareOutput( \\export fn _start() i64 { + \\ bar(); + \\ foo(); + \\ foo(); + \\ bar(); + \\ foo(); + \\ bar(); \\ return 42; \\} + \\fn foo() void { + \\ bar(); + \\} + \\fn bar() void {} , "42\n", ); case.addCompareOutput( \\export fn _start() f32 { + \\ bar(); + \\ foo(); \\ return 42.0; \\} + \\fn foo() void { + \\ bar(); + \\ bar(); + \\ bar(); + \\} + \\fn bar() void {} , // This is what you get when you take the bits of the IEE-754 // representation of 42.0 and reinterpret them as an unsigned From 4237f1afc7f38f68adf0877fc9be811f9189544f Mon Sep 17 00:00:00 2001 From: Nathan Michaels Date: Tue, 18 Aug 2020 22:47:38 -0400 Subject: [PATCH 15/66] Change std.debug.warn to std.log.info in init-exe template. (#5941) --- lib/std/special/init-exe/src/main.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/std/special/init-exe/src/main.zig b/lib/std/special/init-exe/src/main.zig index c6a70af56d..d29869ff88 100644 --- a/lib/std/special/init-exe/src/main.zig +++ b/lib/std/special/init-exe/src/main.zig @@ -1,5 +1,5 @@ const std = @import("std"); pub fn main() anyerror!void { - std.debug.warn("All your codebase are belong to us.\n", .{}); + std.log.info("All your codebase are belong to us.", .{}); } From ffdeb6af9171ccf9cb816a142a93991477d9a4ea Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Wed, 19 Aug 2020 07:43:33 +0200 Subject: [PATCH 16/66] Update src-self-hosted/link/MachO.zig Co-authored-by: Andrew Kelley --- src-self-hosted/link/MachO.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src-self-hosted/link/MachO.zig b/src-self-hosted/link/MachO.zig index e83b2314d8..e2a84d8ceb 100644 --- a/src-self-hosted/link/MachO.zig +++ b/src-self-hosted/link/MachO.zig @@ -4,7 +4,7 @@ const std = @import("std"); const Allocator = std.mem.Allocator; const assert = std.debug.assert; const fs = std.fs; -const log = std.log; +const log = std.log.scoped(.link); const macho = std.macho; const Module = @import("../Module.zig"); From dc35b8641badf3169a3124e84b672c3bf4bfd5f8 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 18 Aug 2020 20:10:27 -0700 Subject: [PATCH 17/66] stage2: Module enumerates the possible top level decls --- src-self-hosted/Module.zig | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src-self-hosted/Module.zig b/src-self-hosted/Module.zig index 3c31c7da44..e5988dfd8a 100644 --- a/src-self-hosted/Module.zig +++ b/src-self-hosted/Module.zig @@ -1583,11 +1583,19 @@ fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void { } } } + } else if (src_decl.castTag(.VarDecl)) |var_decl| { + log.err("TODO: analyze var decl", .{}); + } else if (src_decl.castTag(.Comptime)) |comptime_node| { + log.err("TODO: analyze comptime decl", .{}); + } else if (src_decl.castTag(.ContainerField)) |container_field| { + log.err("TODO: analyze container field", .{}); + } else if (src_decl.castTag(.TestDecl)) |test_decl| { + log.err("TODO: analyze test decl", .{}); + } else if (src_decl.castTag(.Use)) |use_decl| { + log.err("TODO: analyze usingnamespace decl", .{}); } else { - std.debug.panic("TODO: analyzeRootSrcFile {}", .{src_decl.tag}); + unreachable; } - // TODO also look for global variable declarations - // TODO also look for comptime blocks and exported globals } // Handle explicitly deleted decls from the source code. Not to be confused // with when we delete decls because they are no longer referenced. From 083c0f1cebc763e4e43529b50f6df9839c32c1c7 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 18 Aug 2020 23:11:19 -0700 Subject: [PATCH 18/66] stage2 codegen: proper abstraction for re-using dying operands closes #6064 --- src-self-hosted/codegen.zig | 17 ++++++++++---- src-self-hosted/ir.zig | 5 ++++ test/stage2/compare_output.zig | 42 ++++++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 4 deletions(-) diff --git a/src-self-hosted/codegen.zig b/src-self-hosted/codegen.zig index 8887a1e0ca..cb404d8315 100644 --- a/src-self-hosted/codegen.zig +++ b/src-self-hosted/codegen.zig @@ -858,6 +858,16 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { } } + fn reuseOperand(inst: *ir.Inst, op_index: ir.Inst.DeathsBitIndex, mcv: MCValue) bool { + if (!inst.operandDies(op_index) or !mcv.isMutable()) + return false; + + // OK we're going to do it, but we need to clear the operand death bit so that + // it stays allocated. + inst.clearOperandDeath(op_index); + return true; + } + fn genLoad(self: *Self, inst: *ir.Inst.UnOp) !MCValue { const elem_ty = inst.base.ty; if (!elem_ty.hasCodeGenBits()) @@ -867,9 +877,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { if (inst.base.isUnused() and !is_volatile) return MCValue.dead; const dst_mcv: MCValue = blk: { - if (inst.base.operandDies(0) and ptr.isMutable()) { + if (reuseOperand(&inst.base, 0, ptr)) { // The MCValue that holds the pointer can be re-used as the value. - // TODO track this in the register/stack allocation metadata. break :blk ptr; } else { break :blk try self.allocRegOrMem(&inst.base); @@ -966,7 +975,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { var dst_mcv: MCValue = undefined; var src_mcv: MCValue = undefined; var src_inst: *ir.Inst = undefined; - if (inst.operandDies(0) and lhs.isMutable()) { + if (reuseOperand(inst, 0, lhs)) { // LHS dies; use it as the destination. // Both operands cannot be memory. src_inst = op_rhs; @@ -977,7 +986,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { dst_mcv = lhs; src_mcv = rhs; } - } else if (inst.operandDies(1) and rhs.isMutable()) { + } else if (reuseOperand(inst, 1, rhs)) { // RHS dies; use it as the destination. // Both operands cannot be memory. src_inst = op_lhs; diff --git a/src-self-hosted/ir.zig b/src-self-hosted/ir.zig index 91dfad45d7..070f41eb5e 100644 --- a/src-self-hosted/ir.zig +++ b/src-self-hosted/ir.zig @@ -42,6 +42,11 @@ pub const Inst = struct { return @truncate(u1, self.deaths >> index) != 0; } + pub fn clearOperandDeath(self: *Inst, index: DeathsBitIndex) void { + assert(index < deaths_bits); + self.deaths &= ~(@as(DeathsInt, 1) << index); + } + pub fn specialOperandDeaths(self: Inst) bool { return (self.deaths & (1 << deaths_bits)) != 0; } diff --git a/test/stage2/compare_output.zig b/test/stage2/compare_output.zig index ec9d1b9f9e..3513605602 100644 --- a/test/stage2/compare_output.zig +++ b/test/stage2/compare_output.zig @@ -544,6 +544,48 @@ pub fn addCases(ctx: *TestContext) !void { "", ); + // This catches a possible bug in the logic for re-using dying operands. + case.addCompareOutput( + \\export fn _start() noreturn { + \\ assert(add(3, 4) == 116); + \\ + \\ exit(); + \\} + \\ + \\fn add(a: u32, b: u32) u32 { + \\ const x: u32 = blk: { + \\ const c = a + b; // 7 + \\ const d = a + c; // 10 + \\ const e = d + b; // 14 + \\ const f = d + e; // 24 + \\ const g = e + f; // 38 + \\ const h = f + g; // 62 + \\ const i = g + h; // 100 + \\ const j = i + d; // 110 + \\ break :blk j; + \\ }; + \\ const y = x + a; // 113 + \\ const z = y + a; // 116 + \\ return z; + \\} + \\ + \\pub fn assert(ok: bool) void { + \\ if (!ok) unreachable; // assertion failure + \\} + \\ + \\fn exit() noreturn { + \\ asm volatile ("syscall" + \\ : + \\ : [number] "{rax}" (231), + \\ [arg1] "{rdi}" (0) + \\ : "rcx", "r11", "memory" + \\ ); + \\ unreachable; + \\} + , + "", + ); + case.addCompareOutput( \\export fn _start() noreturn { \\ const ignore = From a237283d90ea6799331a7268f474511f352a23d7 Mon Sep 17 00:00:00 2001 From: dbandstra Date: Wed, 19 Aug 2020 13:10:05 -0700 Subject: [PATCH 19/66] fixes and improvements for parseCharLiteral --- lib/std/zig.zig | 86 +++++++++++++++++++++++++++---------------------- 1 file changed, 47 insertions(+), 39 deletions(-) diff --git a/lib/std/zig.zig b/lib/std/zig.zig index 36dfe74086..ab6895e1bf 100644 --- a/lib/std/zig.zig +++ b/lib/std/zig.zig @@ -84,7 +84,7 @@ pub fn binNameAlloc( /// Slice must be valid utf8 starting and ending with "'" and exactly one codepoint in between. pub fn parseCharLiteral( slice: []const u8, - bad_index: *usize, // populated if error.InvalidCharacter is returned) + bad_index: *usize, // populated if error.InvalidCharacter is returned ) error{InvalidCharacter}!u32 { std.debug.assert(slice.len >= 3 and slice[0] == '\'' and slice[slice.len - 1] == '\''); @@ -101,41 +101,8 @@ pub fn parseCharLiteral( bad_index.* = slice.len - 2; return error.InvalidCharacter; } - var value: u32 = 0; for (slice[3..5]) |c, i| { - switch (slice[3]) { - '0'...'9' => { - value *= 16; - value += c - '0'; - }, - 'a'...'f' => { - value *= 16; - value += c - 'a'; - }, - 'A'...'F' => { - value *= 16; - value += c - 'a'; - }, - else => { - bad_index.* = i; - return error.InvalidCharacter; - }, - } - } - return value; - }, - 'u' => { - if (slice.len < 6 or slice[3] != '{') { - bad_index.* = 2; - return error.InvalidCharacter; - } - var value: u32 = 0; - for (slice[4..]) |c, i| { - if (value > 0x10ffff) { - bad_index.* = i; - return error.InvalidCharacter; - } switch (c) { '0'...'9' => { value *= 16; @@ -143,25 +110,56 @@ pub fn parseCharLiteral( }, 'a'...'f' => { value *= 16; - value += c - 'a'; + value += c - 'a' + 10; }, 'A'...'F' => { value *= 16; - value += c - 'A'; + value += c - 'A' + 10; }, - '}' => break, else => { - bad_index.* = i; + bad_index.* = 3 + i; return error.InvalidCharacter; }, } } return value; }, + 'u' => { + if (slice.len < "'\\u{0}'".len or slice[3] != '{' or slice[slice.len - 2] != '}') { + bad_index.* = 2; + return error.InvalidCharacter; + } + var value: u32 = 0; + for (slice[4 .. slice.len - 2]) |c, i| { + switch (c) { + '0'...'9' => { + value *= 16; + value += c - '0'; + }, + 'a'...'f' => { + value *= 16; + value += c - 'a' + 10; + }, + 'A'...'F' => { + value *= 16; + value += c - 'A' + 10; + }, + else => { + bad_index.* = 4 + i; + return error.InvalidCharacter; + }, + } + if (value > 0x10ffff) { + bad_index.* = 4 + i; + return error.InvalidCharacter; + } + } + return value; + }, else => { bad_index.* = 2; return error.InvalidCharacter; - } + }, } } return std.unicode.utf8Decode(slice[1 .. slice.len - 1]) catch unreachable; @@ -172,13 +170,23 @@ test "parseCharLiteral" { std.testing.expectEqual(try parseCharLiteral("'a'", &bad_index), 'a'); std.testing.expectEqual(try parseCharLiteral("'ä'", &bad_index), 'ä'); std.testing.expectEqual(try parseCharLiteral("'\\x00'", &bad_index), 0); + std.testing.expectEqual(try parseCharLiteral("'\\x4f'", &bad_index), 0x4f); + std.testing.expectEqual(try parseCharLiteral("'\\x4F'", &bad_index), 0x4f); std.testing.expectEqual(try parseCharLiteral("'ぁ'", &bad_index), 0x3041); + std.testing.expectEqual(try parseCharLiteral("'\\u{0}'", &bad_index), 0); std.testing.expectEqual(try parseCharLiteral("'\\u{3041}'", &bad_index), 0x3041); + std.testing.expectEqual(try parseCharLiteral("'\\u{7f}'", &bad_index), 0x7f); + std.testing.expectEqual(try parseCharLiteral("'\\u{7FFF}'", &bad_index), 0x7FFF); std.testing.expectError(error.InvalidCharacter, parseCharLiteral("'\\x0'", &bad_index)); + std.testing.expectError(error.InvalidCharacter, parseCharLiteral("'\\x000'", &bad_index)); std.testing.expectError(error.InvalidCharacter, parseCharLiteral("'\\y'", &bad_index)); std.testing.expectError(error.InvalidCharacter, parseCharLiteral("'\\u'", &bad_index)); + std.testing.expectError(error.InvalidCharacter, parseCharLiteral("'\\uFFFF'", &bad_index)); + std.testing.expectError(error.InvalidCharacter, parseCharLiteral("'\\u{}'", &bad_index)); std.testing.expectError(error.InvalidCharacter, parseCharLiteral("'\\u{FFFFFF}'", &bad_index)); + std.testing.expectError(error.InvalidCharacter, parseCharLiteral("'\\u{FFFF'", &bad_index)); + std.testing.expectError(error.InvalidCharacter, parseCharLiteral("'\\u{FFFF}x'", &bad_index)); } test "" { From 0f677810ea9d5c8ba549f6c9948979a768a1eda6 Mon Sep 17 00:00:00 2001 From: Tadeo Kondrak Date: Wed, 19 Aug 2020 13:49:20 -0600 Subject: [PATCH 20/66] Remove offset field from TypeInfo.StructField This isn't needed with @bitOffsetOf/@byteoffsetOf and complicates @Type handling. --- lib/std/builtin.zig | 1 - src/ir.cpp | 31 +++++++----------------------- test/stage1/behavior/type_info.zig | 11 ----------- 3 files changed, 7 insertions(+), 36 deletions(-) diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig index 49edab1fd7..6b3acd799d 100644 --- a/lib/std/builtin.zig +++ b/lib/std/builtin.zig @@ -254,7 +254,6 @@ pub const TypeInfo = union(enum) { /// therefore must be kept in sync with the compiler implementation. pub const StructField = struct { name: []const u8, - offset: ?comptime_int, field_type: type, default_value: anytype, }; diff --git a/src/ir.cpp b/src/ir.cpp index 3625869217..d0a23786af 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -25678,37 +25678,20 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy struct_field_val->type = type_info_struct_field_type; ZigValue **inner_fields = alloc_const_vals_ptrs(ira->codegen, 4); + inner_fields[1]->special = ConstValSpecialStatic; - inner_fields[1]->type = get_optional_type(ira->codegen, ira->codegen->builtin_types.entry_num_lit_int); - - ZigType *field_type = resolve_struct_field_type(ira->codegen, struct_field); - if (field_type == nullptr) - return ErrorSemanticAnalyzeFail; - if ((err = type_resolve(ira->codegen, field_type, ResolveStatusZeroBitsKnown))) - return err; - if (!type_has_bits(ira->codegen, struct_field->type_entry)) { - inner_fields[1]->data.x_optional = nullptr; - } else { - size_t byte_offset = struct_field->offset; - inner_fields[1]->data.x_optional = ira->codegen->pass1_arena->create(); - inner_fields[1]->data.x_optional->special = ConstValSpecialStatic; - inner_fields[1]->data.x_optional->type = ira->codegen->builtin_types.entry_num_lit_int; - bigint_init_unsigned(&inner_fields[1]->data.x_optional->data.x_bigint, byte_offset); - } - - inner_fields[2]->special = ConstValSpecialStatic; - inner_fields[2]->type = ira->codegen->builtin_types.entry_type; - inner_fields[2]->data.x_type = struct_field->type_entry; + inner_fields[1]->type = ira->codegen->builtin_types.entry_type; + inner_fields[1]->data.x_type = struct_field->type_entry; // default_value: anytype - inner_fields[3]->special = ConstValSpecialStatic; - inner_fields[3]->type = get_optional_type2(ira->codegen, struct_field->type_entry); - if (inner_fields[3]->type == nullptr) return ErrorSemanticAnalyzeFail; + inner_fields[2]->special = ConstValSpecialStatic; + inner_fields[2]->type = get_optional_type2(ira->codegen, struct_field->type_entry); + if (inner_fields[2]->type == nullptr) return ErrorSemanticAnalyzeFail; memoize_field_init_val(ira->codegen, type_entry, struct_field); if(struct_field->init_val != nullptr && type_is_invalid(struct_field->init_val->type)){ return ErrorSemanticAnalyzeFail; } - set_optional_payload(inner_fields[3], struct_field->init_val); + set_optional_payload(inner_fields[2], struct_field->init_val); ZigValue *name = create_const_str_lit(ira->codegen, struct_field->name)->data.x_ptr.data.ref.pointee; init_const_slice(ira->codegen, inner_fields[0], name, 0, buf_len(struct_field->name), true); diff --git a/test/stage1/behavior/type_info.zig b/test/stage1/behavior/type_info.zig index a79b3a1554..ab26558c04 100644 --- a/test/stage1/behavior/type_info.zig +++ b/test/stage1/behavior/type_info.zig @@ -238,7 +238,6 @@ fn testStruct() void { expect(struct_info == .Struct); expect(struct_info.Struct.layout == .Packed); expect(struct_info.Struct.fields.len == 4); - expect(struct_info.Struct.fields[1].offset == null); expect(struct_info.Struct.fields[2].field_type == *TestStruct); expect(struct_info.Struct.fields[2].default_value == null); expect(struct_info.Struct.fields[3].default_value.? == 4); @@ -320,16 +319,6 @@ fn testAnyFrame() void { } } -test "type info: optional field unwrapping" { - const Struct = struct { - cdOffset: u32, - }; - - const field = @typeInfo(Struct).Struct.fields[0]; - - _ = field.offset orelse 0; -} - test "type info: pass to function" { _ = passTypeInfo(@typeInfo(void)); _ = comptime passTypeInfo(@typeInfo(void)); From b46d764fd958d31a988d58a6ee0b7da4c0b20acb Mon Sep 17 00:00:00 2001 From: Tadeo Kondrak Date: Wed, 19 Aug 2020 13:46:26 -0600 Subject: [PATCH 21/66] Implement @Type for structs without decls support --- src/all_types.hpp | 1 + src/analyze.cpp | 10 +-- src/analyze.hpp | 1 + src/ir.cpp | 139 +++++++++++++++++++++++++++------- test/stage1/behavior/type.zig | 44 +++++++++++ 5 files changed, 164 insertions(+), 31 deletions(-) diff --git a/src/all_types.hpp b/src/all_types.hpp index 5f142e3dcb..422d530031 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1420,6 +1420,7 @@ struct ZigTypeStruct { bool requires_comptime; bool resolve_loop_flag_zero_bits; bool resolve_loop_flag_other; + bool created_by_at_type; }; struct ZigTypeOptional { diff --git a/src/analyze.cpp b/src/analyze.cpp index 4920571438..7b71d7166b 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -138,7 +138,7 @@ void init_scope(CodeGen *g, Scope *dest, ScopeId id, AstNode *source_node, Scope dest->parent = parent; } -static ScopeDecls *create_decls_scope(CodeGen *g, AstNode *node, Scope *parent, ZigType *container_type, +ScopeDecls *create_decls_scope(CodeGen *g, AstNode *node, Scope *parent, ZigType *container_type, ZigType *import, Buf *bare_name) { ScopeDecls *scope = heap::c_allocator.create(); @@ -2821,7 +2821,7 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) { src_assert(struct_type->data.structure.fields == nullptr, decl_node); struct_type->data.structure.fields = alloc_type_struct_fields(field_count); - } else if (is_anon_container(struct_type)) { + } else if (is_anon_container(struct_type) || struct_type->data.structure.created_by_at_type) { field_count = struct_type->data.structure.src_field_count; 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) { struct_type->data.structure.resolve_status = ResolveStatusInvalid; return ErrorSemanticAnalyzeFail; } - } else if (is_anon_container(struct_type)) { + } else if (is_anon_container(struct_type) || struct_type->data.structure.created_by_at_type) { field_node = type_struct_field->decl_node; 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) { type_struct_field->type_val = field_type_val; if (struct_type->data.structure.resolve_status == ResolveStatusInvalid) return ErrorSemanticAnalyzeFail; - } else if (is_anon_container(struct_type)) { + } else if (is_anon_container(struct_type) || struct_type->data.structure.created_by_at_type) { field_type_val = type_struct_field->type_val; } else zig_unreachable(); @@ -8331,7 +8331,7 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS ZigLLVMDIFile *di_file; ZigLLVMDIScope *di_scope; unsigned line; - if (decl_node != nullptr) { + if (decl_node != nullptr && !struct_type->data.structure.created_by_at_type) { Scope *scope = &struct_type->data.structure.decls_scope->base; ZigType *import = get_scope_import(scope); di_file = import->data.structure.root_struct->di_file; diff --git a/src/analyze.hpp b/src/analyze.hpp index cb58aa6b74..0df1a4ba91 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -116,6 +116,7 @@ void eval_min_max_value_int(CodeGen *g, ZigType *int_type, BigInt *bigint, bool void render_const_value(CodeGen *g, Buf *buf, ZigValue *const_val); +ScopeDecls *create_decls_scope(CodeGen *g, AstNode *node, Scope *parent, ZigType *container_type, ZigType *import, Buf *bare_name); ScopeBlock *create_block_scope(CodeGen *g, AstNode *node, Scope *parent); ScopeDefer *create_defer_scope(CodeGen *g, AstNode *node, Scope *parent); ScopeDeferExpr *create_defer_expr_scope(CodeGen *g, AstNode *node, Scope *parent); diff --git a/src/ir.cpp b/src/ir.cpp index d0a23786af..b2cbe89d12 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -25942,6 +25942,36 @@ static ZigType *get_const_field_meta_type_optional(IrAnalyze *ira, AstNode *sour return value->data.x_optional->data.x_type; } +static Error get_const_field_buf(IrAnalyze *ira, AstNode *source_node, ZigValue *struct_value, + const char *name, size_t field_index, Buf *out) +{ + ZigValue *slice = get_const_field(ira, source_node, struct_value, name, field_index); + ZigValue *ptr = slice->data.x_struct.fields[slice_ptr_index]; + ZigValue *len = slice->data.x_struct.fields[slice_len_index]; + assert(ptr->data.x_ptr.special == ConstPtrSpecialBaseArray); + assert(ptr->data.x_ptr.data.base_array.elem_index == 0); + ZigValue *arr = ptr->data.x_ptr.data.base_array.array_val; + assert(arr->special == ConstValSpecialStatic); + switch (arr->data.x_array.special) { + case ConstArraySpecialUndef: + return ErrorSemanticAnalyzeFail; + case ConstArraySpecialNone: { + buf_resize(out, 0); + size_t count = bigint_as_usize(&len->data.x_bigint); + for (size_t j = 0; j < count; j++) { + ZigValue *ch_val = &arr->data.x_array.data.s_none.elements[j]; + unsigned ch = bigint_as_u32(&ch_val->data.x_bigint); + buf_append_char(out, ch); + } + break; + } + case ConstArraySpecialBuf: + buf_init_from_buf(out, arr->data.x_array.data.s_buf); + break; + } + return ErrorNone; +} + static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeId tagTypeId, ZigValue *payload) { Error err; switch (tagTypeId) { @@ -26145,30 +26175,9 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeI assert(error->type == ir_type_info_get_type(ira, "Error", nullptr)); ErrorTableEntry *err_entry = heap::c_allocator.create(); err_entry->decl_node = source_instr->source_node; - ZigValue *name_slice = get_const_field(ira, source_instr->source_node, error, "name", 0); - ZigValue *name_ptr = name_slice->data.x_struct.fields[slice_ptr_index]; - ZigValue *name_len = name_slice->data.x_struct.fields[slice_len_index]; - assert(name_ptr->data.x_ptr.special == ConstPtrSpecialBaseArray); - assert(name_ptr->data.x_ptr.data.base_array.elem_index == 0); - ZigValue *name_arr = name_ptr->data.x_ptr.data.base_array.array_val; - assert(name_arr->special == ConstValSpecialStatic); - switch (name_arr->data.x_array.special) { - case ConstArraySpecialUndef: - return ira->codegen->invalid_inst_gen->value->type; - case ConstArraySpecialNone: { - buf_resize(&err_entry->name, 0); - size_t name_count = bigint_as_usize(&name_len->data.x_bigint); - for (size_t j = 0; j < name_count; j++) { - ZigValue *ch_val = &name_arr->data.x_array.data.s_none.elements[j]; - unsigned ch = bigint_as_u32(&ch_val->data.x_bigint); - buf_append_char(&err_entry->name, ch); - } - break; - } - case ConstArraySpecialBuf: - buf_init_from_buf(&err_entry->name, name_arr->data.x_array.data.s_buf); - break; - } + Error err; + if ((err = get_const_field_buf(ira, source_instr->source_node, error, "name", 0, &err_entry->name))) + return ira->codegen->invalid_inst_gen->value->type; auto existing_entry = ira->codegen->error_table.put_unique(&err_entry->name, err_entry); if (existing_entry) { err_entry->value = existing_entry->value->value; @@ -26188,14 +26197,92 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeI } return err_set_type; } + case ZigTypeIdStruct: { + assert(payload->special == ConstValSpecialStatic); + assert(payload->type == ir_type_info_get_type(ira, "Struct", nullptr)); + + ZigValue *layout_value = get_const_field(ira, source_instr->source_node, payload, "layout", 0); + assert(layout_value->special == ConstValSpecialStatic); + assert(layout_value->type->id == ZigTypeIdEnum); + ContainerLayout layout = (ContainerLayout)bigint_as_u32(&layout_value->data.x_enum_tag); + + ZigValue *fields_value = get_const_field(ira, source_instr->source_node, payload, "fields", 1); + assert(fields_value->special == ConstValSpecialStatic); + assert(is_slice(fields_value->type)); + ZigValue *fields_ptr = fields_value->data.x_struct.fields[slice_ptr_index]; + ZigValue *fields_len_value = fields_value->data.x_struct.fields[slice_len_index]; + size_t fields_len = bigint_as_usize(&fields_len_value->data.x_bigint); + + ZigValue *decls_value = get_const_field(ira, source_instr->source_node, payload, "decls", 2); + assert(decls_value->special == ConstValSpecialStatic); + assert(is_slice(decls_value->type)); + ZigValue *decls_len_value = decls_value->data.x_struct.fields[slice_len_index]; + size_t decls_len = bigint_as_usize(&decls_len_value->data.x_bigint); + if (decls_len != 0) { + ir_add_error(ira, source_instr, buf_create_from_str("TypeInfo.Struct.decls must be empty for @Type")); + return ira->codegen->invalid_inst_gen->value->type; + } + + bool is_tuple; + get_const_field_bool(ira, source_instr->source_node, payload, "is_tuple", 3, &is_tuple); + + ZigType *entry = new_type_table_entry(ZigTypeIdStruct); + buf_init_from_buf(&entry->name, + get_anon_type_name(ira->codegen, ira->old_irb.exec, "struct", source_instr->scope, source_instr->source_node, &entry->name)); + entry->data.structure.decl_node = source_instr->source_node; + entry->data.structure.fields = alloc_type_struct_fields(fields_len); + entry->data.structure.fields_by_name.init(fields_len); + entry->data.structure.src_field_count = fields_len; + entry->data.structure.layout = layout; + entry->data.structure.special = is_tuple ? StructSpecialInferredTuple : StructSpecialNone; + entry->data.structure.created_by_at_type = true; + entry->data.structure.decls_scope = create_decls_scope(ira->codegen, nullptr, nullptr, entry, entry, buf_create_from_str("a")); + + assert(fields_ptr->data.x_ptr.special == ConstPtrSpecialBaseArray); + assert(fields_ptr->data.x_ptr.data.base_array.elem_index == 0); + ZigValue *fields_arr = fields_ptr->data.x_ptr.data.base_array.array_val; + assert(fields_arr->special == ConstValSpecialStatic); + assert(fields_arr->data.x_array.special == ConstArraySpecialNone); + for (size_t i = 0; i < fields_len; i++) { + ZigValue *field_value = &fields_arr->data.x_array.data.s_none.elements[i]; + assert(field_value->type->id == ZigTypeIdStruct); + TypeStructField *field = entry->data.structure.fields[i]; + field->name = buf_alloc(); + if ((err = get_const_field_buf(ira, source_instr->source_node, field_value, "name", 0, field->name))) + return ira->codegen->invalid_inst_gen->value->type; + field->decl_node = source_instr->source_node; + ZigValue *type_value = get_const_field(ira, source_instr->source_node, field_value, "field_type", 1); + field->type_val = type_value; + field->type_entry = type_value->data.x_type; + if (entry->data.structure.fields_by_name.put_unique(field->name, field) != nullptr) { + ir_add_error(ira, source_instr, buf_sprintf("duplicate struct field '%s'", buf_ptr(field->name))); + return ira->codegen->invalid_inst_gen->value->type; + } + ZigValue *default_value = get_const_field(ira, source_instr->source_node, field_value, "default_value", 2); + if (default_value->type->id == ZigTypeIdNull) { + field->init_val = nullptr; + } else if (default_value->type->id == ZigTypeIdOptional && default_value->type->data.maybe.child_type == field->type_entry) { + field->init_val = default_value->data.x_optional; + } else if (default_value->type == field->type_entry) { + field->init_val = default_value; + } else { + ir_add_error(ira, source_instr, + buf_sprintf("default_value of field '%s' is of type '%s', expected '%s' or '?%s'", + buf_ptr(field->name), buf_ptr(&default_value->type->name), + buf_ptr(&field->type_entry->name), buf_ptr(&field->type_entry->name))); + return ira->codegen->invalid_inst_gen->value->type; + } + } + + return entry; + } case ZigTypeIdEnum: + case ZigTypeIdUnion: ir_add_error(ira, source_instr, buf_sprintf( "TODO implement @Type for 'TypeInfo.%s': see https://github.com/ziglang/zig/issues/2907", type_id_name(tagTypeId))); return ira->codegen->invalid_inst_gen->value->type; - case ZigTypeIdUnion: case ZigTypeIdFn: case ZigTypeIdBoundFn: - case ZigTypeIdStruct: ir_add_error(ira, source_instr, buf_sprintf( "@Type not available for 'TypeInfo.%s'", type_id_name(tagTypeId))); return ira->codegen->invalid_inst_gen->value->type; diff --git a/test/stage1/behavior/type.zig b/test/stage1/behavior/type.zig index f21e9f1ce9..8ebf670279 100644 --- a/test/stage1/behavior/type.zig +++ b/test/stage1/behavior/type.zig @@ -236,3 +236,47 @@ test "Type.ErrorSet" { _ = @Type(@typeInfo(error{A})); _ = @Type(@typeInfo(error{ A, B, C })); } + +test "Type.Struct" { + const A = @Type(@typeInfo(struct { x: u8, y: u32 })); + const infoA = @typeInfo(A).Struct; + testing.expectEqual(TypeInfo.ContainerLayout.Auto, infoA.layout); + testing.expectEqualSlices(u8, "x", infoA.fields[0].name); + testing.expectEqual(u8, infoA.fields[0].field_type); + testing.expectEqual(@as(?u8, null), infoA.fields[0].default_value); + testing.expectEqualSlices(u8, "y", infoA.fields[1].name); + testing.expectEqual(u32, infoA.fields[1].field_type); + testing.expectEqual(@as(?u32, null), infoA.fields[1].default_value); + testing.expectEqualSlices(TypeInfo.Declaration, &[_]TypeInfo.Declaration{}, infoA.decls); + testing.expectEqual(@as(bool, false), infoA.is_tuple); + + var a = A{ .x = 0, .y = 1 }; + testing.expectEqual(@as(u8, 0), a.x); + testing.expectEqual(@as(u32, 1), a.y); + a.y += 1; + testing.expectEqual(@as(u32, 2), a.y); + + const B = @Type(@typeInfo(extern struct { x: u8, y: u32 = 5 })); + const infoB = @typeInfo(B).Struct; + testing.expectEqual(TypeInfo.ContainerLayout.Extern, infoB.layout); + testing.expectEqualSlices(u8, "x", infoB.fields[0].name); + testing.expectEqual(u8, infoB.fields[0].field_type); + testing.expectEqual(@as(?u8, null), infoB.fields[0].default_value); + testing.expectEqualSlices(u8, "y", infoB.fields[1].name); + testing.expectEqual(u32, infoB.fields[1].field_type); + testing.expectEqual(@as(?u32, 5), infoB.fields[1].default_value); + testing.expectEqual(@as(usize, 0), infoB.decls.len); + testing.expectEqual(@as(bool, false), infoB.is_tuple); + + const C = @Type(@typeInfo(packed struct { x: u8 = 3, y: u32 = 5 })); + const infoC = @typeInfo(C).Struct; + testing.expectEqual(TypeInfo.ContainerLayout.Packed, infoC.layout); + testing.expectEqualSlices(u8, "x", infoC.fields[0].name); + testing.expectEqual(u8, infoC.fields[0].field_type); + testing.expectEqual(@as(?u8, 3), infoC.fields[0].default_value); + testing.expectEqualSlices(u8, "y", infoC.fields[1].name); + testing.expectEqual(u32, infoC.fields[1].field_type); + testing.expectEqual(@as(?u32, 5), infoC.fields[1].default_value); + testing.expectEqual(@as(usize, 0), infoC.decls.len); + testing.expectEqual(@as(bool, false), infoC.is_tuple); +} From 759485cc328a4e6f2aba58891e86234c660797b6 Mon Sep 17 00:00:00 2001 From: Tadeo Kondrak Date: Wed, 19 Aug 2020 15:26:03 -0600 Subject: [PATCH 22/66] Update compile-errors test for @Type(.Struct) --- test/compile_errors.zig | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/compile_errors.zig b/test/compile_errors.zig index fd74385d9b..ea0d3b4e7b 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -1395,12 +1395,12 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "tmp.zig:3:36: error: expected type 'std.builtin.TypeInfo', found 'std.builtin.Int'", }); - cases.add("Struct unavailable for @Type", + cases.add("struct with declarations unavailable for @Type", \\export fn entry() void { - \\ _ = @Type(@typeInfo(struct { })); + \\ _ = @Type(@typeInfo(struct { const foo = 1; })); \\} , &[_][]const u8{ - "tmp.zig:2:15: error: @Type not available for 'TypeInfo.Struct'", + "tmp.zig:2:15: error: TypeInfo.Struct.decls must be empty for @Type", }); cases.add("wrong type for argument tuple to @asyncCall", From b0846b6ecbb3e2557c5c95ddee04ecc055881d75 Mon Sep 17 00:00:00 2001 From: Vincent Rischmann Date: Wed, 19 Aug 2020 23:21:16 +0200 Subject: [PATCH 23/66] builder: implement integer options --- lib/std/build.zig | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/lib/std/build.zig b/lib/std/build.zig index 817b103b58..be39e8010c 100644 --- a/lib/std/build.zig +++ b/lib/std/build.zig @@ -449,7 +449,33 @@ pub const Builder = struct { return null; }, }, - .Int => panic("TODO integer options to build script", .{}), + .Int => switch (entry.value.value) { + .Flag => { + warn("Expected -D{} to be an integer, but received a boolean.\n", .{name}); + self.markInvalidUserInput(); + return null; + }, + .Scalar => |s| { + const n = std.fmt.parseInt(T, s, 10) catch |err| switch (err) { + error.Overflow => { + warn("-D{} value {} cannot fit into type {}.\n", .{ name, s, @typeName(T) }); + self.markInvalidUserInput(); + return null; + }, + else => { + warn("Expected -D{} to be an integer of type {}.\n", .{ name, @typeName(T) }); + self.markInvalidUserInput(); + return null; + }, + }; + return n; + }, + .List => { + warn("Expected -D{} to be an integer, but received a list.\n", .{name}); + self.markInvalidUserInput(); + return null; + }, + }, .Float => panic("TODO float options to build script", .{}), .Enum => switch (entry.value.value) { .Flag => { From 8126421d07da21f0d404ec481edfda85da0709fc Mon Sep 17 00:00:00 2001 From: Tadeo Kondrak Date: Wed, 19 Aug 2020 16:35:52 -0600 Subject: [PATCH 24/66] Small fixes for @Type(.Struct) --- src/ir.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index b2cbe89d12..976c50b8ff 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -26203,7 +26203,7 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeI ZigValue *layout_value = get_const_field(ira, source_instr->source_node, payload, "layout", 0); assert(layout_value->special == ConstValSpecialStatic); - assert(layout_value->type->id == ZigTypeIdEnum); + assert(layout_value->type == ir_type_info_get_type(ira, "ContainerLayout", nullptr)); ContainerLayout layout = (ContainerLayout)bigint_as_u32(&layout_value->data.x_enum_tag); ZigValue *fields_value = get_const_field(ira, source_instr->source_node, payload, "fields", 1); @@ -26236,7 +26236,7 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeI entry->data.structure.layout = layout; entry->data.structure.special = is_tuple ? StructSpecialInferredTuple : StructSpecialNone; entry->data.structure.created_by_at_type = true; - entry->data.structure.decls_scope = create_decls_scope(ira->codegen, nullptr, nullptr, entry, entry, buf_create_from_str("a")); + entry->data.structure.decls_scope = create_decls_scope(ira->codegen, nullptr, nullptr, entry, entry, &entry->name); assert(fields_ptr->data.x_ptr.special == ConstPtrSpecialBaseArray); assert(fields_ptr->data.x_ptr.data.base_array.elem_index == 0); @@ -26245,7 +26245,7 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeI assert(fields_arr->data.x_array.special == ConstArraySpecialNone); for (size_t i = 0; i < fields_len; i++) { ZigValue *field_value = &fields_arr->data.x_array.data.s_none.elements[i]; - assert(field_value->type->id == ZigTypeIdStruct); + assert(field_value->type == ir_type_info_get_type(ira, "StructField", nullptr)); TypeStructField *field = entry->data.structure.fields[i]; field->name = buf_alloc(); if ((err = get_const_field_buf(ira, source_instr->source_node, field_value, "name", 0, field->name))) From 338a495648f07a2734e012034fd301a0e77f8202 Mon Sep 17 00:00:00 2001 From: Vexu Date: Wed, 19 Aug 2020 13:56:48 +0300 Subject: [PATCH 25/66] stage2: implement global variables --- src-self-hosted/Module.zig | 218 +++++++++++++++++++++++++++++++++-- src-self-hosted/codegen.zig | 11 ++ src-self-hosted/ir.zig | 16 +++ src-self-hosted/type.zig | 6 +- src-self-hosted/value.zig | 19 +++ src-self-hosted/zir.zig | 5 + src-self-hosted/zir_sema.zig | 4 +- 7 files changed, 266 insertions(+), 13 deletions(-) diff --git a/src-self-hosted/Module.zig b/src-self-hosted/Module.zig index e5988dfd8a..3a68063236 100644 --- a/src-self-hosted/Module.zig +++ b/src-self-hosted/Module.zig @@ -320,6 +320,12 @@ pub const Fn = struct { } }; +pub const Var = struct { + value: ?Value, + owner_decl: *Decl, + is_mutable: bool, +}; + pub const Scope = struct { tag: Tag, @@ -1419,7 +1425,152 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { } return type_changed; }, - .VarDecl => @panic("TODO var decl"), + .VarDecl => { + const var_decl = @fieldParentPtr(ast.Node.VarDecl, "base", ast_node); + + decl.analysis = .in_progress; + + const is_extern = blk: { + const maybe_extern_token = var_decl.getTrailer("extern_export_token") orelse + break :blk false; + break :blk tree.token_ids[maybe_extern_token] == .Keyword_extern; + }; + const is_mutable = tree.token_ids[var_decl.mut_token] == .Keyword_var; + + // We need the memory for the Type to go into the arena for the Decl + var decl_arena = std.heap.ArenaAllocator.init(self.gpa); + errdefer decl_arena.deinit(); + const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State); + + var block_scope: Scope.Block = .{ + .parent = null, + .func = null, + .decl = decl, + .instructions = .{}, + .arena = &decl_arena.allocator, + }; + defer block_scope.instructions.deinit(self.gpa); + + const explicit_type = blk: { + const type_node = var_decl.getTrailer("type_node") orelse + break :blk null; + + var type_scope_arena = std.heap.ArenaAllocator.init(self.gpa); + defer type_scope_arena.deinit(); + var type_scope: Scope.GenZIR = .{ + .decl = decl, + .arena = &type_scope_arena.allocator, + .parent = decl.scope, + }; + defer type_scope.instructions.deinit(self.gpa); + + const src = tree.token_locs[type_node.firstToken()].start; + const type_type = try astgen.addZIRInstConst(self, &type_scope.base, src, .{ + .ty = Type.initTag(.type), + .val = Value.initTag(.type_type), + }); + const var_type = try astgen.expr(self, &type_scope.base, .{ .ty = type_type }, type_node); + _ = try astgen.addZIRUnOp(self, &type_scope.base, src, .@"return", var_type); + + break :blk try zir_sema.analyzeBodyValueAsType(self, &block_scope, .{ + .instructions = type_scope.instructions.items, + }); + }; + + var var_type: Type = undefined; + const value: ?Value = if (var_decl.getTrailer("init_node")) |init_node| blk: { + var gen_scope_arena = std.heap.ArenaAllocator.init(self.gpa); + defer gen_scope_arena.deinit(); + var gen_scope: Scope.GenZIR = .{ + .decl = decl, + .arena = &gen_scope_arena.allocator, + .parent = decl.scope, + }; + defer gen_scope.instructions.deinit(self.gpa); + const src = tree.token_locs[init_node.firstToken()].start; + + // TODO comptime scope here + const init_inst = try astgen.expr(self, &gen_scope.base, .none, init_node); + _ = try astgen.addZIRUnOp(self, &gen_scope.base, src, .@"return", init_inst); + + var inner_block: Scope.Block = .{ + .parent = null, + .func = null, + .decl = decl, + .instructions = .{}, + .arena = &gen_scope_arena.allocator, + }; + defer inner_block.instructions.deinit(self.gpa); + try zir_sema.analyzeBody(self, &inner_block.base, .{ .instructions = gen_scope.instructions.items }); + + for (inner_block.instructions.items) |inst| { + if (inst.castTag(.ret)) |ret| { + const coerced = if (explicit_type) |some| + try self.coerce(&inner_block.base, some, ret.operand) + else + ret.operand; + const val = try self.resolveConstValue(&inner_block.base, coerced); + + var_type = explicit_type orelse try ret.operand.ty.copy(block_scope.arena); + break :blk try val.copy(block_scope.arena); + } else { + return self.fail(&block_scope.base, inst.src, "unable to resolve comptime value", .{}); + } + } + unreachable; + } else if (!is_extern) { + return self.failTok(&block_scope.base, var_decl.firstToken(), "variables must be initialized", .{}); + } else if (explicit_type) |some| blk: { + var_type = some; + break :blk null; + } else { + return self.failTok(&block_scope.base, var_decl.firstToken(), "unable to infer variable type", .{}); + }; + + if (is_mutable and !var_type.isValidVarType(is_extern)) { + return self.failTok(&block_scope.base, var_decl.firstToken(), "variable of type '{}' must be const", .{var_type}); + } + + var type_changed = true; + if (decl.typedValueManaged()) |tvm| { + type_changed = !tvm.typed_value.ty.eql(var_type); + + tvm.deinit(self.gpa); + } + + const new_variable = try decl_arena.allocator.create(Var); + const var_payload = try decl_arena.allocator.create(Value.Payload.Variable); + new_variable.* = .{ + .value = value, + .owner_decl = decl, + .is_mutable = is_mutable, + }; + var_payload.* = .{ .variable = new_variable }; + + decl_arena_state.* = decl_arena.state; + decl.typed_value = .{ + .most_recent = .{ + .typed_value = .{ + .ty = var_type, + .val = Value.initPayload(&var_payload.base), + }, + .arena = decl_arena_state, + }, + }; + decl.analysis = .complete; + decl.generation = self.generation; + + if (var_decl.getTrailer("extern_export_token")) |maybe_export_token| { + if (tree.token_ids[maybe_export_token] == .Keyword_export) { + const export_src = tree.token_locs[maybe_export_token].start; + const name_loc = tree.token_locs[var_decl.name_token]; + const name = tree.tokenSliceLoc(name_loc); + // The scope needs to have the decl in it. + try self.analyzeExport(&block_scope.base, export_src, name, decl); + } + } + return type_changed; + }, .Comptime => @panic("TODO comptime decl"), .Use => @panic("TODO usingnamespace decl"), else => unreachable, @@ -1584,7 +1735,32 @@ fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void { } } } else if (src_decl.castTag(.VarDecl)) |var_decl| { - log.err("TODO: analyze var decl", .{}); + const name_loc = tree.token_locs[var_decl.name_token]; + const name = tree.tokenSliceLoc(name_loc); + const name_hash = root_scope.fullyQualifiedNameHash(name); + const contents_hash = std.zig.hashSrc(tree.getNodeSource(src_decl)); + if (self.decl_table.get(name_hash)) |decl| { + // Update the AST Node index of the decl, even if its contents are unchanged, it may + // have been re-ordered. + decl.src_index = decl_i; + if (deleted_decls.remove(decl) == null) { + decl.analysis = .sema_failure; + const err_msg = try ErrorMsg.create(self.gpa, name_loc.start, "redefinition of '{}'", .{decl.name}); + errdefer err_msg.destroy(self.gpa); + try self.failed_decls.putNoClobber(self.gpa, decl, err_msg); + } else if (!srcHashEql(decl.contents_hash, contents_hash)) { + try self.markOutdatedDecl(decl); + decl.contents_hash = contents_hash; + } + } else { + const new_decl = try self.createNewDecl(&root_scope.base, name, decl_i, name_hash, contents_hash); + root_scope.decls.appendAssumeCapacity(new_decl); + if (var_decl.getTrailer("extern_export_token")) |maybe_export_token| { + if (tree.token_ids[maybe_export_token] == .Keyword_export) { + self.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl }); + } + } + } } else if (src_decl.castTag(.Comptime)) |comptime_node| { log.err("TODO: analyze comptime decl", .{}); } else if (src_decl.castTag(.ContainerField)) |container_field| { @@ -2217,20 +2393,46 @@ pub fn analyzeDeclRef(self: *Module, scope: *Scope, src: usize, decl: *Decl) Inn }; const decl_tv = try decl.typedValue(); - const ty_payload = try scope.arena().create(Type.Payload.Pointer); - ty_payload.* = .{ - .base = .{ .tag = .single_const_pointer }, - .pointee_type = decl_tv.ty, - }; + if (decl_tv.val.tag() == .variable) { + return self.getVarRef(scope, src, decl_tv); + } + const ty = try self.singlePtrType(scope, src, false, decl_tv.ty); const val_payload = try scope.arena().create(Value.Payload.DeclRef); val_payload.* = .{ .decl = decl }; return self.constInst(scope, src, .{ - .ty = Type.initPayload(&ty_payload.base), + .ty = ty, .val = Value.initPayload(&val_payload.base), }); } +fn getVarRef(self: *Module, scope: *Scope, src: usize, tv: TypedValue) InnerError!*Inst { + const variable = tv.val.cast(Value.Payload.Variable).?.variable; + + const ty = try self.singlePtrType(scope, src, variable.is_mutable, tv.ty); + if (!variable.is_mutable and variable.value != null) { + const val_payload = try scope.arena().create(Value.Payload.RefVal); + val_payload.* = .{ .val = variable.value.? }; + return self.constInst(scope, src, .{ + .ty = ty, + .val = Value.initPayload(&val_payload.base), + }); + } + + const b = try self.requireRuntimeBlock(scope, src); + const inst = try b.arena.create(Inst.VarPtr); + inst.* = .{ + .base = .{ + .tag = .varptr, + .ty = ty, + .src = src, + }, + .variable = variable, + }; + try b.instructions.append(self.gpa, &inst.base); + return &inst.base; +} + pub fn analyzeDeref(self: *Module, scope: *Scope, src: usize, ptr: *Inst, ptr_src: usize) InnerError!*Inst { const elem_ty = switch (ptr.ty.zigTypeTag()) { .Pointer => ptr.ty.elemType(), diff --git a/src-self-hosted/codegen.zig b/src-self-hosted/codegen.zig index cb404d8315..1bc76f6b05 100644 --- a/src-self-hosted/codegen.zig +++ b/src-self-hosted/codegen.zig @@ -684,6 +684,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { .unreach => return MCValue{ .unreach = {} }, .unwrap_optional => return self.genUnwrapOptional(inst.castTag(.unwrap_optional).?), .wrap_optional => return self.genWrapOptional(inst.castTag(.wrap_optional).?), + .varptr => return self.genVarPtr(inst.castTag(.varptr).?), } } @@ -858,6 +859,16 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { } } + fn genVarPtr(self: *Self, inst: *ir.Inst.VarPtr) !MCValue { + // No side effects, so if it's unreferenced, do nothing. + if (inst.base.isUnused()) + return MCValue.dead; + + switch (arch) { + else => return self.fail(inst.base.src, "TODO implement varptr for {}", .{self.target.cpu.arch}), + } + } + fn reuseOperand(inst: *ir.Inst, op_index: ir.Inst.DeathsBitIndex, mcv: MCValue) bool { if (!inst.operandDies(op_index) or !mcv.isMutable()) return false; diff --git a/src-self-hosted/ir.zig b/src-self-hosted/ir.zig index 070f41eb5e..ff90c68d42 100644 --- a/src-self-hosted/ir.zig +++ b/src-self-hosted/ir.zig @@ -81,6 +81,7 @@ pub const Inst = struct { ref, ret, retvoid, + varptr, /// Write a value to a pointer. LHS is pointer, RHS is value. store, sub, @@ -135,6 +136,7 @@ pub const Inst = struct { .condbr => CondBr, .constant => Constant, .loop => Loop, + .varptr => VarPtr, }; } @@ -434,6 +436,20 @@ pub const Inst = struct { return null; } }; + + pub const VarPtr = struct { + pub const base_tag = Tag.varptr; + + base: Inst, + variable: *Module.Var, + + pub fn operandCount(self: *const VarPtr) usize { + return 0; + } + pub fn getOperand(self: *const VarPtr, index: usize) ?*Inst { + return null; + } + }; }; pub const Body = struct { diff --git a/src-self-hosted/type.zig b/src-self-hosted/type.zig index a6ec90a35b..82671609d0 100644 --- a/src-self-hosted/type.zig +++ b/src-self-hosted/type.zig @@ -1074,7 +1074,7 @@ pub const Type = extern union { } /// Returns if type can be used for a runtime variable - pub fn isValidVarType(self: Type) bool { + pub fn isValidVarType(self: Type, is_extern: bool) bool { var ty = self; while (true) switch (ty.zigTypeTag()) { .Bool, @@ -1087,6 +1087,7 @@ pub const Type = extern union { .Vector, => return true, + .Opaque => return is_extern, .BoundFn, .ComptimeFloat, .ComptimeInt, @@ -1096,12 +1097,11 @@ pub const Type = extern union { .Void, .Undefined, .Null, - .Opaque, => return false, .Optional => { var buf: Payload.Pointer = undefined; - return ty.optionalChild(&buf).isValidVarType(); + return ty.optionalChild(&buf).isValidVarType(is_extern); }, .Pointer, .Array => ty = ty.elemType(), diff --git a/src-self-hosted/value.zig b/src-self-hosted/value.zig index b6356d9b17..7bebd022ab 100644 --- a/src-self-hosted/value.zig +++ b/src-self-hosted/value.zig @@ -79,6 +79,7 @@ pub const Value = extern union { int_big_positive, int_big_negative, function, + variable, ref_val, decl_ref, elem_ptr, @@ -196,6 +197,7 @@ pub const Value = extern union { @panic("TODO implement copying of big ints"); }, .function => return self.copyPayloadShallow(allocator, Payload.Function), + .variable => return self.copyPayloadShallow(allocator, Payload.Variable), .ref_val => { const payload = @fieldParentPtr(Payload.RefVal, "base", self.ptr_otherwise); const new_payload = try allocator.create(Payload.RefVal); @@ -310,6 +312,7 @@ pub const Value = extern union { .int_big_positive => return out_stream.print("{}", .{val.cast(Payload.IntBigPositive).?.asBigInt()}), .int_big_negative => return out_stream.print("{}", .{val.cast(Payload.IntBigNegative).?.asBigInt()}), .function => return out_stream.writeAll("(function)"), + .variable => return out_stream.writeAll("(variable)"), .ref_val => { const ref_val = val.cast(Payload.RefVal).?; try out_stream.writeAll("&const "); @@ -410,6 +413,7 @@ pub const Value = extern union { .int_big_positive, .int_big_negative, .function, + .variable, .ref_val, .decl_ref, .elem_ptr, @@ -471,6 +475,7 @@ pub const Value = extern union { .enum_literal_type, .null_value, .function, + .variable, .ref_val, .decl_ref, .elem_ptr, @@ -548,6 +553,7 @@ pub const Value = extern union { .enum_literal_type, .null_value, .function, + .variable, .ref_val, .decl_ref, .elem_ptr, @@ -625,6 +631,7 @@ pub const Value = extern union { .enum_literal_type, .null_value, .function, + .variable, .ref_val, .decl_ref, .elem_ptr, @@ -728,6 +735,7 @@ pub const Value = extern union { .enum_literal_type, .null_value, .function, + .variable, .ref_val, .decl_ref, .elem_ptr, @@ -810,6 +818,7 @@ pub const Value = extern union { .enum_literal_type, .null_value, .function, + .variable, .ref_val, .decl_ref, .elem_ptr, @@ -974,6 +983,7 @@ pub const Value = extern union { .bool_false, .null_value, .function, + .variable, .ref_val, .decl_ref, .elem_ptr, @@ -1046,6 +1056,7 @@ pub const Value = extern union { .enum_literal_type, .null_value, .function, + .variable, .ref_val, .decl_ref, .elem_ptr, @@ -1182,6 +1193,7 @@ pub const Value = extern union { .bool_false, .null_value, .function, + .variable, .int_u64, .int_i64, .int_big_positive, @@ -1260,6 +1272,7 @@ pub const Value = extern union { .bool_false, .null_value, .function, + .variable, .int_u64, .int_i64, .int_big_positive, @@ -1355,6 +1368,7 @@ pub const Value = extern union { .bool_true, .bool_false, .function, + .variable, .int_u64, .int_i64, .int_big_positive, @@ -1429,6 +1443,11 @@ pub const Value = extern union { func: *Module.Fn, }; + pub const Variable = struct { + base: Payload = Payload{ .tag = .variable }, + variable: *Module.Var, + }; + pub const ArraySentinel0_u8_Type = struct { base: Payload = Payload{ .tag = .array_sentinel_0_u8_type }, len: u64, diff --git a/src-self-hosted/zir.zig b/src-self-hosted/zir.zig index 1a2c5cebaa..f59d470ffd 100644 --- a/src-self-hosted/zir.zig +++ b/src-self-hosted/zir.zig @@ -1752,6 +1752,9 @@ const EmitZIR = struct { const decl_ref = try self.emitDeclRef(inst.src, declref.decl); try new_body.instructions.append(decl_ref); break :blk decl_ref; + } else if (const_inst.val.cast(Value.Payload.Variable)) |var_pl| blk: { + const owner_decl = var_pl.variable.owner_decl; + break :blk try self.emitDeclVal(inst.src, mem.spanZ(owner_decl.name)); } else blk: { break :blk (try self.emitTypedValue(inst.src, .{ .ty = inst.ty, .val = const_inst.val })).inst; }; @@ -2311,6 +2314,8 @@ const EmitZIR = struct { }; break :blk &new_inst.base; }, + + .varptr => @panic("TODO"), }; try self.metadata.put(new_inst, .{ .deaths = inst.deaths }); try instructions.append(new_inst); diff --git a/src-self-hosted/zir_sema.zig b/src-self-hosted/zir_sema.zig index fb39a1e077..644b73d643 100644 --- a/src-self-hosted/zir_sema.zig +++ b/src-self-hosted/zir_sema.zig @@ -366,7 +366,7 @@ fn analyzeInstEnsureResultNonError(mod: *Module, scope: *Scope, inst: *zir.Inst. fn analyzeInstAlloc(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { const var_type = try resolveType(mod, scope, inst.positionals.operand); // TODO this should happen only for var allocs - if (!var_type.isValidVarType()) { + if (!var_type.isValidVarType(false)) { return mod.fail(scope, inst.base.src, "variable of type '{}' must be const or comptime", .{var_type}); } const ptr_type = try mod.singlePtrType(scope, inst.base.src, true, var_type); @@ -779,7 +779,7 @@ fn analyzeInstFnType(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnType) Inne for (fntype.positionals.param_types) |param_type, i| { const resolved = try resolveType(mod, scope, param_type); // TODO skip for comptime params - if (!resolved.isValidVarType()) { + if (!resolved.isValidVarType(false)) { return mod.fail(scope, param_type.src, "parameter of type '{}' must be declared comptime", .{resolved}); } param_types[i] = resolved; From ab8a9a6605900fc0b064c321504ac4e7dc1ca6f4 Mon Sep 17 00:00:00 2001 From: Vexu Date: Wed, 19 Aug 2020 14:25:47 +0300 Subject: [PATCH 26/66] stage2: fix astgen of decl ref, add test for global consts --- src-self-hosted/astgen.zig | 14 ++++++++------ src-self-hosted/type.zig | 3 ++- src-self-hosted/zir_sema.zig | 3 +-- test/stage2/compare_output.zig | 31 +++++++++++++++++++++++++++++++ 4 files changed, 42 insertions(+), 9 deletions(-) diff --git a/src-self-hosted/astgen.zig b/src-self-hosted/astgen.zig index 9d40c7899a..9f8afa6225 100644 --- a/src-self-hosted/astgen.zig +++ b/src-self-hosted/astgen.zig @@ -1223,9 +1223,10 @@ fn identifier(mod: *Module, scope: *Scope, rl: ResultLoc, ident: *ast.Node.OneTo } if (mod.lookupDeclName(scope, ident_name)) |decl| { - // TODO handle lvalues const result = try addZIRInst(mod, scope, src, zir.Inst.DeclValInModule, .{ .decl = decl }, .{}); - return rlWrap(mod, scope, rl, result); + if (rl == .lvalue or rl == .ref) + return result; + return rlWrap(mod, scope, rl, try addZIRUnOp(mod, scope, src, .deref, result)); } return mod.failNode(scope, &ident.base, "use of undeclared identifier '{}'", .{ident_name}); @@ -1258,7 +1259,8 @@ fn multilineStrLiteral(mod: *Module, scope: *Scope, node: *ast.Node.MultilineStr // line lengths and new lines var len = lines.len - 1; for (lines) |line| { - len += tree.tokenSlice(line).len - 2; + // 2 for the '//' + 1 for '\n' + len += tree.tokenSlice(line).len - 3; } const bytes = try scope.arena().alloc(u8, len); @@ -1268,9 +1270,9 @@ fn multilineStrLiteral(mod: *Module, scope: *Scope, node: *ast.Node.MultilineStr bytes[i] = '\n'; i += 1; } - const slice = tree.tokenSlice(line)[2..]; - mem.copy(u8, bytes[i..], slice); - i += slice.len; + const slice = tree.tokenSlice(line); + mem.copy(u8, bytes[i..], slice[2..slice.len - 1]); + i += slice.len - 3; } return addZIRInst(mod, scope, src, zir.Inst.Str, .{ .bytes = bytes }, .{}); diff --git a/src-self-hosted/type.zig b/src-self-hosted/type.zig index 82671609d0..c2762e1f8a 100644 --- a/src-self-hosted/type.zig +++ b/src-self-hosted/type.zig @@ -457,7 +457,8 @@ pub const Type = extern union { try param_type.format("", .{}, out_stream); } try out_stream.writeAll(") "); - try payload.return_type.format("", .{}, out_stream); + ty = payload.return_type; + continue; }, .array_u8 => { diff --git a/src-self-hosted/zir_sema.zig b/src-self-hosted/zir_sema.zig index 644b73d643..cb1ed08d6d 100644 --- a/src-self-hosted/zir_sema.zig +++ b/src-self-hosted/zir_sema.zig @@ -581,8 +581,7 @@ fn analyzeInstDeclVal(mod: *Module, scope: *Scope, inst: *zir.Inst.DeclVal) Inne fn analyzeInstDeclValInModule(mod: *Module, scope: *Scope, inst: *zir.Inst.DeclValInModule) InnerError!*Inst { const decl = inst.positionals.decl; - const ptr = try mod.analyzeDeclRef(scope, inst.base.src, decl); - return mod.analyzeDeref(scope, inst.base.src, ptr, inst.base.src); + return mod.analyzeDeclRef(scope, inst.base.src, decl); } fn analyzeInstCall(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError!*Inst { diff --git a/test/stage2/compare_output.zig b/test/stage2/compare_output.zig index 3513605602..2b8c8e94cc 100644 --- a/test/stage2/compare_output.zig +++ b/test/stage2/compare_output.zig @@ -617,6 +617,37 @@ pub fn addCases(ctx: *TestContext) !void { , "", ); + + case.addCompareOutput( + \\export fn _start() noreturn { + \\ add(aa, bb); + \\ + \\ exit(); + \\} + \\ + \\const aa = 'ぁ'; + \\const bb = '\x03'; + \\ + \\fn add(a: u32, b: u32) void { + \\ assert(a + b == 12356); + \\} + \\ + \\pub fn assert(ok: bool) void { + \\ if (!ok) unreachable; // assertion failure + \\} + \\ + \\fn exit() noreturn { + \\ asm volatile ("syscall" + \\ : + \\ : [number] "{rax}" (231), + \\ [arg1] "{rdi}" (0) + \\ : "rcx", "r11", "memory" + \\ ); + \\ unreachable; + \\} + , + "", + ); } { From 9801047bdb26c86da430310aa5d043f6899adbfe Mon Sep 17 00:00:00 2001 From: Vexu Date: Wed, 19 Aug 2020 15:19:00 +0300 Subject: [PATCH 27/66] stage2: handle var attributes --- src-self-hosted/Module.zig | 50 ++++++++++++++++++++++++++++-------- src-self-hosted/zir_sema.zig | 1 + 2 files changed, 41 insertions(+), 10 deletions(-) diff --git a/src-self-hosted/Module.zig b/src-self-hosted/Module.zig index 3a68063236..8009bcc32d 100644 --- a/src-self-hosted/Module.zig +++ b/src-self-hosted/Module.zig @@ -290,6 +290,8 @@ pub const Fn = struct { }, owner_decl: *Decl, + is_pub: bool, + /// This memory is temporary and points to stack memory for the duration /// of Fn analysis. pub const Analysis = struct { @@ -323,7 +325,11 @@ pub const Fn = struct { pub const Var = struct { value: ?Value, owner_decl: *Decl, + + is_pub: bool, + is_extern: bool, is_mutable: bool, + is_threadlocal: bool, }; pub const Scope = struct { @@ -1241,6 +1247,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { }; defer fn_type_scope.instructions.deinit(self.gpa); + const is_pub = fn_proto.getTrailer("visib_token") != null; const body_node = fn_proto.getTrailer("body_node") orelse return self.failTok(&fn_type_scope.base, fn_proto.fn_token, "TODO implement extern functions", .{}); @@ -1378,6 +1385,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { new_func.* = .{ .analysis = .{ .queued = fn_zir }, .owner_decl = decl, + .is_pub = is_pub, }; fn_payload.* = .{ .func = new_func }; @@ -1430,13 +1438,6 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { decl.analysis = .in_progress; - const is_extern = blk: { - const maybe_extern_token = var_decl.getTrailer("extern_export_token") orelse - break :blk false; - break :blk tree.token_ids[maybe_extern_token] == .Keyword_extern; - }; - const is_mutable = tree.token_ids[var_decl.mut_token] == .Keyword_var; - // We need the memory for the Type to go into the arena for the Decl var decl_arena = std.heap.ArenaAllocator.init(self.gpa); errdefer decl_arena.deinit(); @@ -1451,6 +1452,32 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { }; defer block_scope.instructions.deinit(self.gpa); + const is_pub = var_decl.getTrailer("visib_token") != null; + const is_extern = blk: { + const maybe_extern_token = var_decl.getTrailer("extern_export_token") orelse + break :blk false; + break :blk tree.token_ids[maybe_extern_token] == .Keyword_extern; + }; + if (var_decl.getTrailer("lib_name")) |lib_name| { + assert(is_extern); + return self.failNode(&block_scope.base, lib_name, "TODO implement function library name", .{}); + } + const is_mutable = tree.token_ids[var_decl.mut_token] == .Keyword_var; + const is_threadlocal = if (var_decl.getTrailer("thread_local_token")) |some| blk: { + if (!is_mutable) { + return self.failTok(&block_scope.base, some, "threadlocal variable cannot be constant", .{}); + } + break :blk true; + } else false; + assert(var_decl.getTrailer("comptime_token") == null); + if (var_decl.getTrailer("align_node")) |align_expr| { + return self.failNode(&block_scope.base, align_expr, "TODO implement function align expression", .{}); + } + if (var_decl.getTrailer("section_node")) |sect_expr| { + return self.failNode(&block_scope.base, sect_expr, "TODO implement function section expression", .{}); + } + + const explicit_type = blk: { const type_node = var_decl.getTrailer("type_node") orelse break :blk null; @@ -1543,7 +1570,10 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { new_variable.* = .{ .value = value, .owner_decl = decl, + .is_pub = is_pub, + .is_extern = is_extern, .is_mutable = is_mutable, + .is_threadlocal = is_threadlocal, }; var_payload.* = .{ .variable = new_variable }; @@ -2394,7 +2424,7 @@ pub fn analyzeDeclRef(self: *Module, scope: *Scope, src: usize, decl: *Decl) Inn const decl_tv = try decl.typedValue(); if (decl_tv.val.tag() == .variable) { - return self.getVarRef(scope, src, decl_tv); + return self.analyzeVarRef(scope, src, decl_tv); } const ty = try self.singlePtrType(scope, src, false, decl_tv.ty); const val_payload = try scope.arena().create(Value.Payload.DeclRef); @@ -2406,11 +2436,11 @@ pub fn analyzeDeclRef(self: *Module, scope: *Scope, src: usize, decl: *Decl) Inn }); } -fn getVarRef(self: *Module, scope: *Scope, src: usize, tv: TypedValue) InnerError!*Inst { +fn analyzeVarRef(self: *Module, scope: *Scope, src: usize, tv: TypedValue) InnerError!*Inst { const variable = tv.val.cast(Value.Payload.Variable).?.variable; const ty = try self.singlePtrType(scope, src, variable.is_mutable, tv.ty); - if (!variable.is_mutable and variable.value != null) { + if (!variable.is_mutable and !variable.is_extern and variable.value != null) { const val_payload = try scope.arena().create(Value.Payload.RefVal); val_payload.* = .{ .val = variable.value.? }; return self.constInst(scope, src, .{ diff --git a/src-self-hosted/zir_sema.zig b/src-self-hosted/zir_sema.zig index cb1ed08d6d..87cce3adb3 100644 --- a/src-self-hosted/zir_sema.zig +++ b/src-self-hosted/zir_sema.zig @@ -666,6 +666,7 @@ fn analyzeInstFn(mod: *Module, scope: *Scope, fn_inst: *zir.Inst.Fn) InnerError! new_func.* = .{ .analysis = .{ .queued = fn_zir }, .owner_decl = scope.decl().?, + .is_pub = false, }; const fn_payload = try scope.arena().create(Value.Payload.Function); fn_payload.* = .{ .func = new_func }; From 5fdcb1a792e271c67f3aec36f8aca9e6c5503013 Mon Sep 17 00:00:00 2001 From: Vexu Date: Wed, 19 Aug 2020 19:12:01 +0300 Subject: [PATCH 28/66] stage2: emit zir variable fix, array type and enum literal support --- src-self-hosted/value.zig | 11 ++++++- src-self-hosted/zir.zig | 65 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 1 deletion(-) diff --git a/src-self-hosted/value.zig b/src-self-hosted/value.zig index 7bebd022ab..95a0746e19 100644 --- a/src-self-hosted/value.zig +++ b/src-self-hosted/value.zig @@ -218,7 +218,7 @@ pub const Value = extern union { }; return Value{ .ptr_otherwise = &new_payload.base }; }, - .enum_literal, .bytes => return self.copyPayloadShallow(allocator, Payload.Bytes), + .bytes => return self.copyPayloadShallow(allocator, Payload.Bytes), .repeated => { const payload = @fieldParentPtr(Payload.Repeated, "base", self.ptr_otherwise); const new_payload = try allocator.create(Payload.Repeated); @@ -232,6 +232,15 @@ pub const Value = extern union { .float_32 => return self.copyPayloadShallow(allocator, Payload.Float_32), .float_64 => return self.copyPayloadShallow(allocator, Payload.Float_64), .float_128 => return self.copyPayloadShallow(allocator, Payload.Float_128), + .enum_literal => { + const payload = @fieldParentPtr(Payload.Bytes, "base", self.ptr_otherwise); + const new_payload = try allocator.create(Payload.Bytes); + new_payload.* = .{ + .base = payload.base, + .data = try allocator.dupe(u8, payload.data), + }; + return Value{ .ptr_otherwise = &new_payload.base }; + }, } } diff --git a/src-self-hosted/zir.zig b/src-self-hosted/zir.zig index f59d470ffd..384463caee 100644 --- a/src-self-hosted/zir.zig +++ b/src-self-hosted/zir.zig @@ -1878,6 +1878,11 @@ const EmitZIR = struct { if (typed_value.val.cast(Value.Payload.DeclRef)) |decl_ref| { const decl = decl_ref.decl; return try self.emitUnnamedDecl(try self.emitDeclRef(src, decl)); + } else if (typed_value.val.cast(Value.Payload.Variable)) |variable| { + return self.emitTypedValue(src, .{ + .ty = typed_value.ty, + .val = variable.variable.value.?, + }); } if (typed_value.val.isUndef()) { const as_inst = try self.arena.allocator.create(Inst.BinOp); @@ -1967,6 +1972,21 @@ const EmitZIR = struct { return self.emitPrimitive(src, .@"true") else return self.emitPrimitive(src, .@"false"), + .EnumLiteral => { + const enum_literal = @fieldParentPtr(Value.Payload.Bytes, "base", typed_value.val.ptr_otherwise); + const inst = try self.arena.allocator.create(Inst.Str); + inst.* = .{ + .base = .{ + .src = src, + .tag = .enum_literal, + }, + .positionals = .{ + .bytes = enum_literal.data, + }, + .kw_args = .{}, + }; + return self.emitUnnamedDecl(&inst.base); + }, else => |t| std.debug.panic("TODO implement emitTypedValue for {}", .{@tagName(t)}), } } @@ -2437,6 +2457,51 @@ const EmitZIR = struct { }; return self.emitUnnamedDecl(&inst.base); }, + .Array => { + var len_pl = Value.Payload.Int_u64{ .int = ty.arrayLen() }; + const len = Value.initPayload(&len_pl.base); + + const inst = if (ty.arraySentinel()) |sentinel| blk: { + const inst = try self.arena.allocator.create(Inst.ArrayTypeSentinel); + inst.* = .{ + .base = .{ + .src = src, + .tag = .array_type, + }, + .positionals = .{ + .len = (try self.emitTypedValue(src, .{ + .ty = Type.initTag(.usize), + .val = len, + })).inst, + .sentinel = (try self.emitTypedValue(src, .{ + .ty = ty.elemType(), + .val = sentinel, + })).inst, + .elem_type = (try self.emitType(src, ty.elemType())).inst, + }, + .kw_args = .{}, + }; + break :blk &inst.base; + } else blk: { + const inst = try self.arena.allocator.create(Inst.BinOp); + inst.* = .{ + .base = .{ + .src = src, + .tag = .array_type, + }, + .positionals = .{ + .lhs = (try self.emitTypedValue(src, .{ + .ty = Type.initTag(.usize), + .val = len, + })).inst, + .rhs = (try self.emitType(src, ty.elemType())).inst, + }, + .kw_args = .{}, + }; + break :blk &inst.base; + }; + return self.emitUnnamedDecl(inst); + }, else => std.debug.panic("TODO implement emitType for {}", .{ty}), }, } From 9ec9c0f5e57820f4baa04b9674a6a4a88235b863 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 19 Aug 2020 17:52:22 -0700 Subject: [PATCH 29/66] optimize the memory layout of Module.Fn and Module.Var `is_pub` added to `Fn` would cost us an additional 8 bytes of memory per function, which is a real bummer since it's only 1 bit of information. If we wanted to really remove this, I suspect we could make this a function isPub() which looks at the AST of the corresponding Decl and finds if the FnProto AST node has the pub token. However I saw an easier approach - The data of whether something is pub or not is actually a property of a Decl anyway, not a function, so we can look at moving the field into Decl. Indeed, doing this, we see that Decl already has deletion_flag: bool which is hiding in the padding bytes between the enum (1 byte) and the following u32 field (generation). So if we put the is_pub bool there, it actually will take up no additional space, with 1 byte of padding remaining. This was an easy reworking of the code since any func.is_pub could be changed simply to func.owner_decl.is_pub. I also modified `Var` to make the init value non-optional and moved the optional bit to a has_init: bool field. This is worse from the perspective of control flow and safety, however it makes `@sizeOf(Var)` go from 32 bytes to 24 bytes. The more code we can fit into memory at once, the more justified we are in using the compiler as a long-running process that does incremental updates. --- src-self-hosted/Module.zig | 26 +++++++++++++------------- src-self-hosted/zir.zig | 2 +- src-self-hosted/zir_sema.zig | 1 - test/stage2/compare_output.zig | 2 ++ 4 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src-self-hosted/Module.zig b/src-self-hosted/Module.zig index 8009bcc32d..ec69f94e3d 100644 --- a/src-self-hosted/Module.zig +++ b/src-self-hosted/Module.zig @@ -170,6 +170,9 @@ pub const Decl = struct { /// This flag is set when this Decl is added to a check_for_deletion set, and cleared /// when removed. deletion_flag: bool, + /// Whether the corresponding AST decl has a `pub` keyword. + is_pub: bool, + /// An integer that can be checked against the corresponding incrementing /// generation field of Module. This is used to determine whether `complete` status /// represents pre- or post- re-analysis. @@ -290,8 +293,6 @@ pub const Fn = struct { }, owner_decl: *Decl, - is_pub: bool, - /// This memory is temporary and points to stack memory for the duration /// of Fn analysis. pub const Analysis = struct { @@ -323,10 +324,10 @@ pub const Fn = struct { }; pub const Var = struct { - value: ?Value, + init: Value, owner_decl: *Decl, - is_pub: bool, + has_init: bool, is_extern: bool, is_mutable: bool, is_threadlocal: bool, @@ -1247,7 +1248,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { }; defer fn_type_scope.instructions.deinit(self.gpa); - const is_pub = fn_proto.getTrailer("visib_token") != null; + decl.is_pub = fn_proto.getTrailer("visib_token") != null; const body_node = fn_proto.getTrailer("body_node") orelse return self.failTok(&fn_type_scope.base, fn_proto.fn_token, "TODO implement extern functions", .{}); @@ -1385,7 +1386,6 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { new_func.* = .{ .analysis = .{ .queued = fn_zir }, .owner_decl = decl, - .is_pub = is_pub, }; fn_payload.* = .{ .func = new_func }; @@ -1452,7 +1452,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { }; defer block_scope.instructions.deinit(self.gpa); - const is_pub = var_decl.getTrailer("visib_token") != null; + decl.is_pub = var_decl.getTrailer("visib_token") != null; const is_extern = blk: { const maybe_extern_token = var_decl.getTrailer("extern_export_token") orelse break :blk false; @@ -1477,7 +1477,6 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { return self.failNode(&block_scope.base, sect_expr, "TODO implement function section expression", .{}); } - const explicit_type = blk: { const type_node = var_decl.getTrailer("type_node") orelse break :blk null; @@ -1568,9 +1567,9 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { const new_variable = try decl_arena.allocator.create(Var); const var_payload = try decl_arena.allocator.create(Value.Payload.Variable); new_variable.* = .{ - .value = value, .owner_decl = decl, - .is_pub = is_pub, + .init = value orelse undefined, + .has_init = value != null, .is_extern = is_extern, .is_mutable = is_mutable, .is_threadlocal = is_threadlocal, @@ -2004,6 +2003,7 @@ fn allocateNewDecl( .wasm => .{ .wasm = null }, }, .generation = 0, + .is_pub = false, }; return new_decl; } @@ -2440,15 +2440,15 @@ fn analyzeVarRef(self: *Module, scope: *Scope, src: usize, tv: TypedValue) Inner const variable = tv.val.cast(Value.Payload.Variable).?.variable; const ty = try self.singlePtrType(scope, src, variable.is_mutable, tv.ty); - if (!variable.is_mutable and !variable.is_extern and variable.value != null) { + if (!variable.is_mutable and !variable.is_extern and variable.has_init) { const val_payload = try scope.arena().create(Value.Payload.RefVal); - val_payload.* = .{ .val = variable.value.? }; + val_payload.* = .{ .val = variable.init }; return self.constInst(scope, src, .{ .ty = ty, .val = Value.initPayload(&val_payload.base), }); } - + const b = try self.requireRuntimeBlock(scope, src); const inst = try b.arena.create(Inst.VarPtr); inst.* = .{ diff --git a/src-self-hosted/zir.zig b/src-self-hosted/zir.zig index 384463caee..552e90956b 100644 --- a/src-self-hosted/zir.zig +++ b/src-self-hosted/zir.zig @@ -1881,7 +1881,7 @@ const EmitZIR = struct { } else if (typed_value.val.cast(Value.Payload.Variable)) |variable| { return self.emitTypedValue(src, .{ .ty = typed_value.ty, - .val = variable.variable.value.?, + .val = variable.variable.init, }); } if (typed_value.val.isUndef()) { diff --git a/src-self-hosted/zir_sema.zig b/src-self-hosted/zir_sema.zig index 87cce3adb3..cb1ed08d6d 100644 --- a/src-self-hosted/zir_sema.zig +++ b/src-self-hosted/zir_sema.zig @@ -666,7 +666,6 @@ fn analyzeInstFn(mod: *Module, scope: *Scope, fn_inst: *zir.Inst.Fn) InnerError! new_func.* = .{ .analysis = .{ .queued = fn_zir }, .owner_decl = scope.decl().?, - .is_pub = false, }; const fn_payload = try scope.arena().create(Value.Payload.Function); fn_payload.* = .{ .func = new_func }; diff --git a/test/stage2/compare_output.zig b/test/stage2/compare_output.zig index 2b8c8e94cc..6fbc760f26 100644 --- a/test/stage2/compare_output.zig +++ b/test/stage2/compare_output.zig @@ -586,6 +586,7 @@ pub fn addCases(ctx: *TestContext) !void { "", ); + // Character literals and multiline strings. case.addCompareOutput( \\export fn _start() noreturn { \\ const ignore = @@ -618,6 +619,7 @@ pub fn addCases(ctx: *TestContext) !void { "", ); + // Global const. case.addCompareOutput( \\export fn _start() noreturn { \\ add(aa, bb); From 59711becc74911ba251001de81bbac2a53e81b9f Mon Sep 17 00:00:00 2001 From: StrangeBug Date: Fri, 22 May 2020 20:24:16 +0200 Subject: [PATCH 30/66] Add handler for INVALID_HANDLE to prevent infinite loop when stderr is not available. --- lib/std/os/windows.zig | 2 ++ src-self-hosted/stage2.zig | 3 +++ 2 files changed, 5 insertions(+) diff --git a/lib/std/os/windows.zig b/lib/std/os/windows.zig index c93feb20d7..c2decaf208 100644 --- a/lib/std/os/windows.zig +++ b/lib/std/os/windows.zig @@ -469,6 +469,7 @@ pub const WriteFileError = error{ SystemResources, OperationAborted, BrokenPipe, + InvalidFd, Unexpected, }; @@ -542,6 +543,7 @@ pub fn WriteFile( .NOT_ENOUGH_QUOTA => return error.SystemResources, .IO_PENDING => unreachable, .BROKEN_PIPE => return error.BrokenPipe, + .INVALID_HANDLE => return error.NotOpenForWriting, else => |err| return unexpectedError(err), } } diff --git a/src-self-hosted/stage2.zig b/src-self-hosted/stage2.zig index 30d2ea44db..148001c575 100644 --- a/src-self-hosted/stage2.zig +++ b/src-self-hosted/stage2.zig @@ -164,6 +164,7 @@ export fn stage2_render_ast(tree: *ast.Tree, output_file: *FILE) Error { error.OutOfMemory => return .OutOfMemory, error.Unexpected => return .Unexpected, error.InputOutput => return .FileSystem, + error.InvalidFd => return .FileSystem, }; return .None; } @@ -635,6 +636,7 @@ export fn stage2_libc_parse(stage1_libc: *Stage2LibCInstallation, libc_file_z: [ error.NotDir => return .NotDir, error.DeviceBusy => return .DeviceBusy, error.FileLocksNotSupported => unreachable, + error.InvalidFd => return .FileSystem, }; stage1_libc.initFromStage2(libc); return .None; @@ -679,6 +681,7 @@ export fn stage2_libc_render(stage1_libc: *Stage2LibCInstallation, output_file: error.AccessDenied => return .AccessDenied, error.Unexpected => return .Unexpected, error.InputOutput => return .FileSystem, + error.InvalidFd => return .FileSystem, }; return .None; } From 23c427b5fbd0e83b08d83a00cd343ff9bc4c1824 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 19 Aug 2020 20:51:06 -0700 Subject: [PATCH 31/66] windows: match the same error code for EBADF --- lib/std/os/windows.zig | 2 +- src-self-hosted/stage2.zig | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/lib/std/os/windows.zig b/lib/std/os/windows.zig index c2decaf208..2f2369a458 100644 --- a/lib/std/os/windows.zig +++ b/lib/std/os/windows.zig @@ -469,7 +469,7 @@ pub const WriteFileError = error{ SystemResources, OperationAborted, BrokenPipe, - InvalidFd, + NotOpenForWriting, Unexpected, }; diff --git a/src-self-hosted/stage2.zig b/src-self-hosted/stage2.zig index 148001c575..30d2ea44db 100644 --- a/src-self-hosted/stage2.zig +++ b/src-self-hosted/stage2.zig @@ -164,7 +164,6 @@ export fn stage2_render_ast(tree: *ast.Tree, output_file: *FILE) Error { error.OutOfMemory => return .OutOfMemory, error.Unexpected => return .Unexpected, error.InputOutput => return .FileSystem, - error.InvalidFd => return .FileSystem, }; return .None; } @@ -636,7 +635,6 @@ export fn stage2_libc_parse(stage1_libc: *Stage2LibCInstallation, libc_file_z: [ error.NotDir => return .NotDir, error.DeviceBusy => return .DeviceBusy, error.FileLocksNotSupported => unreachable, - error.InvalidFd => return .FileSystem, }; stage1_libc.initFromStage2(libc); return .None; @@ -681,7 +679,6 @@ export fn stage2_libc_render(stage1_libc: *Stage2LibCInstallation, output_file: error.AccessDenied => return .AccessDenied, error.Unexpected => return .Unexpected, error.InputOutput => return .FileSystem, - error.InvalidFd => return .FileSystem, }; return .None; } From 9164daaa39a0ebffcfff27d6d8c91f5857bdfe04 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Thu, 20 Aug 2020 08:30:54 +0200 Subject: [PATCH 32/66] Write page zero as first segment for Mach-O exes According to the Mach-O file format reference, the first load command should be a `__PAGEZERO` segment command. The segment is located at virtual memory location 0, has no protection rights, and causes acccesses to NULL to immediately crash. Signed-off-by: Jakub Konka --- src-self-hosted/link/MachO.zig | 60 +++++++++++++++++++++++++++++++--- 1 file changed, 56 insertions(+), 4 deletions(-) diff --git a/src-self-hosted/link/MachO.zig b/src-self-hosted/link/MachO.zig index e2a84d8ceb..5ba8b6f27b 100644 --- a/src-self-hosted/link/MachO.zig +++ b/src-self-hosted/link/MachO.zig @@ -6,6 +6,8 @@ const assert = std.debug.assert; const fs = std.fs; const log = std.log.scoped(.link); const macho = std.macho; +const math = std.math; +const mem = std.mem; const Module = @import("../Module.zig"); const link = @import("../link.zig"); @@ -15,6 +17,14 @@ pub const base_tag: Tag = File.Tag.macho; base: File, +/// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write. +/// Same order as in the file. +segment_cmds: std.ArrayListUnmanaged(macho.segment_command_64) = std.ArrayListUnmanaged(macho.segment_command_64){}, + +/// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write. +/// Same order as in the file. +sections: std.ArrayListUnmanaged(macho.@"section_64") = std.ArrayListUnmanaged(macho.@"section_64"){}, + entry_addr: ?u64 = null, error_flags: File.ErrorFlags = File.ErrorFlags{}, @@ -86,9 +96,34 @@ fn createFile(allocator: *Allocator, file: fs.File, options: link.Options) !Mach }; errdefer self.deinit(); + if (options.output_mode == .Exe) { + // The first segment command for executables is always a __PAGEZERO segment. + try self.segment_cmds.append(allocator, .{ + .cmd = macho.LC_SEGMENT_64, + .cmdsize = @sizeOf(macho.segment_command_64), + .segname = self.makeString("__PAGEZERO"), + .vmaddr = 0, + .vmsize = 0, + .fileoff = 0, + .filesize = 0, + .maxprot = 0, + .initprot = 0, + .nsects = 0, + .flags = 0, + }); + } + return self; } +fn makeString(self: *MachO, comptime bytes: []const u8) [16]u8 { + if (bytes.len > 16) @compileError("MachO segment/section name too long"); + + var buf: [16]u8 = undefined; + mem.copy(u8, buf[0..], bytes); + return buf; +} + fn writeMachOHeader(self: *MachO) !void { var hdr: macho.mach_header_64 = undefined; hdr.magic = macho.MH_MAGIC_64; @@ -122,9 +157,12 @@ fn writeMachOHeader(self: *MachO) !void { }; hdr.filetype = filetype; - // TODO the rest of the header - hdr.ncmds = 0; - hdr.sizeofcmds = 0; + // TODO consider other commands + const ncmds = try math.cast(u32, self.segment_cmds.items.len); + hdr.ncmds = ncmds; + hdr.sizeofcmds = ncmds * @sizeOf(macho.segment_command_64); + + // TODO should these be set to something else? hdr.flags = 0; hdr.reserved = 0; @@ -133,6 +171,17 @@ fn writeMachOHeader(self: *MachO) !void { pub fn flush(self: *MachO, module: *Module) !void { // TODO implement flush + { + const buf = try self.base.allocator.alloc(macho.segment_command_64, self.segment_cmds.items.len); + defer self.base.allocator.free(buf); + + for (buf) |*seg, i| { + seg.* = self.segment_cmds.items[i]; + } + + try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), @sizeOf(macho.mach_header_64)); + } + if (self.entry_addr == null and self.base.options.output_mode == .Exe) { log.debug("flushing. no_entry_point_found = true\n", .{}); self.error_flags.no_entry_point_found = true; @@ -143,7 +192,10 @@ pub fn flush(self: *MachO, module: *Module) !void { } } -pub fn deinit(self: *MachO) void {} +pub fn deinit(self: *MachO) void { + self.segment_cmds.deinit(self.base.allocator); + self.@"sections".deinit(self.base.allocator); +} pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void {} From adc5bce5e8487cf9507ab5dd2b1b60dd7f54cc3d Mon Sep 17 00:00:00 2001 From: Vexu Date: Thu, 20 Aug 2020 10:08:27 +0300 Subject: [PATCH 33/66] translate-c: correct translation of global variables * externs with intializers are translated as exports * non extern without explicit initialization are zero initalized --- lib/std/mem.zig | 20 +++++++++++++++++++- src-self-hosted/translate_c.zig | 27 ++++++++++++++++++++++++--- test/translate_c.zig | 4 ++-- 3 files changed, 45 insertions(+), 6 deletions(-) diff --git a/lib/std/mem.zig b/lib/std/mem.zig index 1ba64f47fa..7f1b5ae618 100644 --- a/lib/std/mem.zig +++ b/lib/std/mem.zig @@ -221,9 +221,19 @@ pub fn zeroes(comptime T: type) T { .Vector => |info| { return @splat(info.len, zeroes(info.child)); }, + .Union => |info| { + if (comptime meta.containerLayout(T) == .Extern) { + // The C language specification states that (global) unions + // should be zero initialized to the first named member. + var item: T = undefined; + @field(item, info.fields[0].name) = zeroes(@TypeOf(@field(item, info.fields[0].name))); + return item; + } + + @compileError("Can't set a " ++ @typeName(T) ++ " to zero."); + }, .ErrorUnion, .ErrorSet, - .Union, .Fn, .BoundFn, .Type, @@ -312,6 +322,14 @@ test "mem.zeroes" { for (b.sentinel) |e| { testing.expectEqual(@as(u8, 0), e); } + + const C_union = extern union { + a: u8, + b: u32, + }; + + var c = zeroes(C_union); + testing.expectEqual(@as(u8, 0), c.a); } /// Sets a slice to zeroes. diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig index 98cb68f059..6c6e3f0c7e 100644 --- a/src-self-hosted/translate_c.zig +++ b/src-self-hosted/translate_c.zig @@ -701,8 +701,14 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void { const qual_type = ZigClangVarDecl_getTypeSourceInfo_getType(var_decl); const storage_class = ZigClangVarDecl_getStorageClass(var_decl); const is_const = ZigClangQualType_isConstQualified(qual_type); + const has_init = ZigClangVarDecl_hasInit(var_decl); - const extern_tok = if (storage_class == .Extern) + // In C extern variables with initializers behave like Zig exports. + // extern int foo = 2; + // does the same as: + // extern int foo; + // int foo = 2; + const extern_tok = if (storage_class == .Extern and !has_init) try appendToken(c, .Keyword_extern, "extern") else if (storage_class != .Static) try appendToken(c, .Keyword_export, "export") @@ -730,7 +736,7 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void { // If the initialization expression is not present, initialize with undefined. // If it is an integer literal, we can skip the @as since it will be redundant // with the variable type. - if (ZigClangVarDecl_hasInit(var_decl)) { + if (has_init) { eq_tok = try appendToken(c, .Equal, "="); init_node = if (ZigClangVarDecl_getInit(var_decl)) |expr| transExprCoercing(rp, &c.global_scope.base, expr, .used, .r_value) catch |err| switch (err) { @@ -745,7 +751,22 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void { try transCreateNodeUndefinedLiteral(c); } else if (storage_class != .Extern) { eq_tok = try appendToken(c, .Equal, "="); - init_node = try transCreateNodeIdentifierUnchecked(c, "undefined"); + // The C language specification states that variables with static or threadlocal + // storage without an initializer are initialized to a zero value. + + // @import("std").mem.zeroes(T) + const import_fn_call = try c.createBuiltinCall("@import", 1); + const std_node = try transCreateNodeStringLiteral(c, "\"std\""); + import_fn_call.params()[0] = std_node; + import_fn_call.rparen_token = try appendToken(c, .RParen, ")"); + const inner_field_access = try transCreateNodeFieldAccess(c, &import_fn_call.base, "mem"); + const outer_field_access = try transCreateNodeFieldAccess(c, inner_field_access, "zeroes"); + + const zero_init_call = try c.createCall(outer_field_access, 1); + zero_init_call.params()[0] = type_node; + zero_init_call.rtoken = try appendToken(c, .RParen, ")"); + + init_node = &zero_init_call.base; } const linksection_expr = blk: { diff --git a/test/translate_c.zig b/test/translate_c.zig index f7e983276e..bfbae2b65e 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -466,7 +466,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { , &[_][]const u8{ \\pub extern var extern_var: c_int; \\pub const int_var: c_int = 13; - \\pub export var foo: c_int = undefined; + \\pub export var foo: c_int = @import("std").mem.zeroes(c_int); }); cases.add("const ptr initializer", @@ -1327,7 +1327,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\static char arr1[] = "hello"; \\char arr2[] = "hello"; , &[_][]const u8{ - \\pub extern var arr0: [*c]u8 = "hello"; + \\pub export var arr0: [*c]u8 = "hello"; \\pub var arr1: [*c]u8 = "hello"; \\pub export var arr2: [*c]u8 = "hello"; }); From ad79b80524820d3f0ec60d4d21461208227cd4c8 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Thu, 20 Aug 2020 09:14:37 +0200 Subject: [PATCH 34/66] Apply suggestions from code review Co-authored-by: Andrew Kelley --- src-self-hosted/link/MachO.zig | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src-self-hosted/link/MachO.zig b/src-self-hosted/link/MachO.zig index 5ba8b6f27b..9947530398 100644 --- a/src-self-hosted/link/MachO.zig +++ b/src-self-hosted/link/MachO.zig @@ -23,7 +23,7 @@ segment_cmds: std.ArrayListUnmanaged(macho.segment_command_64) = std.ArrayListUn /// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write. /// Same order as in the file. -sections: std.ArrayListUnmanaged(macho.@"section_64") = std.ArrayListUnmanaged(macho.@"section_64"){}, +sections: std.ArrayListUnmanaged(macho.section_64) = std.ArrayListUnmanaged(macho.section_64){}, entry_addr: ?u64 = null, @@ -117,9 +117,8 @@ fn createFile(allocator: *Allocator, file: fs.File, options: link.Options) !Mach } fn makeString(self: *MachO, comptime bytes: []const u8) [16]u8 { - if (bytes.len > 16) @compileError("MachO segment/section name too long"); - var buf: [16]u8 = undefined; + if (bytes.len > buf.len) @compileError("MachO segment/section name too long"); mem.copy(u8, buf[0..], bytes); return buf; } @@ -194,7 +193,7 @@ pub fn flush(self: *MachO, module: *Module) !void { pub fn deinit(self: *MachO) void { self.segment_cmds.deinit(self.base.allocator); - self.@"sections".deinit(self.base.allocator); + self.sections.deinit(self.base.allocator); } pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void {} From a553947a51bc5858ff40fb47dfe41daaa9ff75bf Mon Sep 17 00:00:00 2001 From: Vexu Date: Thu, 20 Aug 2020 10:45:55 +0300 Subject: [PATCH 35/66] translate-c: correctly put static and extern local variables in global scope --- src-self-hosted/translate_c.zig | 25 ++++++++++++++++--------- test/run_translated_c.zig | 14 ++++++++++++++ test/translate_c.zig | 17 ++++++++++++++++- 3 files changed, 46 insertions(+), 10 deletions(-) diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig index 6c6e3f0c7e..6628f5b99e 100644 --- a/src-self-hosted/translate_c.zig +++ b/src-self-hosted/translate_c.zig @@ -498,7 +498,7 @@ fn declVisitor(c: *Context, decl: *const ZigClangDecl) Error!void { _ = try transRecordDecl(c, @ptrCast(*const ZigClangRecordDecl, decl)); }, .Var => { - return visitVarDecl(c, @ptrCast(*const ZigClangVarDecl, decl)); + return visitVarDecl(c, @ptrCast(*const ZigClangVarDecl, decl), null); }, .Empty => { // Do nothing @@ -679,12 +679,13 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void { return addTopLevelDecl(c, fn_name, &proto_node.base); } -fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void { - const var_name = try c.str(ZigClangNamedDecl_getName_bytes_begin(@ptrCast(*const ZigClangNamedDecl, var_decl))); +/// if mangled_name is not null, this var decl was declared in a block scope. +fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl, mangled_name: ?[]const u8) Error!void { + const var_name = mangled_name orelse try c.str(ZigClangNamedDecl_getName_bytes_begin(@ptrCast(*const ZigClangNamedDecl, var_decl))); if (c.global_scope.sym_table.contains(var_name)) return; // Avoid processing this decl twice const rp = makeRestorePoint(c); - const visib_tok = try appendToken(c, .Keyword_pub, "pub"); + const visib_tok = if (mangled_name) |_| null else try appendToken(c, .Keyword_pub, "pub"); const thread_local_token = if (ZigClangVarDecl_getTLSKind(var_decl) == .None) null @@ -1582,15 +1583,22 @@ fn transDeclStmtOne( .Var => { const var_decl = @ptrCast(*const ZigClangVarDecl, decl); - const thread_local_token = if (ZigClangVarDecl_getTLSKind(var_decl) == .None) - null - else - try appendToken(c, .Keyword_threadlocal, "threadlocal"); const qual_type = ZigClangVarDecl_getTypeSourceInfo_getType(var_decl); const name = try c.str(ZigClangNamedDecl_getName_bytes_begin( @ptrCast(*const ZigClangNamedDecl, var_decl), )); const mangled_name = try block_scope.makeMangledName(c, name); + + switch (ZigClangVarDecl_getStorageClass(var_decl)) { + .Extern, .Static => { + // This is actually a global variable, put it in the global scope and reference it. + // `_ = mangled_name;` + try visitVarDecl(rp.c, var_decl, mangled_name); + return try maybeSuppressResult(rp, scope, .unused, try transCreateNodeIdentifier(rp.c, mangled_name)); + }, + else => {}, + } + const mut_tok = if (ZigClangQualType_isConstQualified(qual_type)) try appendToken(c, .Keyword_const, "const") else @@ -1618,7 +1626,6 @@ fn transDeclStmtOne( .mut_token = mut_tok, .semicolon_token = semicolon_token, }, .{ - .thread_local_token = thread_local_token, .eq_token = eq_token, .type_node = type_node, .init_node = init_node, diff --git a/test/run_translated_c.zig b/test/run_translated_c.zig index 3fa183ce3b..2b27e3085e 100644 --- a/test/run_translated_c.zig +++ b/test/run_translated_c.zig @@ -3,6 +3,20 @@ const tests = @import("tests.zig"); const nl = std.cstr.line_sep; pub fn addCases(cases: *tests.RunTranslatedCContext) void { + cases.add("static variable in block scope", + \\#include + \\int foo() { + \\ static int bar; + \\ bar += 1; + \\ return bar; + \\} + \\int main() { + \\ foo(); + \\ foo(); + \\ if (foo() != 3) abort(); + \\} + , ""); + cases.add("array initializer", \\#include \\int main(int argc, char **argv) { diff --git a/test/translate_c.zig b/test/translate_c.zig index bfbae2b65e..41f1e78294 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -3,6 +3,20 @@ const std = @import("std"); const CrossTarget = std.zig.CrossTarget; pub fn addCases(cases: *tests.TranslateCContext) void { + cases.add("extern variable in block scope", + \\float bar; + \\int foo() { + \\ _Thread_local static int bar = 2; + \\} + , &[_][]const u8{ + \\pub export var bar: f32 = @import("std").mem.zeroes(f32); + \\threadlocal var bar_1: c_int = 2; + \\pub export fn foo() c_int { + \\ _ = bar_1; + \\ return 0; + \\} + }); + cases.add("missing return stmt", \\int foo() {} \\int bar() { @@ -480,8 +494,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ static const char v2[] = "2.2.2"; \\} , &[_][]const u8{ + \\const v2: [*c]const u8 = "2.2.2"; \\pub export fn foo() void { - \\ const v2: [*c]const u8 = "2.2.2"; + \\ _ = v2; \\} }); From d25674a51ec09640b0140a541a156869b3e03f81 Mon Sep 17 00:00:00 2001 From: Vexu Date: Thu, 20 Aug 2020 11:04:42 +0300 Subject: [PATCH 36/66] disallow extern variables with initializers --- lib/std/c/darwin.zig | 2 +- lib/std/special/c.zig | 2 +- lib/std/special/compiler_rt.zig | 2 +- src-self-hosted/Module.zig | 11 +++++++---- src/parser.cpp | 3 +++ test/compile_errors.zig | 6 ++++++ test/standalone/global_linkage/obj1.zig | 4 ++-- test/standalone/global_linkage/obj2.zig | 4 ++-- 8 files changed, 23 insertions(+), 11 deletions(-) diff --git a/lib/std/c/darwin.zig b/lib/std/c/darwin.zig index 2426638569..b1f66fa575 100644 --- a/lib/std/c/darwin.zig +++ b/lib/std/c/darwin.zig @@ -41,7 +41,7 @@ const mach_hdr = if (@sizeOf(usize) == 8) mach_header_64 else mach_header; /// on this operating system. However when building object files or libraries, /// the system libc won't be linked until the final executable. So we /// export a weak symbol here, to be overridden by the real one. -pub extern "c" var _mh_execute_header: mach_hdr = undefined; +pub extern "c" var _mh_execute_header: mach_hdr; comptime { if (std.Target.current.isDarwin()) { @export(_mh_execute_header, .{ .name = "_mh_execute_header", .linkage = .Weak }); diff --git a/lib/std/special/c.zig b/lib/std/special/c.zig index 170bb98620..8019db9d96 100644 --- a/lib/std/special/c.zig +++ b/lib/std/special/c.zig @@ -35,7 +35,7 @@ comptime { } } -extern var _fltused: c_int = 1; +var _fltused: c_int = 1; extern fn main(argc: c_int, argv: [*:null]?[*:0]u8) c_int; fn wasm_start() callconv(.C) void { diff --git a/lib/std/special/compiler_rt.zig b/lib/std/special/compiler_rt.zig index 2716de8113..36a731ed5a 100644 --- a/lib/std/special/compiler_rt.zig +++ b/lib/std/special/compiler_rt.zig @@ -335,7 +335,7 @@ fn __stack_chk_fail() callconv(.C) noreturn { @panic("stack smashing detected"); } -extern var __stack_chk_guard: usize = blk: { +var __stack_chk_guard: usize = blk: { var buf = [1]u8{0} ** @sizeOf(usize); buf[@sizeOf(usize) - 1] = 255; buf[@sizeOf(usize) - 2] = '\n'; diff --git a/src-self-hosted/Module.zig b/src-self-hosted/Module.zig index ec69f94e3d..d08e7f5746 100644 --- a/src-self-hosted/Module.zig +++ b/src-self-hosted/Module.zig @@ -324,10 +324,10 @@ pub const Fn = struct { }; pub const Var = struct { + /// if is_extern == true this is undefined init: Value, owner_decl: *Decl, - has_init: bool, is_extern: bool, is_mutable: bool, is_threadlocal: bool, @@ -1456,7 +1456,11 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { const is_extern = blk: { const maybe_extern_token = var_decl.getTrailer("extern_export_token") orelse break :blk false; - break :blk tree.token_ids[maybe_extern_token] == .Keyword_extern; + if (tree.token_ids[maybe_extern_token] != .Keyword_extern) break :blk false; + if (var_decl.getTrailer("init_node")) |some| { + return self.failNode(&block_scope.base, some, "extern variables have no initializers", .{}); + } + break :blk true; }; if (var_decl.getTrailer("lib_name")) |lib_name| { assert(is_extern); @@ -1569,7 +1573,6 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { new_variable.* = .{ .owner_decl = decl, .init = value orelse undefined, - .has_init = value != null, .is_extern = is_extern, .is_mutable = is_mutable, .is_threadlocal = is_threadlocal, @@ -2440,7 +2443,7 @@ fn analyzeVarRef(self: *Module, scope: *Scope, src: usize, tv: TypedValue) Inner const variable = tv.val.cast(Value.Payload.Variable).?.variable; const ty = try self.singlePtrType(scope, src, variable.is_mutable, tv.ty); - if (!variable.is_mutable and !variable.is_extern and variable.has_init) { + if (!variable.is_mutable and !variable.is_extern) { const val_payload = try scope.arena().create(Value.Payload.RefVal); val_payload.* = .{ .val = variable.init }; return self.constInst(scope, src, .{ diff --git a/src/parser.cpp b/src/parser.cpp index 26233ec6a4..1253baf9ea 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -680,6 +680,9 @@ static AstNode *ast_parse_top_level_decl(ParseContext *pc, VisibMod visib_mod, B AstNode *var_decl = ast_parse_var_decl(pc); if (var_decl != nullptr) { assert(var_decl->type == NodeTypeVariableDeclaration); + if (first->id == TokenIdKeywordExtern && var_decl->data.variable_declaration.expr != nullptr) { + ast_error(pc, first, "extern variables have no initializers"); + } var_decl->line = first->start_line; var_decl->column = first->start_column; var_decl->data.variable_declaration.threadlocal_tok = thread_local_kw; diff --git a/test/compile_errors.zig b/test/compile_errors.zig index fd74385d9b..311c5b9319 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -2,6 +2,12 @@ const tests = @import("tests.zig"); const std = @import("std"); pub fn addCases(cases: *tests.CompileErrorContext) void { + cases.addTest("reject extern variables with initializers", + \\extern var foo: int = 2; + , &[_][]const u8{ + "tmp.zig:1:1: error: extern variables have no initializers", + }); + cases.addTest("duplicate/unused labels", \\comptime { \\ blk: { blk: while (false) {} } diff --git a/test/standalone/global_linkage/obj1.zig b/test/standalone/global_linkage/obj1.zig index 95814cda3d..83b66f336b 100644 --- a/test/standalone/global_linkage/obj1.zig +++ b/test/standalone/global_linkage/obj1.zig @@ -1,5 +1,5 @@ -extern var internal_integer: usize = 1; -extern var obj1_integer: usize = 421; +var internal_integer: usize = 1; +var obj1_integer: usize = 421; comptime { @export(internal_integer, .{ .name = "internal_integer", .linkage = .Internal }); diff --git a/test/standalone/global_linkage/obj2.zig b/test/standalone/global_linkage/obj2.zig index f2d44b2dc0..2908a627fd 100644 --- a/test/standalone/global_linkage/obj2.zig +++ b/test/standalone/global_linkage/obj2.zig @@ -1,5 +1,5 @@ -extern var internal_integer: usize = 2; -extern var obj2_integer: usize = 422; +var internal_integer: usize = 2; +var obj2_integer: usize = 422; comptime { @export(internal_integer, .{ .name = "internal_integer", .linkage = .Internal }); From 717e2a365d9b5103f855668e4765cc154203a2bf Mon Sep 17 00:00:00 2001 From: Vexu Date: Thu, 20 Aug 2020 14:19:11 +0300 Subject: [PATCH 37/66] correct llvm linkage conversion when weakly exporting external declaration we need to pass LLVMExternalWeakLinkage --- lib/std/c/darwin.zig | 5 +++-- src/codegen.cpp | 9 +++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/std/c/darwin.zig b/lib/std/c/darwin.zig index b1f66fa575..9ff66ac01e 100644 --- a/lib/std/c/darwin.zig +++ b/lib/std/c/darwin.zig @@ -41,10 +41,11 @@ const mach_hdr = if (@sizeOf(usize) == 8) mach_header_64 else mach_header; /// on this operating system. However when building object files or libraries, /// the system libc won't be linked until the final executable. So we /// export a weak symbol here, to be overridden by the real one. -pub extern "c" var _mh_execute_header: mach_hdr; +var dummy_execute_header: mach_hdr = undefined; +pub extern var _mh_execute_header: mach_hdr; comptime { if (std.Target.current.isDarwin()) { - @export(_mh_execute_header, .{ .name = "_mh_execute_header", .linkage = .Weak }); + @export(dummy_execute_header, .{ .name = "_mh_execute_header", .linkage = .Weak }); } } diff --git a/src/codegen.cpp b/src/codegen.cpp index 36ed520069..e2341fe1aa 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -292,13 +292,14 @@ static void add_uwtable_attr(CodeGen *g, LLVMValueRef fn_val) { } } -static LLVMLinkage to_llvm_linkage(GlobalLinkageId id) { +static LLVMLinkage to_llvm_linkage(GlobalLinkageId id, bool is_extern) { switch (id) { case GlobalLinkageIdInternal: return LLVMInternalLinkage; case GlobalLinkageIdStrong: return LLVMExternalLinkage; case GlobalLinkageIdWeak: + if (is_extern) return LLVMExternalWeakLinkage; return LLVMWeakODRLinkage; case GlobalLinkageIdLinkOnce: return LLVMLinkOnceODRLinkage; @@ -521,7 +522,7 @@ static LLVMValueRef make_fn_llvm_value(CodeGen *g, ZigFn *fn) { } - LLVMSetLinkage(llvm_fn, to_llvm_linkage(linkage)); + LLVMSetLinkage(llvm_fn, to_llvm_linkage(linkage, fn->body_node == nullptr)); if (linkage == GlobalLinkageIdInternal) { LLVMSetUnnamedAddr(llvm_fn, true); @@ -7962,7 +7963,7 @@ static void do_code_gen(CodeGen *g) { global_value = LLVMAddGlobal(g->module, get_llvm_type(g, var->var_type), symbol_name); // TODO debug info for the extern variable - LLVMSetLinkage(global_value, to_llvm_linkage(linkage)); + LLVMSetLinkage(global_value, to_llvm_linkage(linkage, true)); maybe_import_dll(g, global_value, GlobalLinkageIdStrong); LLVMSetAlignment(global_value, var->align_bytes); LLVMSetGlobalConstant(global_value, var->gen_is_const); @@ -7975,7 +7976,7 @@ static void do_code_gen(CodeGen *g) { global_value = var->const_value->llvm_global; if (exported) { - LLVMSetLinkage(global_value, to_llvm_linkage(linkage)); + LLVMSetLinkage(global_value, to_llvm_linkage(linkage, false)); maybe_export_dll(g, global_value, GlobalLinkageIdStrong); } if (var->section_name) { From 4a69b11e742365d68e4d92aa18d6493db9d3edaf Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 19 Aug 2020 19:40:15 -0700 Subject: [PATCH 38/66] add license header to all std lib files add SPDX license identifier copyright ownership is zig contributors --- lib/std/array_list.zig | 5 +++++ lib/std/array_list_sentineled.zig | 5 +++++ lib/std/ascii.zig | 5 +++++ lib/std/atomic.zig | 5 +++++ lib/std/atomic/int.zig | 5 +++++ lib/std/atomic/queue.zig | 5 +++++ lib/std/atomic/stack.zig | 5 +++++ lib/std/base64.zig | 5 +++++ lib/std/bloom_filter.zig | 5 +++++ lib/std/buf_map.zig | 5 +++++ lib/std/buf_set.zig | 5 +++++ lib/std/build.zig | 5 +++++ lib/std/build/check_file.zig | 5 +++++ lib/std/build/emit_raw.zig | 5 +++++ lib/std/build/fmt.zig | 5 +++++ lib/std/build/run.zig | 5 +++++ lib/std/build/translate_c.zig | 5 +++++ lib/std/build/write_file.zig | 5 +++++ lib/std/builtin.zig | 5 +++++ lib/std/c.zig | 5 +++++ lib/std/c/ast.zig | 5 +++++ lib/std/c/darwin.zig | 5 +++++ lib/std/c/dragonfly.zig | 5 +++++ lib/std/c/emscripten.zig | 5 +++++ lib/std/c/freebsd.zig | 5 +++++ lib/std/c/fuchsia.zig | 5 +++++ lib/std/c/haiku.zig | 5 +++++ lib/std/c/hermit.zig | 5 +++++ lib/std/c/linux.zig | 5 +++++ lib/std/c/minix.zig | 5 +++++ lib/std/c/netbsd.zig | 5 +++++ lib/std/c/openbsd.zig | 5 +++++ lib/std/c/parse.zig | 5 +++++ lib/std/c/solaris.zig | 5 +++++ lib/std/c/tokenizer.zig | 5 +++++ lib/std/c/windows.zig | 5 +++++ lib/std/cache_hash.zig | 5 +++++ lib/std/child_process.zig | 5 +++++ lib/std/coff.zig | 5 +++++ lib/std/comptime_string_map.zig | 5 +++++ lib/std/crypto.zig | 5 +++++ lib/std/crypto/25519/curve25519.zig | 5 +++++ lib/std/crypto/25519/ed25519.zig | 5 +++++ lib/std/crypto/25519/edwards25519.zig | 5 +++++ lib/std/crypto/25519/field.zig | 5 +++++ lib/std/crypto/25519/ristretto255.zig | 5 +++++ lib/std/crypto/25519/scalar.zig | 5 +++++ lib/std/crypto/25519/x25519.zig | 5 +++++ lib/std/crypto/aes.zig | 5 +++++ lib/std/crypto/benchmark.zig | 5 +++++ lib/std/crypto/blake2.zig | 5 +++++ lib/std/crypto/blake3.zig | 5 +++++ lib/std/crypto/chacha20.zig | 5 +++++ lib/std/crypto/gimli.zig | 5 +++++ lib/std/crypto/hmac.zig | 5 +++++ lib/std/crypto/md5.zig | 5 +++++ lib/std/crypto/poly1305.zig | 5 +++++ lib/std/crypto/sha1.zig | 5 +++++ lib/std/crypto/sha2.zig | 5 +++++ lib/std/crypto/sha3.zig | 5 +++++ lib/std/crypto/test.zig | 5 +++++ lib/std/cstr.zig | 5 +++++ lib/std/debug.zig | 5 +++++ lib/std/debug/leb128.zig | 5 +++++ lib/std/dwarf.zig | 5 +++++ lib/std/dwarf_bits.zig | 5 +++++ lib/std/dynamic_library.zig | 5 +++++ lib/std/elf.zig | 5 +++++ lib/std/event.zig | 5 +++++ lib/std/event/batch.zig | 5 +++++ lib/std/event/channel.zig | 5 +++++ lib/std/event/future.zig | 5 +++++ lib/std/event/group.zig | 5 +++++ lib/std/event/lock.zig | 5 +++++ lib/std/event/locked.zig | 5 +++++ lib/std/event/loop.zig | 5 +++++ lib/std/event/rwlock.zig | 5 +++++ lib/std/event/rwlocked.zig | 5 +++++ lib/std/fifo.zig | 5 +++++ lib/std/fmt.zig | 5 +++++ lib/std/fmt/errol.zig | 5 +++++ lib/std/fmt/errol/enum3.zig | 5 +++++ lib/std/fmt/errol/lookup.zig | 5 +++++ lib/std/fmt/parse_float.zig | 5 +++++ lib/std/fs.zig | 5 +++++ lib/std/fs/file.zig | 5 +++++ lib/std/fs/get_app_data_dir.zig | 5 +++++ lib/std/fs/path.zig | 5 +++++ lib/std/fs/test.zig | 5 +++++ lib/std/fs/wasi.zig | 5 +++++ lib/std/fs/watch.zig | 5 +++++ lib/std/hash.zig | 5 +++++ lib/std/hash/adler.zig | 5 +++++ lib/std/hash/auto_hash.zig | 5 +++++ lib/std/hash/benchmark.zig | 5 +++++ lib/std/hash/cityhash.zig | 5 +++++ lib/std/hash/crc.zig | 5 +++++ lib/std/hash/fnv.zig | 5 +++++ lib/std/hash/murmur.zig | 5 +++++ lib/std/hash/siphash.zig | 5 +++++ lib/std/hash/wyhash.zig | 5 +++++ lib/std/hash_map.zig | 5 +++++ lib/std/heap.zig | 5 +++++ lib/std/heap/arena_allocator.zig | 5 +++++ lib/std/heap/general_purpose_allocator.zig | 5 +++++ lib/std/heap/logging_allocator.zig | 5 +++++ lib/std/http.zig | 5 +++++ lib/std/http/headers.zig | 5 +++++ lib/std/io.zig | 5 +++++ lib/std/io/bit_in_stream.zig | 5 +++++ lib/std/io/bit_out_stream.zig | 5 +++++ lib/std/io/bit_reader.zig | 5 +++++ lib/std/io/bit_writer.zig | 5 +++++ lib/std/io/buffered_atomic_file.zig | 5 +++++ lib/std/io/buffered_in_stream.zig | 5 +++++ lib/std/io/buffered_out_stream.zig | 5 +++++ lib/std/io/buffered_reader.zig | 5 +++++ lib/std/io/buffered_writer.zig | 5 +++++ lib/std/io/c_out_stream.zig | 5 +++++ lib/std/io/c_writer.zig | 5 +++++ lib/std/io/counting_out_stream.zig | 5 +++++ lib/std/io/counting_writer.zig | 5 +++++ lib/std/io/fixed_buffer_stream.zig | 5 +++++ lib/std/io/in_stream.zig | 5 +++++ lib/std/io/multi_out_stream.zig | 5 +++++ lib/std/io/multi_writer.zig | 5 +++++ lib/std/io/out_stream.zig | 5 +++++ lib/std/io/peek_stream.zig | 5 +++++ lib/std/io/reader.zig | 5 +++++ lib/std/io/seekable_stream.zig | 5 +++++ lib/std/io/serialization.zig | 5 +++++ lib/std/io/stream_source.zig | 5 +++++ lib/std/io/test.zig | 5 +++++ lib/std/io/writer.zig | 5 +++++ lib/std/json.zig | 5 +++++ lib/std/json/test.zig | 5 +++++ lib/std/json/write_stream.zig | 5 +++++ lib/std/linked_list.zig | 5 +++++ lib/std/log.zig | 5 +++++ lib/std/macho.zig | 5 +++++ lib/std/math.zig | 5 +++++ lib/std/math/acos.zig | 5 +++++ lib/std/math/acosh.zig | 5 +++++ lib/std/math/asin.zig | 5 +++++ lib/std/math/asinh.zig | 5 +++++ lib/std/math/atan.zig | 5 +++++ lib/std/math/atan2.zig | 5 +++++ lib/std/math/atanh.zig | 5 +++++ lib/std/math/big.zig | 5 +++++ lib/std/math/big/int.zig | 5 +++++ lib/std/math/big/int_test.zig | 5 +++++ lib/std/math/big/rational.zig | 5 +++++ lib/std/math/cbrt.zig | 5 +++++ lib/std/math/ceil.zig | 5 +++++ lib/std/math/complex.zig | 5 +++++ lib/std/math/complex/abs.zig | 5 +++++ lib/std/math/complex/acos.zig | 5 +++++ lib/std/math/complex/acosh.zig | 5 +++++ lib/std/math/complex/arg.zig | 5 +++++ lib/std/math/complex/asin.zig | 5 +++++ lib/std/math/complex/asinh.zig | 5 +++++ lib/std/math/complex/atan.zig | 5 +++++ lib/std/math/complex/atanh.zig | 5 +++++ lib/std/math/complex/conj.zig | 5 +++++ lib/std/math/complex/cos.zig | 5 +++++ lib/std/math/complex/cosh.zig | 5 +++++ lib/std/math/complex/exp.zig | 5 +++++ lib/std/math/complex/ldexp.zig | 5 +++++ lib/std/math/complex/log.zig | 5 +++++ lib/std/math/complex/pow.zig | 5 +++++ lib/std/math/complex/proj.zig | 5 +++++ lib/std/math/complex/sin.zig | 5 +++++ lib/std/math/complex/sinh.zig | 5 +++++ lib/std/math/complex/sqrt.zig | 5 +++++ lib/std/math/complex/tan.zig | 5 +++++ lib/std/math/complex/tanh.zig | 5 +++++ lib/std/math/copysign.zig | 5 +++++ lib/std/math/cos.zig | 5 +++++ lib/std/math/cosh.zig | 5 +++++ lib/std/math/exp.zig | 5 +++++ lib/std/math/exp2.zig | 5 +++++ lib/std/math/expm1.zig | 5 +++++ lib/std/math/expo2.zig | 5 +++++ lib/std/math/fabs.zig | 5 +++++ lib/std/math/floor.zig | 5 +++++ lib/std/math/fma.zig | 5 +++++ lib/std/math/frexp.zig | 5 +++++ lib/std/math/hypot.zig | 5 +++++ lib/std/math/ilogb.zig | 5 +++++ lib/std/math/inf.zig | 5 +++++ lib/std/math/isfinite.zig | 5 +++++ lib/std/math/isinf.zig | 5 +++++ lib/std/math/isnan.zig | 5 +++++ lib/std/math/isnormal.zig | 5 +++++ lib/std/math/ln.zig | 5 +++++ lib/std/math/log.zig | 5 +++++ lib/std/math/log10.zig | 5 +++++ lib/std/math/log1p.zig | 5 +++++ lib/std/math/log2.zig | 5 +++++ lib/std/math/modf.zig | 5 +++++ lib/std/math/nan.zig | 5 +++++ lib/std/math/pow.zig | 5 +++++ lib/std/math/powi.zig | 5 +++++ lib/std/math/round.zig | 5 +++++ lib/std/math/scalbn.zig | 5 +++++ lib/std/math/signbit.zig | 5 +++++ lib/std/math/sin.zig | 5 +++++ lib/std/math/sinh.zig | 5 +++++ lib/std/math/sqrt.zig | 5 +++++ lib/std/math/tan.zig | 5 +++++ lib/std/math/tanh.zig | 5 +++++ lib/std/math/trunc.zig | 5 +++++ lib/std/mem.zig | 5 +++++ lib/std/mem/Allocator.zig | 5 +++++ lib/std/meta.zig | 5 +++++ lib/std/meta/trailer_flags.zig | 5 +++++ lib/std/meta/trait.zig | 5 +++++ lib/std/mutex.zig | 5 +++++ lib/std/net.zig | 5 +++++ lib/std/net/test.zig | 5 +++++ lib/std/once.zig | 5 +++++ lib/std/os.zig | 5 +++++ lib/std/os/bits.zig | 5 +++++ lib/std/os/bits/darwin.zig | 5 +++++ lib/std/os/bits/dragonfly.zig | 5 +++++ lib/std/os/bits/freebsd.zig | 5 +++++ lib/std/os/bits/linux.zig | 5 +++++ lib/std/os/bits/linux/arm-eabi.zig | 5 +++++ lib/std/os/bits/linux/arm64.zig | 5 +++++ lib/std/os/bits/linux/bpf.zig | 5 +++++ lib/std/os/bits/linux/errno-generic.zig | 5 +++++ lib/std/os/bits/linux/errno-mips.zig | 5 +++++ lib/std/os/bits/linux/i386.zig | 5 +++++ lib/std/os/bits/linux/mips.zig | 5 +++++ lib/std/os/bits/linux/netlink.zig | 5 +++++ lib/std/os/bits/linux/riscv64.zig | 5 +++++ lib/std/os/bits/linux/x86_64.zig | 5 +++++ lib/std/os/bits/netbsd.zig | 5 +++++ lib/std/os/bits/wasi.zig | 5 +++++ lib/std/os/bits/windows.zig | 5 +++++ lib/std/os/darwin.zig | 5 +++++ lib/std/os/dragonfly.zig | 5 +++++ lib/std/os/freebsd.zig | 5 +++++ lib/std/os/linux.zig | 5 +++++ lib/std/os/linux/arm-eabi.zig | 5 +++++ lib/std/os/linux/arm64.zig | 5 +++++ lib/std/os/linux/i386.zig | 5 +++++ lib/std/os/linux/mips.zig | 5 +++++ lib/std/os/linux/riscv64.zig | 5 +++++ lib/std/os/linux/test.zig | 5 +++++ lib/std/os/linux/tls.zig | 5 +++++ lib/std/os/linux/vdso.zig | 5 +++++ lib/std/os/linux/x86_64.zig | 5 +++++ lib/std/os/netbsd.zig | 5 +++++ lib/std/os/test.zig | 5 +++++ lib/std/os/uefi.zig | 5 +++++ lib/std/os/uefi/protocols.zig | 5 +++++ lib/std/os/uefi/protocols/absolute_pointer_protocol.zig | 5 +++++ lib/std/os/uefi/protocols/device_path_protocol.zig | 5 +++++ lib/std/os/uefi/protocols/edid_active_protocol.zig | 5 +++++ lib/std/os/uefi/protocols/edid_discovered_protocol.zig | 5 +++++ lib/std/os/uefi/protocols/edid_override_protocol.zig | 5 +++++ lib/std/os/uefi/protocols/file_protocol.zig | 5 +++++ lib/std/os/uefi/protocols/graphics_output_protocol.zig | 5 +++++ lib/std/os/uefi/protocols/hii.zig | 5 +++++ lib/std/os/uefi/protocols/hii_database_protocol.zig | 5 +++++ lib/std/os/uefi/protocols/hii_popup_protocol.zig | 5 +++++ lib/std/os/uefi/protocols/ip6_config_protocol.zig | 5 +++++ lib/std/os/uefi/protocols/ip6_protocol.zig | 5 +++++ lib/std/os/uefi/protocols/ip6_service_binding_protocol.zig | 5 +++++ lib/std/os/uefi/protocols/loaded_image_protocol.zig | 5 +++++ lib/std/os/uefi/protocols/managed_network_protocol.zig | 5 +++++ .../protocols/managed_network_service_binding_protocol.zig | 5 +++++ lib/std/os/uefi/protocols/rng_protocol.zig | 5 +++++ lib/std/os/uefi/protocols/shell_parameters_protocol.zig | 5 +++++ lib/std/os/uefi/protocols/simple_file_system_protocol.zig | 5 +++++ lib/std/os/uefi/protocols/simple_network_protocol.zig | 5 +++++ lib/std/os/uefi/protocols/simple_pointer_protocol.zig | 5 +++++ lib/std/os/uefi/protocols/simple_text_input_ex_protocol.zig | 5 +++++ lib/std/os/uefi/protocols/simple_text_input_protocol.zig | 5 +++++ lib/std/os/uefi/protocols/simple_text_output_protocol.zig | 5 +++++ lib/std/os/uefi/protocols/udp6_protocol.zig | 5 +++++ lib/std/os/uefi/protocols/udp6_service_binding_protocol.zig | 5 +++++ lib/std/os/uefi/status.zig | 5 +++++ lib/std/os/uefi/tables.zig | 5 +++++ lib/std/os/uefi/tables/boot_services.zig | 5 +++++ lib/std/os/uefi/tables/configuration_table.zig | 5 +++++ lib/std/os/uefi/tables/runtime_services.zig | 5 +++++ lib/std/os/uefi/tables/system_table.zig | 5 +++++ lib/std/os/uefi/tables/table_header.zig | 5 +++++ lib/std/os/wasi.zig | 5 +++++ lib/std/os/windows.zig | 5 +++++ lib/std/os/windows/advapi32.zig | 5 +++++ lib/std/os/windows/bits.zig | 5 +++++ lib/std/os/windows/gdi32.zig | 5 +++++ lib/std/os/windows/kernel32.zig | 5 +++++ lib/std/os/windows/lang.zig | 5 +++++ lib/std/os/windows/ntdll.zig | 5 +++++ lib/std/os/windows/ntstatus.zig | 5 +++++ lib/std/os/windows/ole32.zig | 5 +++++ lib/std/os/windows/psapi.zig | 5 +++++ lib/std/os/windows/shell32.zig | 5 +++++ lib/std/os/windows/sublang.zig | 5 +++++ lib/std/os/windows/user32.zig | 5 +++++ lib/std/os/windows/win32error.zig | 5 +++++ lib/std/os/windows/ws2_32.zig | 5 +++++ lib/std/packed_int_array.zig | 5 +++++ lib/std/pdb.zig | 5 +++++ lib/std/priority_queue.zig | 5 +++++ lib/std/process.zig | 5 +++++ lib/std/progress.zig | 5 +++++ lib/std/rand.zig | 5 +++++ lib/std/rand/ziggurat.zig | 5 +++++ lib/std/rb.zig | 5 +++++ lib/std/reset_event.zig | 5 +++++ lib/std/segmented_list.zig | 5 +++++ lib/std/sort.zig | 5 +++++ lib/std/special/build_runner.zig | 5 +++++ lib/std/special/c.zig | 5 +++++ lib/std/special/compiler_rt.zig | 5 +++++ lib/std/special/compiler_rt/addXf3.zig | 5 +++++ lib/std/special/compiler_rt/addXf3_test.zig | 5 +++++ lib/std/special/compiler_rt/arm.zig | 5 +++++ lib/std/special/compiler_rt/ashldi3_test.zig | 5 +++++ lib/std/special/compiler_rt/ashlti3_test.zig | 5 +++++ lib/std/special/compiler_rt/ashrdi3_test.zig | 5 +++++ lib/std/special/compiler_rt/ashrti3_test.zig | 5 +++++ lib/std/special/compiler_rt/atomics.zig | 5 +++++ lib/std/special/compiler_rt/aulldiv.zig | 5 +++++ lib/std/special/compiler_rt/aullrem.zig | 5 +++++ lib/std/special/compiler_rt/clear_cache.zig | 5 +++++ lib/std/special/compiler_rt/clzsi2.zig | 5 +++++ lib/std/special/compiler_rt/clzsi2_test.zig | 5 +++++ lib/std/special/compiler_rt/compareXf2.zig | 5 +++++ lib/std/special/compiler_rt/comparedf2_test.zig | 5 +++++ lib/std/special/compiler_rt/comparesf2_test.zig | 5 +++++ lib/std/special/compiler_rt/divdf3.zig | 5 +++++ lib/std/special/compiler_rt/divdf3_test.zig | 5 +++++ lib/std/special/compiler_rt/divsf3.zig | 5 +++++ lib/std/special/compiler_rt/divsf3_test.zig | 5 +++++ lib/std/special/compiler_rt/divtf3.zig | 5 +++++ lib/std/special/compiler_rt/divtf3_test.zig | 5 +++++ lib/std/special/compiler_rt/divti3.zig | 5 +++++ lib/std/special/compiler_rt/divti3_test.zig | 5 +++++ lib/std/special/compiler_rt/extendXfYf2.zig | 5 +++++ lib/std/special/compiler_rt/extendXfYf2_test.zig | 5 +++++ lib/std/special/compiler_rt/fixdfdi.zig | 5 +++++ lib/std/special/compiler_rt/fixdfdi_test.zig | 5 +++++ lib/std/special/compiler_rt/fixdfsi.zig | 5 +++++ lib/std/special/compiler_rt/fixdfsi_test.zig | 5 +++++ lib/std/special/compiler_rt/fixdfti.zig | 5 +++++ lib/std/special/compiler_rt/fixdfti_test.zig | 5 +++++ lib/std/special/compiler_rt/fixint.zig | 5 +++++ lib/std/special/compiler_rt/fixint_test.zig | 5 +++++ lib/std/special/compiler_rt/fixsfdi.zig | 5 +++++ lib/std/special/compiler_rt/fixsfdi_test.zig | 5 +++++ lib/std/special/compiler_rt/fixsfsi.zig | 5 +++++ lib/std/special/compiler_rt/fixsfsi_test.zig | 5 +++++ lib/std/special/compiler_rt/fixsfti.zig | 5 +++++ lib/std/special/compiler_rt/fixsfti_test.zig | 5 +++++ lib/std/special/compiler_rt/fixtfdi.zig | 5 +++++ lib/std/special/compiler_rt/fixtfdi_test.zig | 5 +++++ lib/std/special/compiler_rt/fixtfsi.zig | 5 +++++ lib/std/special/compiler_rt/fixtfsi_test.zig | 5 +++++ lib/std/special/compiler_rt/fixtfti.zig | 5 +++++ lib/std/special/compiler_rt/fixtfti_test.zig | 5 +++++ lib/std/special/compiler_rt/fixuint.zig | 5 +++++ lib/std/special/compiler_rt/fixunsdfdi.zig | 5 +++++ lib/std/special/compiler_rt/fixunsdfdi_test.zig | 5 +++++ lib/std/special/compiler_rt/fixunsdfsi.zig | 5 +++++ lib/std/special/compiler_rt/fixunsdfsi_test.zig | 5 +++++ lib/std/special/compiler_rt/fixunsdfti.zig | 5 +++++ lib/std/special/compiler_rt/fixunsdfti_test.zig | 5 +++++ lib/std/special/compiler_rt/fixunssfdi.zig | 5 +++++ lib/std/special/compiler_rt/fixunssfdi_test.zig | 5 +++++ lib/std/special/compiler_rt/fixunssfsi.zig | 5 +++++ lib/std/special/compiler_rt/fixunssfsi_test.zig | 5 +++++ lib/std/special/compiler_rt/fixunssfti.zig | 5 +++++ lib/std/special/compiler_rt/fixunssfti_test.zig | 5 +++++ lib/std/special/compiler_rt/fixunstfdi.zig | 5 +++++ lib/std/special/compiler_rt/fixunstfdi_test.zig | 5 +++++ lib/std/special/compiler_rt/fixunstfsi.zig | 5 +++++ lib/std/special/compiler_rt/fixunstfsi_test.zig | 5 +++++ lib/std/special/compiler_rt/fixunstfti.zig | 5 +++++ lib/std/special/compiler_rt/fixunstfti_test.zig | 5 +++++ lib/std/special/compiler_rt/floatdidf.zig | 5 +++++ lib/std/special/compiler_rt/floatdidf_test.zig | 5 +++++ lib/std/special/compiler_rt/floatditf.zig | 5 +++++ lib/std/special/compiler_rt/floatditf_test.zig | 5 +++++ lib/std/special/compiler_rt/floatsiXf.zig | 5 +++++ lib/std/special/compiler_rt/floattidf.zig | 5 +++++ lib/std/special/compiler_rt/floattidf_test.zig | 5 +++++ lib/std/special/compiler_rt/floattisf.zig | 5 +++++ lib/std/special/compiler_rt/floattisf_test.zig | 5 +++++ lib/std/special/compiler_rt/floattitf.zig | 5 +++++ lib/std/special/compiler_rt/floattitf_test.zig | 5 +++++ lib/std/special/compiler_rt/floatundidf.zig | 5 +++++ lib/std/special/compiler_rt/floatundidf_test.zig | 5 +++++ lib/std/special/compiler_rt/floatundisf.zig | 5 +++++ lib/std/special/compiler_rt/floatunditf.zig | 5 +++++ lib/std/special/compiler_rt/floatunditf_test.zig | 5 +++++ lib/std/special/compiler_rt/floatunsidf.zig | 5 +++++ lib/std/special/compiler_rt/floatunsisf.zig | 5 +++++ lib/std/special/compiler_rt/floatunsitf.zig | 5 +++++ lib/std/special/compiler_rt/floatunsitf_test.zig | 5 +++++ lib/std/special/compiler_rt/floatuntidf.zig | 5 +++++ lib/std/special/compiler_rt/floatuntidf_test.zig | 5 +++++ lib/std/special/compiler_rt/floatuntisf.zig | 5 +++++ lib/std/special/compiler_rt/floatuntisf_test.zig | 5 +++++ lib/std/special/compiler_rt/floatuntitf.zig | 5 +++++ lib/std/special/compiler_rt/floatuntitf_test.zig | 5 +++++ lib/std/special/compiler_rt/int.zig | 5 +++++ lib/std/special/compiler_rt/lshrdi3_test.zig | 5 +++++ lib/std/special/compiler_rt/lshrti3_test.zig | 5 +++++ lib/std/special/compiler_rt/modti3.zig | 5 +++++ lib/std/special/compiler_rt/modti3_test.zig | 5 +++++ lib/std/special/compiler_rt/mulXf3.zig | 5 +++++ lib/std/special/compiler_rt/mulXf3_test.zig | 5 +++++ lib/std/special/compiler_rt/muldi3.zig | 5 +++++ lib/std/special/compiler_rt/muldi3_test.zig | 5 +++++ lib/std/special/compiler_rt/mulodi4.zig | 5 +++++ lib/std/special/compiler_rt/mulodi4_test.zig | 5 +++++ lib/std/special/compiler_rt/muloti4.zig | 5 +++++ lib/std/special/compiler_rt/muloti4_test.zig | 5 +++++ lib/std/special/compiler_rt/multi3.zig | 5 +++++ lib/std/special/compiler_rt/multi3_test.zig | 5 +++++ lib/std/special/compiler_rt/negXf2.zig | 5 +++++ lib/std/special/compiler_rt/popcountdi2.zig | 5 +++++ lib/std/special/compiler_rt/popcountdi2_test.zig | 5 +++++ lib/std/special/compiler_rt/shift.zig | 5 +++++ lib/std/special/compiler_rt/stack_probe.zig | 5 +++++ lib/std/special/compiler_rt/truncXfYf2.zig | 5 +++++ lib/std/special/compiler_rt/truncXfYf2_test.zig | 5 +++++ lib/std/special/compiler_rt/udivmod.zig | 5 +++++ lib/std/special/compiler_rt/udivmoddi4_test.zig | 5 +++++ lib/std/special/compiler_rt/udivmodti4.zig | 5 +++++ lib/std/special/compiler_rt/udivmodti4_test.zig | 5 +++++ lib/std/special/compiler_rt/udivti3.zig | 5 +++++ lib/std/special/compiler_rt/umodti3.zig | 5 +++++ lib/std/special/init-exe/build.zig | 5 +++++ lib/std/special/init-exe/src/main.zig | 5 +++++ lib/std/special/init-lib/build.zig | 5 +++++ lib/std/special/init-lib/src/main.zig | 5 +++++ lib/std/special/test_runner.zig | 5 +++++ lib/std/spinlock.zig | 5 +++++ lib/std/start.zig | 5 +++++ lib/std/start_windows_tls.zig | 5 +++++ lib/std/std.zig | 5 +++++ lib/std/target.zig | 5 +++++ lib/std/target/aarch64.zig | 5 +++++ lib/std/target/amdgpu.zig | 5 +++++ lib/std/target/arm.zig | 5 +++++ lib/std/target/avr.zig | 5 +++++ lib/std/target/bpf.zig | 5 +++++ lib/std/target/hexagon.zig | 5 +++++ lib/std/target/mips.zig | 5 +++++ lib/std/target/msp430.zig | 5 +++++ lib/std/target/nvptx.zig | 5 +++++ lib/std/target/powerpc.zig | 5 +++++ lib/std/target/riscv.zig | 5 +++++ lib/std/target/sparc.zig | 5 +++++ lib/std/target/systemz.zig | 5 +++++ lib/std/target/wasm.zig | 5 +++++ lib/std/target/x86.zig | 5 +++++ lib/std/testing.zig | 5 +++++ lib/std/testing/failing_allocator.zig | 5 +++++ lib/std/thread.zig | 5 +++++ lib/std/time.zig | 5 +++++ lib/std/time/epoch.zig | 5 +++++ lib/std/unicode.zig | 5 +++++ lib/std/unicode/throughput_test.zig | 5 +++++ lib/std/valgrind.zig | 5 +++++ lib/std/valgrind/callgrind.zig | 5 +++++ lib/std/valgrind/memcheck.zig | 5 +++++ lib/std/zig.zig | 5 +++++ lib/std/zig/ast.zig | 5 +++++ lib/std/zig/cross_target.zig | 5 +++++ lib/std/zig/parse.zig | 5 +++++ lib/std/zig/parser_test.zig | 5 +++++ lib/std/zig/perf_test.zig | 5 +++++ lib/std/zig/render.zig | 5 +++++ lib/std/zig/string_literal.zig | 5 +++++ lib/std/zig/system.zig | 5 +++++ lib/std/zig/system/macos.zig | 5 +++++ lib/std/zig/system/x86.zig | 5 +++++ lib/std/zig/tokenizer.zig | 5 +++++ test/stack_traces.zig | 6 +++--- 487 files changed, 2433 insertions(+), 3 deletions(-) diff --git a/lib/std/array_list.zig b/lib/std/array_list.zig index e064b38566..a7432a30ae 100644 --- a/lib/std/array_list.zig +++ b/lib/std/array_list.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std.zig"); const debug = std.debug; const assert = debug.assert; diff --git a/lib/std/array_list_sentineled.zig b/lib/std/array_list_sentineled.zig index 828be7462f..d73367327e 100644 --- a/lib/std/array_list_sentineled.zig +++ b/lib/std/array_list_sentineled.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std.zig"); const debug = std.debug; const mem = std.mem; diff --git a/lib/std/ascii.zig b/lib/std/ascii.zig index 20bd9e47eb..25c34ef0cc 100644 --- a/lib/std/ascii.zig +++ b/lib/std/ascii.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Does NOT look at the locale the way C89's toupper(3), isspace() et cetera does. // I could have taken only a u7 to make this clear, but it would be slower // It is my opinion that encodings other than UTF-8 should not be supported. diff --git a/lib/std/atomic.zig b/lib/std/atomic.zig index 6f7b4fe75d..c465708ffa 100644 --- a/lib/std/atomic.zig +++ b/lib/std/atomic.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. pub const Stack = @import("atomic/stack.zig").Stack; pub const Queue = @import("atomic/queue.zig").Queue; pub const Int = @import("atomic/int.zig").Int; diff --git a/lib/std/atomic/int.zig b/lib/std/atomic/int.zig index 446059e7ef..ae8c8da778 100644 --- a/lib/std/atomic/int.zig +++ b/lib/std/atomic/int.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. /// Thread-safe, lock-free integer pub fn Int(comptime T: type) type { return struct { diff --git a/lib/std/atomic/queue.zig b/lib/std/atomic/queue.zig index 4df7522f29..dd139106b4 100644 --- a/lib/std/atomic/queue.zig +++ b/lib/std/atomic/queue.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const builtin = @import("builtin"); const assert = std.debug.assert; diff --git a/lib/std/atomic/stack.zig b/lib/std/atomic/stack.zig index db749ecaac..1e289bae70 100644 --- a/lib/std/atomic/stack.zig +++ b/lib/std/atomic/stack.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const assert = std.debug.assert; const builtin = @import("builtin"); const expect = std.testing.expect; diff --git a/lib/std/base64.zig b/lib/std/base64.zig index 39ad811eb6..0b91a1cf0a 100644 --- a/lib/std/base64.zig +++ b/lib/std/base64.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std.zig"); const assert = std.debug.assert; const testing = std.testing; diff --git a/lib/std/bloom_filter.zig b/lib/std/bloom_filter.zig index 80e168b8fd..34fa42fe00 100644 --- a/lib/std/bloom_filter.zig +++ b/lib/std/bloom_filter.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const builtin = @import("builtin"); const std = @import("std.zig"); const math = std.math; diff --git a/lib/std/buf_map.zig b/lib/std/buf_map.zig index 5cf4a54ed3..0fb2156c43 100644 --- a/lib/std/buf_map.zig +++ b/lib/std/buf_map.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std.zig"); const StringHashMap = std.StringHashMap; const mem = std.mem; diff --git a/lib/std/buf_set.zig b/lib/std/buf_set.zig index d8a0264bd7..1f5dda09c2 100644 --- a/lib/std/buf_set.zig +++ b/lib/std/buf_set.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std.zig"); const StringHashMap = std.StringHashMap; const mem = @import("mem.zig"); diff --git a/lib/std/build.zig b/lib/std/build.zig index be39e8010c..1673737bef 100644 --- a/lib/std/build.zig +++ b/lib/std/build.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std.zig"); const builtin = std.builtin; const io = std.io; diff --git a/lib/std/build/check_file.zig b/lib/std/build/check_file.zig index 2d8e58f92c..e1372c0fe9 100644 --- a/lib/std/build/check_file.zig +++ b/lib/std/build/check_file.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const build = std.build; const Step = build.Step; diff --git a/lib/std/build/emit_raw.zig b/lib/std/build/emit_raw.zig index 688a50e8fa..d499df1817 100644 --- a/lib/std/build/emit_raw.zig +++ b/lib/std/build/emit_raw.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std"); const Allocator = std.mem.Allocator; diff --git a/lib/std/build/fmt.zig b/lib/std/build/fmt.zig index 8fb12df824..8f0176c00e 100644 --- a/lib/std/build/fmt.zig +++ b/lib/std/build/fmt.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const build = @import("../build.zig"); const Step = build.Step; diff --git a/lib/std/build/run.zig b/lib/std/build/run.zig index 839e177edd..71e0d614f5 100644 --- a/lib/std/build/run.zig +++ b/lib/std/build/run.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const builtin = std.builtin; const build = std.build; diff --git a/lib/std/build/translate_c.zig b/lib/std/build/translate_c.zig index 1bc36ba8c4..8ca2b87209 100644 --- a/lib/std/build/translate_c.zig +++ b/lib/std/build/translate_c.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const build = std.build; const Step = build.Step; diff --git a/lib/std/build/write_file.zig b/lib/std/build/write_file.zig index ad0e13bed2..fe15e6e0e3 100644 --- a/lib/std/build/write_file.zig +++ b/lib/std/build/write_file.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const build = @import("../build.zig"); const Step = build.Step; diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig index 49edab1fd7..7f3fcfc96c 100644 --- a/lib/std/builtin.zig +++ b/lib/std/builtin.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. pub usingnamespace @import("builtin"); /// Deprecated: use `std.Target`. diff --git a/lib/std/c.zig b/lib/std/c.zig index e836a49c30..b4e5fc7392 100644 --- a/lib/std/c.zig +++ b/lib/std/c.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std"); const builtin = std.builtin; const page_size = std.mem.page_size; diff --git a/lib/std/c/ast.zig b/lib/std/c/ast.zig index 467050d57d..550ba52b84 100644 --- a/lib/std/c/ast.zig +++ b/lib/std/c/ast.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std"); const SegmentedList = std.SegmentedList; const Token = std.c.Token; diff --git a/lib/std/c/darwin.zig b/lib/std/c/darwin.zig index 2426638569..411aeb8056 100644 --- a/lib/std/c/darwin.zig +++ b/lib/std/c/darwin.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const assert = std.debug.assert; const builtin = @import("builtin"); diff --git a/lib/std/c/dragonfly.zig b/lib/std/c/dragonfly.zig index 0c859018be..2550cacc5b 100644 --- a/lib/std/c/dragonfly.zig +++ b/lib/std/c/dragonfly.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); usingnamespace std.c; extern "c" threadlocal var errno: c_int; diff --git a/lib/std/c/emscripten.zig b/lib/std/c/emscripten.zig index e91e1421c7..e94a6f1004 100644 --- a/lib/std/c/emscripten.zig +++ b/lib/std/c/emscripten.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. pub const pthread_mutex_t = extern struct { size: [__SIZEOF_PTHREAD_MUTEX_T]u8 align(4) = [_]u8{0} ** __SIZEOF_PTHREAD_MUTEX_T, }; diff --git a/lib/std/c/freebsd.zig b/lib/std/c/freebsd.zig index ea52c05f0b..1545a0e153 100644 --- a/lib/std/c/freebsd.zig +++ b/lib/std/c/freebsd.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); usingnamespace std.c; diff --git a/lib/std/c/fuchsia.zig b/lib/std/c/fuchsia.zig index 4f52b8900d..ceeb34a763 100644 --- a/lib/std/c/fuchsia.zig +++ b/lib/std/c/fuchsia.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. pub const pthread_mutex_t = extern struct { size: [__SIZEOF_PTHREAD_MUTEX_T]u8 align(@alignOf(usize)) = [_]u8{0} ** __SIZEOF_PTHREAD_MUTEX_T, }; diff --git a/lib/std/c/haiku.zig b/lib/std/c/haiku.zig index eb1e52a618..6b56e163c8 100644 --- a/lib/std/c/haiku.zig +++ b/lib/std/c/haiku.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. pub const pthread_mutex_t = extern struct { flags: u32 = 0, lock: i32 = 0, diff --git a/lib/std/c/hermit.zig b/lib/std/c/hermit.zig index 1730aa43ac..6762e60962 100644 --- a/lib/std/c/hermit.zig +++ b/lib/std/c/hermit.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. pub const pthread_mutex_t = extern struct { inner: usize = ~@as(usize, 0), }; diff --git a/lib/std/c/linux.zig b/lib/std/c/linux.zig index b9f29b211d..538fbdfd7d 100644 --- a/lib/std/c/linux.zig +++ b/lib/std/c/linux.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const builtin = @import("builtin"); const std = @import("../std.zig"); const maxInt = std.math.maxInt; diff --git a/lib/std/c/minix.zig b/lib/std/c/minix.zig index 98ec087a93..2bc1bac47a 100644 --- a/lib/std/c/minix.zig +++ b/lib/std/c/minix.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const builtin = @import("builtin"); pub const pthread_mutex_t = extern struct { size: [__SIZEOF_PTHREAD_MUTEX_T]u8 align(@alignOf(usize)) = [_]u8{0} ** __SIZEOF_PTHREAD_MUTEX_T, diff --git a/lib/std/c/netbsd.zig b/lib/std/c/netbsd.zig index 31adbb1f59..0eb8e32bae 100644 --- a/lib/std/c/netbsd.zig +++ b/lib/std/c/netbsd.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const builtin = std.builtin; diff --git a/lib/std/c/openbsd.zig b/lib/std/c/openbsd.zig index 22963b08c3..8a6439fc83 100644 --- a/lib/std/c/openbsd.zig +++ b/lib/std/c/openbsd.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. pub const pthread_mutex_t = extern struct { inner: ?*c_void = null, }; diff --git a/lib/std/c/parse.zig b/lib/std/c/parse.zig index 4c6c2fb462..d5b1a4a01e 100644 --- a/lib/std/c/parse.zig +++ b/lib/std/c/parse.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std"); const mem = std.mem; const assert = std.debug.assert; diff --git a/lib/std/c/solaris.zig b/lib/std/c/solaris.zig index 7c70a01fc4..49ce0886f7 100644 --- a/lib/std/c/solaris.zig +++ b/lib/std/c/solaris.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. pub const pthread_mutex_t = extern struct { __pthread_mutex_flag1: u16 = 0, __pthread_mutex_flag2: u8 = 0, diff --git a/lib/std/c/tokenizer.zig b/lib/std/c/tokenizer.zig index a3e6710e2f..9e9b5f4147 100644 --- a/lib/std/c/tokenizer.zig +++ b/lib/std/c/tokenizer.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std"); const mem = std.mem; diff --git a/lib/std/c/windows.zig b/lib/std/c/windows.zig index 35ca217131..cd39324192 100644 --- a/lib/std/c/windows.zig +++ b/lib/std/c/windows.zig @@ -1 +1,6 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. pub extern "c" fn _errno() *c_int; diff --git a/lib/std/cache_hash.zig b/lib/std/cache_hash.zig index 79597a2663..58c9f444f3 100644 --- a/lib/std/cache_hash.zig +++ b/lib/std/cache_hash.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std.zig"); const Blake3 = std.crypto.Blake3; const fs = std.fs; diff --git a/lib/std/child_process.zig b/lib/std/child_process.zig index 5754cc2d53..3254b958b7 100644 --- a/lib/std/child_process.zig +++ b/lib/std/child_process.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std.zig"); const cstr = std.cstr; const unicode = std.unicode; diff --git a/lib/std/coff.zig b/lib/std/coff.zig index 1ab88f6baf..cd567b3a6e 100644 --- a/lib/std/coff.zig +++ b/lib/std/coff.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const builtin = @import("builtin"); const std = @import("std.zig"); const io = std.io; diff --git a/lib/std/comptime_string_map.zig b/lib/std/comptime_string_map.zig index 8cc5cac130..ed647124a8 100644 --- a/lib/std/comptime_string_map.zig +++ b/lib/std/comptime_string_map.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std.zig"); const mem = std.mem; diff --git a/lib/std/crypto.zig b/lib/std/crypto.zig index c1909a1823..edca2bc2ff 100644 --- a/lib/std/crypto.zig +++ b/lib/std/crypto.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. pub const Md5 = @import("crypto/md5.zig").Md5; pub const Sha1 = @import("crypto/sha1.zig").Sha1; diff --git a/lib/std/crypto/25519/curve25519.zig b/lib/std/crypto/25519/curve25519.zig index 46d7b9a3a6..94490f674c 100644 --- a/lib/std/crypto/25519/curve25519.zig +++ b/lib/std/crypto/25519/curve25519.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std"); /// Group operations over Curve25519. diff --git a/lib/std/crypto/25519/ed25519.zig b/lib/std/crypto/25519/ed25519.zig index eb004d2607..935abaecb3 100644 --- a/lib/std/crypto/25519/ed25519.zig +++ b/lib/std/crypto/25519/ed25519.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std"); const fmt = std.fmt; const mem = std.mem; diff --git a/lib/std/crypto/25519/edwards25519.zig b/lib/std/crypto/25519/edwards25519.zig index 11f5963101..176e5337da 100644 --- a/lib/std/crypto/25519/edwards25519.zig +++ b/lib/std/crypto/25519/edwards25519.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std"); const fmt = std.fmt; diff --git a/lib/std/crypto/25519/field.zig b/lib/std/crypto/25519/field.zig index 85b8c68315..61929ba044 100644 --- a/lib/std/crypto/25519/field.zig +++ b/lib/std/crypto/25519/field.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std"); const readIntLittle = std.mem.readIntLittle; const writeIntLittle = std.mem.writeIntLittle; diff --git a/lib/std/crypto/25519/ristretto255.zig b/lib/std/crypto/25519/ristretto255.zig index a9636074a6..4e6494ed38 100644 --- a/lib/std/crypto/25519/ristretto255.zig +++ b/lib/std/crypto/25519/ristretto255.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std"); const fmt = std.fmt; diff --git a/lib/std/crypto/25519/scalar.zig b/lib/std/crypto/25519/scalar.zig index 3a3a29d4bc..2658126eeb 100644 --- a/lib/std/crypto/25519/scalar.zig +++ b/lib/std/crypto/25519/scalar.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std"); const mem = std.mem; diff --git a/lib/std/crypto/25519/x25519.zig b/lib/std/crypto/25519/x25519.zig index 4b5a8b8482..913140657d 100644 --- a/lib/std/crypto/25519/x25519.zig +++ b/lib/std/crypto/25519/x25519.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std"); const mem = std.mem; const fmt = std.fmt; diff --git a/lib/std/crypto/aes.zig b/lib/std/crypto/aes.zig index 25070b3a44..2174fbdd4f 100644 --- a/lib/std/crypto/aes.zig +++ b/lib/std/crypto/aes.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Based on Go stdlib implementation const std = @import("../std.zig"); diff --git a/lib/std/crypto/benchmark.zig b/lib/std/crypto/benchmark.zig index 267c2881b4..5c27f2f4f5 100644 --- a/lib/std/crypto/benchmark.zig +++ b/lib/std/crypto/benchmark.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // zig run benchmark.zig --release-fast --override-lib-dir .. const builtin = @import("builtin"); diff --git a/lib/std/crypto/blake2.zig b/lib/std/crypto/blake2.zig index ab44ca5298..9f5194994d 100644 --- a/lib/std/crypto/blake2.zig +++ b/lib/std/crypto/blake2.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const mem = @import("../mem.zig"); const builtin = @import("builtin"); const debug = @import("../debug.zig"); diff --git a/lib/std/crypto/blake3.zig b/lib/std/crypto/blake3.zig index 08479d65a5..08986965fc 100644 --- a/lib/std/crypto/blake3.zig +++ b/lib/std/crypto/blake3.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Translated from BLAKE3 reference implementation. // Source: https://github.com/BLAKE3-team/BLAKE3 diff --git a/lib/std/crypto/chacha20.zig b/lib/std/crypto/chacha20.zig index e51123eb81..d402eb6750 100644 --- a/lib/std/crypto/chacha20.zig +++ b/lib/std/crypto/chacha20.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Based on public domain Supercop by Daniel J. Bernstein const std = @import("../std.zig"); diff --git a/lib/std/crypto/gimli.zig b/lib/std/crypto/gimli.zig index 6861c72a63..33afae5f82 100644 --- a/lib/std/crypto/gimli.zig +++ b/lib/std/crypto/gimli.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Gimli is a 384-bit permutation designed to achieve high security with high // performance across a broad range of platforms, including 64-bit Intel/AMD // server CPUs, 64-bit and 32-bit ARM smartphone CPUs, 32-bit ARM diff --git a/lib/std/crypto/hmac.zig b/lib/std/crypto/hmac.zig index 69c1b86386..984dacc967 100644 --- a/lib/std/crypto/hmac.zig +++ b/lib/std/crypto/hmac.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const crypto = std.crypto; const debug = std.debug; diff --git a/lib/std/crypto/md5.zig b/lib/std/crypto/md5.zig index ac8948ca20..d578ba8b95 100644 --- a/lib/std/crypto/md5.zig +++ b/lib/std/crypto/md5.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const mem = @import("../mem.zig"); const math = @import("../math.zig"); const endian = @import("../endian.zig"); diff --git a/lib/std/crypto/poly1305.zig b/lib/std/crypto/poly1305.zig index fda978307d..2ed97f4c2e 100644 --- a/lib/std/crypto/poly1305.zig +++ b/lib/std/crypto/poly1305.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Translated from monocypher which is licensed under CC-0/BSD-3. // // https://monocypher.org/ diff --git a/lib/std/crypto/sha1.zig b/lib/std/crypto/sha1.zig index 6edf7b745e..7cb4fbcf36 100644 --- a/lib/std/crypto/sha1.zig +++ b/lib/std/crypto/sha1.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const mem = @import("../mem.zig"); const math = @import("../math.zig"); const endian = @import("../endian.zig"); diff --git a/lib/std/crypto/sha2.zig b/lib/std/crypto/sha2.zig index f004bceac3..cac18ca1f7 100644 --- a/lib/std/crypto/sha2.zig +++ b/lib/std/crypto/sha2.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const mem = @import("../mem.zig"); const math = @import("../math.zig"); const endian = @import("../endian.zig"); diff --git a/lib/std/crypto/sha3.zig b/lib/std/crypto/sha3.zig index 7c60674d75..03635ca553 100644 --- a/lib/std/crypto/sha3.zig +++ b/lib/std/crypto/sha3.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const mem = @import("../mem.zig"); const math = @import("../math.zig"); const endian = @import("../endian.zig"); diff --git a/lib/std/crypto/test.zig b/lib/std/crypto/test.zig index 61260c7e39..e4e34e543b 100644 --- a/lib/std/crypto/test.zig +++ b/lib/std/crypto/test.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const testing = std.testing; const mem = std.mem; diff --git a/lib/std/cstr.zig b/lib/std/cstr.zig index 9cb16b0ed3..4e11ad9201 100644 --- a/lib/std/cstr.zig +++ b/lib/std/cstr.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std.zig"); const builtin = @import("builtin"); const debug = std.debug; diff --git a/lib/std/debug.zig b/lib/std/debug.zig index fb1c3a3a88..be57c0b2fd 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std.zig"); const builtin = std.builtin; const math = std.math; diff --git a/lib/std/debug/leb128.zig b/lib/std/debug/leb128.zig index 7f43fdf494..eca777c1cf 100644 --- a/lib/std/debug/leb128.zig +++ b/lib/std/debug/leb128.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std"); const testing = std.testing; diff --git a/lib/std/dwarf.zig b/lib/std/dwarf.zig index 085e394a8f..37b76b1c14 100644 --- a/lib/std/dwarf.zig +++ b/lib/std/dwarf.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std.zig"); const builtin = @import("builtin"); const debug = std.debug; diff --git a/lib/std/dwarf_bits.zig b/lib/std/dwarf_bits.zig index a40fa8a277..bf9c97154c 100644 --- a/lib/std/dwarf_bits.zig +++ b/lib/std/dwarf_bits.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. pub const TAG_padding = 0x00; pub const TAG_array_type = 0x01; pub const TAG_class_type = 0x02; diff --git a/lib/std/dynamic_library.zig b/lib/std/dynamic_library.zig index 65c65292bc..238854f07f 100644 --- a/lib/std/dynamic_library.zig +++ b/lib/std/dynamic_library.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const builtin = @import("builtin"); const std = @import("std.zig"); diff --git a/lib/std/elf.zig b/lib/std/elf.zig index a241ef9537..79303e7163 100644 --- a/lib/std/elf.zig +++ b/lib/std/elf.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std.zig"); const builtin = std.builtin; const io = std.io; diff --git a/lib/std/event.zig b/lib/std/event.zig index d042e2ad9b..42f3176a1b 100644 --- a/lib/std/event.zig +++ b/lib/std/event.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. pub const Channel = @import("event/channel.zig").Channel; pub const Future = @import("event/future.zig").Future; pub const Group = @import("event/group.zig").Group; diff --git a/lib/std/event/batch.zig b/lib/std/event/batch.zig index 8f2954d85b..2ace2f7914 100644 --- a/lib/std/event/batch.zig +++ b/lib/std/event/batch.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const testing = std.testing; diff --git a/lib/std/event/channel.zig b/lib/std/event/channel.zig index 5aef0bb3ba..de5b2c67ab 100644 --- a/lib/std/event/channel.zig +++ b/lib/std/event/channel.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const builtin = @import("builtin"); const assert = std.debug.assert; diff --git a/lib/std/event/future.zig b/lib/std/event/future.zig index 5de22c574c..c9777288e4 100644 --- a/lib/std/event/future.zig +++ b/lib/std/event/future.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const assert = std.debug.assert; const testing = std.testing; diff --git a/lib/std/event/group.zig b/lib/std/event/group.zig index 0dc6550218..e91adbbe8c 100644 --- a/lib/std/event/group.zig +++ b/lib/std/event/group.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const builtin = @import("builtin"); const Lock = std.event.Lock; diff --git a/lib/std/event/lock.zig b/lib/std/event/lock.zig index 179b881c9c..d27a12aef8 100644 --- a/lib/std/event/lock.zig +++ b/lib/std/event/lock.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const builtin = @import("builtin"); const assert = std.debug.assert; diff --git a/lib/std/event/locked.zig b/lib/std/event/locked.zig index e921803447..9a53116fd6 100644 --- a/lib/std/event/locked.zig +++ b/lib/std/event/locked.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const Lock = std.event.Lock; diff --git a/lib/std/event/loop.zig b/lib/std/event/loop.zig index 0abcad32e1..b34ad8c940 100644 --- a/lib/std/event/loop.zig +++ b/lib/std/event/loop.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const builtin = @import("builtin"); const root = @import("root"); diff --git a/lib/std/event/rwlock.zig b/lib/std/event/rwlock.zig index 7a47c27dd8..3e3928d379 100644 --- a/lib/std/event/rwlock.zig +++ b/lib/std/event/rwlock.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const builtin = @import("builtin"); const assert = std.debug.assert; diff --git a/lib/std/event/rwlocked.zig b/lib/std/event/rwlocked.zig index 9a569e8f1f..4fb25b59a1 100644 --- a/lib/std/event/rwlocked.zig +++ b/lib/std/event/rwlocked.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const RwLock = std.event.RwLock; diff --git a/lib/std/fifo.zig b/lib/std/fifo.zig index 1edb413f47..c92da615f9 100644 --- a/lib/std/fifo.zig +++ b/lib/std/fifo.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // FIFO of fixed size items // Usually used for e.g. byte buffers diff --git a/lib/std/fmt.zig b/lib/std/fmt.zig index 6dbef5db67..16d0eaa07a 100644 --- a/lib/std/fmt.zig +++ b/lib/std/fmt.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std.zig"); const math = std.math; const assert = std.debug.assert; diff --git a/lib/std/fmt/errol.zig b/lib/std/fmt/errol.zig index e697b7d42f..6a0a2256d8 100644 --- a/lib/std/fmt/errol.zig +++ b/lib/std/fmt/errol.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const enum3 = @import("errol/enum3.zig").enum3; const enum3_data = @import("errol/enum3.zig").enum3_data; diff --git a/lib/std/fmt/errol/enum3.zig b/lib/std/fmt/errol/enum3.zig index c27753483d..9dbe27c072 100644 --- a/lib/std/fmt/errol/enum3.zig +++ b/lib/std/fmt/errol/enum3.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. pub const enum3 = [_]u64{ 0x4e2e2785c3a2a20b, 0x240a28877a09a4e1, diff --git a/lib/std/fmt/errol/lookup.zig b/lib/std/fmt/errol/lookup.zig index 2fb6b167bb..85a4234bca 100644 --- a/lib/std/fmt/errol/lookup.zig +++ b/lib/std/fmt/errol/lookup.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. pub const HP = struct { val: f64, off: f64, diff --git a/lib/std/fmt/parse_float.zig b/lib/std/fmt/parse_float.zig index 2ab245043c..69557714f6 100644 --- a/lib/std/fmt/parse_float.zig +++ b/lib/std/fmt/parse_float.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Adapted from https://github.com/grzegorz-kraszewski/stringtofloat. // MIT License diff --git a/lib/std/fs.zig b/lib/std/fs.zig index a492a43499..df368e070b 100644 --- a/lib/std/fs.zig +++ b/lib/std/fs.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const builtin = @import("builtin"); const std = @import("std.zig"); const os = std.os; diff --git a/lib/std/fs/file.zig b/lib/std/fs/file.zig index ce71571c9f..3e22528ea9 100644 --- a/lib/std/fs/file.zig +++ b/lib/std/fs/file.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const builtin = @import("builtin"); const os = std.os; diff --git a/lib/std/fs/get_app_data_dir.zig b/lib/std/fs/get_app_data_dir.zig index c68232d0b5..17d365f684 100644 --- a/lib/std/fs/get_app_data_dir.zig +++ b/lib/std/fs/get_app_data_dir.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const builtin = @import("builtin"); const unicode = std.unicode; diff --git a/lib/std/fs/path.zig b/lib/std/fs/path.zig index 2176498feb..5e418e8e5c 100644 --- a/lib/std/fs/path.zig +++ b/lib/std/fs/path.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const builtin = @import("builtin"); const std = @import("../std.zig"); const debug = std.debug; diff --git a/lib/std/fs/test.zig b/lib/std/fs/test.zig index 9e6f4bb3ac..4be64ef225 100644 --- a/lib/std/fs/test.zig +++ b/lib/std/fs/test.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const testing = std.testing; const builtin = std.builtin; diff --git a/lib/std/fs/wasi.zig b/lib/std/fs/wasi.zig index 149ede252d..cad86e2314 100644 --- a/lib/std/fs/wasi.zig +++ b/lib/std/fs/wasi.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std"); const os = std.os; const mem = std.mem; diff --git a/lib/std/fs/watch.zig b/lib/std/fs/watch.zig index 635818b702..269cdec6d8 100644 --- a/lib/std/fs/watch.zig +++ b/lib/std/fs/watch.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const builtin = @import("builtin"); const event = std.event; diff --git a/lib/std/hash.zig b/lib/std/hash.zig index c51353b328..1cc078959c 100644 --- a/lib/std/hash.zig +++ b/lib/std/hash.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const adler = @import("hash/adler.zig"); pub const Adler32 = adler.Adler32; diff --git a/lib/std/hash/adler.zig b/lib/std/hash/adler.zig index 173a07596c..a3fc915f76 100644 --- a/lib/std/hash/adler.zig +++ b/lib/std/hash/adler.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Adler32 checksum. // // https://tools.ietf.org/html/rfc1950#section-9 diff --git a/lib/std/hash/auto_hash.zig b/lib/std/hash/auto_hash.zig index 996d6ede38..2905a6af13 100644 --- a/lib/std/hash/auto_hash.zig +++ b/lib/std/hash/auto_hash.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std"); const builtin = @import("builtin"); const assert = std.debug.assert; diff --git a/lib/std/hash/benchmark.zig b/lib/std/hash/benchmark.zig index 5f8a15831c..c23743160b 100644 --- a/lib/std/hash/benchmark.zig +++ b/lib/std/hash/benchmark.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // zig run benchmark.zig --release-fast --override-lib-dir .. const builtin = @import("builtin"); diff --git a/lib/std/hash/cityhash.zig b/lib/std/hash/cityhash.zig index 73b94acbd2..38e62d88ef 100644 --- a/lib/std/hash/cityhash.zig +++ b/lib/std/hash/cityhash.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std"); const builtin = @import("builtin"); diff --git a/lib/std/hash/crc.zig b/lib/std/hash/crc.zig index 506d8c8aed..37695df8b3 100644 --- a/lib/std/hash/crc.zig +++ b/lib/std/hash/crc.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // There are two implementations of CRC32 implemented with the following key characteristics: // // - Crc32WithPoly uses 8Kb of tables but is ~10x faster than the small method. diff --git a/lib/std/hash/fnv.zig b/lib/std/hash/fnv.zig index 8094134e19..81285be9a8 100644 --- a/lib/std/hash/fnv.zig +++ b/lib/std/hash/fnv.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // FNV1a - Fowler-Noll-Vo hash function // // FNV1a is a fast, non-cryptographic hash function with fairly good distribution properties. diff --git a/lib/std/hash/murmur.zig b/lib/std/hash/murmur.zig index effa13ad69..d4204509c1 100644 --- a/lib/std/hash/murmur.zig +++ b/lib/std/hash/murmur.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std"); const builtin = @import("builtin"); const testing = std.testing; diff --git a/lib/std/hash/siphash.zig b/lib/std/hash/siphash.zig index ebafdd6855..107ea19728 100644 --- a/lib/std/hash/siphash.zig +++ b/lib/std/hash/siphash.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Siphash // // SipHash is a moderately fast, non-cryptographic keyed hash function designed for resistance diff --git a/lib/std/hash/wyhash.zig b/lib/std/hash/wyhash.zig index ed2f03350c..12b400c38f 100644 --- a/lib/std/hash/wyhash.zig +++ b/lib/std/hash/wyhash.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std"); const mem = std.mem; diff --git a/lib/std/hash_map.zig b/lib/std/hash_map.zig index d52a337422..8966737a0c 100644 --- a/lib/std/hash_map.zig +++ b/lib/std/hash_map.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std.zig"); const debug = std.debug; const assert = debug.assert; diff --git a/lib/std/heap.zig b/lib/std/heap.zig index 4a2837d408..d6977f2f9c 100644 --- a/lib/std/heap.zig +++ b/lib/std/heap.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std.zig"); const root = @import("root"); const debug = std.debug; diff --git a/lib/std/heap/arena_allocator.zig b/lib/std/heap/arena_allocator.zig index 191f0c19e9..e4bce8087f 100644 --- a/lib/std/heap/arena_allocator.zig +++ b/lib/std/heap/arena_allocator.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const assert = std.debug.assert; const mem = std.mem; diff --git a/lib/std/heap/general_purpose_allocator.zig b/lib/std/heap/general_purpose_allocator.zig index cb53af113e..5d8de5845d 100644 --- a/lib/std/heap/general_purpose_allocator.zig +++ b/lib/std/heap/general_purpose_allocator.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. //! # General Purpose Allocator //! //! ## Design Priorities diff --git a/lib/std/heap/logging_allocator.zig b/lib/std/heap/logging_allocator.zig index eff20a5c46..0e3e460b89 100644 --- a/lib/std/heap/logging_allocator.zig +++ b/lib/std/heap/logging_allocator.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const Allocator = std.mem.Allocator; diff --git a/lib/std/http.zig b/lib/std/http.zig index acb005a75f..2b8495db71 100644 --- a/lib/std/http.zig +++ b/lib/std/http.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. test "std.http" { _ = @import("http/headers.zig"); } diff --git a/lib/std/http/headers.zig b/lib/std/http/headers.zig index 86aff5f364..8c80af512f 100644 --- a/lib/std/http/headers.zig +++ b/lib/std/http/headers.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // HTTP Header data structure/type // Based on lua-http's http.header module // diff --git a/lib/std/io.zig b/lib/std/io.zig index 6d613b514a..e30ed1fa92 100644 --- a/lib/std/io.zig +++ b/lib/std/io.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std.zig"); const builtin = @import("builtin"); const root = @import("root"); diff --git a/lib/std/io/bit_in_stream.zig b/lib/std/io/bit_in_stream.zig index 7759927e6d..a027deb802 100644 --- a/lib/std/io/bit_in_stream.zig +++ b/lib/std/io/bit_in_stream.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. /// Deprecated: use `std.io.bit_reader.BitReader` pub const BitInStream = @import("./bit_reader.zig").BitReader; diff --git a/lib/std/io/bit_out_stream.zig b/lib/std/io/bit_out_stream.zig index 20a3795d59..171fb542da 100644 --- a/lib/std/io/bit_out_stream.zig +++ b/lib/std/io/bit_out_stream.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. /// Deprecated: use `std.io.bit_writer.BitWriter` pub const BitOutStream = @import("./bit_writer.zig").BitWriter; diff --git a/lib/std/io/bit_reader.zig b/lib/std/io/bit_reader.zig index fbdf7fbe78..4ea2ed75a0 100644 --- a/lib/std/io/bit_reader.zig +++ b/lib/std/io/bit_reader.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const builtin = std.builtin; const io = std.io; diff --git a/lib/std/io/bit_writer.zig b/lib/std/io/bit_writer.zig index 7c1d3e5dba..de95e54404 100644 --- a/lib/std/io/bit_writer.zig +++ b/lib/std/io/bit_writer.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const builtin = std.builtin; const io = std.io; diff --git a/lib/std/io/buffered_atomic_file.zig b/lib/std/io/buffered_atomic_file.zig index 3a3deb43bf..6284d4e44f 100644 --- a/lib/std/io/buffered_atomic_file.zig +++ b/lib/std/io/buffered_atomic_file.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const mem = std.mem; const fs = std.fs; diff --git a/lib/std/io/buffered_in_stream.zig b/lib/std/io/buffered_in_stream.zig index 42ec0a5d6a..f055978152 100644 --- a/lib/std/io/buffered_in_stream.zig +++ b/lib/std/io/buffered_in_stream.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. /// Deprecated: use `std.io.buffered_reader.BufferedReader` pub const BufferedInStream = @import("./buffered_reader.zig").BufferedReader; diff --git a/lib/std/io/buffered_out_stream.zig b/lib/std/io/buffered_out_stream.zig index 6f9efa9575..5f1eaa6faf 100644 --- a/lib/std/io/buffered_out_stream.zig +++ b/lib/std/io/buffered_out_stream.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. /// Deprecated: use `std.io.buffered_writer.BufferedWriter` pub const BufferedOutStream = @import("./buffered_writer.zig").BufferedWriter; diff --git a/lib/std/io/buffered_reader.zig b/lib/std/io/buffered_reader.zig index 73d74b465f..58c4f3b4fc 100644 --- a/lib/std/io/buffered_reader.zig +++ b/lib/std/io/buffered_reader.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const io = std.io; const assert = std.debug.assert; diff --git a/lib/std/io/buffered_writer.zig b/lib/std/io/buffered_writer.zig index a970f899d6..bee3ff48af 100644 --- a/lib/std/io/buffered_writer.zig +++ b/lib/std/io/buffered_writer.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const io = std.io; diff --git a/lib/std/io/c_out_stream.zig b/lib/std/io/c_out_stream.zig index e10795ae0a..69f4d9f5af 100644 --- a/lib/std/io/c_out_stream.zig +++ b/lib/std/io/c_out_stream.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. /// Deprecated: use `std.io.c_writer.CWriter` pub const COutStream = @import("./c_writer.zig").CWriter; diff --git a/lib/std/io/c_writer.zig b/lib/std/io/c_writer.zig index 6292450223..9fd10d827e 100644 --- a/lib/std/io/c_writer.zig +++ b/lib/std/io/c_writer.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const builtin = std.builtin; const io = std.io; diff --git a/lib/std/io/counting_out_stream.zig b/lib/std/io/counting_out_stream.zig index 5b0b35b4c5..fecdf8adb0 100644 --- a/lib/std/io/counting_out_stream.zig +++ b/lib/std/io/counting_out_stream.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. /// Deprecated: use `std.io.counting_writer.CountingWriter` pub const CountingOutStream = @import("./counting_writer.zig").CountingWriter; diff --git a/lib/std/io/counting_writer.zig b/lib/std/io/counting_writer.zig index c0cd53c7ee..aefd459b90 100644 --- a/lib/std/io/counting_writer.zig +++ b/lib/std/io/counting_writer.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const io = std.io; const testing = std.testing; diff --git a/lib/std/io/fixed_buffer_stream.zig b/lib/std/io/fixed_buffer_stream.zig index 32625f3b7a..b1d2aaf89a 100644 --- a/lib/std/io/fixed_buffer_stream.zig +++ b/lib/std/io/fixed_buffer_stream.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const io = std.io; const testing = std.testing; diff --git a/lib/std/io/in_stream.zig b/lib/std/io/in_stream.zig index c58f5d7b77..4583591d42 100644 --- a/lib/std/io/in_stream.zig +++ b/lib/std/io/in_stream.zig @@ -1,2 +1,7 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. /// Deprecated: use `std.io.reader.Reader` pub const InStream = @import("./reader.zig").Reader; diff --git a/lib/std/io/multi_out_stream.zig b/lib/std/io/multi_out_stream.zig index fa7a60de51..7b96cc3d15 100644 --- a/lib/std/io/multi_out_stream.zig +++ b/lib/std/io/multi_out_stream.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. /// Deprecated: use `std.io.multi_writer.MultiWriter` pub const MultiOutStream = @import("./multi_writer.zig").MultiWriter; diff --git a/lib/std/io/multi_writer.zig b/lib/std/io/multi_writer.zig index e63940bff7..7ee43eddeb 100644 --- a/lib/std/io/multi_writer.zig +++ b/lib/std/io/multi_writer.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const io = std.io; const testing = std.testing; diff --git a/lib/std/io/out_stream.zig b/lib/std/io/out_stream.zig index a3fe3e32b5..c937ccf16a 100644 --- a/lib/std/io/out_stream.zig +++ b/lib/std/io/out_stream.zig @@ -1,2 +1,7 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. /// Deprecated: use `std.io.writer.Writer` pub const OutStream = @import("./writer.zig").Writer; diff --git a/lib/std/io/peek_stream.zig b/lib/std/io/peek_stream.zig index 08e940c6ec..82554d05ca 100644 --- a/lib/std/io/peek_stream.zig +++ b/lib/std/io/peek_stream.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const io = std.io; const mem = std.mem; diff --git a/lib/std/io/reader.zig b/lib/std/io/reader.zig index 4c682e8aba..07327a431d 100644 --- a/lib/std/io/reader.zig +++ b/lib/std/io/reader.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const builtin = std.builtin; const math = std.math; diff --git a/lib/std/io/seekable_stream.zig b/lib/std/io/seekable_stream.zig index 1aa653dbe5..15e537baa2 100644 --- a/lib/std/io/seekable_stream.zig +++ b/lib/std/io/seekable_stream.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); pub fn SeekableStream( diff --git a/lib/std/io/serialization.zig b/lib/std/io/serialization.zig index 317dde6417..4f8c149b47 100644 --- a/lib/std/io/serialization.zig +++ b/lib/std/io/serialization.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const builtin = std.builtin; const io = std.io; diff --git a/lib/std/io/stream_source.zig b/lib/std/io/stream_source.zig index 63d9ea9f2e..3bfe0d2e64 100644 --- a/lib/std/io/stream_source.zig +++ b/lib/std/io/stream_source.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const io = std.io; const testing = std.testing; diff --git a/lib/std/io/test.zig b/lib/std/io/test.zig index 779f52a2aa..ecad26a448 100644 --- a/lib/std/io/test.zig +++ b/lib/std/io/test.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std"); const builtin = std.builtin; const io = std.io; diff --git a/lib/std/io/writer.zig b/lib/std/io/writer.zig index a98e3b1acd..39729ef0a2 100644 --- a/lib/std/io/writer.zig +++ b/lib/std/io/writer.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const builtin = std.builtin; const mem = std.mem; diff --git a/lib/std/json.zig b/lib/std/json.zig index 59c765ac42..2f8a70d0ef 100644 --- a/lib/std/json.zig +++ b/lib/std/json.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // JSON parser conforming to RFC8259. // // https://tools.ietf.org/html/rfc8259 diff --git a/lib/std/json/test.zig b/lib/std/json/test.zig index ed7454cce3..3a7c25e383 100644 --- a/lib/std/json/test.zig +++ b/lib/std/json/test.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // RFC 8529 conformance tests. // // Tests are taken from https://github.com/nst/JSONTestSuite diff --git a/lib/std/json/write_stream.zig b/lib/std/json/write_stream.zig index 778173cc24..59bebd69d3 100644 --- a/lib/std/json/write_stream.zig +++ b/lib/std/json/write_stream.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const assert = std.debug.assert; const maxInt = std.math.maxInt; diff --git a/lib/std/linked_list.zig b/lib/std/linked_list.zig index 39f52021b2..e99f3d8725 100644 --- a/lib/std/linked_list.zig +++ b/lib/std/linked_list.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std.zig"); const debug = std.debug; const assert = debug.assert; diff --git a/lib/std/log.zig b/lib/std/log.zig index 8d5554aa46..50bdfdc068 100644 --- a/lib/std/log.zig +++ b/lib/std/log.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std.zig"); const builtin = std.builtin; const root = @import("root"); diff --git a/lib/std/macho.zig b/lib/std/macho.zig index 950283b59f..99a8cd776c 100644 --- a/lib/std/macho.zig +++ b/lib/std/macho.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. pub const mach_header = extern struct { magic: u32, cputype: cpu_type_t, diff --git a/lib/std/math.zig b/lib/std/math.zig index 2c9065a89e..a76f0a391d 100644 --- a/lib/std/math.zig +++ b/lib/std/math.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std.zig"); const assert = std.debug.assert; const testing = std.testing; diff --git a/lib/std/math/acos.zig b/lib/std/math/acos.zig index cdd86601fd..f085680176 100644 --- a/lib/std/math/acos.zig +++ b/lib/std/math/acos.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Ported from musl, which is licensed under the MIT license: // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT // diff --git a/lib/std/math/acosh.zig b/lib/std/math/acosh.zig index 9a594f9cc4..76d6edff3e 100644 --- a/lib/std/math/acosh.zig +++ b/lib/std/math/acosh.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Ported from musl, which is licensed under the MIT license: // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT // diff --git a/lib/std/math/asin.zig b/lib/std/math/asin.zig index 4cff69fc1b..a4a19c74d9 100644 --- a/lib/std/math/asin.zig +++ b/lib/std/math/asin.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Ported from musl, which is licensed under the MIT license: // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT // diff --git a/lib/std/math/asinh.zig b/lib/std/math/asinh.zig index 940b953d06..dc97ac3082 100644 --- a/lib/std/math/asinh.zig +++ b/lib/std/math/asinh.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Ported from musl, which is licensed under the MIT license: // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT // diff --git a/lib/std/math/atan.zig b/lib/std/math/atan.zig index 9342b6ed59..390e10b3c4 100644 --- a/lib/std/math/atan.zig +++ b/lib/std/math/atan.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Ported from musl, which is licensed under the MIT license: // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT // diff --git a/lib/std/math/atan2.zig b/lib/std/math/atan2.zig index 68e381607d..6540eced84 100644 --- a/lib/std/math/atan2.zig +++ b/lib/std/math/atan2.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Ported from musl, which is licensed under the MIT license: // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT // diff --git a/lib/std/math/atanh.zig b/lib/std/math/atanh.zig index de742bd4cd..abd573bb1a 100644 --- a/lib/std/math/atanh.zig +++ b/lib/std/math/atanh.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Ported from musl, which is licensed under the MIT license: // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT // diff --git a/lib/std/math/big.zig b/lib/std/math/big.zig index ab651c05c6..6246a4fb8b 100644 --- a/lib/std/math/big.zig +++ b/lib/std/math/big.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const assert = std.debug.assert; diff --git a/lib/std/math/big/int.zig b/lib/std/math/big/int.zig index 92b3f80429..adb5848931 100644 --- a/lib/std/math/big/int.zig +++ b/lib/std/math/big/int.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../../std.zig"); const math = std.math; const Limb = std.math.big.Limb; diff --git a/lib/std/math/big/int_test.zig b/lib/std/math/big/int_test.zig index a86b55d2de..5931767a82 100644 --- a/lib/std/math/big/int_test.zig +++ b/lib/std/math/big/int_test.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../../std.zig"); const mem = std.mem; const testing = std.testing; diff --git a/lib/std/math/big/rational.zig b/lib/std/math/big/rational.zig index 6f62a462b8..e83139cf37 100644 --- a/lib/std/math/big/rational.zig +++ b/lib/std/math/big/rational.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../../std.zig"); const debug = std.debug; const math = std.math; diff --git a/lib/std/math/cbrt.zig b/lib/std/math/cbrt.zig index 42163b96dc..0d097a0c75 100644 --- a/lib/std/math/cbrt.zig +++ b/lib/std/math/cbrt.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Ported from musl, which is licensed under the MIT license: // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT // diff --git a/lib/std/math/ceil.zig b/lib/std/math/ceil.zig index 39de46f361..ac04c9a8cc 100644 --- a/lib/std/math/ceil.zig +++ b/lib/std/math/ceil.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Ported from musl, which is licensed under the MIT license: // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT // diff --git a/lib/std/math/complex.zig b/lib/std/math/complex.zig index 8bff2313fc..ec76f425eb 100644 --- a/lib/std/math/complex.zig +++ b/lib/std/math/complex.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const testing = std.testing; const math = std.math; diff --git a/lib/std/math/complex/abs.zig b/lib/std/math/complex/abs.zig index db31aef42a..db9c43e89d 100644 --- a/lib/std/math/complex/abs.zig +++ b/lib/std/math/complex/abs.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../../std.zig"); const testing = std.testing; const math = std.math; diff --git a/lib/std/math/complex/acos.zig b/lib/std/math/complex/acos.zig index 072fd77f08..1372c280e2 100644 --- a/lib/std/math/complex/acos.zig +++ b/lib/std/math/complex/acos.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../../std.zig"); const testing = std.testing; const math = std.math; diff --git a/lib/std/math/complex/acosh.zig b/lib/std/math/complex/acosh.zig index 59117a8b27..49d9fd0302 100644 --- a/lib/std/math/complex/acosh.zig +++ b/lib/std/math/complex/acosh.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../../std.zig"); const testing = std.testing; const math = std.math; diff --git a/lib/std/math/complex/arg.zig b/lib/std/math/complex/arg.zig index 6cf959a081..7cfbc8bd0f 100644 --- a/lib/std/math/complex/arg.zig +++ b/lib/std/math/complex/arg.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../../std.zig"); const testing = std.testing; const math = std.math; diff --git a/lib/std/math/complex/asin.zig b/lib/std/math/complex/asin.zig index 9f7cd396aa..5c5de3ff4f 100644 --- a/lib/std/math/complex/asin.zig +++ b/lib/std/math/complex/asin.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../../std.zig"); const testing = std.testing; const math = std.math; diff --git a/lib/std/math/complex/asinh.zig b/lib/std/math/complex/asinh.zig index 0c3c2bd115..a3f5f04fbc 100644 --- a/lib/std/math/complex/asinh.zig +++ b/lib/std/math/complex/asinh.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../../std.zig"); const testing = std.testing; const math = std.math; diff --git a/lib/std/math/complex/atan.zig b/lib/std/math/complex/atan.zig index 98bde3e125..e5c49976ac 100644 --- a/lib/std/math/complex/atan.zig +++ b/lib/std/math/complex/atan.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Ported from musl, which is licensed under the MIT license: // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT // diff --git a/lib/std/math/complex/atanh.zig b/lib/std/math/complex/atanh.zig index a07c2969e4..4ab2410258 100644 --- a/lib/std/math/complex/atanh.zig +++ b/lib/std/math/complex/atanh.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../../std.zig"); const testing = std.testing; const math = std.math; diff --git a/lib/std/math/complex/conj.zig b/lib/std/math/complex/conj.zig index 42a34e7dfc..159469da86 100644 --- a/lib/std/math/complex/conj.zig +++ b/lib/std/math/complex/conj.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../../std.zig"); const testing = std.testing; const math = std.math; diff --git a/lib/std/math/complex/cos.zig b/lib/std/math/complex/cos.zig index 9daf89c730..559613cc34 100644 --- a/lib/std/math/complex/cos.zig +++ b/lib/std/math/complex/cos.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../../std.zig"); const testing = std.testing; const math = std.math; diff --git a/lib/std/math/complex/cosh.zig b/lib/std/math/complex/cosh.zig index bd51629bd4..f668cb60ce 100644 --- a/lib/std/math/complex/cosh.zig +++ b/lib/std/math/complex/cosh.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Ported from musl, which is licensed under the MIT license: // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT // diff --git a/lib/std/math/complex/exp.zig b/lib/std/math/complex/exp.zig index 6f6061a947..3ad51fe06f 100644 --- a/lib/std/math/complex/exp.zig +++ b/lib/std/math/complex/exp.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Ported from musl, which is licensed under the MIT license: // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT // diff --git a/lib/std/math/complex/ldexp.zig b/lib/std/math/complex/ldexp.zig index c23b9b346e..b1cf8a0e42 100644 --- a/lib/std/math/complex/ldexp.zig +++ b/lib/std/math/complex/ldexp.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Ported from musl, which is licensed under the MIT license: // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT // diff --git a/lib/std/math/complex/log.zig b/lib/std/math/complex/log.zig index ec02c6c325..cb719f4b31 100644 --- a/lib/std/math/complex/log.zig +++ b/lib/std/math/complex/log.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../../std.zig"); const testing = std.testing; const math = std.math; diff --git a/lib/std/math/complex/pow.zig b/lib/std/math/complex/pow.zig index a2480453fc..7be38cadf2 100644 --- a/lib/std/math/complex/pow.zig +++ b/lib/std/math/complex/pow.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../../std.zig"); const testing = std.testing; const math = std.math; diff --git a/lib/std/math/complex/proj.zig b/lib/std/math/complex/proj.zig index e208ae0370..67f087f8ba 100644 --- a/lib/std/math/complex/proj.zig +++ b/lib/std/math/complex/proj.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../../std.zig"); const testing = std.testing; const math = std.math; diff --git a/lib/std/math/complex/sin.zig b/lib/std/math/complex/sin.zig index 1b10f8fca6..2f33e13354 100644 --- a/lib/std/math/complex/sin.zig +++ b/lib/std/math/complex/sin.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../../std.zig"); const testing = std.testing; const math = std.math; diff --git a/lib/std/math/complex/sinh.zig b/lib/std/math/complex/sinh.zig index 32f2a730fb..3242adef79 100644 --- a/lib/std/math/complex/sinh.zig +++ b/lib/std/math/complex/sinh.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Ported from musl, which is licensed under the MIT license: // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT // diff --git a/lib/std/math/complex/sqrt.zig b/lib/std/math/complex/sqrt.zig index 0edb02a7a9..8abb9a6064 100644 --- a/lib/std/math/complex/sqrt.zig +++ b/lib/std/math/complex/sqrt.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Ported from musl, which is licensed under the MIT license: // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT // diff --git a/lib/std/math/complex/tan.zig b/lib/std/math/complex/tan.zig index 050898c573..adcda786c1 100644 --- a/lib/std/math/complex/tan.zig +++ b/lib/std/math/complex/tan.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../../std.zig"); const testing = std.testing; const math = std.math; diff --git a/lib/std/math/complex/tanh.zig b/lib/std/math/complex/tanh.zig index 1d614cca58..fd63114982 100644 --- a/lib/std/math/complex/tanh.zig +++ b/lib/std/math/complex/tanh.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Ported from musl, which is licensed under the MIT license: // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT // diff --git a/lib/std/math/copysign.zig b/lib/std/math/copysign.zig index e874da0bb9..1547382cbd 100644 --- a/lib/std/math/copysign.zig +++ b/lib/std/math/copysign.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Ported from musl, which is licensed under the MIT license: // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT // diff --git a/lib/std/math/cos.zig b/lib/std/math/cos.zig index df5c0a53be..3d282c82e1 100644 --- a/lib/std/math/cos.zig +++ b/lib/std/math/cos.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Ported from go, which is licensed under a BSD-3 license. // https://golang.org/LICENSE // diff --git a/lib/std/math/cosh.zig b/lib/std/math/cosh.zig index bab47dcdbd..221ebcf089 100644 --- a/lib/std/math/cosh.zig +++ b/lib/std/math/cosh.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Ported from musl, which is licensed under the MIT license: // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT // diff --git a/lib/std/math/exp.zig b/lib/std/math/exp.zig index c84d929adf..36d18f83b2 100644 --- a/lib/std/math/exp.zig +++ b/lib/std/math/exp.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Ported from musl, which is licensed under the MIT license: // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT // diff --git a/lib/std/math/exp2.zig b/lib/std/math/exp2.zig index da391189b2..b97690948e 100644 --- a/lib/std/math/exp2.zig +++ b/lib/std/math/exp2.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Ported from musl, which is licensed under the MIT license: // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT // diff --git a/lib/std/math/expm1.zig b/lib/std/math/expm1.zig index 80cdefae20..98e66b17d5 100644 --- a/lib/std/math/expm1.zig +++ b/lib/std/math/expm1.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Ported from musl, which is licensed under the MIT license: // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT // diff --git a/lib/std/math/expo2.zig b/lib/std/math/expo2.zig index f404570fb6..a81c9920e0 100644 --- a/lib/std/math/expo2.zig +++ b/lib/std/math/expo2.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Ported from musl, which is licensed under the MIT license: // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT // diff --git a/lib/std/math/fabs.zig b/lib/std/math/fabs.zig index ca91f594fd..f263bfbc58 100644 --- a/lib/std/math/fabs.zig +++ b/lib/std/math/fabs.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Ported from musl, which is licensed under the MIT license: // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT // diff --git a/lib/std/math/floor.zig b/lib/std/math/floor.zig index 3a71cc7cdf..7b61980a5e 100644 --- a/lib/std/math/floor.zig +++ b/lib/std/math/floor.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Ported from musl, which is licensed under the MIT license: // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT // diff --git a/lib/std/math/fma.zig b/lib/std/math/fma.zig index 014593cda5..6993fc9786 100644 --- a/lib/std/math/fma.zig +++ b/lib/std/math/fma.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Ported from musl, which is licensed under the MIT license: // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT // diff --git a/lib/std/math/frexp.zig b/lib/std/math/frexp.zig index 0e4558dc37..2d99c85c51 100644 --- a/lib/std/math/frexp.zig +++ b/lib/std/math/frexp.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Ported from musl, which is licensed under the MIT license: // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT // diff --git a/lib/std/math/hypot.zig b/lib/std/math/hypot.zig index 59116014b3..595563076b 100644 --- a/lib/std/math/hypot.zig +++ b/lib/std/math/hypot.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Ported from musl, which is licensed under the MIT license: // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT // diff --git a/lib/std/math/ilogb.zig b/lib/std/math/ilogb.zig index 748cf9ea0d..a6fb031973 100644 --- a/lib/std/math/ilogb.zig +++ b/lib/std/math/ilogb.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Ported from musl, which is licensed under the MIT license: // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT // diff --git a/lib/std/math/inf.zig b/lib/std/math/inf.zig index 86ff245533..f2e0283e03 100644 --- a/lib/std/math/inf.zig +++ b/lib/std/math/inf.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const math = std.math; diff --git a/lib/std/math/isfinite.zig b/lib/std/math/isfinite.zig index 0681eae0b7..938c495d65 100644 --- a/lib/std/math/isfinite.zig +++ b/lib/std/math/isfinite.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const math = std.math; const expect = std.testing.expect; diff --git a/lib/std/math/isinf.zig b/lib/std/math/isinf.zig index 19357d89d1..2ecd9c2b9c 100644 --- a/lib/std/math/isinf.zig +++ b/lib/std/math/isinf.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const math = std.math; const expect = std.testing.expect; diff --git a/lib/std/math/isnan.zig b/lib/std/math/isnan.zig index 797c115d1d..fc58e7334c 100644 --- a/lib/std/math/isnan.zig +++ b/lib/std/math/isnan.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const math = std.math; const expect = std.testing.expect; diff --git a/lib/std/math/isnormal.zig b/lib/std/math/isnormal.zig index a3144f2784..b9ff515bdc 100644 --- a/lib/std/math/isnormal.zig +++ b/lib/std/math/isnormal.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const math = std.math; const expect = std.testing.expect; diff --git a/lib/std/math/ln.zig b/lib/std/math/ln.zig index 99e54c4cc7..60a2f528aa 100644 --- a/lib/std/math/ln.zig +++ b/lib/std/math/ln.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Ported from musl, which is licensed under the MIT license: // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT // diff --git a/lib/std/math/log.zig b/lib/std/math/log.zig index 6f5025cd50..4286b74960 100644 --- a/lib/std/math/log.zig +++ b/lib/std/math/log.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Ported from musl, which is licensed under the MIT license: // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT // diff --git a/lib/std/math/log10.zig b/lib/std/math/log10.zig index e55bd8c1e8..d7d192a564 100644 --- a/lib/std/math/log10.zig +++ b/lib/std/math/log10.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Ported from musl, which is licensed under the MIT license: // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT // diff --git a/lib/std/math/log1p.zig b/lib/std/math/log1p.zig index e24ba8d84d..5a87e92313 100644 --- a/lib/std/math/log1p.zig +++ b/lib/std/math/log1p.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Ported from musl, which is licensed under the MIT license: // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT // diff --git a/lib/std/math/log2.zig b/lib/std/math/log2.zig index 95d06a2b60..2b9fbe3d84 100644 --- a/lib/std/math/log2.zig +++ b/lib/std/math/log2.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Ported from musl, which is licensed under the MIT license: // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT // diff --git a/lib/std/math/modf.zig b/lib/std/math/modf.zig index 5ab5318a79..830b99257e 100644 --- a/lib/std/math/modf.zig +++ b/lib/std/math/modf.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Ported from musl, which is licensed under the MIT license: // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT // diff --git a/lib/std/math/nan.zig b/lib/std/math/nan.zig index 5a01a5b3bd..b8e3b517e2 100644 --- a/lib/std/math/nan.zig +++ b/lib/std/math/nan.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const math = @import("../math.zig"); /// Returns the nan representation for type T. diff --git a/lib/std/math/pow.zig b/lib/std/math/pow.zig index cb39dd59e3..30b52acbda 100644 --- a/lib/std/math/pow.zig +++ b/lib/std/math/pow.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Ported from go, which is licensed under a BSD-3 license. // https://golang.org/LICENSE // diff --git a/lib/std/math/powi.zig b/lib/std/math/powi.zig index ce3a3713e3..660aeddc05 100644 --- a/lib/std/math/powi.zig +++ b/lib/std/math/powi.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Based on Rust, which is licensed under the MIT license. // https://github.com/rust-lang/rust/blob/360432f1e8794de58cd94f34c9c17ad65871e5b5/LICENSE-MIT // diff --git a/lib/std/math/round.zig b/lib/std/math/round.zig index 854adee4ba..7798e6157a 100644 --- a/lib/std/math/round.zig +++ b/lib/std/math/round.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Ported from musl, which is licensed under the MIT license: // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT // diff --git a/lib/std/math/scalbn.zig b/lib/std/math/scalbn.zig index 71a8110ce7..7243084dd4 100644 --- a/lib/std/math/scalbn.zig +++ b/lib/std/math/scalbn.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Ported from musl, which is licensed under the MIT license: // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT // diff --git a/lib/std/math/signbit.zig b/lib/std/math/signbit.zig index 49397f7bd4..defd02aa3a 100644 --- a/lib/std/math/signbit.zig +++ b/lib/std/math/signbit.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const math = std.math; const expect = std.testing.expect; diff --git a/lib/std/math/sin.zig b/lib/std/math/sin.zig index df3b294ca6..c7db4f8623 100644 --- a/lib/std/math/sin.zig +++ b/lib/std/math/sin.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Ported from go, which is licensed under a BSD-3 license. // https://golang.org/LICENSE // diff --git a/lib/std/math/sinh.zig b/lib/std/math/sinh.zig index 26e0e05f38..1246c89cc0 100644 --- a/lib/std/math/sinh.zig +++ b/lib/std/math/sinh.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Ported from musl, which is licensed under the MIT license: // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT // diff --git a/lib/std/math/sqrt.zig b/lib/std/math/sqrt.zig index 2f0d251432..34851ca647 100644 --- a/lib/std/math/sqrt.zig +++ b/lib/std/math/sqrt.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const math = std.math; const expect = std.testing.expect; diff --git a/lib/std/math/tan.zig b/lib/std/math/tan.zig index 2cd5a407df..5e5a80e15d 100644 --- a/lib/std/math/tan.zig +++ b/lib/std/math/tan.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Ported from go, which is licensed under a BSD-3 license. // https://golang.org/LICENSE // diff --git a/lib/std/math/tanh.zig b/lib/std/math/tanh.zig index 7697db5271..3abc5d4d75 100644 --- a/lib/std/math/tanh.zig +++ b/lib/std/math/tanh.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Ported from musl, which is licensed under the MIT license: // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT // diff --git a/lib/std/math/trunc.zig b/lib/std/math/trunc.zig index df24b77111..85bc68f226 100644 --- a/lib/std/math/trunc.zig +++ b/lib/std/math/trunc.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Ported from musl, which is licensed under the MIT license: // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT // diff --git a/lib/std/mem.zig b/lib/std/mem.zig index 1ba64f47fa..33977e3ce3 100644 --- a/lib/std/mem.zig +++ b/lib/std/mem.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std.zig"); const debug = std.debug; const assert = debug.assert; diff --git a/lib/std/mem/Allocator.zig b/lib/std/mem/Allocator.zig index e73050165e..bb59de2a7e 100644 --- a/lib/std/mem/Allocator.zig +++ b/lib/std/mem/Allocator.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. //! The standard memory allocation interface. const std = @import("../std.zig"); diff --git a/lib/std/meta.zig b/lib/std/meta.zig index 6340a44fae..aaa8e7ca78 100644 --- a/lib/std/meta.zig +++ b/lib/std/meta.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std.zig"); const builtin = @import("builtin"); const debug = std.debug; diff --git a/lib/std/meta/trailer_flags.zig b/lib/std/meta/trailer_flags.zig index 0da7ca815a..6e1d8bea32 100644 --- a/lib/std/meta/trailer_flags.zig +++ b/lib/std/meta/trailer_flags.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const meta = std.meta; const testing = std.testing; diff --git a/lib/std/meta/trait.zig b/lib/std/meta/trait.zig index f04d6353c6..2455542e4f 100644 --- a/lib/std/meta/trait.zig +++ b/lib/std/meta/trait.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const builtin = std.builtin; const mem = std.mem; diff --git a/lib/std/mutex.zig b/lib/std/mutex.zig index 3361a42e21..706685d1fa 100644 --- a/lib/std/mutex.zig +++ b/lib/std/mutex.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std.zig"); const builtin = @import("builtin"); const os = std.os; diff --git a/lib/std/net.zig b/lib/std/net.zig index 0cd34376e1..10e5b371f8 100644 --- a/lib/std/net.zig +++ b/lib/std/net.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std.zig"); const builtin = @import("builtin"); const assert = std.debug.assert; diff --git a/lib/std/net/test.zig b/lib/std/net/test.zig index 89b84ac83d..815ee81d7f 100644 --- a/lib/std/net/test.zig +++ b/lib/std/net/test.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const builtin = std.builtin; const net = std.net; diff --git a/lib/std/once.zig b/lib/std/once.zig index cf42d021a2..6e0e4867d8 100644 --- a/lib/std/once.zig +++ b/lib/std/once.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std.zig"); const builtin = std.builtin; const testing = std.testing; diff --git a/lib/std/os.zig b/lib/std/os.zig index 6f58d7f077..e8431c386b 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // This file contains thin wrappers around OS-specific APIs, with these // specific goals in mind: // * Convert "errno"-style error codes into Zig errors. diff --git a/lib/std/os/bits.zig b/lib/std/os/bits.zig index 38f019d775..177b7daad2 100644 --- a/lib/std/os/bits.zig +++ b/lib/std/os/bits.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. //! Platform-dependent types and values that are used along with OS-specific APIs. //! These are imported into `std.c`, `std.os`, and `std.os.linux`. //! Root source files can define `os.bits` and these will additionally be added diff --git a/lib/std/os/bits/darwin.zig b/lib/std/os/bits/darwin.zig index 4581490e6f..375127f278 100644 --- a/lib/std/os/bits/darwin.zig +++ b/lib/std/os/bits/darwin.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../../std.zig"); const assert = std.debug.assert; const maxInt = std.math.maxInt; diff --git a/lib/std/os/bits/dragonfly.zig b/lib/std/os/bits/dragonfly.zig index df22678323..8b6d6be212 100644 --- a/lib/std/os/bits/dragonfly.zig +++ b/lib/std/os/bits/dragonfly.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../../std.zig"); const maxInt = std.math.maxInt; diff --git a/lib/std/os/bits/freebsd.zig b/lib/std/os/bits/freebsd.zig index 3622fb7641..22edf4b9d1 100644 --- a/lib/std/os/bits/freebsd.zig +++ b/lib/std/os/bits/freebsd.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../../std.zig"); const maxInt = std.math.maxInt; diff --git a/lib/std/os/bits/linux.zig b/lib/std/os/bits/linux.zig index 4ad1fc7de4..4fa8a02d3d 100644 --- a/lib/std/os/bits/linux.zig +++ b/lib/std/os/bits/linux.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const builtin = @import("builtin"); const std = @import("../../std.zig"); const maxInt = std.math.maxInt; diff --git a/lib/std/os/bits/linux/arm-eabi.zig b/lib/std/os/bits/linux/arm-eabi.zig index b32d3ef9d4..36f1f4f442 100644 --- a/lib/std/os/bits/linux/arm-eabi.zig +++ b/lib/std/os/bits/linux/arm-eabi.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // arm-eabi-specific declarations that are intended to be imported into the POSIX namespace. const std = @import("../../../std.zig"); const linux = std.os.linux; diff --git a/lib/std/os/bits/linux/arm64.zig b/lib/std/os/bits/linux/arm64.zig index 0745f19fb0..6ecbcc9ae1 100644 --- a/lib/std/os/bits/linux/arm64.zig +++ b/lib/std/os/bits/linux/arm64.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // arm64-specific declarations that are intended to be imported into the POSIX namespace. // This does include Linux-only APIs. diff --git a/lib/std/os/bits/linux/bpf.zig b/lib/std/os/bits/linux/bpf.zig index 150d3e9135..e86e082ff7 100644 --- a/lib/std/os/bits/linux/bpf.zig +++ b/lib/std/os/bits/linux/bpf.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. usingnamespace std.os; const std = @import("../../../std.zig"); diff --git a/lib/std/os/bits/linux/errno-generic.zig b/lib/std/os/bits/linux/errno-generic.zig index 53af9cc5e5..a99f20a1a8 100644 --- a/lib/std/os/bits/linux/errno-generic.zig +++ b/lib/std/os/bits/linux/errno-generic.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. /// Operation not permitted pub const EPERM = 1; diff --git a/lib/std/os/bits/linux/errno-mips.zig b/lib/std/os/bits/linux/errno-mips.zig index 81cbde4af4..1258863086 100644 --- a/lib/std/os/bits/linux/errno-mips.zig +++ b/lib/std/os/bits/linux/errno-mips.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. pub const EPERM = 1; pub const ENOENT = 2; pub const ESRCH = 3; diff --git a/lib/std/os/bits/linux/i386.zig b/lib/std/os/bits/linux/i386.zig index 868e4f537b..a560c14613 100644 --- a/lib/std/os/bits/linux/i386.zig +++ b/lib/std/os/bits/linux/i386.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // i386-specific declarations that are intended to be imported into the POSIX namespace. // This does include Linux-only APIs. diff --git a/lib/std/os/bits/linux/mips.zig b/lib/std/os/bits/linux/mips.zig index 5946e821ad..4b81c6e622 100644 --- a/lib/std/os/bits/linux/mips.zig +++ b/lib/std/os/bits/linux/mips.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../../../std.zig"); const linux = std.os.linux; const socklen_t = linux.socklen_t; diff --git a/lib/std/os/bits/linux/netlink.zig b/lib/std/os/bits/linux/netlink.zig index f3d000e785..3e75733b9a 100644 --- a/lib/std/os/bits/linux/netlink.zig +++ b/lib/std/os/bits/linux/netlink.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. usingnamespace @import("../linux.zig"); /// Routing/device hook diff --git a/lib/std/os/bits/linux/riscv64.zig b/lib/std/os/bits/linux/riscv64.zig index 220e673622..c4b0f044f2 100644 --- a/lib/std/os/bits/linux/riscv64.zig +++ b/lib/std/os/bits/linux/riscv64.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // riscv64-specific declarations that are intended to be imported into the POSIX namespace. const std = @import("../../../std.zig"); const uid_t = std.os.linux.uid_t; diff --git a/lib/std/os/bits/linux/x86_64.zig b/lib/std/os/bits/linux/x86_64.zig index c87bca6f8e..0800feeddf 100644 --- a/lib/std/os/bits/linux/x86_64.zig +++ b/lib/std/os/bits/linux/x86_64.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // x86-64-specific declarations that are intended to be imported into the POSIX namespace. const std = @import("../../../std.zig"); const pid_t = linux.pid_t; diff --git a/lib/std/os/bits/netbsd.zig b/lib/std/os/bits/netbsd.zig index 91e101620f..d628bf4566 100644 --- a/lib/std/os/bits/netbsd.zig +++ b/lib/std/os/bits/netbsd.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../../std.zig"); const builtin = std.builtin; const maxInt = std.math.maxInt; diff --git a/lib/std/os/bits/wasi.zig b/lib/std/os/bits/wasi.zig index 270345c53b..f768b5522b 100644 --- a/lib/std/os/bits/wasi.zig +++ b/lib/std/os/bits/wasi.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Convenience types and consts used by std.os module pub const STDIN_FILENO = 0; pub const STDOUT_FILENO = 1; diff --git a/lib/std/os/bits/windows.zig b/lib/std/os/bits/windows.zig index 5316a048cc..836d273c1c 100644 --- a/lib/std/os/bits/windows.zig +++ b/lib/std/os/bits/windows.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // The reference for these types and values is Microsoft Windows's ucrt (Universal C RunTime). usingnamespace @import("../windows/bits.zig"); diff --git a/lib/std/os/darwin.zig b/lib/std/os/darwin.zig index d3e9cefb86..1bd983398b 100644 --- a/lib/std/os/darwin.zig +++ b/lib/std/os/darwin.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const builtin = @import("builtin"); const std = @import("../std.zig"); pub usingnamespace std.c; diff --git a/lib/std/os/dragonfly.zig b/lib/std/os/dragonfly.zig index 5f9684b96d..a713a009ad 100644 --- a/lib/std/os/dragonfly.zig +++ b/lib/std/os/dragonfly.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); pub usingnamespace std.c; pub usingnamespace @import("bits.zig"); diff --git a/lib/std/os/freebsd.zig b/lib/std/os/freebsd.zig index 5f9684b96d..a713a009ad 100644 --- a/lib/std/os/freebsd.zig +++ b/lib/std/os/freebsd.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); pub usingnamespace std.c; pub usingnamespace @import("bits.zig"); diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig index 7fe0ba00ae..ae66e619c3 100644 --- a/lib/std/os/linux.zig +++ b/lib/std/os/linux.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // This file provides the system interface functions for Linux matching those // that are provided by libc, whether or not libc is linked. The following // abstractions are made: diff --git a/lib/std/os/linux/arm-eabi.zig b/lib/std/os/linux/arm-eabi.zig index 352afeeb04..a72799a26a 100644 --- a/lib/std/os/linux/arm-eabi.zig +++ b/lib/std/os/linux/arm-eabi.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. usingnamespace @import("../bits.zig"); pub fn syscall0(number: SYS) usize { diff --git a/lib/std/os/linux/arm64.zig b/lib/std/os/linux/arm64.zig index 49548522ec..6727cbce8e 100644 --- a/lib/std/os/linux/arm64.zig +++ b/lib/std/os/linux/arm64.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. usingnamespace @import("../bits.zig"); pub fn syscall0(number: SYS) usize { diff --git a/lib/std/os/linux/i386.zig b/lib/std/os/linux/i386.zig index a4fdf8a346..ed5bc88f0f 100644 --- a/lib/std/os/linux/i386.zig +++ b/lib/std/os/linux/i386.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. usingnamespace @import("../bits.zig"); pub fn syscall0(number: SYS) usize { diff --git a/lib/std/os/linux/mips.zig b/lib/std/os/linux/mips.zig index 5b5c1e1f34..ad673e06f9 100644 --- a/lib/std/os/linux/mips.zig +++ b/lib/std/os/linux/mips.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. usingnamespace @import("../bits.zig"); pub fn syscall0(number: SYS) usize { diff --git a/lib/std/os/linux/riscv64.zig b/lib/std/os/linux/riscv64.zig index 39cc13f5b6..034340d0b3 100644 --- a/lib/std/os/linux/riscv64.zig +++ b/lib/std/os/linux/riscv64.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. usingnamespace @import("../bits.zig"); pub fn syscall0(number: SYS) usize { diff --git a/lib/std/os/linux/test.zig b/lib/std/os/linux/test.zig index aa6655b7d8..7599cfc395 100644 --- a/lib/std/os/linux/test.zig +++ b/lib/std/os/linux/test.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../../std.zig"); const builtin = @import("builtin"); const linux = std.os.linux; diff --git a/lib/std/os/linux/tls.zig b/lib/std/os/linux/tls.zig index 8cba45d4b3..b10dae14d7 100644 --- a/lib/std/os/linux/tls.zig +++ b/lib/std/os/linux/tls.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std"); const builtin = std.builtin; const os = std.os; diff --git a/lib/std/os/linux/vdso.zig b/lib/std/os/linux/vdso.zig index 27c56d6c42..776737d928 100644 --- a/lib/std/os/linux/vdso.zig +++ b/lib/std/os/linux/vdso.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../../std.zig"); const elf = std.elf; const linux = std.os.linux; diff --git a/lib/std/os/linux/x86_64.zig b/lib/std/os/linux/x86_64.zig index 33d2b66670..8987e1aab3 100644 --- a/lib/std/os/linux/x86_64.zig +++ b/lib/std/os/linux/x86_64.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. usingnamespace @import("../bits.zig"); pub fn syscall0(number: SYS) usize { diff --git a/lib/std/os/netbsd.zig b/lib/std/os/netbsd.zig index 5f9684b96d..a713a009ad 100644 --- a/lib/std/os/netbsd.zig +++ b/lib/std/os/netbsd.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); pub usingnamespace std.c; pub usingnamespace @import("bits.zig"); diff --git a/lib/std/os/test.zig b/lib/std/os/test.zig index dc8a89c688..93c4ee0403 100644 --- a/lib/std/os/test.zig +++ b/lib/std/os/test.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const os = std.os; const testing = std.testing; diff --git a/lib/std/os/uefi.zig b/lib/std/os/uefi.zig index c037075cd8..0127033db2 100644 --- a/lib/std/os/uefi.zig +++ b/lib/std/os/uefi.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. /// A protocol is an interface identified by a GUID. pub const protocols = @import("uefi/protocols.zig"); diff --git a/lib/std/os/uefi/protocols.zig b/lib/std/os/uefi/protocols.zig index 353c628a05..1519092b84 100644 --- a/lib/std/os/uefi/protocols.zig +++ b/lib/std/os/uefi/protocols.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. pub const LoadedImageProtocol = @import("protocols/loaded_image_protocol.zig").LoadedImageProtocol; pub const loaded_image_device_path_protocol_guid = @import("protocols/loaded_image_protocol.zig").loaded_image_device_path_protocol_guid; diff --git a/lib/std/os/uefi/protocols/absolute_pointer_protocol.zig b/lib/std/os/uefi/protocols/absolute_pointer_protocol.zig index a06a19c1a4..3ec6aab5b9 100644 --- a/lib/std/os/uefi/protocols/absolute_pointer_protocol.zig +++ b/lib/std/os/uefi/protocols/absolute_pointer_protocol.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const uefi = @import("std").os.uefi; const Event = uefi.Event; const Guid = uefi.Guid; diff --git a/lib/std/os/uefi/protocols/device_path_protocol.zig b/lib/std/os/uefi/protocols/device_path_protocol.zig index f359484eb9..1a998f0f78 100644 --- a/lib/std/os/uefi/protocols/device_path_protocol.zig +++ b/lib/std/os/uefi/protocols/device_path_protocol.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const uefi = @import("std").os.uefi; const Guid = uefi.Guid; diff --git a/lib/std/os/uefi/protocols/edid_active_protocol.zig b/lib/std/os/uefi/protocols/edid_active_protocol.zig index fcdef78d83..dc8057b4f8 100644 --- a/lib/std/os/uefi/protocols/edid_active_protocol.zig +++ b/lib/std/os/uefi/protocols/edid_active_protocol.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const uefi = @import("std").os.uefi; const Guid = uefi.Guid; diff --git a/lib/std/os/uefi/protocols/edid_discovered_protocol.zig b/lib/std/os/uefi/protocols/edid_discovered_protocol.zig index 00b59cb6c8..1ed2b6277d 100644 --- a/lib/std/os/uefi/protocols/edid_discovered_protocol.zig +++ b/lib/std/os/uefi/protocols/edid_discovered_protocol.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const uefi = @import("std").os.uefi; const Guid = uefi.Guid; diff --git a/lib/std/os/uefi/protocols/edid_override_protocol.zig b/lib/std/os/uefi/protocols/edid_override_protocol.zig index efe73982e9..83260f7b88 100644 --- a/lib/std/os/uefi/protocols/edid_override_protocol.zig +++ b/lib/std/os/uefi/protocols/edid_override_protocol.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const uefi = @import("std").os.uefi; const Guid = uefi.Guid; const Handle = uefi.Handle; diff --git a/lib/std/os/uefi/protocols/file_protocol.zig b/lib/std/os/uefi/protocols/file_protocol.zig index eacd777008..ce34a2d6e5 100644 --- a/lib/std/os/uefi/protocols/file_protocol.zig +++ b/lib/std/os/uefi/protocols/file_protocol.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const uefi = @import("std").os.uefi; const Guid = uefi.Guid; const Time = uefi.Time; diff --git a/lib/std/os/uefi/protocols/graphics_output_protocol.zig b/lib/std/os/uefi/protocols/graphics_output_protocol.zig index 1ceccce0bf..3ec1c39ab8 100644 --- a/lib/std/os/uefi/protocols/graphics_output_protocol.zig +++ b/lib/std/os/uefi/protocols/graphics_output_protocol.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const uefi = @import("std").os.uefi; const Guid = uefi.Guid; const Status = uefi.Status; diff --git a/lib/std/os/uefi/protocols/hii.zig b/lib/std/os/uefi/protocols/hii.zig index 750e004c8b..960402828e 100644 --- a/lib/std/os/uefi/protocols/hii.zig +++ b/lib/std/os/uefi/protocols/hii.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const uefi = @import("std").os.uefi; const Guid = uefi.Guid; diff --git a/lib/std/os/uefi/protocols/hii_database_protocol.zig b/lib/std/os/uefi/protocols/hii_database_protocol.zig index e34f72c2f3..d0b16ff943 100644 --- a/lib/std/os/uefi/protocols/hii_database_protocol.zig +++ b/lib/std/os/uefi/protocols/hii_database_protocol.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const uefi = @import("std").os.uefi; const Guid = uefi.Guid; const Status = uefi.Status; diff --git a/lib/std/os/uefi/protocols/hii_popup_protocol.zig b/lib/std/os/uefi/protocols/hii_popup_protocol.zig index 2e4f621b41..1f5c5ce0f4 100644 --- a/lib/std/os/uefi/protocols/hii_popup_protocol.zig +++ b/lib/std/os/uefi/protocols/hii_popup_protocol.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const uefi = @import("std").os.uefi; const Guid = uefi.Guid; const Status = uefi.Status; diff --git a/lib/std/os/uefi/protocols/ip6_config_protocol.zig b/lib/std/os/uefi/protocols/ip6_config_protocol.zig index 99ba76aa17..16002f62a6 100644 --- a/lib/std/os/uefi/protocols/ip6_config_protocol.zig +++ b/lib/std/os/uefi/protocols/ip6_config_protocol.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const uefi = @import("std").os.uefi; const Guid = uefi.Guid; const Event = uefi.Event; diff --git a/lib/std/os/uefi/protocols/ip6_protocol.zig b/lib/std/os/uefi/protocols/ip6_protocol.zig index b39ae60b2a..578a3cfb01 100644 --- a/lib/std/os/uefi/protocols/ip6_protocol.zig +++ b/lib/std/os/uefi/protocols/ip6_protocol.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const uefi = @import("std").os.uefi; const Guid = uefi.Guid; const Event = uefi.Event; diff --git a/lib/std/os/uefi/protocols/ip6_service_binding_protocol.zig b/lib/std/os/uefi/protocols/ip6_service_binding_protocol.zig index 97ab1a431c..59605cc11b 100644 --- a/lib/std/os/uefi/protocols/ip6_service_binding_protocol.zig +++ b/lib/std/os/uefi/protocols/ip6_service_binding_protocol.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const uefi = @import("std").os.uefi; const Handle = uefi.Handle; const Guid = uefi.Guid; diff --git a/lib/std/os/uefi/protocols/loaded_image_protocol.zig b/lib/std/os/uefi/protocols/loaded_image_protocol.zig index b8afcb1063..96aa10f08d 100644 --- a/lib/std/os/uefi/protocols/loaded_image_protocol.zig +++ b/lib/std/os/uefi/protocols/loaded_image_protocol.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const uefi = @import("std").os.uefi; const Guid = uefi.Guid; const Handle = uefi.Handle; diff --git a/lib/std/os/uefi/protocols/managed_network_protocol.zig b/lib/std/os/uefi/protocols/managed_network_protocol.zig index 34ef6c40fa..9202c6f139 100644 --- a/lib/std/os/uefi/protocols/managed_network_protocol.zig +++ b/lib/std/os/uefi/protocols/managed_network_protocol.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const uefi = @import("std").os.uefi; const Guid = uefi.Guid; const Event = uefi.Event; diff --git a/lib/std/os/uefi/protocols/managed_network_service_binding_protocol.zig b/lib/std/os/uefi/protocols/managed_network_service_binding_protocol.zig index e9657e4456..0c684336c8 100644 --- a/lib/std/os/uefi/protocols/managed_network_service_binding_protocol.zig +++ b/lib/std/os/uefi/protocols/managed_network_service_binding_protocol.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const uefi = @import("std").os.uefi; const Handle = uefi.Handle; const Guid = uefi.Guid; diff --git a/lib/std/os/uefi/protocols/rng_protocol.zig b/lib/std/os/uefi/protocols/rng_protocol.zig index a32b202f44..713b76b371 100644 --- a/lib/std/os/uefi/protocols/rng_protocol.zig +++ b/lib/std/os/uefi/protocols/rng_protocol.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const uefi = @import("std").os.uefi; const Guid = uefi.Guid; const Status = uefi.Status; diff --git a/lib/std/os/uefi/protocols/shell_parameters_protocol.zig b/lib/std/os/uefi/protocols/shell_parameters_protocol.zig index afbd26e939..7ec46b732c 100644 --- a/lib/std/os/uefi/protocols/shell_parameters_protocol.zig +++ b/lib/std/os/uefi/protocols/shell_parameters_protocol.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const uefi = @import("std").os.uefi; const Guid = uefi.Guid; const FileHandle = uefi.FileHandle; diff --git a/lib/std/os/uefi/protocols/simple_file_system_protocol.zig b/lib/std/os/uefi/protocols/simple_file_system_protocol.zig index 119c1e6587..946c88a89b 100644 --- a/lib/std/os/uefi/protocols/simple_file_system_protocol.zig +++ b/lib/std/os/uefi/protocols/simple_file_system_protocol.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const uefi = @import("std").os.uefi; const Guid = uefi.Guid; const FileProtocol = uefi.protocols.FileProtocol; diff --git a/lib/std/os/uefi/protocols/simple_network_protocol.zig b/lib/std/os/uefi/protocols/simple_network_protocol.zig index ac7446036e..f74f11a857 100644 --- a/lib/std/os/uefi/protocols/simple_network_protocol.zig +++ b/lib/std/os/uefi/protocols/simple_network_protocol.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const uefi = @import("std").os.uefi; const Event = uefi.Event; const Guid = uefi.Guid; diff --git a/lib/std/os/uefi/protocols/simple_pointer_protocol.zig b/lib/std/os/uefi/protocols/simple_pointer_protocol.zig index d217ab5930..5f8ca7569e 100644 --- a/lib/std/os/uefi/protocols/simple_pointer_protocol.zig +++ b/lib/std/os/uefi/protocols/simple_pointer_protocol.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const uefi = @import("std").os.uefi; const Event = uefi.Event; const Guid = uefi.Guid; diff --git a/lib/std/os/uefi/protocols/simple_text_input_ex_protocol.zig b/lib/std/os/uefi/protocols/simple_text_input_ex_protocol.zig index 4a2b098e61..096013bfb0 100644 --- a/lib/std/os/uefi/protocols/simple_text_input_ex_protocol.zig +++ b/lib/std/os/uefi/protocols/simple_text_input_ex_protocol.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const uefi = @import("std").os.uefi; const Event = uefi.Event; const Guid = uefi.Guid; diff --git a/lib/std/os/uefi/protocols/simple_text_input_protocol.zig b/lib/std/os/uefi/protocols/simple_text_input_protocol.zig index 58ed071331..d093186532 100644 --- a/lib/std/os/uefi/protocols/simple_text_input_protocol.zig +++ b/lib/std/os/uefi/protocols/simple_text_input_protocol.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const uefi = @import("std").os.uefi; const Event = uefi.Event; const Guid = uefi.Guid; diff --git a/lib/std/os/uefi/protocols/simple_text_output_protocol.zig b/lib/std/os/uefi/protocols/simple_text_output_protocol.zig index 84f540cb78..f9bbc37140 100644 --- a/lib/std/os/uefi/protocols/simple_text_output_protocol.zig +++ b/lib/std/os/uefi/protocols/simple_text_output_protocol.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const uefi = @import("std").os.uefi; const Guid = uefi.Guid; const Status = uefi.Status; diff --git a/lib/std/os/uefi/protocols/udp6_protocol.zig b/lib/std/os/uefi/protocols/udp6_protocol.zig index 46c76beaa6..50b7dae7c4 100644 --- a/lib/std/os/uefi/protocols/udp6_protocol.zig +++ b/lib/std/os/uefi/protocols/udp6_protocol.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const uefi = @import("std").os.uefi; const Guid = uefi.Guid; const Event = uefi.Event; diff --git a/lib/std/os/uefi/protocols/udp6_service_binding_protocol.zig b/lib/std/os/uefi/protocols/udp6_service_binding_protocol.zig index 811692adc3..4f4e0a2638 100644 --- a/lib/std/os/uefi/protocols/udp6_service_binding_protocol.zig +++ b/lib/std/os/uefi/protocols/udp6_service_binding_protocol.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const uefi = @import("std").os.uefi; const Handle = uefi.Handle; const Guid = uefi.Guid; diff --git a/lib/std/os/uefi/status.zig b/lib/std/os/uefi/status.zig index 0da4508e8f..3e86962202 100644 --- a/lib/std/os/uefi/status.zig +++ b/lib/std/os/uefi/status.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const high_bit = 1 << @typeInfo(usize).Int.bits - 1; pub const Status = extern enum(usize) { diff --git a/lib/std/os/uefi/tables.zig b/lib/std/os/uefi/tables.zig index 0011c80a9c..b796eb6e06 100644 --- a/lib/std/os/uefi/tables.zig +++ b/lib/std/os/uefi/tables.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. pub const AllocateType = @import("tables/boot_services.zig").AllocateType; pub const BootServices = @import("tables/boot_services.zig").BootServices; pub const ConfigurationTable = @import("tables/configuration_table.zig").ConfigurationTable; diff --git a/lib/std/os/uefi/tables/boot_services.zig b/lib/std/os/uefi/tables/boot_services.zig index a1d2c1ca59..09431cf3f4 100644 --- a/lib/std/os/uefi/tables/boot_services.zig +++ b/lib/std/os/uefi/tables/boot_services.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const uefi = @import("std").os.uefi; const Event = uefi.Event; const Guid = uefi.Guid; diff --git a/lib/std/os/uefi/tables/configuration_table.zig b/lib/std/os/uefi/tables/configuration_table.zig index 0ac3bd73c8..c7dedad5fb 100644 --- a/lib/std/os/uefi/tables/configuration_table.zig +++ b/lib/std/os/uefi/tables/configuration_table.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const uefi = @import("std").os.uefi; const Guid = uefi.Guid; diff --git a/lib/std/os/uefi/tables/runtime_services.zig b/lib/std/os/uefi/tables/runtime_services.zig index 981e07275b..a2012168ee 100644 --- a/lib/std/os/uefi/tables/runtime_services.zig +++ b/lib/std/os/uefi/tables/runtime_services.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const uefi = @import("std").os.uefi; const Guid = uefi.Guid; const TableHeader = uefi.tables.TableHeader; diff --git a/lib/std/os/uefi/tables/system_table.zig b/lib/std/os/uefi/tables/system_table.zig index 40fec34d44..cbe66fbb68 100644 --- a/lib/std/os/uefi/tables/system_table.zig +++ b/lib/std/os/uefi/tables/system_table.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const uefi = @import("std").os.uefi; const BootServices = uefi.tables.BootServices; const ConfigurationTable = uefi.tables.ConfigurationTable; diff --git a/lib/std/os/uefi/tables/table_header.zig b/lib/std/os/uefi/tables/table_header.zig index d5d4094232..a8343c967a 100644 --- a/lib/std/os/uefi/tables/table_header.zig +++ b/lib/std/os/uefi/tables/table_header.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. pub const TableHeader = extern struct { signature: u64, revision: u32, diff --git a/lib/std/os/wasi.zig b/lib/std/os/wasi.zig index 23df66f385..899541f3fe 100644 --- a/lib/std/os/wasi.zig +++ b/lib/std/os/wasi.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // wasi_snapshot_preview1 spec available (in witx format) here: // * typenames -- https://github.com/WebAssembly/WASI/blob/master/phases/snapshot/witx/typenames.witx // * module -- https://github.com/WebAssembly/WASI/blob/master/phases/snapshot/witx/wasi_snapshot_preview1.witx diff --git a/lib/std/os/windows.zig b/lib/std/os/windows.zig index 2f2369a458..a23eead14f 100644 --- a/lib/std/os/windows.zig +++ b/lib/std/os/windows.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // This file contains thin wrappers around Windows-specific APIs, with these // specific goals in mind: // * Convert "errno"-style error codes into Zig errors. diff --git a/lib/std/os/windows/advapi32.zig b/lib/std/os/windows/advapi32.zig index 6364c5bddb..b6dbaf9a7a 100644 --- a/lib/std/os/windows/advapi32.zig +++ b/lib/std/os/windows/advapi32.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. usingnamespace @import("bits.zig"); pub extern "advapi32" fn RegOpenKeyExW( diff --git a/lib/std/os/windows/bits.zig b/lib/std/os/windows/bits.zig index 44bc1ba437..d22f42d6e8 100644 --- a/lib/std/os/windows/bits.zig +++ b/lib/std/os/windows/bits.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Platform-dependent types and values that are used along with OS-specific APIs. const builtin = @import("builtin"); diff --git a/lib/std/os/windows/gdi32.zig b/lib/std/os/windows/gdi32.zig index 676065b574..f36732ba1e 100644 --- a/lib/std/os/windows/gdi32.zig +++ b/lib/std/os/windows/gdi32.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. usingnamespace @import("bits.zig"); pub const PIXELFORMATDESCRIPTOR = extern struct { diff --git a/lib/std/os/windows/kernel32.zig b/lib/std/os/windows/kernel32.zig index b50143b075..fce9eea908 100644 --- a/lib/std/os/windows/kernel32.zig +++ b/lib/std/os/windows/kernel32.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. usingnamespace @import("bits.zig"); pub extern "kernel32" fn AddVectoredExceptionHandler(First: c_ulong, Handler: ?VECTORED_EXCEPTION_HANDLER) callconv(.Stdcall) ?*c_void; diff --git a/lib/std/os/windows/lang.zig b/lib/std/os/windows/lang.zig index b173a62a73..61efa3bdb3 100644 --- a/lib/std/os/windows/lang.zig +++ b/lib/std/os/windows/lang.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. pub const NEUTRAL = 0x00; pub const INVARIANT = 0x7f; pub const AFRIKAANS = 0x36; diff --git a/lib/std/os/windows/ntdll.zig b/lib/std/os/windows/ntdll.zig index 5edad85c20..c11098b6bc 100644 --- a/lib/std/os/windows/ntdll.zig +++ b/lib/std/os/windows/ntdll.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. usingnamespace @import("bits.zig"); pub extern "NtDll" fn RtlGetVersion( diff --git a/lib/std/os/windows/ntstatus.zig b/lib/std/os/windows/ntstatus.zig index 5c9344d639..0e567df510 100644 --- a/lib/std/os/windows/ntstatus.zig +++ b/lib/std/os/windows/ntstatus.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // NTSTATUS codes from https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/596a1078-e883-4972-9bbc-49e60bebca55? pub const NTSTATUS = extern enum(u32) { /// The operation completed successfully. diff --git a/lib/std/os/windows/ole32.zig b/lib/std/os/windows/ole32.zig index a472089078..f46ee33047 100644 --- a/lib/std/os/windows/ole32.zig +++ b/lib/std/os/windows/ole32.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. usingnamespace @import("bits.zig"); pub extern "ole32" fn CoTaskMemFree(pv: LPVOID) callconv(.Stdcall) void; diff --git a/lib/std/os/windows/psapi.zig b/lib/std/os/windows/psapi.zig index 1a5a7d4bf2..db6fc93314 100644 --- a/lib/std/os/windows/psapi.zig +++ b/lib/std/os/windows/psapi.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. usingnamespace @import("bits.zig"); pub extern "psapi" fn EmptyWorkingSet(hProcess: HANDLE) callconv(.Stdcall) BOOL; diff --git a/lib/std/os/windows/shell32.zig b/lib/std/os/windows/shell32.zig index 762589c6de..ce9d54f6df 100644 --- a/lib/std/os/windows/shell32.zig +++ b/lib/std/os/windows/shell32.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. usingnamespace @import("bits.zig"); pub extern "shell32" fn SHGetKnownFolderPath(rfid: *const KNOWNFOLDERID, dwFlags: DWORD, hToken: ?HANDLE, ppszPath: *[*:0]WCHAR) callconv(.Stdcall) HRESULT; diff --git a/lib/std/os/windows/sublang.zig b/lib/std/os/windows/sublang.zig index e9929c6d79..5249e8ed0a 100644 --- a/lib/std/os/windows/sublang.zig +++ b/lib/std/os/windows/sublang.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. pub const NEUTRAL = 0x00; pub const DEFAULT = 0x01; pub const SYS_DEFAULT = 0x02; diff --git a/lib/std/os/windows/user32.zig b/lib/std/os/windows/user32.zig index 3877e19ad8..6a80a92cad 100644 --- a/lib/std/os/windows/user32.zig +++ b/lib/std/os/windows/user32.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. usingnamespace @import("bits.zig"); // PM diff --git a/lib/std/os/windows/win32error.zig b/lib/std/os/windows/win32error.zig index 037797e25f..2e1f111d92 100644 --- a/lib/std/os/windows/win32error.zig +++ b/lib/std/os/windows/win32error.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Codes are from https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/18d8fbe8-a967-4f1c-ae50-99ca8e491d2d pub const Win32Error = extern enum(u16) { /// The operation completed successfully. diff --git a/lib/std/os/windows/ws2_32.zig b/lib/std/os/windows/ws2_32.zig index 1e36a72038..cfc212d15a 100644 --- a/lib/std/os/windows/ws2_32.zig +++ b/lib/std/os/windows/ws2_32.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. usingnamespace @import("bits.zig"); pub const SOCKET = *@Type(.Opaque); diff --git a/lib/std/packed_int_array.zig b/lib/std/packed_int_array.zig index 07a79655ad..de99afa303 100644 --- a/lib/std/packed_int_array.zig +++ b/lib/std/packed_int_array.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std"); const builtin = @import("builtin"); const debug = std.debug; diff --git a/lib/std/pdb.zig b/lib/std/pdb.zig index a702a8aed6..e8c61f859d 100644 --- a/lib/std/pdb.zig +++ b/lib/std/pdb.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const builtin = @import("builtin"); const std = @import("std.zig"); const io = std.io; diff --git a/lib/std/priority_queue.zig b/lib/std/priority_queue.zig index 69b9e06a5b..1c0d230d4d 100644 --- a/lib/std/priority_queue.zig +++ b/lib/std/priority_queue.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std.zig"); const Allocator = std.mem.Allocator; const assert = std.debug.assert; diff --git a/lib/std/process.zig b/lib/std/process.zig index 1a0dfad474..69befa2fc8 100644 --- a/lib/std/process.zig +++ b/lib/std/process.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std.zig"); const builtin = std.builtin; const os = std.os; diff --git a/lib/std/progress.zig b/lib/std/progress.zig index b81e81aa2c..654d8cc228 100644 --- a/lib/std/progress.zig +++ b/lib/std/progress.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std"); const windows = std.os.windows; const testing = std.testing; diff --git a/lib/std/rand.zig b/lib/std/rand.zig index 1e5bb37592..85f11ff449 100644 --- a/lib/std/rand.zig +++ b/lib/std/rand.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // The engines provided here should be initialized from an external source. For now, randomBytes // from the crypto package is the most suitable. Be sure to use a CSPRNG when required, otherwise using // a normal PRNG will be faster and use substantially less stack space. diff --git a/lib/std/rand/ziggurat.zig b/lib/std/rand/ziggurat.zig index 06728f170c..da189637bf 100644 --- a/lib/std/rand/ziggurat.zig +++ b/lib/std/rand/ziggurat.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Implements ZIGNOR [1]. // // [1]: Jurgen A. Doornik (2005). [*An Improved Ziggurat Method to Generate Normal Random Samples*] diff --git a/lib/std/rb.zig b/lib/std/rb.zig index a39b815e74..8cf90a1eea 100644 --- a/lib/std/rb.zig +++ b/lib/std/rb.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std"); const assert = std.debug.assert; const testing = std.testing; diff --git a/lib/std/reset_event.zig b/lib/std/reset_event.zig index 6f520773d8..31e6c28cf8 100644 --- a/lib/std/reset_event.zig +++ b/lib/std/reset_event.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std.zig"); const builtin = @import("builtin"); const testing = std.testing; diff --git a/lib/std/segmented_list.zig b/lib/std/segmented_list.zig index d39fe3e239..a63196c443 100644 --- a/lib/std/segmented_list.zig +++ b/lib/std/segmented_list.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std.zig"); const assert = std.debug.assert; const testing = std.testing; diff --git a/lib/std/sort.zig b/lib/std/sort.zig index 464054e4a5..e2e4cc662d 100644 --- a/lib/std/sort.zig +++ b/lib/std/sort.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std.zig"); const assert = std.debug.assert; const testing = std.testing; diff --git a/lib/std/special/build_runner.zig b/lib/std/special/build_runner.zig index 83c181e841..46d3b0b615 100644 --- a/lib/std/special/build_runner.zig +++ b/lib/std/special/build_runner.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const root = @import("@build"); const std = @import("std"); const builtin = @import("builtin"); diff --git a/lib/std/special/c.zig b/lib/std/special/c.zig index 170bb98620..f18fe11e66 100644 --- a/lib/std/special/c.zig +++ b/lib/std/special/c.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // This is Zig's multi-target implementation of libc. // When builtin.link_libc is true, we need to export all the functions and // provide an entire C API. diff --git a/lib/std/special/compiler_rt.zig b/lib/std/special/compiler_rt.zig index 2716de8113..42db6b96bf 100644 --- a/lib/std/special/compiler_rt.zig +++ b/lib/std/special/compiler_rt.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std"); const builtin = std.builtin; const is_test = builtin.is_test; diff --git a/lib/std/special/compiler_rt/addXf3.zig b/lib/std/special/compiler_rt/addXf3.zig index 849efa1cd2..6dd0faaebb 100644 --- a/lib/std/special/compiler_rt/addXf3.zig +++ b/lib/std/special/compiler_rt/addXf3.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Ported from: // // https://github.com/llvm/llvm-project/blob/02d85149a05cb1f6dc49f0ba7a2ceca53718ae17/compiler-rt/lib/builtins/fp_add_impl.inc diff --git a/lib/std/special/compiler_rt/addXf3_test.zig b/lib/std/special/compiler_rt/addXf3_test.zig index af991b37e9..3d75309507 100644 --- a/lib/std/special/compiler_rt/addXf3_test.zig +++ b/lib/std/special/compiler_rt/addXf3_test.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Ported from: // // https://github.com/llvm/llvm-project/blob/02d85149a05cb1f6dc49f0ba7a2ceca53718ae17/compiler-rt/test/builtins/Unit/addtf3_test.c diff --git a/lib/std/special/compiler_rt/arm.zig b/lib/std/special/compiler_rt/arm.zig index 5e718ed4c4..1eecd3ceac 100644 --- a/lib/std/special/compiler_rt/arm.zig +++ b/lib/std/special/compiler_rt/arm.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // ARM specific builtins const builtin = @import("builtin"); diff --git a/lib/std/special/compiler_rt/ashldi3_test.zig b/lib/std/special/compiler_rt/ashldi3_test.zig index 547c315b24..874681a79a 100644 --- a/lib/std/special/compiler_rt/ashldi3_test.zig +++ b/lib/std/special/compiler_rt/ashldi3_test.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const __ashldi3 = @import("shift.zig").__ashldi3; const testing = @import("std").testing; diff --git a/lib/std/special/compiler_rt/ashlti3_test.zig b/lib/std/special/compiler_rt/ashlti3_test.zig index a4510f52d7..42cb3a47bb 100644 --- a/lib/std/special/compiler_rt/ashlti3_test.zig +++ b/lib/std/special/compiler_rt/ashlti3_test.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const __ashlti3 = @import("shift.zig").__ashlti3; const testing = @import("std").testing; diff --git a/lib/std/special/compiler_rt/ashrdi3_test.zig b/lib/std/special/compiler_rt/ashrdi3_test.zig index 3ba30edbfe..e80b95af9e 100644 --- a/lib/std/special/compiler_rt/ashrdi3_test.zig +++ b/lib/std/special/compiler_rt/ashrdi3_test.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const __ashrdi3 = @import("shift.zig").__ashrdi3; const testing = @import("std").testing; diff --git a/lib/std/special/compiler_rt/ashrti3_test.zig b/lib/std/special/compiler_rt/ashrti3_test.zig index 43d5d11910..958b8a8a74 100644 --- a/lib/std/special/compiler_rt/ashrti3_test.zig +++ b/lib/std/special/compiler_rt/ashrti3_test.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const __ashrti3 = @import("shift.zig").__ashrti3; const testing = @import("std").testing; diff --git a/lib/std/special/compiler_rt/atomics.zig b/lib/std/special/compiler_rt/atomics.zig index e2cb45bef3..a76695ff2c 100644 --- a/lib/std/special/compiler_rt/atomics.zig +++ b/lib/std/special/compiler_rt/atomics.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std"); const builtin = std.builtin; diff --git a/lib/std/special/compiler_rt/aulldiv.zig b/lib/std/special/compiler_rt/aulldiv.zig index 2e2dd364d5..cf9b26c5a6 100644 --- a/lib/std/special/compiler_rt/aulldiv.zig +++ b/lib/std/special/compiler_rt/aulldiv.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const builtin = @import("builtin"); pub fn _alldiv(a: i64, b: i64) callconv(.Stdcall) i64 { diff --git a/lib/std/special/compiler_rt/aullrem.zig b/lib/std/special/compiler_rt/aullrem.zig index 4244f1bb80..7c981cc088 100644 --- a/lib/std/special/compiler_rt/aullrem.zig +++ b/lib/std/special/compiler_rt/aullrem.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const builtin = @import("builtin"); pub fn _allrem(a: i64, b: i64) callconv(.Stdcall) i64 { diff --git a/lib/std/special/compiler_rt/clear_cache.zig b/lib/std/special/compiler_rt/clear_cache.zig index 6306d5b575..d862f739d3 100644 --- a/lib/std/special/compiler_rt/clear_cache.zig +++ b/lib/std/special/compiler_rt/clear_cache.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std"); const arch = std.builtin.cpu.arch; const os = std.builtin.os.tag; diff --git a/lib/std/special/compiler_rt/clzsi2.zig b/lib/std/special/compiler_rt/clzsi2.zig index 0c9c5d4318..ac314ff9e0 100644 --- a/lib/std/special/compiler_rt/clzsi2.zig +++ b/lib/std/special/compiler_rt/clzsi2.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const builtin = @import("builtin"); fn __clzsi2_generic(a: i32) callconv(.C) i32 { diff --git a/lib/std/special/compiler_rt/clzsi2_test.zig b/lib/std/special/compiler_rt/clzsi2_test.zig index 8a2896fcb6..2d9ba3d1b3 100644 --- a/lib/std/special/compiler_rt/clzsi2_test.zig +++ b/lib/std/special/compiler_rt/clzsi2_test.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const clzsi2 = @import("clzsi2.zig"); const testing = @import("std").testing; diff --git a/lib/std/special/compiler_rt/compareXf2.zig b/lib/std/special/compiler_rt/compareXf2.zig index 6489d283ff..f50dc67474 100644 --- a/lib/std/special/compiler_rt/compareXf2.zig +++ b/lib/std/special/compiler_rt/compareXf2.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Ported from: // // https://github.com/llvm/llvm-project/commit/d674d96bc56c0f377879d01c9d8dfdaaa7859cdb/compiler-rt/lib/builtins/comparesf2.c diff --git a/lib/std/special/compiler_rt/comparedf2_test.zig b/lib/std/special/compiler_rt/comparedf2_test.zig index 16a2a258ce..9d681b8f81 100644 --- a/lib/std/special/compiler_rt/comparedf2_test.zig +++ b/lib/std/special/compiler_rt/comparedf2_test.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Ported from: // // https://github.com/llvm/llvm-project/commit/d674d96bc56c0f377879d01c9d8dfdaaa7859cdb/compiler-rt/test/builtins/Unit/comparedf2_test.c diff --git a/lib/std/special/compiler_rt/comparesf2_test.zig b/lib/std/special/compiler_rt/comparesf2_test.zig index e3966c021b..da7fe940a0 100644 --- a/lib/std/special/compiler_rt/comparesf2_test.zig +++ b/lib/std/special/compiler_rt/comparesf2_test.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Ported from: // // https://github.com/llvm/llvm-project/commit/d674d96bc56c0f377879d01c9d8dfdaaa7859cdb/compiler-rt/test/builtins/Unit/comparesf2_test.c diff --git a/lib/std/special/compiler_rt/divdf3.zig b/lib/std/special/compiler_rt/divdf3.zig index 8b7525e931..ad72f96057 100644 --- a/lib/std/special/compiler_rt/divdf3.zig +++ b/lib/std/special/compiler_rt/divdf3.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Ported from: // // https://github.com/llvm/llvm-project/commit/d674d96bc56c0f377879d01c9d8dfdaaa7859cdb/compiler-rt/lib/builtins/divdf3.c diff --git a/lib/std/special/compiler_rt/divdf3_test.zig b/lib/std/special/compiler_rt/divdf3_test.zig index 61d6731ea7..04cac956d2 100644 --- a/lib/std/special/compiler_rt/divdf3_test.zig +++ b/lib/std/special/compiler_rt/divdf3_test.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Ported from: // // https://github.com/llvm/llvm-project/commit/d674d96bc56c0f377879d01c9d8dfdaaa7859cdb/compiler-rt/test/builtins/Unit/divdf3_test.c diff --git a/lib/std/special/compiler_rt/divsf3.zig b/lib/std/special/compiler_rt/divsf3.zig index 62a6c56262..80af806eb1 100644 --- a/lib/std/special/compiler_rt/divsf3.zig +++ b/lib/std/special/compiler_rt/divsf3.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Ported from: // // https://github.com/llvm/llvm-project/commit/d674d96bc56c0f377879d01c9d8dfdaaa7859cdb/compiler-rt/lib/builtins/divsf3.c diff --git a/lib/std/special/compiler_rt/divsf3_test.zig b/lib/std/special/compiler_rt/divsf3_test.zig index 188842af58..30dcba462b 100644 --- a/lib/std/special/compiler_rt/divsf3_test.zig +++ b/lib/std/special/compiler_rt/divsf3_test.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Ported from: // // https://github.com/llvm/llvm-project/commit/d674d96bc56c0f377879d01c9d8dfdaaa7859cdb/compiler-rt/test/builtins/Unit/divsf3_test.c diff --git a/lib/std/special/compiler_rt/divtf3.zig b/lib/std/special/compiler_rt/divtf3.zig index d177454ad2..f6f7c1bf7d 100644 --- a/lib/std/special/compiler_rt/divtf3.zig +++ b/lib/std/special/compiler_rt/divtf3.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std"); const builtin = @import("builtin"); diff --git a/lib/std/special/compiler_rt/divtf3_test.zig b/lib/std/special/compiler_rt/divtf3_test.zig index 4940b2c403..cf6f2f2eaf 100644 --- a/lib/std/special/compiler_rt/divtf3_test.zig +++ b/lib/std/special/compiler_rt/divtf3_test.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std"); const math = std.math; const testing = std.testing; diff --git a/lib/std/special/compiler_rt/divti3.zig b/lib/std/special/compiler_rt/divti3.zig index afb30950b8..4b7d459991 100644 --- a/lib/std/special/compiler_rt/divti3.zig +++ b/lib/std/special/compiler_rt/divti3.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const udivmod = @import("udivmod.zig").udivmod; const builtin = @import("builtin"); diff --git a/lib/std/special/compiler_rt/divti3_test.zig b/lib/std/special/compiler_rt/divti3_test.zig index 8601cfae03..18fab24ed1 100644 --- a/lib/std/special/compiler_rt/divti3_test.zig +++ b/lib/std/special/compiler_rt/divti3_test.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const __divti3 = @import("divti3.zig").__divti3; const testing = @import("std").testing; diff --git a/lib/std/special/compiler_rt/extendXfYf2.zig b/lib/std/special/compiler_rt/extendXfYf2.zig index 6aca0ac98f..e0536c04ad 100644 --- a/lib/std/special/compiler_rt/extendXfYf2.zig +++ b/lib/std/special/compiler_rt/extendXfYf2.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std"); const builtin = @import("builtin"); const is_test = builtin.is_test; diff --git a/lib/std/special/compiler_rt/extendXfYf2_test.zig b/lib/std/special/compiler_rt/extendXfYf2_test.zig index e2664f6bae..d82a8baf4c 100644 --- a/lib/std/special/compiler_rt/extendXfYf2_test.zig +++ b/lib/std/special/compiler_rt/extendXfYf2_test.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const builtin = @import("builtin"); const __extenddftf2 = @import("extendXfYf2.zig").__extenddftf2; const __extendhfsf2 = @import("extendXfYf2.zig").__extendhfsf2; diff --git a/lib/std/special/compiler_rt/fixdfdi.zig b/lib/std/special/compiler_rt/fixdfdi.zig index 11b5009129..28de1ecd23 100644 --- a/lib/std/special/compiler_rt/fixdfdi.zig +++ b/lib/std/special/compiler_rt/fixdfdi.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const fixint = @import("fixint.zig").fixint; const builtin = @import("builtin"); diff --git a/lib/std/special/compiler_rt/fixdfdi_test.zig b/lib/std/special/compiler_rt/fixdfdi_test.zig index 92dbdc2a5e..83835106cd 100644 --- a/lib/std/special/compiler_rt/fixdfdi_test.zig +++ b/lib/std/special/compiler_rt/fixdfdi_test.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const __fixdfdi = @import("fixdfdi.zig").__fixdfdi; const std = @import("std"); const math = std.math; diff --git a/lib/std/special/compiler_rt/fixdfsi.zig b/lib/std/special/compiler_rt/fixdfsi.zig index 8a6d8da342..678c75d0c1 100644 --- a/lib/std/special/compiler_rt/fixdfsi.zig +++ b/lib/std/special/compiler_rt/fixdfsi.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const fixint = @import("fixint.zig").fixint; const builtin = @import("builtin"); diff --git a/lib/std/special/compiler_rt/fixdfsi_test.zig b/lib/std/special/compiler_rt/fixdfsi_test.zig index fb90518892..8050a1b9c5 100644 --- a/lib/std/special/compiler_rt/fixdfsi_test.zig +++ b/lib/std/special/compiler_rt/fixdfsi_test.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const __fixdfsi = @import("fixdfsi.zig").__fixdfsi; const std = @import("std"); const math = std.math; diff --git a/lib/std/special/compiler_rt/fixdfti.zig b/lib/std/special/compiler_rt/fixdfti.zig index 0e21f0ba19..3d9266ae1f 100644 --- a/lib/std/special/compiler_rt/fixdfti.zig +++ b/lib/std/special/compiler_rt/fixdfti.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const fixint = @import("fixint.zig").fixint; const builtin = @import("builtin"); diff --git a/lib/std/special/compiler_rt/fixdfti_test.zig b/lib/std/special/compiler_rt/fixdfti_test.zig index f66e4a3d88..796855b716 100644 --- a/lib/std/special/compiler_rt/fixdfti_test.zig +++ b/lib/std/special/compiler_rt/fixdfti_test.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const __fixdfti = @import("fixdfti.zig").__fixdfti; const std = @import("std"); const math = std.math; diff --git a/lib/std/special/compiler_rt/fixint.zig b/lib/std/special/compiler_rt/fixint.zig index daf7a1bdc7..0bf0c8be1e 100644 --- a/lib/std/special/compiler_rt/fixint.zig +++ b/lib/std/special/compiler_rt/fixint.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const is_test = @import("builtin").is_test; const std = @import("std"); const math = std.math; diff --git a/lib/std/special/compiler_rt/fixint_test.zig b/lib/std/special/compiler_rt/fixint_test.zig index 4efb1e6ab3..49942e5382 100644 --- a/lib/std/special/compiler_rt/fixint_test.zig +++ b/lib/std/special/compiler_rt/fixint_test.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const is_test = @import("builtin").is_test; const std = @import("std"); const math = std.math; diff --git a/lib/std/special/compiler_rt/fixsfdi.zig b/lib/std/special/compiler_rt/fixsfdi.zig index d0d958cdd6..cc5731946d 100644 --- a/lib/std/special/compiler_rt/fixsfdi.zig +++ b/lib/std/special/compiler_rt/fixsfdi.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const fixint = @import("fixint.zig").fixint; const builtin = @import("builtin"); diff --git a/lib/std/special/compiler_rt/fixsfdi_test.zig b/lib/std/special/compiler_rt/fixsfdi_test.zig index 5888c9804d..d93c3d4218 100644 --- a/lib/std/special/compiler_rt/fixsfdi_test.zig +++ b/lib/std/special/compiler_rt/fixsfdi_test.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const __fixsfdi = @import("fixsfdi.zig").__fixsfdi; const std = @import("std"); const math = std.math; diff --git a/lib/std/special/compiler_rt/fixsfsi.zig b/lib/std/special/compiler_rt/fixsfsi.zig index 84395d0fa6..62334574b0 100644 --- a/lib/std/special/compiler_rt/fixsfsi.zig +++ b/lib/std/special/compiler_rt/fixsfsi.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const fixint = @import("fixint.zig").fixint; const builtin = @import("builtin"); diff --git a/lib/std/special/compiler_rt/fixsfsi_test.zig b/lib/std/special/compiler_rt/fixsfsi_test.zig index 844235bc9d..56c28d91ab 100644 --- a/lib/std/special/compiler_rt/fixsfsi_test.zig +++ b/lib/std/special/compiler_rt/fixsfsi_test.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const __fixsfsi = @import("fixsfsi.zig").__fixsfsi; const std = @import("std"); const math = std.math; diff --git a/lib/std/special/compiler_rt/fixsfti.zig b/lib/std/special/compiler_rt/fixsfti.zig index d7ce4b3a60..31dea953e8 100644 --- a/lib/std/special/compiler_rt/fixsfti.zig +++ b/lib/std/special/compiler_rt/fixsfti.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const fixint = @import("fixint.zig").fixint; const builtin = @import("builtin"); diff --git a/lib/std/special/compiler_rt/fixsfti_test.zig b/lib/std/special/compiler_rt/fixsfti_test.zig index 9eb2883f38..d0bdcc4e75 100644 --- a/lib/std/special/compiler_rt/fixsfti_test.zig +++ b/lib/std/special/compiler_rt/fixsfti_test.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const __fixsfti = @import("fixsfti.zig").__fixsfti; const std = @import("std"); const math = std.math; diff --git a/lib/std/special/compiler_rt/fixtfdi.zig b/lib/std/special/compiler_rt/fixtfdi.zig index 0ef3aa2259..edf70dbe49 100644 --- a/lib/std/special/compiler_rt/fixtfdi.zig +++ b/lib/std/special/compiler_rt/fixtfdi.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const fixint = @import("fixint.zig").fixint; const builtin = @import("builtin"); diff --git a/lib/std/special/compiler_rt/fixtfdi_test.zig b/lib/std/special/compiler_rt/fixtfdi_test.zig index 6baa9011c3..b926f33d50 100644 --- a/lib/std/special/compiler_rt/fixtfdi_test.zig +++ b/lib/std/special/compiler_rt/fixtfdi_test.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const __fixtfdi = @import("fixtfdi.zig").__fixtfdi; const std = @import("std"); const math = std.math; diff --git a/lib/std/special/compiler_rt/fixtfsi.zig b/lib/std/special/compiler_rt/fixtfsi.zig index 15e89a11b0..cf614ec8b3 100644 --- a/lib/std/special/compiler_rt/fixtfsi.zig +++ b/lib/std/special/compiler_rt/fixtfsi.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const fixint = @import("fixint.zig").fixint; const builtin = @import("builtin"); diff --git a/lib/std/special/compiler_rt/fixtfsi_test.zig b/lib/std/special/compiler_rt/fixtfsi_test.zig index c7294fe250..86207f7dbc 100644 --- a/lib/std/special/compiler_rt/fixtfsi_test.zig +++ b/lib/std/special/compiler_rt/fixtfsi_test.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const __fixtfsi = @import("fixtfsi.zig").__fixtfsi; const std = @import("std"); const math = std.math; diff --git a/lib/std/special/compiler_rt/fixtfti.zig b/lib/std/special/compiler_rt/fixtfti.zig index 733fa1eed1..e796b86d50 100644 --- a/lib/std/special/compiler_rt/fixtfti.zig +++ b/lib/std/special/compiler_rt/fixtfti.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const fixint = @import("fixint.zig").fixint; const builtin = @import("builtin"); diff --git a/lib/std/special/compiler_rt/fixtfti_test.zig b/lib/std/special/compiler_rt/fixtfti_test.zig index 6b8218e2f6..65a64ac431 100644 --- a/lib/std/special/compiler_rt/fixtfti_test.zig +++ b/lib/std/special/compiler_rt/fixtfti_test.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const __fixtfti = @import("fixtfti.zig").__fixtfti; const std = @import("std"); const math = std.math; diff --git a/lib/std/special/compiler_rt/fixuint.zig b/lib/std/special/compiler_rt/fixuint.zig index 1e96b7c283..01eb03baa5 100644 --- a/lib/std/special/compiler_rt/fixuint.zig +++ b/lib/std/special/compiler_rt/fixuint.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const is_test = @import("builtin").is_test; const Log2Int = @import("std").math.Log2Int; diff --git a/lib/std/special/compiler_rt/fixunsdfdi.zig b/lib/std/special/compiler_rt/fixunsdfdi.zig index 800c9b1148..19f94c95a8 100644 --- a/lib/std/special/compiler_rt/fixunsdfdi.zig +++ b/lib/std/special/compiler_rt/fixunsdfdi.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const fixuint = @import("fixuint.zig").fixuint; const builtin = @import("builtin"); diff --git a/lib/std/special/compiler_rt/fixunsdfdi_test.zig b/lib/std/special/compiler_rt/fixunsdfdi_test.zig index 67eeb70520..da6fef3376 100644 --- a/lib/std/special/compiler_rt/fixunsdfdi_test.zig +++ b/lib/std/special/compiler_rt/fixunsdfdi_test.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const __fixunsdfdi = @import("fixunsdfdi.zig").__fixunsdfdi; const testing = @import("std").testing; diff --git a/lib/std/special/compiler_rt/fixunsdfsi.zig b/lib/std/special/compiler_rt/fixunsdfsi.zig index 156c21a887..2f622aff39 100644 --- a/lib/std/special/compiler_rt/fixunsdfsi.zig +++ b/lib/std/special/compiler_rt/fixunsdfsi.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const fixuint = @import("fixuint.zig").fixuint; const builtin = @import("builtin"); diff --git a/lib/std/special/compiler_rt/fixunsdfsi_test.zig b/lib/std/special/compiler_rt/fixunsdfsi_test.zig index c006473fb9..ddbb05c705 100644 --- a/lib/std/special/compiler_rt/fixunsdfsi_test.zig +++ b/lib/std/special/compiler_rt/fixunsdfsi_test.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const __fixunsdfsi = @import("fixunsdfsi.zig").__fixunsdfsi; const testing = @import("std").testing; diff --git a/lib/std/special/compiler_rt/fixunsdfti.zig b/lib/std/special/compiler_rt/fixunsdfti.zig index 3dcec6bf89..f11f6b937f 100644 --- a/lib/std/special/compiler_rt/fixunsdfti.zig +++ b/lib/std/special/compiler_rt/fixunsdfti.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const fixuint = @import("fixuint.zig").fixuint; const builtin = @import("builtin"); diff --git a/lib/std/special/compiler_rt/fixunsdfti_test.zig b/lib/std/special/compiler_rt/fixunsdfti_test.zig index 8241900692..11ba3bc425 100644 --- a/lib/std/special/compiler_rt/fixunsdfti_test.zig +++ b/lib/std/special/compiler_rt/fixunsdfti_test.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const __fixunsdfti = @import("fixunsdfti.zig").__fixunsdfti; const testing = @import("std").testing; diff --git a/lib/std/special/compiler_rt/fixunssfdi.zig b/lib/std/special/compiler_rt/fixunssfdi.zig index ec00a7ee35..5dd9b27d10 100644 --- a/lib/std/special/compiler_rt/fixunssfdi.zig +++ b/lib/std/special/compiler_rt/fixunssfdi.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const fixuint = @import("fixuint.zig").fixuint; const builtin = @import("builtin"); diff --git a/lib/std/special/compiler_rt/fixunssfdi_test.zig b/lib/std/special/compiler_rt/fixunssfdi_test.zig index e2089822d2..018c94ce7c 100644 --- a/lib/std/special/compiler_rt/fixunssfdi_test.zig +++ b/lib/std/special/compiler_rt/fixunssfdi_test.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const __fixunssfdi = @import("fixunssfdi.zig").__fixunssfdi; const testing = @import("std").testing; diff --git a/lib/std/special/compiler_rt/fixunssfsi.zig b/lib/std/special/compiler_rt/fixunssfsi.zig index a4e5a323f5..ce983cb78a 100644 --- a/lib/std/special/compiler_rt/fixunssfsi.zig +++ b/lib/std/special/compiler_rt/fixunssfsi.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const fixuint = @import("fixuint.zig").fixuint; const builtin = @import("builtin"); diff --git a/lib/std/special/compiler_rt/fixunssfsi_test.zig b/lib/std/special/compiler_rt/fixunssfsi_test.zig index 4aee84d2d2..98cac8a1e4 100644 --- a/lib/std/special/compiler_rt/fixunssfsi_test.zig +++ b/lib/std/special/compiler_rt/fixunssfsi_test.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const __fixunssfsi = @import("fixunssfsi.zig").__fixunssfsi; const testing = @import("std").testing; diff --git a/lib/std/special/compiler_rt/fixunssfti.zig b/lib/std/special/compiler_rt/fixunssfti.zig index dff9eb7498..bbaeafd6a8 100644 --- a/lib/std/special/compiler_rt/fixunssfti.zig +++ b/lib/std/special/compiler_rt/fixunssfti.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const fixuint = @import("fixuint.zig").fixuint; const builtin = @import("builtin"); diff --git a/lib/std/special/compiler_rt/fixunssfti_test.zig b/lib/std/special/compiler_rt/fixunssfti_test.zig index 4cb27cbb8a..b5c79906b7 100644 --- a/lib/std/special/compiler_rt/fixunssfti_test.zig +++ b/lib/std/special/compiler_rt/fixunssfti_test.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const __fixunssfti = @import("fixunssfti.zig").__fixunssfti; const testing = @import("std").testing; diff --git a/lib/std/special/compiler_rt/fixunstfdi.zig b/lib/std/special/compiler_rt/fixunstfdi.zig index 907116c165..3062e5322c 100644 --- a/lib/std/special/compiler_rt/fixunstfdi.zig +++ b/lib/std/special/compiler_rt/fixunstfdi.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const fixuint = @import("fixuint.zig").fixuint; const builtin = @import("builtin"); diff --git a/lib/std/special/compiler_rt/fixunstfdi_test.zig b/lib/std/special/compiler_rt/fixunstfdi_test.zig index 0d47641c09..299c509cea 100644 --- a/lib/std/special/compiler_rt/fixunstfdi_test.zig +++ b/lib/std/special/compiler_rt/fixunstfdi_test.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const __fixunstfdi = @import("fixunstfdi.zig").__fixunstfdi; const testing = @import("std").testing; diff --git a/lib/std/special/compiler_rt/fixunstfsi.zig b/lib/std/special/compiler_rt/fixunstfsi.zig index c66a3f18b4..6836e5df36 100644 --- a/lib/std/special/compiler_rt/fixunstfsi.zig +++ b/lib/std/special/compiler_rt/fixunstfsi.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const fixuint = @import("fixuint.zig").fixuint; const builtin = @import("builtin"); diff --git a/lib/std/special/compiler_rt/fixunstfsi_test.zig b/lib/std/special/compiler_rt/fixunstfsi_test.zig index 286567629a..2e5139e5e2 100644 --- a/lib/std/special/compiler_rt/fixunstfsi_test.zig +++ b/lib/std/special/compiler_rt/fixunstfsi_test.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const __fixunstfsi = @import("fixunstfsi.zig").__fixunstfsi; const testing = @import("std").testing; diff --git a/lib/std/special/compiler_rt/fixunstfti.zig b/lib/std/special/compiler_rt/fixunstfti.zig index 1867c69234..da3319ee5c 100644 --- a/lib/std/special/compiler_rt/fixunstfti.zig +++ b/lib/std/special/compiler_rt/fixunstfti.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const fixuint = @import("fixuint.zig").fixuint; const builtin = @import("builtin"); diff --git a/lib/std/special/compiler_rt/fixunstfti_test.zig b/lib/std/special/compiler_rt/fixunstfti_test.zig index 62a9bbfecf..2fbde63e63 100644 --- a/lib/std/special/compiler_rt/fixunstfti_test.zig +++ b/lib/std/special/compiler_rt/fixunstfti_test.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const __fixunstfti = @import("fixunstfti.zig").__fixunstfti; const testing = @import("std").testing; diff --git a/lib/std/special/compiler_rt/floatdidf.zig b/lib/std/special/compiler_rt/floatdidf.zig index afe9e906fd..2a1ba4cadd 100644 --- a/lib/std/special/compiler_rt/floatdidf.zig +++ b/lib/std/special/compiler_rt/floatdidf.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const builtin = @import("builtin"); const std = @import("std"); diff --git a/lib/std/special/compiler_rt/floatdidf_test.zig b/lib/std/special/compiler_rt/floatdidf_test.zig index c854183809..a2072cc922 100644 --- a/lib/std/special/compiler_rt/floatdidf_test.zig +++ b/lib/std/special/compiler_rt/floatdidf_test.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const __floatdidf = @import("floatdidf.zig").__floatdidf; const testing = @import("std").testing; diff --git a/lib/std/special/compiler_rt/floatditf.zig b/lib/std/special/compiler_rt/floatditf.zig index 581a0e0532..aa945ca5dd 100644 --- a/lib/std/special/compiler_rt/floatditf.zig +++ b/lib/std/special/compiler_rt/floatditf.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const builtin = @import("builtin"); const is_test = builtin.is_test; const std = @import("std"); diff --git a/lib/std/special/compiler_rt/floatditf_test.zig b/lib/std/special/compiler_rt/floatditf_test.zig index 8cdb8157a9..ff4f10927c 100644 --- a/lib/std/special/compiler_rt/floatditf_test.zig +++ b/lib/std/special/compiler_rt/floatditf_test.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const __floatditf = @import("floatditf.zig").__floatditf; const testing = @import("std").testing; diff --git a/lib/std/special/compiler_rt/floatsiXf.zig b/lib/std/special/compiler_rt/floatsiXf.zig index 6a1dc422b7..75db3d7040 100644 --- a/lib/std/special/compiler_rt/floatsiXf.zig +++ b/lib/std/special/compiler_rt/floatsiXf.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const builtin = @import("builtin"); const std = @import("std"); const maxInt = std.math.maxInt; diff --git a/lib/std/special/compiler_rt/floattidf.zig b/lib/std/special/compiler_rt/floattidf.zig index 6b5013287b..73d86f7747 100644 --- a/lib/std/special/compiler_rt/floattidf.zig +++ b/lib/std/special/compiler_rt/floattidf.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const builtin = @import("builtin"); const is_test = builtin.is_test; const std = @import("std"); diff --git a/lib/std/special/compiler_rt/floattidf_test.zig b/lib/std/special/compiler_rt/floattidf_test.zig index 4914342c31..d299ed8087 100644 --- a/lib/std/special/compiler_rt/floattidf_test.zig +++ b/lib/std/special/compiler_rt/floattidf_test.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const __floattidf = @import("floattidf.zig").__floattidf; const testing = @import("std").testing; diff --git a/lib/std/special/compiler_rt/floattisf.zig b/lib/std/special/compiler_rt/floattisf.zig index 3f020dadd8..7975d59e83 100644 --- a/lib/std/special/compiler_rt/floattisf.zig +++ b/lib/std/special/compiler_rt/floattisf.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const builtin = @import("builtin"); const is_test = builtin.is_test; const std = @import("std"); diff --git a/lib/std/special/compiler_rt/floattisf_test.zig b/lib/std/special/compiler_rt/floattisf_test.zig index a6aa115307..f5638c2106 100644 --- a/lib/std/special/compiler_rt/floattisf_test.zig +++ b/lib/std/special/compiler_rt/floattisf_test.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const __floattisf = @import("floattisf.zig").__floattisf; const testing = @import("std").testing; diff --git a/lib/std/special/compiler_rt/floattitf.zig b/lib/std/special/compiler_rt/floattitf.zig index 90bc241306..87408ea445 100644 --- a/lib/std/special/compiler_rt/floattitf.zig +++ b/lib/std/special/compiler_rt/floattitf.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const builtin = @import("builtin"); const is_test = builtin.is_test; const std = @import("std"); diff --git a/lib/std/special/compiler_rt/floattitf_test.zig b/lib/std/special/compiler_rt/floattitf_test.zig index 53e3e48bdb..c4014a6298 100644 --- a/lib/std/special/compiler_rt/floattitf_test.zig +++ b/lib/std/special/compiler_rt/floattitf_test.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const __floattitf = @import("floattitf.zig").__floattitf; const testing = @import("std").testing; diff --git a/lib/std/special/compiler_rt/floatundidf.zig b/lib/std/special/compiler_rt/floatundidf.zig index 1efe55da40..a88ca4a03d 100644 --- a/lib/std/special/compiler_rt/floatundidf.zig +++ b/lib/std/special/compiler_rt/floatundidf.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const builtin = @import("builtin"); const std = @import("std"); diff --git a/lib/std/special/compiler_rt/floatundidf_test.zig b/lib/std/special/compiler_rt/floatundidf_test.zig index 084ada51c9..c0651cb359 100644 --- a/lib/std/special/compiler_rt/floatundidf_test.zig +++ b/lib/std/special/compiler_rt/floatundidf_test.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const __floatundidf = @import("floatundidf.zig").__floatundidf; const testing = @import("std").testing; diff --git a/lib/std/special/compiler_rt/floatundisf.zig b/lib/std/special/compiler_rt/floatundisf.zig index ff242721d6..b580ec91fd 100644 --- a/lib/std/special/compiler_rt/floatundisf.zig +++ b/lib/std/special/compiler_rt/floatundisf.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const builtin = @import("builtin"); const std = @import("std"); const maxInt = std.math.maxInt; diff --git a/lib/std/special/compiler_rt/floatunditf.zig b/lib/std/special/compiler_rt/floatunditf.zig index 209f66fc2e..90191c6388 100644 --- a/lib/std/special/compiler_rt/floatunditf.zig +++ b/lib/std/special/compiler_rt/floatunditf.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const builtin = @import("builtin"); const is_test = builtin.is_test; const std = @import("std"); diff --git a/lib/std/special/compiler_rt/floatunditf_test.zig b/lib/std/special/compiler_rt/floatunditf_test.zig index 7bb3333693..19d1b4a2a3 100644 --- a/lib/std/special/compiler_rt/floatunditf_test.zig +++ b/lib/std/special/compiler_rt/floatunditf_test.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const __floatunditf = @import("floatunditf.zig").__floatunditf; fn test__floatunditf(a: u64, expected_hi: u64, expected_lo: u64) void { diff --git a/lib/std/special/compiler_rt/floatunsidf.zig b/lib/std/special/compiler_rt/floatunsidf.zig index 771b4938e1..c9a31eff8e 100644 --- a/lib/std/special/compiler_rt/floatunsidf.zig +++ b/lib/std/special/compiler_rt/floatunsidf.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const builtin = @import("builtin"); const std = @import("std"); const maxInt = std.math.maxInt; diff --git a/lib/std/special/compiler_rt/floatunsisf.zig b/lib/std/special/compiler_rt/floatunsisf.zig index c11243e6e4..17eae51092 100644 --- a/lib/std/special/compiler_rt/floatunsisf.zig +++ b/lib/std/special/compiler_rt/floatunsisf.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const builtin = @import("builtin"); const std = @import("std"); const maxInt = std.math.maxInt; diff --git a/lib/std/special/compiler_rt/floatunsitf.zig b/lib/std/special/compiler_rt/floatunsitf.zig index a10ff6b703..ceb55f12c8 100644 --- a/lib/std/special/compiler_rt/floatunsitf.zig +++ b/lib/std/special/compiler_rt/floatunsitf.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const builtin = @import("builtin"); const is_test = builtin.is_test; const std = @import("std"); diff --git a/lib/std/special/compiler_rt/floatunsitf_test.zig b/lib/std/special/compiler_rt/floatunsitf_test.zig index 52e4786903..deb95ca396 100644 --- a/lib/std/special/compiler_rt/floatunsitf_test.zig +++ b/lib/std/special/compiler_rt/floatunsitf_test.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const __floatunsitf = @import("floatunsitf.zig").__floatunsitf; fn test__floatunsitf(a: u64, expected_hi: u64, expected_lo: u64) void { diff --git a/lib/std/special/compiler_rt/floatuntidf.zig b/lib/std/special/compiler_rt/floatuntidf.zig index 5b5adc0491..adb804d0ec 100644 --- a/lib/std/special/compiler_rt/floatuntidf.zig +++ b/lib/std/special/compiler_rt/floatuntidf.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const builtin = @import("builtin"); const is_test = builtin.is_test; const std = @import("std"); diff --git a/lib/std/special/compiler_rt/floatuntidf_test.zig b/lib/std/special/compiler_rt/floatuntidf_test.zig index 974f3e4be3..cce3893860 100644 --- a/lib/std/special/compiler_rt/floatuntidf_test.zig +++ b/lib/std/special/compiler_rt/floatuntidf_test.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const __floatuntidf = @import("floatuntidf.zig").__floatuntidf; const testing = @import("std").testing; diff --git a/lib/std/special/compiler_rt/floatuntisf.zig b/lib/std/special/compiler_rt/floatuntisf.zig index 33e6e41a84..d0c9a76562 100644 --- a/lib/std/special/compiler_rt/floatuntisf.zig +++ b/lib/std/special/compiler_rt/floatuntisf.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const builtin = @import("builtin"); const is_test = builtin.is_test; const std = @import("std"); diff --git a/lib/std/special/compiler_rt/floatuntisf_test.zig b/lib/std/special/compiler_rt/floatuntisf_test.zig index 3a97807066..42379d8084 100644 --- a/lib/std/special/compiler_rt/floatuntisf_test.zig +++ b/lib/std/special/compiler_rt/floatuntisf_test.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const __floatuntisf = @import("floatuntisf.zig").__floatuntisf; const testing = @import("std").testing; diff --git a/lib/std/special/compiler_rt/floatuntitf.zig b/lib/std/special/compiler_rt/floatuntitf.zig index 0b96076206..c87ff50e9a 100644 --- a/lib/std/special/compiler_rt/floatuntitf.zig +++ b/lib/std/special/compiler_rt/floatuntitf.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const builtin = @import("builtin"); const is_test = builtin.is_test; const std = @import("std"); diff --git a/lib/std/special/compiler_rt/floatuntitf_test.zig b/lib/std/special/compiler_rt/floatuntitf_test.zig index 09f3eabb3e..62c9b631df 100644 --- a/lib/std/special/compiler_rt/floatuntitf_test.zig +++ b/lib/std/special/compiler_rt/floatuntitf_test.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const __floatuntitf = @import("floatuntitf.zig").__floatuntitf; const testing = @import("std").testing; diff --git a/lib/std/special/compiler_rt/int.zig b/lib/std/special/compiler_rt/int.zig index a72c13e233..141c4e52c1 100644 --- a/lib/std/special/compiler_rt/int.zig +++ b/lib/std/special/compiler_rt/int.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Builtin functions that operate on integer types const builtin = @import("builtin"); const testing = @import("std").testing; diff --git a/lib/std/special/compiler_rt/lshrdi3_test.zig b/lib/std/special/compiler_rt/lshrdi3_test.zig index 906d428d1e..de83f0a9c8 100644 --- a/lib/std/special/compiler_rt/lshrdi3_test.zig +++ b/lib/std/special/compiler_rt/lshrdi3_test.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const __lshrdi3 = @import("shift.zig").__lshrdi3; const testing = @import("std").testing; diff --git a/lib/std/special/compiler_rt/lshrti3_test.zig b/lib/std/special/compiler_rt/lshrti3_test.zig index c0aa191a6f..f831e8b132 100644 --- a/lib/std/special/compiler_rt/lshrti3_test.zig +++ b/lib/std/special/compiler_rt/lshrti3_test.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const __lshrti3 = @import("shift.zig").__lshrti3; const testing = @import("std").testing; diff --git a/lib/std/special/compiler_rt/modti3.zig b/lib/std/special/compiler_rt/modti3.zig index 78be44026c..1f859c2329 100644 --- a/lib/std/special/compiler_rt/modti3.zig +++ b/lib/std/special/compiler_rt/modti3.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Ported from: // // https://github.com/llvm/llvm-project/blob/2ffb1b0413efa9a24eb3c49e710e36f92e2cb50b/compiler-rt/lib/builtins/modti3.c diff --git a/lib/std/special/compiler_rt/modti3_test.zig b/lib/std/special/compiler_rt/modti3_test.zig index 10f81d59d2..cad60c015e 100644 --- a/lib/std/special/compiler_rt/modti3_test.zig +++ b/lib/std/special/compiler_rt/modti3_test.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const __modti3 = @import("modti3.zig").__modti3; const testing = @import("std").testing; diff --git a/lib/std/special/compiler_rt/mulXf3.zig b/lib/std/special/compiler_rt/mulXf3.zig index af49d27952..b6984ebbb6 100644 --- a/lib/std/special/compiler_rt/mulXf3.zig +++ b/lib/std/special/compiler_rt/mulXf3.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Ported from: // // https://github.com/llvm/llvm-project/blob/2ffb1b0413efa9a24eb3c49e710e36f92e2cb50b/compiler-rt/lib/builtins/fp_mul_impl.inc diff --git a/lib/std/special/compiler_rt/mulXf3_test.zig b/lib/std/special/compiler_rt/mulXf3_test.zig index 57dc385321..c9994b089b 100644 --- a/lib/std/special/compiler_rt/mulXf3_test.zig +++ b/lib/std/special/compiler_rt/mulXf3_test.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Ported from: // // https://github.com/llvm/llvm-project/blob/2ffb1b0413efa9a24eb3c49e710e36f92e2cb50b/compiler-rt/test/builtins/Unit/multf3_test.c diff --git a/lib/std/special/compiler_rt/muldi3.zig b/lib/std/special/compiler_rt/muldi3.zig index 4f605d441c..2de96ea66c 100644 --- a/lib/std/special/compiler_rt/muldi3.zig +++ b/lib/std/special/compiler_rt/muldi3.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const builtin = @import("builtin"); // Ported from diff --git a/lib/std/special/compiler_rt/muldi3_test.zig b/lib/std/special/compiler_rt/muldi3_test.zig index db4daf1e1e..b4962189cd 100644 --- a/lib/std/special/compiler_rt/muldi3_test.zig +++ b/lib/std/special/compiler_rt/muldi3_test.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const __muldi3 = @import("muldi3.zig").__muldi3; const testing = @import("std").testing; diff --git a/lib/std/special/compiler_rt/mulodi4.zig b/lib/std/special/compiler_rt/mulodi4.zig index b70d1657e7..b05931e937 100644 --- a/lib/std/special/compiler_rt/mulodi4.zig +++ b/lib/std/special/compiler_rt/mulodi4.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const builtin = @import("builtin"); const compiler_rt = @import("../compiler_rt.zig"); const maxInt = std.math.maxInt; diff --git a/lib/std/special/compiler_rt/mulodi4_test.zig b/lib/std/special/compiler_rt/mulodi4_test.zig index 803d60e8fa..a96f7a1996 100644 --- a/lib/std/special/compiler_rt/mulodi4_test.zig +++ b/lib/std/special/compiler_rt/mulodi4_test.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const __mulodi4 = @import("mulodi4.zig").__mulodi4; const testing = @import("std").testing; diff --git a/lib/std/special/compiler_rt/muloti4.zig b/lib/std/special/compiler_rt/muloti4.zig index 190959b801..4beafa3e15 100644 --- a/lib/std/special/compiler_rt/muloti4.zig +++ b/lib/std/special/compiler_rt/muloti4.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const builtin = @import("builtin"); const compiler_rt = @import("../compiler_rt.zig"); diff --git a/lib/std/special/compiler_rt/muloti4_test.zig b/lib/std/special/compiler_rt/muloti4_test.zig index f94a13e04f..44ab93a069 100644 --- a/lib/std/special/compiler_rt/muloti4_test.zig +++ b/lib/std/special/compiler_rt/muloti4_test.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const __muloti4 = @import("muloti4.zig").__muloti4; const testing = @import("std").testing; diff --git a/lib/std/special/compiler_rt/multi3.zig b/lib/std/special/compiler_rt/multi3.zig index c237f1b259..fad73789ac 100644 --- a/lib/std/special/compiler_rt/multi3.zig +++ b/lib/std/special/compiler_rt/multi3.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const builtin = @import("builtin"); const compiler_rt = @import("../compiler_rt.zig"); diff --git a/lib/std/special/compiler_rt/multi3_test.zig b/lib/std/special/compiler_rt/multi3_test.zig index 92c580e20f..04b70d0538 100644 --- a/lib/std/special/compiler_rt/multi3_test.zig +++ b/lib/std/special/compiler_rt/multi3_test.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const __multi3 = @import("multi3.zig").__multi3; const testing = @import("std").testing; diff --git a/lib/std/special/compiler_rt/negXf2.zig b/lib/std/special/compiler_rt/negXf2.zig index 0739ecb83c..11f9e401e9 100644 --- a/lib/std/special/compiler_rt/negXf2.zig +++ b/lib/std/special/compiler_rt/negXf2.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std"); pub fn __negsf2(a: f32) callconv(.C) f32 { diff --git a/lib/std/special/compiler_rt/popcountdi2.zig b/lib/std/special/compiler_rt/popcountdi2.zig index b7e7220c7b..5bb49ce402 100644 --- a/lib/std/special/compiler_rt/popcountdi2.zig +++ b/lib/std/special/compiler_rt/popcountdi2.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const builtin = @import("builtin"); const compiler_rt = @import("../compiler_rt.zig"); diff --git a/lib/std/special/compiler_rt/popcountdi2_test.zig b/lib/std/special/compiler_rt/popcountdi2_test.zig index fe02786e15..6ea181bf0e 100644 --- a/lib/std/special/compiler_rt/popcountdi2_test.zig +++ b/lib/std/special/compiler_rt/popcountdi2_test.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const __popcountdi2 = @import("popcountdi2.zig").__popcountdi2; const testing = @import("std").testing; diff --git a/lib/std/special/compiler_rt/shift.zig b/lib/std/special/compiler_rt/shift.zig index f811c5124d..1609cb115c 100644 --- a/lib/std/special/compiler_rt/shift.zig +++ b/lib/std/special/compiler_rt/shift.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std"); const builtin = std.builtin; const Log2Int = std.math.Log2Int; diff --git a/lib/std/special/compiler_rt/stack_probe.zig b/lib/std/special/compiler_rt/stack_probe.zig index dd441b2f32..58cce9fb6f 100644 --- a/lib/std/special/compiler_rt/stack_probe.zig +++ b/lib/std/special/compiler_rt/stack_probe.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const builtin = @import("builtin"); // Zig's own stack-probe routine (available only on x86 and x86_64) diff --git a/lib/std/special/compiler_rt/truncXfYf2.zig b/lib/std/special/compiler_rt/truncXfYf2.zig index d345bf30a3..e096e7e4f0 100644 --- a/lib/std/special/compiler_rt/truncXfYf2.zig +++ b/lib/std/special/compiler_rt/truncXfYf2.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std"); pub fn __truncsfhf2(a: f32) callconv(.C) u16 { diff --git a/lib/std/special/compiler_rt/truncXfYf2_test.zig b/lib/std/special/compiler_rt/truncXfYf2_test.zig index baec2a4450..048005f86d 100644 --- a/lib/std/special/compiler_rt/truncXfYf2_test.zig +++ b/lib/std/special/compiler_rt/truncXfYf2_test.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const __truncsfhf2 = @import("truncXfYf2.zig").__truncsfhf2; fn test__truncsfhf2(a: u32, expected: u16) void { diff --git a/lib/std/special/compiler_rt/udivmod.zig b/lib/std/special/compiler_rt/udivmod.zig index ba53d1dee0..2836f34c85 100644 --- a/lib/std/special/compiler_rt/udivmod.zig +++ b/lib/std/special/compiler_rt/udivmod.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const builtin = @import("builtin"); const is_test = builtin.is_test; diff --git a/lib/std/special/compiler_rt/udivmoddi4_test.zig b/lib/std/special/compiler_rt/udivmoddi4_test.zig index 48a38faa04..74a4a828e8 100644 --- a/lib/std/special/compiler_rt/udivmoddi4_test.zig +++ b/lib/std/special/compiler_rt/udivmoddi4_test.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Disable formatting to avoid unnecessary source repository bloat. // zig fmt: off const __udivmoddi4 = @import("int.zig").__udivmoddi4; diff --git a/lib/std/special/compiler_rt/udivmodti4.zig b/lib/std/special/compiler_rt/udivmodti4.zig index cc1141dbbc..ff33a35680 100644 --- a/lib/std/special/compiler_rt/udivmodti4.zig +++ b/lib/std/special/compiler_rt/udivmodti4.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const udivmod = @import("udivmod.zig").udivmod; const builtin = @import("builtin"); const compiler_rt = @import("../compiler_rt.zig"); diff --git a/lib/std/special/compiler_rt/udivmodti4_test.zig b/lib/std/special/compiler_rt/udivmodti4_test.zig index fdeae7c02b..1852d5c7af 100644 --- a/lib/std/special/compiler_rt/udivmodti4_test.zig +++ b/lib/std/special/compiler_rt/udivmodti4_test.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // Disable formatting to avoid unnecessary source repository bloat. // zig fmt: off const __udivmodti4 = @import("udivmodti4.zig").__udivmodti4; diff --git a/lib/std/special/compiler_rt/udivti3.zig b/lib/std/special/compiler_rt/udivti3.zig index 52afa0420f..187b4a1577 100644 --- a/lib/std/special/compiler_rt/udivti3.zig +++ b/lib/std/special/compiler_rt/udivti3.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const udivmodti4 = @import("udivmodti4.zig"); const builtin = @import("builtin"); diff --git a/lib/std/special/compiler_rt/umodti3.zig b/lib/std/special/compiler_rt/umodti3.zig index 29eb572892..3bc5be8ffc 100644 --- a/lib/std/special/compiler_rt/umodti3.zig +++ b/lib/std/special/compiler_rt/umodti3.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const udivmodti4 = @import("udivmodti4.zig"); const builtin = @import("builtin"); const compiler_rt = @import("../compiler_rt.zig"); diff --git a/lib/std/special/init-exe/build.zig b/lib/std/special/init-exe/build.zig index fd71588c5f..db818cbe92 100644 --- a/lib/std/special/init-exe/build.zig +++ b/lib/std/special/init-exe/build.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const Builder = @import("std").build.Builder; pub fn build(b: *Builder) void { diff --git a/lib/std/special/init-exe/src/main.zig b/lib/std/special/init-exe/src/main.zig index d29869ff88..e4b2e7d8ec 100644 --- a/lib/std/special/init-exe/src/main.zig +++ b/lib/std/special/init-exe/src/main.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std"); pub fn main() anyerror!void { diff --git a/lib/std/special/init-lib/build.zig b/lib/std/special/init-lib/build.zig index 558e447c15..edc8a0215d 100644 --- a/lib/std/special/init-lib/build.zig +++ b/lib/std/special/init-lib/build.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const Builder = @import("std").build.Builder; pub fn build(b: *Builder) void { diff --git a/lib/std/special/init-lib/src/main.zig b/lib/std/special/init-lib/src/main.zig index 747bb08573..9a82bcc26b 100644 --- a/lib/std/special/init-lib/src/main.zig +++ b/lib/std/special/init-lib/src/main.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std"); const testing = std.testing; diff --git a/lib/std/special/test_runner.zig b/lib/std/special/test_runner.zig index 4267151638..87b011ede8 100644 --- a/lib/std/special/test_runner.zig +++ b/lib/std/special/test_runner.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std"); const io = std.io; const builtin = @import("builtin"); diff --git a/lib/std/spinlock.zig b/lib/std/spinlock.zig index 0af08e9a84..d72ac14ecf 100644 --- a/lib/std/spinlock.zig +++ b/lib/std/spinlock.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std.zig"); const builtin = @import("builtin"); diff --git a/lib/std/start.zig b/lib/std/start.zig index 811e05012f..2b1bae060e 100644 --- a/lib/std/start.zig +++ b/lib/std/start.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. // This file is included in the compilation unit when exporting an executable. const root = @import("root"); diff --git a/lib/std/start_windows_tls.zig b/lib/std/start_windows_tls.zig index f6dd2bc132..18c016d206 100644 --- a/lib/std/start_windows_tls.zig +++ b/lib/std/start_windows_tls.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std"); const builtin = std.builtin; diff --git a/lib/std/std.zig b/lib/std/std.zig index 940fc498d6..2ff44f5e41 100644 --- a/lib/std/std.zig +++ b/lib/std/std.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. pub const ArrayList = @import("array_list.zig").ArrayList; pub const ArrayListAligned = @import("array_list.zig").ArrayListAligned; pub const ArrayListAlignedUnmanaged = @import("array_list.zig").ArrayListAlignedUnmanaged; diff --git a/lib/std/target.zig b/lib/std/target.zig index 14cea9dd57..b162bdd0c3 100644 --- a/lib/std/target.zig +++ b/lib/std/target.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std.zig"); const mem = std.mem; const builtin = std.builtin; diff --git a/lib/std/target/aarch64.zig b/lib/std/target/aarch64.zig index 9af95dfada..0f64b2fd69 100644 --- a/lib/std/target/aarch64.zig +++ b/lib/std/target/aarch64.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const CpuFeature = std.Target.Cpu.Feature; const CpuModel = std.Target.Cpu.Model; diff --git a/lib/std/target/amdgpu.zig b/lib/std/target/amdgpu.zig index 4b3f83bbc3..9fa52c317d 100644 --- a/lib/std/target/amdgpu.zig +++ b/lib/std/target/amdgpu.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const CpuFeature = std.Target.Cpu.Feature; const CpuModel = std.Target.Cpu.Model; diff --git a/lib/std/target/arm.zig b/lib/std/target/arm.zig index 90b060c03f..e96a9aa4e6 100644 --- a/lib/std/target/arm.zig +++ b/lib/std/target/arm.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const CpuFeature = std.Target.Cpu.Feature; const CpuModel = std.Target.Cpu.Model; diff --git a/lib/std/target/avr.zig b/lib/std/target/avr.zig index af4f5ba5be..3ad603eabe 100644 --- a/lib/std/target/avr.zig +++ b/lib/std/target/avr.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const CpuFeature = std.Target.Cpu.Feature; const CpuModel = std.Target.Cpu.Model; diff --git a/lib/std/target/bpf.zig b/lib/std/target/bpf.zig index ddb12d3d85..5e23c233c8 100644 --- a/lib/std/target/bpf.zig +++ b/lib/std/target/bpf.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const CpuFeature = std.Target.Cpu.Feature; const CpuModel = std.Target.Cpu.Model; diff --git a/lib/std/target/hexagon.zig b/lib/std/target/hexagon.zig index f429099d88..c5eac1886f 100644 --- a/lib/std/target/hexagon.zig +++ b/lib/std/target/hexagon.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const CpuFeature = std.Target.Cpu.Feature; const CpuModel = std.Target.Cpu.Model; diff --git a/lib/std/target/mips.zig b/lib/std/target/mips.zig index fc95b2dee8..6d82caf0c0 100644 --- a/lib/std/target/mips.zig +++ b/lib/std/target/mips.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const CpuFeature = std.Target.Cpu.Feature; const CpuModel = std.Target.Cpu.Model; diff --git a/lib/std/target/msp430.zig b/lib/std/target/msp430.zig index 947137b3e2..38ea358f90 100644 --- a/lib/std/target/msp430.zig +++ b/lib/std/target/msp430.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const CpuFeature = std.Target.Cpu.Feature; const CpuModel = std.Target.Cpu.Model; diff --git a/lib/std/target/nvptx.zig b/lib/std/target/nvptx.zig index d719a6bb71..1282c48e1a 100644 --- a/lib/std/target/nvptx.zig +++ b/lib/std/target/nvptx.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const CpuFeature = std.Target.Cpu.Feature; const CpuModel = std.Target.Cpu.Model; diff --git a/lib/std/target/powerpc.zig b/lib/std/target/powerpc.zig index 19b050c5bd..e13e3dd97f 100644 --- a/lib/std/target/powerpc.zig +++ b/lib/std/target/powerpc.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const CpuFeature = std.Target.Cpu.Feature; const CpuModel = std.Target.Cpu.Model; diff --git a/lib/std/target/riscv.zig b/lib/std/target/riscv.zig index dbdb107024..9d4429bd5c 100644 --- a/lib/std/target/riscv.zig +++ b/lib/std/target/riscv.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const CpuFeature = std.Target.Cpu.Feature; const CpuModel = std.Target.Cpu.Model; diff --git a/lib/std/target/sparc.zig b/lib/std/target/sparc.zig index e1cbc845fc..8baac12635 100644 --- a/lib/std/target/sparc.zig +++ b/lib/std/target/sparc.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const CpuFeature = std.Target.Cpu.Feature; const CpuModel = std.Target.Cpu.Model; diff --git a/lib/std/target/systemz.zig b/lib/std/target/systemz.zig index f065a8b169..4f3415626c 100644 --- a/lib/std/target/systemz.zig +++ b/lib/std/target/systemz.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const CpuFeature = std.Target.Cpu.Feature; const CpuModel = std.Target.Cpu.Model; diff --git a/lib/std/target/wasm.zig b/lib/std/target/wasm.zig index 72b2b6d431..3021834ec4 100644 --- a/lib/std/target/wasm.zig +++ b/lib/std/target/wasm.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const CpuFeature = std.Target.Cpu.Feature; const CpuModel = std.Target.Cpu.Model; diff --git a/lib/std/target/x86.zig b/lib/std/target/x86.zig index bfcd1abc1a..61219e13b0 100644 --- a/lib/std/target/x86.zig +++ b/lib/std/target/x86.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const CpuFeature = std.Target.Cpu.Feature; const CpuModel = std.Target.Cpu.Model; diff --git a/lib/std/testing.zig b/lib/std/testing.zig index 27026149bc..658d31bb82 100644 --- a/lib/std/testing.zig +++ b/lib/std/testing.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std.zig"); const print = std.debug.print; diff --git a/lib/std/testing/failing_allocator.zig b/lib/std/testing/failing_allocator.zig index d8b243d0fa..61912e6933 100644 --- a/lib/std/testing/failing_allocator.zig +++ b/lib/std/testing/failing_allocator.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const mem = std.mem; diff --git a/lib/std/thread.zig b/lib/std/thread.zig index 3d20f54558..d73907690e 100644 --- a/lib/std/thread.zig +++ b/lib/std/thread.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std.zig"); const builtin = std.builtin; const os = std.os; diff --git a/lib/std/time.zig b/lib/std/time.zig index 6a0b9a13aa..ae128f6b0c 100644 --- a/lib/std/time.zig +++ b/lib/std/time.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std.zig"); const builtin = std.builtin; const assert = std.debug.assert; diff --git a/lib/std/time/epoch.zig b/lib/std/time/epoch.zig index 126c4fceb7..3a42c85a6d 100644 --- a/lib/std/time/epoch.zig +++ b/lib/std/time/epoch.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. //! Epoch reference times in terms of their difference from //! UTC 1970-01-01 in seconds. diff --git a/lib/std/unicode.zig b/lib/std/unicode.zig index 2c88d2ba0c..86b805b892 100644 --- a/lib/std/unicode.zig +++ b/lib/std/unicode.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("./std.zig"); const builtin = @import("builtin"); const assert = std.debug.assert; diff --git a/lib/std/unicode/throughput_test.zig b/lib/std/unicode/throughput_test.zig index 050340cd55..e59953a21f 100644 --- a/lib/std/unicode/throughput_test.zig +++ b/lib/std/unicode/throughput_test.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const builtin = @import("builtin"); const std = @import("std"); diff --git a/lib/std/valgrind.zig b/lib/std/valgrind.zig index 38c4a491e0..5373a2d513 100644 --- a/lib/std/valgrind.zig +++ b/lib/std/valgrind.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const builtin = @import("builtin"); const std = @import("std.zig"); const math = std.math; diff --git a/lib/std/valgrind/callgrind.zig b/lib/std/valgrind/callgrind.zig index 82725e9103..5e025c4ffe 100644 --- a/lib/std/valgrind/callgrind.zig +++ b/lib/std/valgrind/callgrind.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const valgrind = std.valgrind; diff --git a/lib/std/valgrind/memcheck.zig b/lib/std/valgrind/memcheck.zig index e0aefa7d5f..449b4c4a46 100644 --- a/lib/std/valgrind/memcheck.zig +++ b/lib/std/valgrind/memcheck.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const testing = std.testing; const valgrind = std.valgrind; diff --git a/lib/std/zig.zig b/lib/std/zig.zig index ab6895e1bf..34e03eb164 100644 --- a/lib/std/zig.zig +++ b/lib/std/zig.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std.zig"); const tokenizer = @import("zig/tokenizer.zig"); diff --git a/lib/std/zig/ast.zig b/lib/std/zig/ast.zig index f5149e3a82..f6ba29a9ef 100644 --- a/lib/std/zig/ast.zig +++ b/lib/std/zig/ast.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const assert = std.debug.assert; const testing = std.testing; diff --git a/lib/std/zig/cross_target.zig b/lib/std/zig/cross_target.zig index 5466b39f0b..75fc5969a5 100644 --- a/lib/std/zig/cross_target.zig +++ b/lib/std/zig/cross_target.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const assert = std.debug.assert; const Target = std.Target; diff --git a/lib/std/zig/parse.zig b/lib/std/zig/parse.zig index e0eb2dd895..2af2ee4a45 100644 --- a/lib/std/zig/parse.zig +++ b/lib/std/zig/parse.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const assert = std.debug.assert; const Allocator = std.mem.Allocator; diff --git a/lib/std/zig/parser_test.zig b/lib/std/zig/parser_test.zig index 87807255b0..8259af32a6 100644 --- a/lib/std/zig/parser_test.zig +++ b/lib/std/zig/parser_test.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. test "zig fmt: convert var to anytype" { // TODO remove in next release cycle try testTransform( diff --git a/lib/std/zig/perf_test.zig b/lib/std/zig/perf_test.zig index 689fea96f6..30ae99e57c 100644 --- a/lib/std/zig/perf_test.zig +++ b/lib/std/zig/perf_test.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std"); const mem = std.mem; const warn = std.debug.warn; diff --git a/lib/std/zig/render.zig b/lib/std/zig/render.zig index 7b9036f259..4d44c41bfa 100644 --- a/lib/std/zig/render.zig +++ b/lib/std/zig/render.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const assert = std.debug.assert; const mem = std.mem; diff --git a/lib/std/zig/string_literal.zig b/lib/std/zig/string_literal.zig index 560a233723..ca3585944e 100644 --- a/lib/std/zig/string_literal.zig +++ b/lib/std/zig/string_literal.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const assert = std.debug.assert; diff --git a/lib/std/zig/system.zig b/lib/std/zig/system.zig index be47da46bb..175b0e4555 100644 --- a/lib/std/zig/system.zig +++ b/lib/std/zig/system.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const elf = std.elf; const mem = std.mem; diff --git a/lib/std/zig/system/macos.zig b/lib/std/zig/system/macos.zig index dd34fe26f9..e0e69b6b8b 100644 --- a/lib/std/zig/system/macos.zig +++ b/lib/std/zig/system/macos.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std"); pub fn version_from_build(build: []const u8) !std.builtin.Version { diff --git a/lib/std/zig/system/x86.zig b/lib/std/zig/system/x86.zig index b4964596d2..cbede308dc 100644 --- a/lib/std/zig/system/x86.zig +++ b/lib/std/zig/system/x86.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("std"); const Target = std.Target; const CrossTarget = std.zig.CrossTarget; diff --git a/lib/std/zig/tokenizer.zig b/lib/std/zig/tokenizer.zig index 7f9c6f6288..47c7d23b35 100644 --- a/lib/std/zig/tokenizer.zig +++ b/lib/std/zig/tokenizer.zig @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. const std = @import("../std.zig"); const mem = std.mem; diff --git a/test/stack_traces.zig b/test/stack_traces.zig index 616136b9ee..2ab022e6ec 100644 --- a/test/stack_traces.zig +++ b/test/stack_traces.zig @@ -282,10 +282,10 @@ pub fn addCases(cases: *tests.StackTracesContext) void { \\source.zig:10:8: [address] in main (test) \\ foo(); \\ ^ - \\start.zig:249:29: [address] in std.start.posixCallMainAndExit (test) + \\start.zig:254:29: [address] in std.start.posixCallMainAndExit (test) \\ return root.main(); \\ ^ - \\start.zig:123:5: [address] in std.start._start (test) + \\start.zig:128:5: [address] in std.start._start (test) \\ @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{}); \\ ^ \\ @@ -294,7 +294,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void { switch (std.Target.current.cpu.arch) { .aarch64 => "", // TODO disabled; results in segfault else => - \\start.zig:123:5: [address] in std.start._start (test) + \\start.zig:128:5: [address] in std.start._start (test) \\ @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{}); \\ ^ \\ From 1a4059ed88740c0289b7fea5735115fa9481a8e5 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 20 Aug 2020 13:16:04 -0700 Subject: [PATCH 39/66] allow running the stage2 tests in release mode --- build.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.zig b/build.zig index 2536b24bc0..9c50025375 100644 --- a/build.zig +++ b/build.zig @@ -38,7 +38,7 @@ pub fn build(b: *Builder) !void { const test_step = b.step("test", "Run all the tests"); var test_stage2 = b.addTest("src-self-hosted/test.zig"); - test_stage2.setBuildMode(.Debug); // note this is only the mode of the test harness + test_stage2.setBuildMode(mode); test_stage2.addPackagePath("stage2_tests", "test/stage2/test.zig"); const fmt_build_zig = b.addFmt(&[_][]const u8{"build.zig"}); From 6f9ea9eaef79863ebdc9bf44b2af67ec4caad031 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Wed, 19 Aug 2020 16:21:05 +0200 Subject: [PATCH 40/66] Breaking: sort std/crypto functions into categories Instead of having all primitives and constructions share the same namespace, they are now organized by category and function family. Types within the same category are expected to share the exact same API. --- lib/std/bloom_filter.zig | 2 +- lib/std/build/write_file.zig | 2 +- lib/std/cache_hash.zig | 2 +- lib/std/crypto.zig | 125 +++++++++++++++------------- lib/std/crypto/25519/ed25519.zig | 2 +- lib/std/crypto/benchmark.zig | 33 ++++---- lib/std/crypto/chacha20.zig | 134 ++++++++++++++++--------------- lib/std/crypto/gimli.zig | 10 ++- lib/std/crypto/hmac.zig | 23 ++++-- lib/std/crypto/md5.zig | 26 +++--- lib/std/crypto/sha1.zig | 28 ++++--- lib/std/crypto/sha2.zig | 31 +++---- lib/std/crypto/sha3.zig | 10 +-- lib/std/rand.zig | 4 +- lib/std/zig.zig | 2 +- tools/process_headers.zig | 2 +- 16 files changed, 242 insertions(+), 194 deletions(-) diff --git a/lib/std/bloom_filter.zig b/lib/std/bloom_filter.zig index 34fa42fe00..5ccef8d140 100644 --- a/lib/std/bloom_filter.zig +++ b/lib/std/bloom_filter.zig @@ -158,7 +158,7 @@ pub fn BloomFilter( } fn hashFunc(out: []u8, Ki: usize, in: []const u8) void { - var st = std.crypto.gimli.Hash.init(); + var st = std.crypto.hash.Gimli.init(); st.update(std.mem.asBytes(&Ki)); st.update(in); st.final(out); diff --git a/lib/std/build/write_file.zig b/lib/std/build/write_file.zig index fe15e6e0e3..222de7c79a 100644 --- a/lib/std/build/write_file.zig +++ b/lib/std/build/write_file.zig @@ -58,7 +58,7 @@ pub const WriteFileStep = struct { // TODO port the cache system from stage1 to zig std lib. Until then we use blake2b // directly and construct the path, and no "cache hit" detection happens; the files // are always written. - var hash = std.crypto.Blake2b384.init(); + var hash = std.crypto.hash.blake2.Blake2b384.init(); // Random bytes to make WriteFileStep unique. Refresh this with // new random bytes when WriteFileStep implementation is modified diff --git a/lib/std/cache_hash.zig b/lib/std/cache_hash.zig index 58c9f444f3..8025929347 100644 --- a/lib/std/cache_hash.zig +++ b/lib/std/cache_hash.zig @@ -4,7 +4,7 @@ // The MIT license requires this copyright notice to be included in all copies // and substantial portions of the software. const std = @import("std.zig"); -const Blake3 = std.crypto.Blake3; +const Blake3 = std.crypto.hash.Blake3; const fs = std.fs; const base64 = std.base64; const ArrayList = std.ArrayList; diff --git a/lib/std/crypto.zig b/lib/std/crypto.zig index edca2bc2ff..2a18bd88c7 100644 --- a/lib/std/crypto.zig +++ b/lib/std/crypto.zig @@ -3,60 +3,68 @@ // This file is part of [zig](https://ziglang.org/), which is MIT licensed. // The MIT license requires this copyright notice to be included in all copies // and substantial portions of the software. -pub const Md5 = @import("crypto/md5.zig").Md5; -pub const Sha1 = @import("crypto/sha1.zig").Sha1; -const sha2 = @import("crypto/sha2.zig"); -pub const Sha224 = sha2.Sha224; -pub const Sha256 = sha2.Sha256; -pub const Sha384 = sha2.Sha384; -pub const Sha512 = sha2.Sha512; +/// Hash functions. +pub const hash = struct { + pub const Md5 = @import("crypto/md5.zig").Md5; + pub const Sha1 = @import("crypto/sha1.zig").Sha1; + pub const sha2 = @import("crypto/sha2.zig"); + pub const sha3 = @import("crypto/sha3.zig"); + pub const blake2 = @import("crypto/blake2.zig"); + pub const Blake3 = @import("crypto/blake3.zig").Blake3; + pub const Gimli = @import("crypto/gimli.zig").Hash; +}; -const sha3 = @import("crypto/sha3.zig"); -pub const Sha3_224 = sha3.Sha3_224; -pub const Sha3_256 = sha3.Sha3_256; -pub const Sha3_384 = sha3.Sha3_384; -pub const Sha3_512 = sha3.Sha3_512; - -pub const gimli = @import("crypto/gimli.zig"); - -const blake2 = @import("crypto/blake2.zig"); -pub const Blake2s224 = blake2.Blake2s224; -pub const Blake2s256 = blake2.Blake2s256; -pub const Blake2b384 = blake2.Blake2b384; -pub const Blake2b512 = blake2.Blake2b512; - -pub const Blake3 = @import("crypto/blake3.zig").Blake3; - -const hmac = @import("crypto/hmac.zig"); -pub const HmacMd5 = hmac.HmacMd5; -pub const HmacSha1 = hmac.HmacSha1; -pub const HmacSha256 = hmac.HmacSha256; -pub const HmacBlake2s256 = hmac.HmacBlake2s256; - -pub const chacha20 = @import("crypto/chacha20.zig"); -pub const chaCha20IETF = chacha20.chaCha20IETF; -pub const chaCha20With64BitNonce = chacha20.chaCha20With64BitNonce; -pub const xChaCha20IETF = chacha20.xChaCha20IETF; - -pub const Poly1305 = @import("crypto/poly1305.zig").Poly1305; - -const import_aes = @import("crypto/aes.zig"); -pub const AES128 = import_aes.AES128; -pub const AES256 = import_aes.AES256; - -pub const Curve25519 = @import("crypto/25519/curve25519.zig").Curve25519; -pub const Ed25519 = @import("crypto/25519/ed25519.zig").Ed25519; -pub const Edwards25519 = @import("crypto/25519/edwards25519.zig").Edwards25519; -pub const X25519 = @import("crypto/25519/x25519.zig").X25519; -pub const Ristretto255 = @import("crypto/25519/ristretto255.zig").Ristretto255; +/// Authentication (MAC) functions. +pub const auth = struct { + pub const hmac = @import("crypto/hmac.zig"); +}; +/// Authenticated Encryption with Associated Data pub const aead = struct { - pub const Gimli = gimli.Aead; + const chacha20 = @import("crypto/chacha20.zig"); + + pub const Gimli = @import("crypto/gimli.zig").Aead; pub const ChaCha20Poly1305 = chacha20.Chacha20Poly1305; pub const XChaCha20Poly1305 = chacha20.XChacha20Poly1305; }; +/// MAC functions requiring single-use secret keys. +pub const onetimeauth = struct { + pub const Poly1305 = @import("crypto/poly1305.zig").Poly1305; +}; + +/// Core functions, that should rarely be used directly by applications. +pub const core = struct { + pub const aes = @import("crypto/aes.zig"); + pub const Gimli = @import("crypto/gimli.zig").State; +}; + +/// Elliptic-curve arithmetic. +pub const ecc = struct { + pub const Curve25519 = @import("crypto/25519/curve25519.zig").Curve25519; + pub const Edwards25519 = @import("crypto/25519/edwards25519.zig").Edwards25519; + pub const Ristretto255 = @import("crypto/25519/ristretto255.zig").Ristretto255; +}; + +/// Diffie-Hellman key exchange functions. +pub const dh = struct { + pub const X25519 = @import("crypto/25519/x25519.zig").X25519; +}; + +/// Digital signature functions. +pub const sign = struct { + pub const Ed25519 = @import("crypto/25519/ed25519.zig").Ed25519; +}; + +/// Stream ciphers. These do not provide any kind of authentication. +/// Most applications should be using AEAD constructions instead of stream ciphers directly. +pub const stream = struct { + pub const ChaCha20IETF = @import("crypto/chacha20.zig").ChaCha20IETF; + pub const XChaCha20IETF = @import("crypto/chacha20.zig").XChaCha20IETF; + pub const ChaCha20With64BitNonce = @import("crypto/chacha20.zig").ChaCha20With64BitNonce; +}; + const std = @import("std.zig"); pub const randomBytes = std.os.getrandom; @@ -83,16 +91,21 @@ test "crypto" { test "issue #4532: no index out of bounds" { const types = [_]type{ - Md5, - Sha1, - Sha224, - Sha256, - Sha384, - Sha512, - Blake2s224, - Blake2s256, - Blake2b384, - Blake2b512, + hash.Md5, + hash.Sha1, + hash.sha2.Sha224, + hash.sha2.Sha256, + hash.sha2.Sha384, + hash.sha2.Sha512, + hash.sha3.Sha3_224, + hash.sha3.Sha3_256, + hash.sha3.Sha3_384, + hash.sha3.Sha3_512, + hash.blake2.Blake2s224, + hash.blake2.Blake2s256, + hash.blake2.Blake2b384, + hash.blake2.Blake2b512, + hash.Gimli, }; inline for (types) |Hasher| { diff --git a/lib/std/crypto/25519/ed25519.zig b/lib/std/crypto/25519/ed25519.zig index 935abaecb3..d02fa0a2fd 100644 --- a/lib/std/crypto/25519/ed25519.zig +++ b/lib/std/crypto/25519/ed25519.zig @@ -6,7 +6,7 @@ const std = @import("std"); const fmt = std.fmt; const mem = std.mem; -const Sha512 = std.crypto.Sha512; +const Sha512 = std.crypto.hash.sha2.Sha512; /// Ed25519 (EdDSA) signatures. pub const Ed25519 = struct { diff --git a/lib/std/crypto/benchmark.zig b/lib/std/crypto/benchmark.zig index 5c27f2f4f5..748d575751 100644 --- a/lib/std/crypto/benchmark.zig +++ b/lib/std/crypto/benchmark.zig @@ -22,16 +22,16 @@ const Crypto = struct { }; const hashes = [_]Crypto{ - Crypto{ .ty = crypto.Md5, .name = "md5" }, - Crypto{ .ty = crypto.Sha1, .name = "sha1" }, - Crypto{ .ty = crypto.Sha256, .name = "sha256" }, - Crypto{ .ty = crypto.Sha512, .name = "sha512" }, - Crypto{ .ty = crypto.Sha3_256, .name = "sha3-256" }, - Crypto{ .ty = crypto.Sha3_512, .name = "sha3-512" }, - Crypto{ .ty = crypto.gimli.Hash, .name = "gimli-hash" }, - Crypto{ .ty = crypto.Blake2s256, .name = "blake2s" }, - Crypto{ .ty = crypto.Blake2b512, .name = "blake2b" }, - Crypto{ .ty = crypto.Blake3, .name = "blake3" }, + Crypto{ .ty = crypto.hash.Md5, .name = "md5" }, + Crypto{ .ty = crypto.hash.Sha1, .name = "sha1" }, + Crypto{ .ty = crypto.hash.sha2.Sha256, .name = "sha256" }, + Crypto{ .ty = crypto.hash.sha2.Sha512, .name = "sha512" }, + Crypto{ .ty = crypto.hash.sha3.Sha3_256, .name = "sha3-256" }, + Crypto{ .ty = crypto.hash.sha3.Sha3_512, .name = "sha3-512" }, + Crypto{ .ty = crypto.hash.Gimli, .name = "gimli-hash" }, + Crypto{ .ty = crypto.hash.blake2.Blake2s256, .name = "blake2s" }, + Crypto{ .ty = crypto.hash.blake2.Blake2b512, .name = "blake2b" }, + Crypto{ .ty = crypto.hash.Blake3, .name = "blake3" }, }; pub fn benchmarkHash(comptime Hash: anytype, comptime bytes: comptime_int) !u64 { @@ -55,10 +55,11 @@ pub fn benchmarkHash(comptime Hash: anytype, comptime bytes: comptime_int) !u64 } const macs = [_]Crypto{ - Crypto{ .ty = crypto.Poly1305, .name = "poly1305" }, - Crypto{ .ty = crypto.HmacMd5, .name = "hmac-md5" }, - Crypto{ .ty = crypto.HmacSha1, .name = "hmac-sha1" }, - Crypto{ .ty = crypto.HmacSha256, .name = "hmac-sha256" }, + Crypto{ .ty = crypto.onetimeauth.Poly1305, .name = "poly1305" }, + Crypto{ .ty = crypto.auth.HmacMd5, .name = "hmac-md5" }, + Crypto{ .ty = crypto.auth.HmacSha1, .name = "hmac-sha1" }, + Crypto{ .ty = crypto.auth.sha2.HmacSha256, .name = "hmac-sha256" }, + Crypto{ .ty = crypto.auth.sha2.HmacSha512, .name = "hmac-sha512" }, }; pub fn benchmarkMac(comptime Mac: anytype, comptime bytes: comptime_int) !u64 { @@ -84,7 +85,7 @@ pub fn benchmarkMac(comptime Mac: anytype, comptime bytes: comptime_int) !u64 { return throughput; } -const exchanges = [_]Crypto{Crypto{ .ty = crypto.X25519, .name = "x25519" }}; +const exchanges = [_]Crypto{Crypto{ .ty = crypto.dh.X25519, .name = "x25519" }}; pub fn benchmarkKeyExchange(comptime DhKeyExchange: anytype, comptime exchange_count: comptime_int) !u64 { std.debug.assert(DhKeyExchange.minimum_key_length >= DhKeyExchange.secret_length); @@ -111,7 +112,7 @@ pub fn benchmarkKeyExchange(comptime DhKeyExchange: anytype, comptime exchange_c return throughput; } -const signatures = [_]Crypto{Crypto{ .ty = crypto.Ed25519, .name = "ed25519" }}; +const signatures = [_]Crypto{Crypto{ .ty = crypto.sign.Ed25519, .name = "ed25519" }}; pub fn benchmarkSignatures(comptime Signature: anytype, comptime signatures_count: comptime_int) !u64 { var seed: [Signature.seed_length]u8 = undefined; diff --git a/lib/std/crypto/chacha20.zig b/lib/std/crypto/chacha20.zig index d402eb6750..1a359ecfc7 100644 --- a/lib/std/crypto/chacha20.zig +++ b/lib/std/crypto/chacha20.zig @@ -12,7 +12,7 @@ const assert = std.debug.assert; const testing = std.testing; const builtin = @import("builtin"); const maxInt = std.math.maxInt; -const Poly1305 = std.crypto.Poly1305; +const Poly1305 = std.crypto.onetimeauth.Poly1305; const QuarterRound = struct { a: usize, @@ -137,56 +137,60 @@ fn keyToWords(key: [32]u8) [8]u32 { /// /// ChaCha20 is self-reversing. To decrypt just run the cipher with the same /// counter, nonce, and key. -pub fn chaCha20IETF(out: []u8, in: []const u8, counter: u32, key: [32]u8, nonce: [12]u8) void { - assert(in.len >= out.len); - assert((in.len >> 6) + counter <= maxInt(u32)); +pub const ChaCha20IETF = struct { + pub fn xor(out: []u8, in: []const u8, counter: u32, key: [32]u8, nonce: [12]u8) void { + assert(in.len >= out.len); + assert((in.len >> 6) + counter <= maxInt(u32)); - var c: [4]u32 = undefined; - c[0] = counter; - c[1] = mem.readIntLittle(u32, nonce[0..4]); - c[2] = mem.readIntLittle(u32, nonce[4..8]); - c[3] = mem.readIntLittle(u32, nonce[8..12]); - chaCha20_internal(out, in, keyToWords(key), c); -} + var c: [4]u32 = undefined; + c[0] = counter; + c[1] = mem.readIntLittle(u32, nonce[0..4]); + c[2] = mem.readIntLittle(u32, nonce[4..8]); + c[3] = mem.readIntLittle(u32, nonce[8..12]); + chaCha20_internal(out, in, keyToWords(key), c); + } +}; /// This is the original ChaCha20 before RFC 7539, which recommends using the /// orgininal version on applications such as disk or file encryption that might /// exceed the 256 GiB limit of the 96-bit nonce version. -pub fn chaCha20With64BitNonce(out: []u8, in: []const u8, counter: u64, key: [32]u8, nonce: [8]u8) void { - assert(in.len >= out.len); - assert(counter +% (in.len >> 6) >= counter); +pub const ChaCha20With64BitNonce = struct { + pub fn xor(out: []u8, in: []const u8, counter: u64, key: [32]u8, nonce: [8]u8) void { + assert(in.len >= out.len); + assert(counter +% (in.len >> 6) >= counter); - var cursor: usize = 0; - const k = keyToWords(key); - var c: [4]u32 = undefined; - c[0] = @truncate(u32, counter); - c[1] = @truncate(u32, counter >> 32); - c[2] = mem.readIntLittle(u32, nonce[0..4]); - c[3] = mem.readIntLittle(u32, nonce[4..8]); + var cursor: usize = 0; + const k = keyToWords(key); + var c: [4]u32 = undefined; + c[0] = @truncate(u32, counter); + c[1] = @truncate(u32, counter >> 32); + c[2] = mem.readIntLittle(u32, nonce[0..4]); + c[3] = mem.readIntLittle(u32, nonce[4..8]); - const block_size = (1 << 6); - // The full block size is greater than the address space on a 32bit machine - const big_block = if (@sizeOf(usize) > 4) (block_size << 32) else maxInt(usize); + const block_size = (1 << 6); + // The full block size is greater than the address space on a 32bit machine + const big_block = if (@sizeOf(usize) > 4) (block_size << 32) else maxInt(usize); - // first partial big block - if (((@intCast(u64, maxInt(u32) - @truncate(u32, counter)) + 1) << 6) < in.len) { - chaCha20_internal(out[cursor..big_block], in[cursor..big_block], k, c); - cursor = big_block - cursor; - c[1] += 1; - if (comptime @sizeOf(usize) > 4) { - // A big block is giant: 256 GiB, but we can avoid this limitation - var remaining_blocks: u32 = @intCast(u32, (in.len / big_block)); - var i: u32 = 0; - while (remaining_blocks > 0) : (remaining_blocks -= 1) { - chaCha20_internal(out[cursor .. cursor + big_block], in[cursor .. cursor + big_block], k, c); - c[1] += 1; // upper 32-bit of counter, generic chaCha20_internal() doesn't know about this. - cursor += big_block; + // first partial big block + if (((@intCast(u64, maxInt(u32) - @truncate(u32, counter)) + 1) << 6) < in.len) { + chaCha20_internal(out[cursor..big_block], in[cursor..big_block], k, c); + cursor = big_block - cursor; + c[1] += 1; + if (comptime @sizeOf(usize) > 4) { + // A big block is giant: 256 GiB, but we can avoid this limitation + var remaining_blocks: u32 = @intCast(u32, (in.len / big_block)); + var i: u32 = 0; + while (remaining_blocks > 0) : (remaining_blocks -= 1) { + chaCha20_internal(out[cursor .. cursor + big_block], in[cursor .. cursor + big_block], k, c); + c[1] += 1; // upper 32-bit of counter, generic chaCha20_internal() doesn't know about this. + cursor += big_block; + } } } - } - chaCha20_internal(out[cursor..], in[cursor..], k, c); -} + chaCha20_internal(out[cursor..], in[cursor..], k, c); + } +}; // https://tools.ietf.org/html/rfc7539#section-2.4.2 test "crypto.chacha20 test vector sunscreen" { @@ -221,12 +225,12 @@ test "crypto.chacha20 test vector sunscreen" { 0, 0, 0, 0, }; - chaCha20IETF(result[0..], input[0..], 1, key, nonce); + ChaCha20IETF.xor(result[0..], input[0..], 1, key, nonce); testing.expectEqualSlices(u8, &expected_result, &result); // Chacha20 is self-reversing. var plaintext: [114]u8 = undefined; - chaCha20IETF(plaintext[0..], result[0..], 1, key, nonce); + ChaCha20IETF.xor(plaintext[0..], result[0..], 1, key, nonce); testing.expect(mem.order(u8, input, &plaintext) == .eq); } @@ -261,7 +265,7 @@ test "crypto.chacha20 test vector 1" { }; const nonce = [_]u8{ 0, 0, 0, 0, 0, 0, 0, 0 }; - chaCha20With64BitNonce(result[0..], input[0..], 0, key, nonce); + ChaCha20With64BitNonce.xor(result[0..], input[0..], 0, key, nonce); testing.expectEqualSlices(u8, &expected_result, &result); } @@ -295,7 +299,7 @@ test "crypto.chacha20 test vector 2" { }; const nonce = [_]u8{ 0, 0, 0, 0, 0, 0, 0, 0 }; - chaCha20With64BitNonce(result[0..], input[0..], 0, key, nonce); + ChaCha20With64BitNonce.xor(result[0..], input[0..], 0, key, nonce); testing.expectEqualSlices(u8, &expected_result, &result); } @@ -329,7 +333,7 @@ test "crypto.chacha20 test vector 3" { }; const nonce = [_]u8{ 0, 0, 0, 0, 0, 0, 0, 1 }; - chaCha20With64BitNonce(result[0..], input[0..], 0, key, nonce); + ChaCha20With64BitNonce.xor(result[0..], input[0..], 0, key, nonce); testing.expectEqualSlices(u8, &expected_result, &result); } @@ -363,7 +367,7 @@ test "crypto.chacha20 test vector 4" { }; const nonce = [_]u8{ 1, 0, 0, 0, 0, 0, 0, 0 }; - chaCha20With64BitNonce(result[0..], input[0..], 0, key, nonce); + ChaCha20With64BitNonce.xor(result[0..], input[0..], 0, key, nonce); testing.expectEqualSlices(u8, &expected_result, &result); } @@ -435,21 +439,21 @@ test "crypto.chacha20 test vector 5" { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, }; - chaCha20With64BitNonce(result[0..], input[0..], 0, key, nonce); + ChaCha20With64BitNonce.xor(result[0..], input[0..], 0, key, nonce); testing.expectEqualSlices(u8, &expected_result, &result); } pub const chacha20poly1305_tag_size = 16; -pub fn chacha20poly1305SealDetached(ciphertext: []u8, tag: *[chacha20poly1305_tag_size]u8, plaintext: []const u8, data: []const u8, key: [32]u8, nonce: [12]u8) void { +fn chacha20poly1305SealDetached(ciphertext: []u8, tag: *[chacha20poly1305_tag_size]u8, plaintext: []const u8, data: []const u8, key: [32]u8, nonce: [12]u8) void { assert(ciphertext.len >= plaintext.len); // derive poly1305 key var polyKey = [_]u8{0} ** 32; - chaCha20IETF(polyKey[0..], polyKey[0..], 0, key, nonce); + ChaCha20IETF.xor(polyKey[0..], polyKey[0..], 0, key, nonce); // encrypt plaintext - chaCha20IETF(ciphertext[0..plaintext.len], plaintext, 1, key, nonce); + ChaCha20IETF.xor(ciphertext[0..plaintext.len], plaintext, 1, key, nonce); // construct mac var mac = Poly1305.init(polyKey[0..]); @@ -472,18 +476,18 @@ pub fn chacha20poly1305SealDetached(ciphertext: []u8, tag: *[chacha20poly1305_ta mac.final(tag); } -pub fn chacha20poly1305Seal(ciphertextAndTag: []u8, plaintext: []const u8, data: []const u8, key: [32]u8, nonce: [12]u8) void { +fn chacha20poly1305Seal(ciphertextAndTag: []u8, plaintext: []const u8, data: []const u8, key: [32]u8, nonce: [12]u8) void { return chacha20poly1305SealDetached(ciphertextAndTag[0..plaintext.len], ciphertextAndTag[plaintext.len..][0..chacha20poly1305_tag_size], plaintext, data, key, nonce); } /// Verifies and decrypts an authenticated message produced by chacha20poly1305SealDetached. -pub fn chacha20poly1305OpenDetached(dst: []u8, ciphertext: []const u8, tag: *const [chacha20poly1305_tag_size]u8, data: []const u8, key: [32]u8, nonce: [12]u8) !void { +fn chacha20poly1305OpenDetached(dst: []u8, ciphertext: []const u8, tag: *const [chacha20poly1305_tag_size]u8, data: []const u8, key: [32]u8, nonce: [12]u8) !void { // split ciphertext and tag assert(dst.len >= ciphertext.len); // derive poly1305 key var polyKey = [_]u8{0} ** 32; - chaCha20IETF(polyKey[0..], polyKey[0..], 0, key, nonce); + ChaCha20IETF.xor(polyKey[0..], polyKey[0..], 0, key, nonce); // construct mac var mac = Poly1305.init(polyKey[0..]); @@ -519,11 +523,11 @@ pub fn chacha20poly1305OpenDetached(dst: []u8, ciphertext: []const u8, tag: *con } // decrypt ciphertext - chaCha20IETF(dst[0..ciphertext.len], ciphertext, 1, key, nonce); + ChaCha20IETF.xor(dst[0..ciphertext.len], ciphertext, 1, key, nonce); } /// Verifies and decrypts an authenticated message produced by chacha20poly1305Seal. -pub fn chacha20poly1305Open(dst: []u8, ciphertextAndTag: []const u8, data: []const u8, key: [32]u8, nonce: [12]u8) !void { +fn chacha20poly1305Open(dst: []u8, ciphertextAndTag: []const u8, data: []const u8, key: [32]u8, nonce: [12]u8) !void { if (ciphertextAndTag.len < chacha20poly1305_tag_size) { return error.InvalidMessage; } @@ -562,31 +566,33 @@ fn extend(key: [32]u8, nonce: [24]u8) struct { key: [32]u8, nonce: [12]u8 } { }; } -pub fn xChaCha20IETF(out: []u8, in: []const u8, counter: u32, key: [32]u8, nonce: [24]u8) void { - const extended = extend(key, nonce); - chaCha20IETF(out, in, counter, extended.key, extended.nonce); -} +pub const XChaCha20IETF = struct { + pub fn xor(out: []u8, in: []const u8, counter: u32, key: [32]u8, nonce: [24]u8) void { + const extended = extend(key, nonce); + ChaCha20IETF.xor(out, in, counter, extended.key, extended.nonce); + } +}; pub const xchacha20poly1305_tag_size = 16; -pub fn xchacha20poly1305SealDetached(ciphertext: []u8, tag: *[chacha20poly1305_tag_size]u8, plaintext: []const u8, data: []const u8, key: [32]u8, nonce: [24]u8) void { +fn xchacha20poly1305SealDetached(ciphertext: []u8, tag: *[chacha20poly1305_tag_size]u8, plaintext: []const u8, data: []const u8, key: [32]u8, nonce: [24]u8) void { const extended = extend(key, nonce); return chacha20poly1305SealDetached(ciphertext, tag, plaintext, data, extended.key, extended.nonce); } -pub fn xchacha20poly1305Seal(ciphertextAndTag: []u8, plaintext: []const u8, data: []const u8, key: [32]u8, nonce: [24]u8) void { +fn xchacha20poly1305Seal(ciphertextAndTag: []u8, plaintext: []const u8, data: []const u8, key: [32]u8, nonce: [24]u8) void { const extended = extend(key, nonce); return chacha20poly1305Seal(ciphertextAndTag, plaintext, data, extended.key, extended.nonce); } /// Verifies and decrypts an authenticated message produced by xchacha20poly1305SealDetached. -pub fn xchacha20poly1305OpenDetached(plaintext: []u8, ciphertext: []const u8, tag: *const [chacha20poly1305_tag_size]u8, data: []const u8, key: [32]u8, nonce: [24]u8) !void { +fn xchacha20poly1305OpenDetached(plaintext: []u8, ciphertext: []const u8, tag: *const [chacha20poly1305_tag_size]u8, data: []const u8, key: [32]u8, nonce: [24]u8) !void { const extended = extend(key, nonce); return try chacha20poly1305OpenDetached(plaintext, ciphertext, tag, data, extended.key, extended.nonce); } /// Verifies and decrypts an authenticated message produced by xchacha20poly1305Seal. -pub fn xchacha20poly1305Open(ciphertextAndTag: []u8, msgAndTag: []const u8, data: []const u8, key: [32]u8, nonce: [24]u8) !void { +fn xchacha20poly1305Open(ciphertextAndTag: []u8, msgAndTag: []const u8, data: []const u8, key: [32]u8, nonce: [24]u8) !void { const extended = extend(key, nonce); return try chacha20poly1305Open(ciphertextAndTag, msgAndTag, data, extended.key, extended.nonce); } @@ -714,7 +720,7 @@ test "crypto.xchacha20" { 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."; { var ciphertext: [input.len]u8 = undefined; - xChaCha20IETF(ciphertext[0..], input[0..], 0, key, nonce); + XChaCha20IETF.xor(ciphertext[0..], input[0..], 0, key, nonce); var buf: [2 * ciphertext.len]u8 = undefined; testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{ciphertext}), "E0A1BCF939654AFDBDC1746EC49832647C19D891F0D1A81FC0C1703B4514BDEA584B512F6908C2C5E9DD18D5CBC1805DE5803FE3B9CA5F193FB8359E91FAB0C3BB40309A292EB1CF49685C65C4A3ADF4F11DB0CD2B6B67FBC174BC2E860E8F769FD3565BBFAD1C845E05A0FED9BE167C240D"); } diff --git a/lib/std/crypto/gimli.zig b/lib/std/crypto/gimli.zig index 33afae5f82..77ea74fe0e 100644 --- a/lib/std/crypto/gimli.zig +++ b/lib/std/crypto/gimli.zig @@ -109,17 +109,21 @@ pub const Hash = struct { state: State, buf_off: usize, + pub const block_length = State.RATE; + const Self = @This(); pub fn init() Self { return Self{ - .state = State{ - .data = [_]u32{0} ** (State.BLOCKBYTES / 4), - }, + .state = State{ .data = [_]u32{0} ** (State.BLOCKBYTES / 4) }, .buf_off = 0, }; } + pub fn reset(self: *Self) void { + self.* = init(); + } + /// Also known as 'absorb' pub fn update(self: *Self, data: []const u8) void { const buf = self.state.toSlice(); diff --git a/lib/std/crypto/hmac.zig b/lib/std/crypto/hmac.zig index 984dacc967..212bc3e7b0 100644 --- a/lib/std/crypto/hmac.zig +++ b/lib/std/crypto/hmac.zig @@ -8,10 +8,19 @@ const crypto = std.crypto; const debug = std.debug; const mem = std.mem; -pub const HmacMd5 = Hmac(crypto.Md5); -pub const HmacSha1 = Hmac(crypto.Sha1); -pub const HmacSha256 = Hmac(crypto.Sha256); -pub const HmacBlake2s256 = Hmac(crypto.Blake2s256); +pub const HmacMd5 = Hmac(crypto.hash.legacy.Md5); +pub const HmacSha1 = Hmac(crypto.hash.legacy.Sha1); + +pub const sha2 = struct { + pub const HmacSha224 = Hmac(crypto.hash.sha2.Sha224); + pub const HmacSha256 = Hmac(crypto.hash.sha2.Sha256); + pub const HmacSha384 = Hmac(crypto.hash.sha2.Sha384); + pub const HmacSha512 = Hmac(crypto.hash.sha2.Sha512); +}; + +pub const blake2 = struct { + pub const HmacBlake2s256 = Hmac(crypto.hash.blake2.Blake2s256); +}; pub fn Hmac(comptime Hash: type) type { return struct { @@ -95,10 +104,10 @@ test "hmac sha1" { } test "hmac sha256" { - var out: [HmacSha256.mac_length]u8 = undefined; - HmacSha256.create(out[0..], "", ""); + var out: [sha2.HmacSha256.mac_length]u8 = undefined; + sha2.HmacSha256.create(out[0..], "", ""); htest.assertEqual("b613679a0814d9ec772f95d778c35fc5ff1697c493715653c6c712144292c5ad", out[0..]); - HmacSha256.create(out[0..], "The quick brown fox jumps over the lazy dog", "key"); + sha2.HmacSha256.create(out[0..], "The quick brown fox jumps over the lazy dog", "key"); htest.assertEqual("f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8", out[0..]); } diff --git a/lib/std/crypto/md5.zig b/lib/std/crypto/md5.zig index d578ba8b95..950e52e126 100644 --- a/lib/std/crypto/md5.zig +++ b/lib/std/crypto/md5.zig @@ -32,6 +32,9 @@ fn Rp(a: usize, b: usize, c: usize, d: usize, k: usize, s: u32, t: u32) RoundPar }; } +/// The MD5 function is now considered cryptographically broken. +/// Namely, it is trivial to find multiple inputs producing the same hash. +/// For a fast-performing, cryptographically secure hash function, see SHA512/256, BLAKE2 or BLAKE3. pub const Md5 = struct { const Self = @This(); pub const block_length = 64; @@ -44,18 +47,21 @@ pub const Md5 = struct { total_len: u64, pub fn init() Self { - var d: Self = undefined; - d.reset(); - return d; + return Self{ + .s = [_]u32{ + 0x67452301, + 0xEFCDAB89, + 0x98BADCFE, + 0x10325476, + }, + .buf = undefined, + .buf_len = 0, + .total_len = 0, + }; } - pub fn reset(d: *Self) void { - d.s[0] = 0x67452301; - d.s[1] = 0xEFCDAB89; - d.s[2] = 0x98BADCFE; - d.s[3] = 0x10325476; - d.buf_len = 0; - d.total_len = 0; + pub fn reset(self: *Self) void { + self.* = init(); } pub fn hash(b: []const u8, out: []u8) void { diff --git a/lib/std/crypto/sha1.zig b/lib/std/crypto/sha1.zig index 7cb4fbcf36..ce18ca5ef7 100644 --- a/lib/std/crypto/sha1.zig +++ b/lib/std/crypto/sha1.zig @@ -29,6 +29,9 @@ fn Rp(a: usize, b: usize, c: usize, d: usize, e: usize, i: u32) RoundParam { }; } +/// The SHA-1 function is now considered cryptographically broken. +/// Namely, it is feasible to find multiple inputs producing the same hash. +/// For a fast-performing, cryptographically secure hash function, see SHA512/256, BLAKE2 or BLAKE3. pub const Sha1 = struct { const Self = @This(); pub const block_length = 64; @@ -41,19 +44,22 @@ pub const Sha1 = struct { total_len: u64, pub fn init() Self { - var d: Self = undefined; - d.reset(); - return d; + return Self{ + .s = [_]u32{ + 0x67452301, + 0xEFCDAB89, + 0x98BADCFE, + 0x10325476, + 0xC3D2E1F0, + }, + .buf = undefined, + .buf_len = 0, + .total_len = 0, + }; } - pub fn reset(d: *Self) void { - d.s[0] = 0x67452301; - d.s[1] = 0xEFCDAB89; - d.s[2] = 0x98BADCFE; - d.s[3] = 0x10325476; - d.s[4] = 0xC3D2E1F0; - d.buf_len = 0; - d.total_len = 0; + pub fn reset(self: *Self) void { + self.* = init(); } pub fn hash(b: []const u8, out: []u8) void { diff --git a/lib/std/crypto/sha2.zig b/lib/std/crypto/sha2.zig index cac18ca1f7..e7d0135e81 100644 --- a/lib/std/crypto/sha2.zig +++ b/lib/std/crypto/sha2.zig @@ -93,22 +93,25 @@ fn Sha2_32(comptime params: Sha2Params32) type { total_len: u64, pub fn init() Self { - var d: Self = undefined; - d.reset(); - return d; + return Self{ + .s = [_]u32{ + params.iv0, + params.iv1, + params.iv2, + params.iv3, + params.iv4, + params.iv5, + params.iv6, + params.iv7, + }, + .buf = undefined, + .buf_len = 0, + .total_len = 0, + }; } - pub fn reset(d: *Self) void { - d.s[0] = params.iv0; - d.s[1] = params.iv1; - d.s[2] = params.iv2; - d.s[3] = params.iv3; - d.s[4] = params.iv4; - d.s[5] = params.iv5; - d.s[6] = params.iv6; - d.s[7] = params.iv7; - d.buf_len = 0; - d.total_len = 0; + pub fn reset(self: *Self) void { + self.* = init(); } pub fn hash(b: []const u8, out: []u8) void { diff --git a/lib/std/crypto/sha3.zig b/lib/std/crypto/sha3.zig index 03635ca553..630a44fbfb 100644 --- a/lib/std/crypto/sha3.zig +++ b/lib/std/crypto/sha3.zig @@ -27,14 +27,14 @@ fn Keccak(comptime bits: usize, comptime delim: u8) type { pub fn init() Self { var d: Self = undefined; - d.reset(); - return d; - } - - pub fn reset(d: *Self) void { mem.set(u8, d.s[0..], 0); d.offset = 0; d.rate = 200 - (bits / 4); + return d; + } + + pub fn reset(self: *Self) void { + self.* = init(); } pub fn hash(b: []const u8, out: []u8) void { diff --git a/lib/std/rand.zig b/lib/std/rand.zig index 85f11ff449..42726472bf 100644 --- a/lib/std/rand.zig +++ b/lib/std/rand.zig @@ -737,12 +737,12 @@ test "xoroshiro sequence" { // CSPRNG pub const Gimli = struct { random: Random, - state: std.crypto.gimli.State, + state: std.crypto.core.Gimli, pub fn init(init_s: u64) Gimli { var self = Gimli{ .random = Random{ .fillFn = fill }, - .state = std.crypto.gimli.State{ + .state = std.crypto.core.Gimli{ .data = [_]u32{0} ** (std.crypto.gimli.State.BLOCKBYTES / 4), }, }; diff --git a/lib/std/zig.zig b/lib/std/zig.zig index 34e03eb164..c93c22f257 100644 --- a/lib/std/zig.zig +++ b/lib/std/zig.zig @@ -26,7 +26,7 @@ pub fn hashSrc(src: []const u8) SrcHash { std.mem.copy(u8, &out, src); std.mem.set(u8, out[src.len..], 0); } else { - std.crypto.Blake3.hash(src, &out); + std.crypto.hash.Blake3.hash(src, &out); } return out; } diff --git a/tools/process_headers.zig b/tools/process_headers.zig index d17069401e..ba9fde6683 100644 --- a/tools/process_headers.zig +++ b/tools/process_headers.zig @@ -313,7 +313,7 @@ pub fn main() !void { var max_bytes_saved: usize = 0; var total_bytes: usize = 0; - var hasher = std.crypto.Sha256.init(); + var hasher = std.crypto.hash.sha2.Sha256.init(); for (libc_targets) |libc_target| { const dest_target = DestTarget{ From 3bed749b1c1285aa340f793fadb6b5b7275529cf Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Thu, 20 Aug 2020 12:56:42 +0200 Subject: [PATCH 41/66] Add truncated SHA512 variants --- lib/std/crypto/hmac.zig | 4 ++-- lib/std/crypto/sha2.zig | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/lib/std/crypto/hmac.zig b/lib/std/crypto/hmac.zig index 212bc3e7b0..3731fca34e 100644 --- a/lib/std/crypto/hmac.zig +++ b/lib/std/crypto/hmac.zig @@ -8,8 +8,8 @@ const crypto = std.crypto; const debug = std.debug; const mem = std.mem; -pub const HmacMd5 = Hmac(crypto.hash.legacy.Md5); -pub const HmacSha1 = Hmac(crypto.hash.legacy.Sha1); +pub const HmacMd5 = Hmac(crypto.hash.Md5); +pub const HmacSha1 = Hmac(crypto.hash.Sha1); pub const sha2 = struct { pub const HmacSha224 = Hmac(crypto.hash.sha2.Sha224); diff --git a/lib/std/crypto/sha2.zig b/lib/std/crypto/sha2.zig index e7d0135e81..1d460934d1 100644 --- a/lib/std/crypto/sha2.zig +++ b/lib/std/crypto/sha2.zig @@ -77,7 +77,10 @@ const Sha256Params = Sha2Params32{ .out_len = 256, }; +/// SHA-224 pub const Sha224 = Sha2_32(Sha224Params); + +/// SHA-256 pub const Sha256 = Sha2_32(Sha256Params); fn Sha2_32(comptime params: Sha2Params32) type { @@ -421,9 +424,42 @@ const Sha512Params = Sha2Params64{ .out_len = 512, }; +const Sha512256Params = Sha2Params64{ + .iv0 = 0x22312194FC2BF72C, + .iv1 = 0x9F555FA3C84C64C2, + .iv2 = 0x2393B86B6F53B151, + .iv3 = 0x963877195940EABD, + .iv4 = 0x96283EE2A88EFFE3, + .iv5 = 0xBE5E1E2553863992, + .iv6 = 0x2B0199FC2C85B8AA, + .iv7 = 0x0EB72DDC81C52CA2, + .out_len = 256, +}; + +const Sha512T256Params = Sha2Params64{ + .iv0 = 0x6A09E667F3BCC908, + .iv1 = 0xBB67AE8584CAA73B, + .iv2 = 0x3C6EF372FE94F82B, + .iv3 = 0xA54FF53A5F1D36F1, + .iv4 = 0x510E527FADE682D1, + .iv5 = 0x9B05688C2B3E6C1F, + .iv6 = 0x1F83D9ABFB41BD6B, + .iv7 = 0x5BE0CD19137E2179, + .out_len = 256, +}; + +/// SHA-384 pub const Sha384 = Sha2_64(Sha384Params); + +/// SHA-512 pub const Sha512 = Sha2_64(Sha512Params); +/// SHA-512/256 +pub const Sha512256 = Sha2_64(Sha512256Params); + +/// Truncated SHA-512 +pub const Sha512T256 = Sha2_64(Sha512T256Params); + fn Sha2_64(comptime params: Sha2Params64) type { return struct { const Self = @This(); From f92a5d79440402233bd0215e2bb2aeeb4f333931 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Thu, 20 Aug 2020 13:06:23 +0200 Subject: [PATCH 42/66] Repair crypto/benchmark; add BLAKE2b256 Some MACs have a 64-bit output --- lib/std/crypto/benchmark.zig | 12 ++++++------ lib/std/crypto/blake2.zig | 3 ++- lib/std/crypto/blake3.zig | 2 +- lib/std/crypto/sha3.zig | 10 +++++----- 4 files changed, 14 insertions(+), 13 deletions(-) diff --git a/lib/std/crypto/benchmark.zig b/lib/std/crypto/benchmark.zig index 748d575751..681739e1bd 100644 --- a/lib/std/crypto/benchmark.zig +++ b/lib/std/crypto/benchmark.zig @@ -56,19 +56,19 @@ pub fn benchmarkHash(comptime Hash: anytype, comptime bytes: comptime_int) !u64 const macs = [_]Crypto{ Crypto{ .ty = crypto.onetimeauth.Poly1305, .name = "poly1305" }, - Crypto{ .ty = crypto.auth.HmacMd5, .name = "hmac-md5" }, - Crypto{ .ty = crypto.auth.HmacSha1, .name = "hmac-sha1" }, - Crypto{ .ty = crypto.auth.sha2.HmacSha256, .name = "hmac-sha256" }, - Crypto{ .ty = crypto.auth.sha2.HmacSha512, .name = "hmac-sha512" }, + Crypto{ .ty = crypto.auth.hmac.HmacMd5, .name = "hmac-md5" }, + Crypto{ .ty = crypto.auth.hmac.HmacSha1, .name = "hmac-sha1" }, + Crypto{ .ty = crypto.auth.hmac.sha2.HmacSha256, .name = "hmac-sha256" }, + Crypto{ .ty = crypto.auth.hmac.sha2.HmacSha512, .name = "hmac-sha512" }, }; pub fn benchmarkMac(comptime Mac: anytype, comptime bytes: comptime_int) !u64 { - std.debug.assert(32 >= Mac.mac_length and 32 >= Mac.minimum_key_length); + std.debug.assert(64 >= Mac.mac_length and 32 >= Mac.minimum_key_length); var in: [1 * MiB]u8 = undefined; prng.random.bytes(in[0..]); - var key: [32]u8 = undefined; + var key: [64]u8 = undefined; prng.random.bytes(key[0..]); var offset: usize = 0; diff --git a/lib/std/crypto/blake2.zig b/lib/std/crypto/blake2.zig index 9f5194994d..5e39e7aa40 100644 --- a/lib/std/crypto/blake2.zig +++ b/lib/std/crypto/blake2.zig @@ -74,7 +74,7 @@ pub fn Blake2s(comptime out_len: usize) type { key: []const u8, pub fn init() Self { - return init_keyed(""); + return comptime init_keyed(""); } pub fn init_keyed(key: []const u8) Self { @@ -364,6 +364,7 @@ test "comptime blake2s256" { ///////////////////// // Blake2b +pub const Blake2b256 = Blake2b(256); pub const Blake2b384 = Blake2b(384); pub const Blake2b512 = Blake2b(512); diff --git a/lib/std/crypto/blake3.zig b/lib/std/crypto/blake3.zig index 08986965fc..2428c85d58 100644 --- a/lib/std/crypto/blake3.zig +++ b/lib/std/crypto/blake3.zig @@ -298,7 +298,7 @@ pub const Blake3 = struct { /// Construct a new `Blake3` for the regular hash function. pub fn init() Blake3 { - return Blake3.init_internal(IV, 0); + return comptime Blake3.init_internal(IV, 0); } /// Construct a new `Blake3` for the keyed hash function. diff --git a/lib/std/crypto/sha3.zig b/lib/std/crypto/sha3.zig index 630a44fbfb..d8575290a6 100644 --- a/lib/std/crypto/sha3.zig +++ b/lib/std/crypto/sha3.zig @@ -26,11 +26,11 @@ fn Keccak(comptime bits: usize, comptime delim: u8) type { rate: usize, pub fn init() Self { - var d: Self = undefined; - mem.set(u8, d.s[0..], 0); - d.offset = 0; - d.rate = 200 - (bits / 4); - return d; + return comptime Self{ + .s = [_]u8{0} ** 200, + .offset = 0, + .rate = 200 - (bits / 4), + }; } pub fn reset(self: *Self) void { From 446597bd3c935be632287a8ad6cfd72892d674e6 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Thu, 20 Aug 2020 22:36:57 +0200 Subject: [PATCH 43/66] Remove the reset() function from hash functions Justification: - reset() is unnecessary; states that have to be reused can be copied - reset() is error-prone. Copying a previous state prevents forgetting struct members. - reset() forces implementation to store sensitive data (key, initial state) in memory even when they are not needed. - reset() is confusing as it has a different meaning elsewhere in Zig. --- lib/std/crypto.zig | 6 ++-- lib/std/crypto/blake2.zig | 74 ++++++++++++++++----------------------- lib/std/crypto/blake3.zig | 13 ++++--- lib/std/crypto/gimli.zig | 4 --- lib/std/crypto/hmac.zig | 8 ++--- lib/std/crypto/md5.zig | 8 ++--- lib/std/crypto/sha1.zig | 17 +++------ lib/std/crypto/sha2.zig | 63 ++++++++++++++------------------- lib/std/crypto/sha3.zig | 26 +++++--------- 9 files changed, 85 insertions(+), 134 deletions(-) diff --git a/lib/std/crypto.zig b/lib/std/crypto.zig index 2a18bd88c7..bb55f52a40 100644 --- a/lib/std/crypto.zig +++ b/lib/std/crypto.zig @@ -112,11 +112,11 @@ test "issue #4532: no index out of bounds" { var block = [_]u8{'#'} ** Hasher.block_length; var out1: [Hasher.digest_length]u8 = undefined; var out2: [Hasher.digest_length]u8 = undefined; - - var h = Hasher.init(); + const h0 = Hasher.init(); + var h = h0; h.update(block[0..]); h.final(out1[0..]); - h.reset(); + h = h0; h.update(block[0..1]); h.update(block[1..]); h.final(out2[0..]); diff --git a/lib/std/crypto/blake2.zig b/lib/std/crypto/blake2.zig index 5e39e7aa40..ca310669f6 100644 --- a/lib/std/crypto/blake2.zig +++ b/lib/std/crypto/blake2.zig @@ -71,8 +71,6 @@ pub fn Blake2s(comptime out_len: usize) type { buf: [64]u8, buf_len: u8, - key: []const u8, - pub fn init() Self { return comptime init_keyed(""); } @@ -80,25 +78,20 @@ pub fn Blake2s(comptime out_len: usize) type { pub fn init_keyed(key: []const u8) Self { debug.assert(8 <= out_len and out_len <= 512); - var s: Self = undefined; - s.key = key; - s.reset(); - return s; - } - - pub fn reset(d: *Self) void { + var d: Self = undefined; mem.copy(u32, d.h[0..], iv[0..]); // default parameters - d.h[0] ^= 0x01010000 ^ @truncate(u32, d.key.len << 8) ^ @intCast(u32, out_len >> 3); + d.h[0] ^= 0x01010000 ^ @truncate(u32, key.len << 8) ^ @intCast(u32, out_len >> 3); d.t = 0; d.buf_len = 0; - if (d.key.len > 0) { - mem.set(u8, d.buf[d.key.len..], 0); - d.update(d.key); + if (key.len > 0) { + mem.set(u8, d.buf[key.len..], 0); + d.update(key); d.buf_len = 64; } + return d; } pub fn hash(b: []const u8, out: []u8) void { @@ -225,12 +218,12 @@ test "blake2s224 streaming" { const h2 = "0b033fc226df7abde29f67a05d3dc62cf271ef3dfea4d387407fbd55"; - h.reset(); + h = Blake2s224.init(); h.update("abc"); h.final(out[0..]); htest.assertEqual(h2, out[0..]); - h.reset(); + h = Blake2s224.init(); h.update("a"); h.update("b"); h.update("c"); @@ -239,13 +232,13 @@ test "blake2s224 streaming" { const h3 = "557381a78facd2b298640f4e32113e58967d61420af1aa939d0cfe01"; - h.reset(); + h = Blake2s224.init(); h.update("a" ** 32); h.update("b" ** 32); h.final(out[0..]); htest.assertEqual(h3, out[0..]); - h.reset(); + h = Blake2s224.init(); h.update("a" ** 32 ++ "b" ** 32); h.final(out[0..]); htest.assertEqual(h3, out[0..]); @@ -294,12 +287,12 @@ test "blake2s256 streaming" { const h2 = "508c5e8c327c14e2e1a72ba34eeb452f37458b209ed63a294d999b4c86675982"; - h.reset(); + h = Blake2s256.init(); h.update("abc"); h.final(out[0..]); htest.assertEqual(h2, out[0..]); - h.reset(); + h = Blake2s256.init(); h.update("a"); h.update("b"); h.update("c"); @@ -308,13 +301,13 @@ test "blake2s256 streaming" { const h3 = "8d8711dade07a6b92b9a3ea1f40bee9b2c53ff3edd2a273dec170b0163568977"; - h.reset(); + h = Blake2s256.init(); h.update("a" ** 32); h.update("b" ** 32); h.final(out[0..]); htest.assertEqual(h3, out[0..]); - h.reset(); + h = Blake2s256.init(); h.update("a" ** 32 ++ "b" ** 32); h.final(out[0..]); htest.assertEqual(h3, out[0..]); @@ -335,7 +328,7 @@ test "blake2s256 keyed" { htest.assertEqual(h1, out[0..]); - h.reset(); + h = Blake2s256.init_keyed(key); h.update("a" ** 64); h.update("b" ** 64); h.final(out[0..]); @@ -406,8 +399,6 @@ pub fn Blake2b(comptime out_len: usize) type { buf: [128]u8, buf_len: u8, - key: []const u8, - pub fn init() Self { return init_keyed(""); } @@ -415,25 +406,20 @@ pub fn Blake2b(comptime out_len: usize) type { pub fn init_keyed(key: []const u8) Self { debug.assert(8 <= out_len and out_len <= 512); - var s: Self = undefined; - s.key = key; - s.reset(); - return s; - } - - pub fn reset(d: *Self) void { + var d: Self = undefined; mem.copy(u64, d.h[0..], iv[0..]); // default parameters - d.h[0] ^= 0x01010000 ^ (d.key.len << 8) ^ (out_len >> 3); + d.h[0] ^= 0x01010000 ^ (key.len << 8) ^ (out_len >> 3); d.t = 0; d.buf_len = 0; - if (d.key.len > 0) { - mem.set(u8, d.buf[d.key.len..], 0); - d.update(d.key); + if (key.len > 0) { + mem.set(u8, d.buf[key.len..], 0); + d.update(key); d.buf_len = 128; } + return d; } pub fn hash(b: []const u8, out: []u8) void { @@ -558,12 +544,12 @@ test "blake2b384 streaming" { const h2 = "6f56a82c8e7ef526dfe182eb5212f7db9df1317e57815dbda46083fc30f54ee6c66ba83be64b302d7cba6ce15bb556f4"; - h.reset(); + h = Blake2b384.init(); h.update("abc"); h.final(out[0..]); htest.assertEqual(h2, out[0..]); - h.reset(); + h = Blake2b384.init(); h.update("a"); h.update("b"); h.update("c"); @@ -572,12 +558,12 @@ test "blake2b384 streaming" { const h3 = "b7283f0172fecbbd7eca32ce10d8a6c06b453cb3cf675b33eb4246f0da2bb94a6c0bdd6eec0b5fd71ec4fd51be80bf4c"; - h.reset(); + h = Blake2b384.init(); h.update("a" ** 64 ++ "b" ** 64); h.final(out[0..]); htest.assertEqual(h3, out[0..]); - h.reset(); + h = Blake2b384.init(); h.update("a" ** 64); h.update("b" ** 64); h.final(out[0..]); @@ -627,12 +613,12 @@ test "blake2b512 streaming" { const h2 = "ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d17d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923"; - h.reset(); + h = Blake2b512.init(); h.update("abc"); h.final(out[0..]); htest.assertEqual(h2, out[0..]); - h.reset(); + h = Blake2b512.init(); h.update("a"); h.update("b"); h.update("c"); @@ -641,12 +627,12 @@ test "blake2b512 streaming" { const h3 = "049980af04d6a2cf16b4b49793c3ed7e40732073788806f2c989ebe9547bda0541d63abe298ec8955d08af48ae731f2e8a0bd6d201655a5473b4aa79d211b920"; - h.reset(); + h = Blake2b512.init(); h.update("a" ** 64 ++ "b" ** 64); h.final(out[0..]); htest.assertEqual(h3, out[0..]); - h.reset(); + h = Blake2b512.init(); h.update("a" ** 64); h.update("b" ** 64); h.final(out[0..]); @@ -668,7 +654,7 @@ test "blake2b512 keyed" { htest.assertEqual(h1, out[0..]); - h.reset(); + h = Blake2b512.init_keyed(key); h.update("a" ** 64); h.update("b" ** 64); h.final(out[0..]); diff --git a/lib/std/crypto/blake3.zig b/lib/std/crypto/blake3.zig index 2428c85d58..056a11be25 100644 --- a/lib/std/crypto/blake3.zig +++ b/lib/std/crypto/blake3.zig @@ -326,12 +326,6 @@ pub const Blake3 = struct { hasher.final(out); } - /// Reset the `Blake3` to its initial state. - pub fn reset(self: *Blake3) void { - self.chunk_state = ChunkState.init(self.key, 0, self.flags); - self.cv_stack_len = 0; - } - fn push_cv(self: *Blake3, cv: [8]u32) void { self.cv_stack[self.cv_stack_len] = cv; self.cv_stack_len += 1; @@ -566,6 +560,9 @@ const reference_test = ReferenceTest{ }; fn test_blake3(hasher: *Blake3, input_len: usize, expected_hex: [262]u8) void { + // Save initial state + const initial_state = hasher.*; + // Setup input pattern var input_pattern: [251]u8 = undefined; for (input_pattern) |*e, i| e.* = @truncate(u8, i); @@ -581,12 +578,14 @@ fn test_blake3(hasher: *Blake3, input_len: usize, expected_hex: [262]u8) void { // Read final hash value var actual_bytes: [expected_hex.len / 2]u8 = undefined; hasher.final(actual_bytes[0..]); - hasher.reset(); // Compare to expected value var expected_bytes: [expected_hex.len / 2]u8 = undefined; fmt.hexToBytes(expected_bytes[0..], expected_hex[0..]) catch unreachable; testing.expectEqual(actual_bytes, expected_bytes); + + // Restore initial state + hasher.* = initial_state; } test "BLAKE3 reference test cases" { diff --git a/lib/std/crypto/gimli.zig b/lib/std/crypto/gimli.zig index 77ea74fe0e..b59d06e754 100644 --- a/lib/std/crypto/gimli.zig +++ b/lib/std/crypto/gimli.zig @@ -120,10 +120,6 @@ pub const Hash = struct { }; } - pub fn reset(self: *Self) void { - self.* = init(); - } - /// Also known as 'absorb' pub fn update(self: *Self, data: []const u8) void { const buf = self.state.toSlice(); diff --git a/lib/std/crypto/hmac.zig b/lib/std/crypto/hmac.zig index 3731fca34e..77db5bcaae 100644 --- a/lib/std/crypto/hmac.zig +++ b/lib/std/crypto/hmac.zig @@ -75,10 +75,10 @@ pub fn Hmac(comptime Hash: type) type { debug.assert(Hash.block_length >= out.len and out.len >= mac_length); ctx.hash.final(ctx.scratch[0..mac_length]); - ctx.hash.reset(); - ctx.hash.update(ctx.o_key_pad[0..]); - ctx.hash.update(ctx.scratch[0..mac_length]); - ctx.hash.final(out[0..mac_length]); + var ohash = Hash.init(); + ohash.update(ctx.o_key_pad[0..]); + ohash.update(ctx.scratch[0..mac_length]); + ohash.final(out[0..mac_length]); } }; } diff --git a/lib/std/crypto/md5.zig b/lib/std/crypto/md5.zig index 950e52e126..c33bee2e56 100644 --- a/lib/std/crypto/md5.zig +++ b/lib/std/crypto/md5.zig @@ -60,10 +60,6 @@ pub const Md5 = struct { }; } - pub fn reset(self: *Self) void { - self.* = init(); - } - pub fn hash(b: []const u8, out: []u8) void { var d = Md5.init(); d.update(b); @@ -267,12 +263,12 @@ test "md5 streaming" { h.final(out[0..]); htest.assertEqual("d41d8cd98f00b204e9800998ecf8427e", out[0..]); - h.reset(); + h = Md5.init(); h.update("abc"); h.final(out[0..]); htest.assertEqual("900150983cd24fb0d6963f7d28e17f72", out[0..]); - h.reset(); + h = Md5.init(); h.update("a"); h.update("b"); h.update("c"); diff --git a/lib/std/crypto/sha1.zig b/lib/std/crypto/sha1.zig index ce18ca5ef7..a62343eb7a 100644 --- a/lib/std/crypto/sha1.zig +++ b/lib/std/crypto/sha1.zig @@ -39,9 +39,9 @@ pub const Sha1 = struct { s: [5]u32, // Streaming Cache - buf: [64]u8, - buf_len: u8, - total_len: u64, + buf: [64]u8 = undefined, + buf_len: u8 = 0, + total_len: u64 = 0, pub fn init() Self { return Self{ @@ -52,16 +52,9 @@ pub const Sha1 = struct { 0x10325476, 0xC3D2E1F0, }, - .buf = undefined, - .buf_len = 0, - .total_len = 0, }; } - pub fn reset(self: *Self) void { - self.* = init(); - } - pub fn hash(b: []const u8, out: []u8) void { var d = Sha1.init(); d.update(b); @@ -289,12 +282,12 @@ test "sha1 streaming" { h.final(out[0..]); htest.assertEqual("da39a3ee5e6b4b0d3255bfef95601890afd80709", out[0..]); - h.reset(); + h = Sha1.init(); h.update("abc"); h.final(out[0..]); htest.assertEqual("a9993e364706816aba3e25717850c26c9cd0d89d", out[0..]); - h.reset(); + h = Sha1.init(); h.update("a"); h.update("b"); h.update("c"); diff --git a/lib/std/crypto/sha2.zig b/lib/std/crypto/sha2.zig index 1d460934d1..851b1dc405 100644 --- a/lib/std/crypto/sha2.zig +++ b/lib/std/crypto/sha2.zig @@ -91,9 +91,9 @@ fn Sha2_32(comptime params: Sha2Params32) type { s: [8]u32, // Streaming Cache - buf: [64]u8, - buf_len: u8, - total_len: u64, + buf: [64]u8 = undefined, + buf_len: u8 = 0, + total_len: u64 = 0, pub fn init() Self { return Self{ @@ -107,16 +107,9 @@ fn Sha2_32(comptime params: Sha2Params32) type { params.iv6, params.iv7, }, - .buf = undefined, - .buf_len = 0, - .total_len = 0, }; } - pub fn reset(self: *Self) void { - self.* = init(); - } - pub fn hash(b: []const u8, out: []u8) void { var d = Self.init(); d.update(b); @@ -309,12 +302,12 @@ test "sha224 streaming" { h.final(out[0..]); htest.assertEqual("d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f", out[0..]); - h.reset(); + h = Sha224.init(); h.update("abc"); h.final(out[0..]); htest.assertEqual("23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7", out[0..]); - h.reset(); + h = Sha224.init(); h.update("a"); h.update("b"); h.update("c"); @@ -335,12 +328,12 @@ test "sha256 streaming" { h.final(out[0..]); htest.assertEqual("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", out[0..]); - h.reset(); + h = Sha256.init(); h.update("abc"); h.final(out[0..]); htest.assertEqual("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", out[0..]); - h.reset(); + h = Sha256.init(); h.update("a"); h.update("b"); h.update("c"); @@ -468,27 +461,23 @@ fn Sha2_64(comptime params: Sha2Params64) type { s: [8]u64, // Streaming Cache - buf: [128]u8, - buf_len: u8, - total_len: u128, + buf: [128]u8 = undefined, + buf_len: u8 = 0, + total_len: u128 = 0, pub fn init() Self { - var d: Self = undefined; - d.reset(); - return d; - } - - pub fn reset(d: *Self) void { - d.s[0] = params.iv0; - d.s[1] = params.iv1; - d.s[2] = params.iv2; - d.s[3] = params.iv3; - d.s[4] = params.iv4; - d.s[5] = params.iv5; - d.s[6] = params.iv6; - d.s[7] = params.iv7; - d.buf_len = 0; - d.total_len = 0; + return Self{ + .s = [_]u64{ + params.iv0, + params.iv1, + params.iv2, + params.iv3, + params.iv4, + params.iv5, + params.iv6, + params.iv7, + }, + }; } pub fn hash(b: []const u8, out: []u8) void { @@ -713,12 +702,12 @@ test "sha384 streaming" { const h2 = "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7"; - h.reset(); + h = Sha384.init(); h.update("abc"); h.final(out[0..]); htest.assertEqual(h2, out[0..]); - h.reset(); + h = Sha384.init(); h.update("a"); h.update("b"); h.update("c"); @@ -747,12 +736,12 @@ test "sha512 streaming" { const h2 = "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f"; - h.reset(); + h = Sha512.init(); h.update("abc"); h.final(out[0..]); htest.assertEqual(h2, out[0..]); - h.reset(); + h = Sha512.init(); h.update("a"); h.update("b"); h.update("c"); diff --git a/lib/std/crypto/sha3.zig b/lib/std/crypto/sha3.zig index d8575290a6..273e5eea6d 100644 --- a/lib/std/crypto/sha3.zig +++ b/lib/std/crypto/sha3.zig @@ -26,15 +26,7 @@ fn Keccak(comptime bits: usize, comptime delim: u8) type { rate: usize, pub fn init() Self { - return comptime Self{ - .s = [_]u8{0} ** 200, - .offset = 0, - .rate = 200 - (bits / 4), - }; - } - - pub fn reset(self: *Self) void { - self.* = init(); + return Self{ .s = [_]u8{0} ** 200, .offset = 0, .rate = 200 - (bits / 4) }; } pub fn hash(b: []const u8, out: []u8) void { @@ -189,12 +181,12 @@ test "sha3-224 streaming" { h.final(out[0..]); htest.assertEqual("6b4e03423667dbb73b6e15454f0eb1abd4597f9a1b078e3f5b5a6bc7", out[0..]); - h.reset(); + h = Sha3_224.init(); h.update("abc"); h.final(out[0..]); htest.assertEqual("e642824c3f8cf24ad09234ee7d3c766fc9a3a5168d0c94ad73b46fdf", out[0..]); - h.reset(); + h = Sha3_224.init(); h.update("a"); h.update("b"); h.update("c"); @@ -215,12 +207,12 @@ test "sha3-256 streaming" { h.final(out[0..]); htest.assertEqual("a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a", out[0..]); - h.reset(); + h = Sha3_256.init(); h.update("abc"); h.final(out[0..]); htest.assertEqual("3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532", out[0..]); - h.reset(); + h = Sha3_256.init(); h.update("a"); h.update("b"); h.update("c"); @@ -255,12 +247,12 @@ test "sha3-384 streaming" { htest.assertEqual(h1, out[0..]); const h2 = "ec01498288516fc926459f58e2c6ad8df9b473cb0fc08c2596da7cf0e49be4b298d88cea927ac7f539f1edf228376d25"; - h.reset(); + h = Sha3_384.init(); h.update("abc"); h.final(out[0..]); htest.assertEqual(h2, out[0..]); - h.reset(); + h = Sha3_384.init(); h.update("a"); h.update("b"); h.update("c"); @@ -286,12 +278,12 @@ test "sha3-512 streaming" { htest.assertEqual(h1, out[0..]); const h2 = "b751850b1a57168a5693cd924b6b096e08f621827444f70d884f5d0240d2712e10e116e9192af3c91a7ec57647e3934057340b4cf408d5a56592f8274eec53f0"; - h.reset(); + h = Sha3_512.init(); h.update("abc"); h.final(out[0..]); htest.assertEqual(h2, out[0..]); - h.reset(); + h = Sha3_512.init(); h.update("a"); h.update("b"); h.update("c"); From adf3d00e874275557b69ef65164a2b2a0dd88167 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Thu, 20 Aug 2020 22:51:19 +0200 Subject: [PATCH 44/66] Remove explicit comptime --- lib/std/crypto/blake2.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/std/crypto/blake2.zig b/lib/std/crypto/blake2.zig index ca310669f6..bb07390286 100644 --- a/lib/std/crypto/blake2.zig +++ b/lib/std/crypto/blake2.zig @@ -72,7 +72,7 @@ pub fn Blake2s(comptime out_len: usize) type { buf_len: u8, pub fn init() Self { - return comptime init_keyed(""); + return init_keyed(""); } pub fn init_keyed(key: []const u8) Self { From 1ca49b92c650e9b8988a35983e202cdb9c7ba6e7 Mon Sep 17 00:00:00 2001 From: heidezomp Date: Thu, 20 Aug 2020 11:54:29 +0200 Subject: [PATCH 45/66] add UTIME_NOW and UTIME_OMIT constants for use in utimensat/futimens copied from lib/libc/include/generic-musl/sys/stat.h --- lib/std/os/bits/linux.zig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/std/os/bits/linux.zig b/lib/std/os/bits/linux.zig index 4fa8a02d3d..5c81ee8c06 100644 --- a/lib/std/os/bits/linux.zig +++ b/lib/std/os/bits/linux.zig @@ -775,6 +775,9 @@ pub fn S_ISSOCK(m: u32) bool { return m & S_IFMT == S_IFSOCK; } +pub const UTIME_NOW = 0x3fffffff; +pub const UTIME_OMIT = 0x3ffffffe; + pub const TFD_NONBLOCK = O_NONBLOCK; pub const TFD_CLOEXEC = O_CLOEXEC; From fc55cd458a7cd72ea876cf747b1ddd43d8dc6e20 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Fri, 21 Aug 2020 00:51:14 +0200 Subject: [PATCH 46/66] Hash functions now accept an option set - This avoids having multiple `init()` functions for every combination of optional parameters - The API is consistent across all hash functions - New options can be added later without breaking existing applications. For example, this is going to come in handy if we implement parallelization for BLAKE2 and BLAKE3. - We don't have a mix of snake_case and camelCase functions any more, at least in the public crypto API Support for BLAKE2 salt and personalization (more commonly called context) parameters have been implemented by the way to illustrate this. --- lib/std/bloom_filter.zig | 2 +- lib/std/cache_hash.zig | 10 +- lib/std/crypto.zig | 2 +- lib/std/crypto/25519/ed25519.zig | 10 +- lib/std/crypto/benchmark.zig | 2 +- lib/std/crypto/blake2.zig | 157 +++++++++++++++++++------------ lib/std/crypto/blake3.zig | 34 +++---- lib/std/crypto/gimli.zig | 9 +- lib/std/crypto/hmac.zig | 6 +- lib/std/crypto/md5.zig | 15 +-- lib/std/crypto/sha1.zig | 15 +-- lib/std/crypto/sha2.zig | 42 +++++---- lib/std/crypto/sha3.zig | 35 +++---- lib/std/crypto/test.zig | 2 +- lib/std/zig.zig | 2 +- 15 files changed, 194 insertions(+), 149 deletions(-) diff --git a/lib/std/bloom_filter.zig b/lib/std/bloom_filter.zig index 5ccef8d140..0e251f548f 100644 --- a/lib/std/bloom_filter.zig +++ b/lib/std/bloom_filter.zig @@ -158,7 +158,7 @@ pub fn BloomFilter( } fn hashFunc(out: []u8, Ki: usize, in: []const u8) void { - var st = std.crypto.hash.Gimli.init(); + var st = std.crypto.hash.Gimli.init(.{}); st.update(std.mem.asBytes(&Ki)); st.update(in); st.final(out); diff --git a/lib/std/cache_hash.zig b/lib/std/cache_hash.zig index 8025929347..edd0ebf126 100644 --- a/lib/std/cache_hash.zig +++ b/lib/std/cache_hash.zig @@ -56,7 +56,7 @@ pub const CacheHash = struct { pub fn init(allocator: *Allocator, dir: fs.Dir, manifest_dir_path: []const u8) !CacheHash { return CacheHash{ .allocator = allocator, - .blake3 = Blake3.init(), + .blake3 = Blake3.init(.{}), .manifest_dir = try dir.makeOpenPath(manifest_dir_path, .{}), .manifest_file = null, .manifest_dirty = false, @@ -137,7 +137,7 @@ pub const CacheHash = struct { base64_encoder.encode(self.b64_digest[0..], &bin_digest); - self.blake3 = Blake3.init(); + self.blake3 = Blake3.init(.{}); self.blake3.update(&bin_digest); const manifest_file_path = try fmt.allocPrint(self.allocator, "{}.txt", .{self.b64_digest}); @@ -256,7 +256,7 @@ pub const CacheHash = struct { // cache miss // keep the manifest file open // reset the hash - self.blake3 = Blake3.init(); + self.blake3 = Blake3.init(.{}); self.blake3.update(&bin_digest); // Remove files not in the initial hash @@ -304,7 +304,7 @@ pub const CacheHash = struct { // Hash while reading from disk, to keep the contents in the cpu cache while // doing hashing. - var blake3 = Blake3.init(); + var blake3 = Blake3.init(.{}); var off: usize = 0; while (true) { // give me everything you've got, captain @@ -434,7 +434,7 @@ pub const CacheHash = struct { }; fn hashFile(file: fs.File, bin_digest: []u8) !void { - var blake3 = Blake3.init(); + var blake3 = Blake3.init(.{}); var buf: [1024]u8 = undefined; while (true) { diff --git a/lib/std/crypto.zig b/lib/std/crypto.zig index bb55f52a40..32ab5071c5 100644 --- a/lib/std/crypto.zig +++ b/lib/std/crypto.zig @@ -112,7 +112,7 @@ test "issue #4532: no index out of bounds" { var block = [_]u8{'#'} ** Hasher.block_length; var out1: [Hasher.digest_length]u8 = undefined; var out2: [Hasher.digest_length]u8 = undefined; - const h0 = Hasher.init(); + const h0 = Hasher.init(.{}); var h = h0; h.update(block[0..]); h.final(out1[0..]); diff --git a/lib/std/crypto/25519/ed25519.zig b/lib/std/crypto/25519/ed25519.zig index d02fa0a2fd..9993afb6d2 100644 --- a/lib/std/crypto/25519/ed25519.zig +++ b/lib/std/crypto/25519/ed25519.zig @@ -33,7 +33,7 @@ pub const Ed25519 = struct { /// from which the actual secret is derived. pub fn createKeyPair(seed: [seed_length]u8) ![keypair_length]u8 { var az: [Sha512.digest_length]u8 = undefined; - var h = Sha512.init(); + var h = Sha512.init(.{}); h.update(&seed); h.final(&az); const p = try Curve.basePoint.clampedMul(az[0..32].*); @@ -56,11 +56,11 @@ pub const Ed25519 = struct { pub fn sign(msg: []const u8, key_pair: [keypair_length]u8, noise: ?[noise_length]u8) ![signature_length]u8 { const public_key = key_pair[32..]; var az: [Sha512.digest_length]u8 = undefined; - var h = Sha512.init(); + var h = Sha512.init(.{}); h.update(key_pair[0..seed_length]); h.final(&az); - h = Sha512.init(); + h = Sha512.init(.{}); if (noise) |*z| { h.update(z); } @@ -74,7 +74,7 @@ pub const Ed25519 = struct { var sig: [signature_length]u8 = undefined; mem.copy(u8, sig[0..32], &r.toBytes()); mem.copy(u8, sig[32..], public_key); - h = Sha512.init(); + h = Sha512.init(.{}); h.update(&sig); h.update(msg); var hram64: [Sha512.digest_length]u8 = undefined; @@ -98,7 +98,7 @@ pub const Ed25519 = struct { const a = try Curve.fromBytes(public_key); try a.rejectIdentity(); - var h = Sha512.init(); + var h = Sha512.init(.{}); h.update(r); h.update(&public_key); h.update(msg); diff --git a/lib/std/crypto/benchmark.zig b/lib/std/crypto/benchmark.zig index 681739e1bd..70bd30d6bb 100644 --- a/lib/std/crypto/benchmark.zig +++ b/lib/std/crypto/benchmark.zig @@ -35,7 +35,7 @@ const hashes = [_]Crypto{ }; pub fn benchmarkHash(comptime Hash: anytype, comptime bytes: comptime_int) !u64 { - var h = Hash.init(); + var h = Hash.init(.{}); var block: [Hash.digest_length]u8 = undefined; prng.random.bytes(block[0..]); diff --git a/lib/std/crypto/blake2.zig b/lib/std/crypto/blake2.zig index bb07390286..1cb143811c 100644 --- a/lib/std/crypto/blake2.zig +++ b/lib/std/crypto/blake2.zig @@ -40,6 +40,7 @@ pub fn Blake2s(comptime out_len: usize) type { const Self = @This(); pub const block_length = 64; pub const digest_length = out_len / 8; + pub const Options = struct { key: ?[]const u8 = null, salt: ?[8]u8 = null, context: ?[8]u8 = null }; const iv = [8]u32{ 0x6A09E667, @@ -71,35 +72,36 @@ pub fn Blake2s(comptime out_len: usize) type { buf: [64]u8, buf_len: u8, - pub fn init() Self { - return init_keyed(""); - } - - pub fn init_keyed(key: []const u8) Self { + pub fn init(options: Options) Self { debug.assert(8 <= out_len and out_len <= 512); var d: Self = undefined; mem.copy(u32, d.h[0..], iv[0..]); + const key_len = if (options.key) |key| key.len else 0; // default parameters - d.h[0] ^= 0x01010000 ^ @truncate(u32, key.len << 8) ^ @intCast(u32, out_len >> 3); + d.h[0] ^= 0x01010000 ^ @truncate(u32, key_len << 8) ^ @intCast(u32, out_len >> 3); d.t = 0; d.buf_len = 0; - if (key.len > 0) { - mem.set(u8, d.buf[key.len..], 0); - d.update(key); + if (options.salt) |salt| { + d.h[4] ^= mem.readIntLittle(u32, salt[0..4]); + d.h[5] ^= mem.readIntLittle(u32, salt[4..8]); + } + if (options.context) |context| { + d.h[6] ^= mem.readIntLittle(u32, context[0..4]); + d.h[7] ^= mem.readIntLittle(u32, context[4..8]); + } + if (key_len > 0) { + mem.set(u8, d.buf[key_len..], 0); + d.update(options.key.?); d.buf_len = 64; } return d; } - pub fn hash(b: []const u8, out: []u8) void { - Self.hash_keyed("", b, out); - } - - pub fn hash_keyed(key: []const u8, b: []const u8, out: []u8) void { - var d = Self.init_keyed(key); + pub fn hash(b: []const u8, out: []u8, options: Options) void { + var d = Self.init(options); d.update(b); d.final(out); } @@ -208,7 +210,7 @@ test "blake2s224 single" { } test "blake2s224 streaming" { - var h = Blake2s224.init(); + var h = Blake2s224.init(.{}); var out: [28]u8 = undefined; const h1 = "1fa1291e65248b37b3433475b2a0dd63d54a11ecc4e3e034e7bc1ef4"; @@ -218,12 +220,12 @@ test "blake2s224 streaming" { const h2 = "0b033fc226df7abde29f67a05d3dc62cf271ef3dfea4d387407fbd55"; - h = Blake2s224.init(); + h = Blake2s224.init(.{}); h.update("abc"); h.final(out[0..]); htest.assertEqual(h2, out[0..]); - h = Blake2s224.init(); + h = Blake2s224.init(.{}); h.update("a"); h.update("b"); h.update("c"); @@ -232,16 +234,29 @@ test "blake2s224 streaming" { const h3 = "557381a78facd2b298640f4e32113e58967d61420af1aa939d0cfe01"; - h = Blake2s224.init(); + h = Blake2s224.init(.{}); h.update("a" ** 32); h.update("b" ** 32); h.final(out[0..]); htest.assertEqual(h3, out[0..]); - h = Blake2s224.init(); + h = Blake2s224.init(.{}); h.update("a" ** 32 ++ "b" ** 32); h.final(out[0..]); htest.assertEqual(h3, out[0..]); + + const h4 = "a4d6a9d253441b80e5dfd60a04db169ffab77aec56a2855c402828c3"; + + h = Blake2s224.init(.{ .context = [_]u8{0x69} ** 8, .salt = [_]u8{0x42} ** 8 }); + h.update("a" ** 32); + h.update("b" ** 32); + h.final(out[0..]); + htest.assertEqual(h4, out[0..]); + + h = Blake2s224.init(.{ .context = [_]u8{0x69} ** 8, .salt = [_]u8{0x42} ** 8 }); + h.update("a" ** 32 ++ "b" ** 32); + h.final(out[0..]); + htest.assertEqual(h4, out[0..]); } test "comptime blake2s224" { @@ -254,7 +269,7 @@ test "comptime blake2s224" { htest.assertEqualHash(Blake2s224, h1, block[0..]); - var h = Blake2s224.init(); + var h = Blake2s224.init(.{}); h.update(&block); h.final(out[0..]); @@ -277,7 +292,7 @@ test "blake2s256 single" { } test "blake2s256 streaming" { - var h = Blake2s256.init(); + var h = Blake2s256.init(.{}); var out: [32]u8 = undefined; const h1 = "69217a3079908094e11121d042354a7c1f55b6482ca1a51e1b250dfd1ed0eef9"; @@ -287,12 +302,12 @@ test "blake2s256 streaming" { const h2 = "508c5e8c327c14e2e1a72ba34eeb452f37458b209ed63a294d999b4c86675982"; - h = Blake2s256.init(); + h = Blake2s256.init(.{}); h.update("abc"); h.final(out[0..]); htest.assertEqual(h2, out[0..]); - h = Blake2s256.init(); + h = Blake2s256.init(.{}); h.update("a"); h.update("b"); h.update("c"); @@ -301,13 +316,13 @@ test "blake2s256 streaming" { const h3 = "8d8711dade07a6b92b9a3ea1f40bee9b2c53ff3edd2a273dec170b0163568977"; - h = Blake2s256.init(); + h = Blake2s256.init(.{}); h.update("a" ** 32); h.update("b" ** 32); h.final(out[0..]); htest.assertEqual(h3, out[0..]); - h = Blake2s256.init(); + h = Blake2s256.init(.{}); h.update("a" ** 32 ++ "b" ** 32); h.final(out[0..]); htest.assertEqual(h3, out[0..]); @@ -319,16 +334,16 @@ test "blake2s256 keyed" { const h1 = "10f918da4d74fab3302e48a5d67d03804b1ec95372a62a0f33b7c9fa28ba1ae6"; const key = "secret_key"; - Blake2s256.hash_keyed(key, "a" ** 64 ++ "b" ** 64, &out); + Blake2s256.hash("a" ** 64 ++ "b" ** 64, &out, .{ .key = key }); htest.assertEqual(h1, out[0..]); - var h = Blake2s256.init_keyed(key); + var h = Blake2s256.init(.{ .key = key }); h.update("a" ** 64 ++ "b" ** 64); h.final(out[0..]); htest.assertEqual(h1, out[0..]); - h = Blake2s256.init_keyed(key); + h = Blake2s256.init(.{ .key = key }); h.update("a" ** 64); h.update("b" ** 64); h.final(out[0..]); @@ -346,7 +361,7 @@ test "comptime blake2s256" { htest.assertEqualHash(Blake2s256, h1, block[0..]); - var h = Blake2s256.init(); + var h = Blake2s256.init(.{}); h.update(&block); h.final(out[0..]); @@ -366,6 +381,7 @@ pub fn Blake2b(comptime out_len: usize) type { const Self = @This(); pub const block_length = 128; pub const digest_length = out_len / 8; + pub const Options = struct { key: ?[]const u8 = null, salt: ?[16]u8 = null, context: ?[16]u8 = null }; const iv = [8]u64{ 0x6a09e667f3bcc908, @@ -399,35 +415,36 @@ pub fn Blake2b(comptime out_len: usize) type { buf: [128]u8, buf_len: u8, - pub fn init() Self { - return init_keyed(""); - } - - pub fn init_keyed(key: []const u8) Self { + pub fn init(options: Options) Self { debug.assert(8 <= out_len and out_len <= 512); var d: Self = undefined; mem.copy(u64, d.h[0..], iv[0..]); + const key_len = if (options.key) |key| key.len else 0; // default parameters - d.h[0] ^= 0x01010000 ^ (key.len << 8) ^ (out_len >> 3); + d.h[0] ^= 0x01010000 ^ (key_len << 8) ^ (out_len >> 3); d.t = 0; d.buf_len = 0; - if (key.len > 0) { - mem.set(u8, d.buf[key.len..], 0); - d.update(key); + if (options.salt) |salt| { + d.h[4] ^= mem.readIntLittle(u64, salt[0..8]); + d.h[5] ^= mem.readIntLittle(u64, salt[8..16]); + } + if (options.context) |context| { + d.h[6] ^= mem.readIntLittle(u64, context[0..8]); + d.h[7] ^= mem.readIntLittle(u64, context[8..16]); + } + if (key_len > 0) { + mem.set(u8, d.buf[key_len..], 0); + d.update(options.key.?); d.buf_len = 128; } return d; } - pub fn hash(b: []const u8, out: []u8) void { - Self.hash_keyed("", b, out); - } - - pub fn hash_keyed(key: []const u8, b: []const u8, out: []u8) void { - var d = Self.init_keyed(key); + pub fn hash(b: []const u8, out: []u8, options: Options) void { + var d = Self.init(options); d.update(b); d.final(out); } @@ -534,7 +551,7 @@ test "blake2b384 single" { } test "blake2b384 streaming" { - var h = Blake2b384.init(); + var h = Blake2b384.init(.{}); var out: [48]u8 = undefined; const h1 = "b32811423377f52d7862286ee1a72ee540524380fda1724a6f25d7978c6fd3244a6caf0498812673c5e05ef583825100"; @@ -544,12 +561,12 @@ test "blake2b384 streaming" { const h2 = "6f56a82c8e7ef526dfe182eb5212f7db9df1317e57815dbda46083fc30f54ee6c66ba83be64b302d7cba6ce15bb556f4"; - h = Blake2b384.init(); + h = Blake2b384.init(.{}); h.update("abc"); h.final(out[0..]); htest.assertEqual(h2, out[0..]); - h = Blake2b384.init(); + h = Blake2b384.init(.{}); h.update("a"); h.update("b"); h.update("c"); @@ -558,16 +575,36 @@ test "blake2b384 streaming" { const h3 = "b7283f0172fecbbd7eca32ce10d8a6c06b453cb3cf675b33eb4246f0da2bb94a6c0bdd6eec0b5fd71ec4fd51be80bf4c"; - h = Blake2b384.init(); + h = Blake2b384.init(.{}); h.update("a" ** 64 ++ "b" ** 64); h.final(out[0..]); htest.assertEqual(h3, out[0..]); - h = Blake2b384.init(); + h = Blake2b384.init(.{}); h.update("a" ** 64); h.update("b" ** 64); h.final(out[0..]); htest.assertEqual(h3, out[0..]); + + h = Blake2b384.init(.{}); + h.update("a" ** 64); + h.update("b" ** 64); + h.final(out[0..]); + htest.assertEqual(h3, out[0..]); + + const h4 = "934c48fcb197031c71f583d92f98703510805e72142e0b46f5752d1e971bc86c355d556035613ff7a4154b4de09dac5c"; + + h = Blake2b384.init(.{ .context = [_]u8{0x69} ** 16, .salt = [_]u8{0x42} ** 16 }); + h.update("a" ** 64); + h.update("b" ** 64); + h.final(out[0..]); + htest.assertEqual(h4, out[0..]); + + h = Blake2b384.init(.{ .context = [_]u8{0x69} ** 16, .salt = [_]u8{0x42} ** 16 }); + h.update("a" ** 64); + h.update("b" ** 64); + h.final(out[0..]); + htest.assertEqual(h4, out[0..]); } test "comptime blake2b384" { @@ -580,7 +617,7 @@ test "comptime blake2b384" { htest.assertEqualHash(Blake2b384, h1, block[0..]); - var h = Blake2b384.init(); + var h = Blake2b384.init(.{}); h.update(&block); h.final(out[0..]); @@ -603,7 +640,7 @@ test "blake2b512 single" { } test "blake2b512 streaming" { - var h = Blake2b512.init(); + var h = Blake2b512.init(.{}); var out: [64]u8 = undefined; const h1 = "786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce"; @@ -613,12 +650,12 @@ test "blake2b512 streaming" { const h2 = "ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d17d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923"; - h = Blake2b512.init(); + h = Blake2b512.init(.{}); h.update("abc"); h.final(out[0..]); htest.assertEqual(h2, out[0..]); - h = Blake2b512.init(); + h = Blake2b512.init(.{}); h.update("a"); h.update("b"); h.update("c"); @@ -627,12 +664,12 @@ test "blake2b512 streaming" { const h3 = "049980af04d6a2cf16b4b49793c3ed7e40732073788806f2c989ebe9547bda0541d63abe298ec8955d08af48ae731f2e8a0bd6d201655a5473b4aa79d211b920"; - h = Blake2b512.init(); + h = Blake2b512.init(.{}); h.update("a" ** 64 ++ "b" ** 64); h.final(out[0..]); htest.assertEqual(h3, out[0..]); - h = Blake2b512.init(); + h = Blake2b512.init(.{}); h.update("a" ** 64); h.update("b" ** 64); h.final(out[0..]); @@ -645,16 +682,16 @@ test "blake2b512 keyed" { const h1 = "8a978060ccaf582f388f37454363071ac9a67e3a704585fd879fb8a419a447e389c7c6de790faa20a7a7dccf197de736bc5b40b98a930b36df5bee7555750c4d"; const key = "secret_key"; - Blake2b512.hash_keyed(key, "a" ** 64 ++ "b" ** 64, &out); + Blake2b512.hash("a" ** 64 ++ "b" ** 64, &out, .{ .key = key }); htest.assertEqual(h1, out[0..]); - var h = Blake2b512.init_keyed(key); + var h = Blake2b512.init(.{ .key = key }); h.update("a" ** 64 ++ "b" ** 64); h.final(out[0..]); htest.assertEqual(h1, out[0..]); - h = Blake2b512.init_keyed(key); + h = Blake2b512.init(.{ .key = key }); h.update("a" ** 64); h.update("b" ** 64); h.final(out[0..]); @@ -672,7 +709,7 @@ test "comptime blake2b512" { htest.assertEqualHash(Blake2b512, h1, block[0..]); - var h = Blake2b512.init(); + var h = Blake2b512.init(.{}); h.update(&block); h.final(out[0..]); diff --git a/lib/std/crypto/blake3.zig b/lib/std/crypto/blake3.zig index 056a11be25..163c91b358 100644 --- a/lib/std/crypto/blake3.zig +++ b/lib/std/crypto/blake3.zig @@ -279,6 +279,9 @@ fn parent_cv( /// An incremental hasher that can accept any number of writes. pub const Blake3 = struct { + pub const Options = struct { key: ?[KEY_LEN]u8 = null }; + pub const KdfOptions = struct {}; + chunk_state: ChunkState, key: [8]u32, cv_stack: [54][8]u32 = undefined, // Space for 54 subtree chaining values: @@ -296,21 +299,20 @@ pub const Blake3 = struct { }; } - /// Construct a new `Blake3` for the regular hash function. - pub fn init() Blake3 { - return comptime Blake3.init_internal(IV, 0); - } - - /// Construct a new `Blake3` for the keyed hash function. - pub fn init_keyed(key: [KEY_LEN]u8) Blake3 { - var key_words: [8]u32 = undefined; - words_from_little_endian_bytes(key_words[0..], key[0..]); - return Blake3.init_internal(key_words, KEYED_HASH); + /// Construct a new `Blake3` for the hash function, with an optional key + pub fn init(options: Options) Blake3 { + if (options.key) |key| { + var key_words: [8]u32 = undefined; + words_from_little_endian_bytes(key_words[0..], key[0..]); + return Blake3.init_internal(key_words, KEYED_HASH); + } else { + return Blake3.init_internal(IV, 0); + } } /// Construct a new `Blake3` for the key derivation function. The context /// string should be hardcoded, globally unique, and application-specific. - pub fn init_derive_key(context: []const u8) Blake3 { + pub fn initKdf(context: []const u8, options: KdfOptions) Blake3 { var context_hasher = Blake3.init_internal(IV, DERIVE_KEY_CONTEXT); context_hasher.update(context); var context_key: [KEY_LEN]u8 = undefined; @@ -320,8 +322,8 @@ pub const Blake3 = struct { return Blake3.init_internal(context_key_words, DERIVE_KEY_MATERIAL); } - pub fn hash(in: []const u8, out: []u8) void { - var hasher = Blake3.init(); + pub fn hash(in: []const u8, out: []u8, options: Options) void { + var hasher = Blake3.init(options); hasher.update(in); hasher.final(out); } @@ -589,9 +591,9 @@ fn test_blake3(hasher: *Blake3, input_len: usize, expected_hex: [262]u8) void { } test "BLAKE3 reference test cases" { - var hash = &Blake3.init(); - var keyed_hash = &Blake3.init_keyed(reference_test.key.*); - var derive_key = &Blake3.init_derive_key(reference_test.context_string); + var hash = &Blake3.init(.{}); + var keyed_hash = &Blake3.init(.{ .key = reference_test.key.* }); + var derive_key = &Blake3.initKdf(reference_test.context_string, .{}); for (reference_test.cases) |t| { test_blake3(hash, t.input_len, t.hash.*); diff --git a/lib/std/crypto/gimli.zig b/lib/std/crypto/gimli.zig index b59d06e754..9d139d6716 100644 --- a/lib/std/crypto/gimli.zig +++ b/lib/std/crypto/gimli.zig @@ -110,10 +110,11 @@ pub const Hash = struct { buf_off: usize, pub const block_length = State.RATE; + pub const Options = struct {}; const Self = @This(); - pub fn init() Self { + pub fn init(options: Options) Self { return Self{ .state = State{ .data = [_]u32{0} ** (State.BLOCKBYTES / 4) }, .buf_off = 0, @@ -160,8 +161,8 @@ pub const Hash = struct { } }; -pub fn hash(out: []u8, in: []const u8) void { - var st = Hash.init(); +pub fn hash(out: []u8, in: []const u8, options: Hash.Options) void { + var st = Hash.init(options); st.update(in); st.final(out); } @@ -174,7 +175,7 @@ test "hash" { var msg: [58 / 2]u8 = undefined; try std.fmt.hexToBytes(&msg, "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C"); var md: [32]u8 = undefined; - hash(&md, &msg); + hash(&md, &msg, .{}); htest.assertEqual("1C9A03DC6A5DDC5444CFC6F4B154CFF5CF081633B2CEA4D7D0AE7CCFED5AAA44", &md); } diff --git a/lib/std/crypto/hmac.zig b/lib/std/crypto/hmac.zig index 77db5bcaae..700904555d 100644 --- a/lib/std/crypto/hmac.zig +++ b/lib/std/crypto/hmac.zig @@ -45,7 +45,7 @@ pub fn Hmac(comptime Hash: type) type { // Normalize key length to block size of hash if (key.len > Hash.block_length) { - Hash.hash(key, ctx.scratch[0..mac_length]); + Hash.hash(key, ctx.scratch[0..mac_length], .{}); mem.set(u8, ctx.scratch[mac_length..Hash.block_length], 0); } else if (key.len < Hash.block_length) { mem.copy(u8, ctx.scratch[0..key.len], key); @@ -62,7 +62,7 @@ pub fn Hmac(comptime Hash: type) type { b.* = ctx.scratch[i] ^ 0x36; } - ctx.hash = Hash.init(); + ctx.hash = Hash.init(.{}); ctx.hash.update(ctx.i_key_pad[0..]); return ctx; } @@ -75,7 +75,7 @@ pub fn Hmac(comptime Hash: type) type { debug.assert(Hash.block_length >= out.len and out.len >= mac_length); ctx.hash.final(ctx.scratch[0..mac_length]); - var ohash = Hash.init(); + var ohash = Hash.init(.{}); ohash.update(ctx.o_key_pad[0..]); ohash.update(ctx.scratch[0..mac_length]); ohash.final(out[0..mac_length]); diff --git a/lib/std/crypto/md5.zig b/lib/std/crypto/md5.zig index c33bee2e56..0d221fabf6 100644 --- a/lib/std/crypto/md5.zig +++ b/lib/std/crypto/md5.zig @@ -39,6 +39,7 @@ pub const Md5 = struct { const Self = @This(); pub const block_length = 64; pub const digest_length = 16; + pub const Options = struct {}; s: [4]u32, // Streaming Cache @@ -46,7 +47,7 @@ pub const Md5 = struct { buf_len: u8, total_len: u64, - pub fn init() Self { + pub fn init(options: Options) Self { return Self{ .s = [_]u32{ 0x67452301, @@ -60,8 +61,8 @@ pub const Md5 = struct { }; } - pub fn hash(b: []const u8, out: []u8) void { - var d = Md5.init(); + pub fn hash(b: []const u8, out: []u8, options: Options) void { + var d = Md5.init(options); d.update(b); d.final(out); } @@ -257,18 +258,18 @@ test "md5 single" { } test "md5 streaming" { - var h = Md5.init(); + var h = Md5.init(.{}); var out: [16]u8 = undefined; h.final(out[0..]); htest.assertEqual("d41d8cd98f00b204e9800998ecf8427e", out[0..]); - h = Md5.init(); + h = Md5.init(.{}); h.update("abc"); h.final(out[0..]); htest.assertEqual("900150983cd24fb0d6963f7d28e17f72", out[0..]); - h = Md5.init(); + h = Md5.init(.{}); h.update("a"); h.update("b"); h.update("c"); @@ -281,7 +282,7 @@ test "md5 aligned final" { var block = [_]u8{0} ** Md5.block_length; var out: [Md5.digest_length]u8 = undefined; - var h = Md5.init(); + var h = Md5.init(.{}); h.update(&block); h.final(out[0..]); } diff --git a/lib/std/crypto/sha1.zig b/lib/std/crypto/sha1.zig index a62343eb7a..03fd55b6a0 100644 --- a/lib/std/crypto/sha1.zig +++ b/lib/std/crypto/sha1.zig @@ -36,6 +36,7 @@ pub const Sha1 = struct { const Self = @This(); pub const block_length = 64; pub const digest_length = 20; + pub const Options = struct {}; s: [5]u32, // Streaming Cache @@ -43,7 +44,7 @@ pub const Sha1 = struct { buf_len: u8 = 0, total_len: u64 = 0, - pub fn init() Self { + pub fn init(options: Options) Self { return Self{ .s = [_]u32{ 0x67452301, @@ -55,8 +56,8 @@ pub const Sha1 = struct { }; } - pub fn hash(b: []const u8, out: []u8) void { - var d = Sha1.init(); + pub fn hash(b: []const u8, out: []u8, options: Options) void { + var d = Sha1.init(options); d.update(b); d.final(out); } @@ -276,18 +277,18 @@ test "sha1 single" { } test "sha1 streaming" { - var h = Sha1.init(); + var h = Sha1.init(.{}); var out: [20]u8 = undefined; h.final(out[0..]); htest.assertEqual("da39a3ee5e6b4b0d3255bfef95601890afd80709", out[0..]); - h = Sha1.init(); + h = Sha1.init(.{}); h.update("abc"); h.final(out[0..]); htest.assertEqual("a9993e364706816aba3e25717850c26c9cd0d89d", out[0..]); - h = Sha1.init(); + h = Sha1.init(.{}); h.update("a"); h.update("b"); h.update("c"); @@ -299,7 +300,7 @@ test "sha1 aligned final" { var block = [_]u8{0} ** Sha1.block_length; var out: [Sha1.digest_length]u8 = undefined; - var h = Sha1.init(); + var h = Sha1.init(.{}); h.update(&block); h.final(out[0..]); } diff --git a/lib/std/crypto/sha2.zig b/lib/std/crypto/sha2.zig index 851b1dc405..af2c22fe1c 100644 --- a/lib/std/crypto/sha2.zig +++ b/lib/std/crypto/sha2.zig @@ -88,6 +88,7 @@ fn Sha2_32(comptime params: Sha2Params32) type { const Self = @This(); pub const block_length = 64; pub const digest_length = params.out_len / 8; + pub const Options = struct {}; s: [8]u32, // Streaming Cache @@ -95,7 +96,7 @@ fn Sha2_32(comptime params: Sha2Params32) type { buf_len: u8 = 0, total_len: u64 = 0, - pub fn init() Self { + pub fn init(options: Options) Self { return Self{ .s = [_]u32{ params.iv0, @@ -110,8 +111,8 @@ fn Sha2_32(comptime params: Sha2Params32) type { }; } - pub fn hash(b: []const u8, out: []u8) void { - var d = Self.init(); + pub fn hash(b: []const u8, out: []u8, options: Options) void { + var d = Self.init(options); d.update(b); d.final(out); } @@ -296,18 +297,18 @@ test "sha224 single" { } test "sha224 streaming" { - var h = Sha224.init(); + var h = Sha224.init(.{}); var out: [28]u8 = undefined; h.final(out[0..]); htest.assertEqual("d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f", out[0..]); - h = Sha224.init(); + h = Sha224.init(.{}); h.update("abc"); h.final(out[0..]); htest.assertEqual("23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7", out[0..]); - h = Sha224.init(); + h = Sha224.init(.{}); h.update("a"); h.update("b"); h.update("c"); @@ -322,18 +323,18 @@ test "sha256 single" { } test "sha256 streaming" { - var h = Sha256.init(); + var h = Sha256.init(.{}); var out: [32]u8 = undefined; h.final(out[0..]); htest.assertEqual("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", out[0..]); - h = Sha256.init(); + h = Sha256.init(.{}); h.update("abc"); h.final(out[0..]); htest.assertEqual("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", out[0..]); - h = Sha256.init(); + h = Sha256.init(.{}); h.update("a"); h.update("b"); h.update("c"); @@ -345,7 +346,7 @@ test "sha256 aligned final" { var block = [_]u8{0} ** Sha256.block_length; var out: [Sha256.digest_length]u8 = undefined; - var h = Sha256.init(); + var h = Sha256.init(.{}); h.update(&block); h.final(out[0..]); } @@ -458,6 +459,7 @@ fn Sha2_64(comptime params: Sha2Params64) type { const Self = @This(); pub const block_length = 128; pub const digest_length = params.out_len / 8; + pub const Options = struct {}; s: [8]u64, // Streaming Cache @@ -465,7 +467,7 @@ fn Sha2_64(comptime params: Sha2Params64) type { buf_len: u8 = 0, total_len: u128 = 0, - pub fn init() Self { + pub fn init(options: Options) Self { return Self{ .s = [_]u64{ params.iv0, @@ -480,8 +482,8 @@ fn Sha2_64(comptime params: Sha2Params64) type { }; } - pub fn hash(b: []const u8, out: []u8) void { - var d = Self.init(); + pub fn hash(b: []const u8, out: []u8, options: Options) void { + var d = Self.init(options); d.update(b); d.final(out); } @@ -693,7 +695,7 @@ test "sha384 single" { } test "sha384 streaming" { - var h = Sha384.init(); + var h = Sha384.init(.{}); var out: [48]u8 = undefined; const h1 = "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b"; @@ -702,12 +704,12 @@ test "sha384 streaming" { const h2 = "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7"; - h = Sha384.init(); + h = Sha384.init(.{}); h.update("abc"); h.final(out[0..]); htest.assertEqual(h2, out[0..]); - h = Sha384.init(); + h = Sha384.init(.{}); h.update("a"); h.update("b"); h.update("c"); @@ -727,7 +729,7 @@ test "sha512 single" { } test "sha512 streaming" { - var h = Sha512.init(); + var h = Sha512.init(.{}); var out: [64]u8 = undefined; const h1 = "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e"; @@ -736,12 +738,12 @@ test "sha512 streaming" { const h2 = "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f"; - h = Sha512.init(); + h = Sha512.init(.{}); h.update("abc"); h.final(out[0..]); htest.assertEqual(h2, out[0..]); - h = Sha512.init(); + h = Sha512.init(.{}); h.update("a"); h.update("b"); h.update("c"); @@ -753,7 +755,7 @@ test "sha512 aligned final" { var block = [_]u8{0} ** Sha512.block_length; var out: [Sha512.digest_length]u8 = undefined; - var h = Sha512.init(); + var h = Sha512.init(.{}); h.update(&block); h.final(out[0..]); } diff --git a/lib/std/crypto/sha3.zig b/lib/std/crypto/sha3.zig index 273e5eea6d..3d6dad1be1 100644 --- a/lib/std/crypto/sha3.zig +++ b/lib/std/crypto/sha3.zig @@ -20,17 +20,18 @@ fn Keccak(comptime bits: usize, comptime delim: u8) type { const Self = @This(); pub const block_length = 200; pub const digest_length = bits / 8; + pub const Options = struct {}; s: [200]u8, offset: usize, rate: usize, - pub fn init() Self { + pub fn init(options: Options) Self { return Self{ .s = [_]u8{0} ** 200, .offset = 0, .rate = 200 - (bits / 4) }; } - pub fn hash(b: []const u8, out: []u8) void { - var d = Self.init(); + pub fn hash(b: []const u8, out: []u8, options: Options) void { + var d = Self.init(options); d.update(b); d.final(out); } @@ -175,18 +176,18 @@ test "sha3-224 single" { } test "sha3-224 streaming" { - var h = Sha3_224.init(); + var h = Sha3_224.init(.{}); var out: [28]u8 = undefined; h.final(out[0..]); htest.assertEqual("6b4e03423667dbb73b6e15454f0eb1abd4597f9a1b078e3f5b5a6bc7", out[0..]); - h = Sha3_224.init(); + h = Sha3_224.init(.{}); h.update("abc"); h.final(out[0..]); htest.assertEqual("e642824c3f8cf24ad09234ee7d3c766fc9a3a5168d0c94ad73b46fdf", out[0..]); - h = Sha3_224.init(); + h = Sha3_224.init(.{}); h.update("a"); h.update("b"); h.update("c"); @@ -201,18 +202,18 @@ test "sha3-256 single" { } test "sha3-256 streaming" { - var h = Sha3_256.init(); + var h = Sha3_256.init(.{}); var out: [32]u8 = undefined; h.final(out[0..]); htest.assertEqual("a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a", out[0..]); - h = Sha3_256.init(); + h = Sha3_256.init(.{}); h.update("abc"); h.final(out[0..]); htest.assertEqual("3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532", out[0..]); - h = Sha3_256.init(); + h = Sha3_256.init(.{}); h.update("a"); h.update("b"); h.update("c"); @@ -224,7 +225,7 @@ test "sha3-256 aligned final" { var block = [_]u8{0} ** Sha3_256.block_length; var out: [Sha3_256.digest_length]u8 = undefined; - var h = Sha3_256.init(); + var h = Sha3_256.init(.{}); h.update(&block); h.final(out[0..]); } @@ -239,7 +240,7 @@ test "sha3-384 single" { } test "sha3-384 streaming" { - var h = Sha3_384.init(); + var h = Sha3_384.init(.{}); var out: [48]u8 = undefined; const h1 = "0c63a75b845e4f7d01107d852e4c2485c51a50aaaa94fc61995e71bbee983a2ac3713831264adb47fb6bd1e058d5f004"; @@ -247,12 +248,12 @@ test "sha3-384 streaming" { htest.assertEqual(h1, out[0..]); const h2 = "ec01498288516fc926459f58e2c6ad8df9b473cb0fc08c2596da7cf0e49be4b298d88cea927ac7f539f1edf228376d25"; - h = Sha3_384.init(); + h = Sha3_384.init(.{}); h.update("abc"); h.final(out[0..]); htest.assertEqual(h2, out[0..]); - h = Sha3_384.init(); + h = Sha3_384.init(.{}); h.update("a"); h.update("b"); h.update("c"); @@ -270,7 +271,7 @@ test "sha3-512 single" { } test "sha3-512 streaming" { - var h = Sha3_512.init(); + var h = Sha3_512.init(.{}); var out: [64]u8 = undefined; const h1 = "a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a615b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26"; @@ -278,12 +279,12 @@ test "sha3-512 streaming" { htest.assertEqual(h1, out[0..]); const h2 = "b751850b1a57168a5693cd924b6b096e08f621827444f70d884f5d0240d2712e10e116e9192af3c91a7ec57647e3934057340b4cf408d5a56592f8274eec53f0"; - h = Sha3_512.init(); + h = Sha3_512.init(.{}); h.update("abc"); h.final(out[0..]); htest.assertEqual(h2, out[0..]); - h = Sha3_512.init(); + h = Sha3_512.init(.{}); h.update("a"); h.update("b"); h.update("c"); @@ -295,7 +296,7 @@ test "sha3-512 aligned final" { var block = [_]u8{0} ** Sha3_512.block_length; var out: [Sha3_512.digest_length]u8 = undefined; - var h = Sha3_512.init(); + var h = Sha3_512.init(.{}); h.update(&block); h.final(out[0..]); } diff --git a/lib/std/crypto/test.zig b/lib/std/crypto/test.zig index e4e34e543b..2987706b11 100644 --- a/lib/std/crypto/test.zig +++ b/lib/std/crypto/test.zig @@ -11,7 +11,7 @@ const fmt = std.fmt; // Hash using the specified hasher `H` asserting `expected == H(input)`. pub fn assertEqualHash(comptime Hasher: anytype, comptime expected: []const u8, input: []const u8) void { var h: [expected.len / 2]u8 = undefined; - Hasher.hash(input, h[0..]); + Hasher.hash(input, h[0..], .{}); assertEqual(expected, &h); } diff --git a/lib/std/zig.zig b/lib/std/zig.zig index c93c22f257..e86a12884f 100644 --- a/lib/std/zig.zig +++ b/lib/std/zig.zig @@ -26,7 +26,7 @@ pub fn hashSrc(src: []const u8) SrcHash { std.mem.copy(u8, &out, src); std.mem.set(u8, out[src.len..], 0); } else { - std.crypto.hash.Blake3.hash(src, &out); + std.crypto.hash.Blake3.hash(src, &out, .{}); } return out; } From 3edace34d38c95673e56930ccfee1d16d0003359 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Fri, 21 Aug 2020 00:57:29 +0200 Subject: [PATCH 47/66] Update tools/process_headers.zig --- tools/process_headers.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/process_headers.zig b/tools/process_headers.zig index ba9fde6683..918802f65d 100644 --- a/tools/process_headers.zig +++ b/tools/process_headers.zig @@ -313,7 +313,7 @@ pub fn main() !void { var max_bytes_saved: usize = 0; var total_bytes: usize = 0; - var hasher = std.crypto.hash.sha2.Sha256.init(); + var hasher = std.crypto.hash.sha2.Sha256.init(.{}); for (libc_targets) |libc_target| { const dest_target = DestTarget{ From eef111fe78d7b246b634a07561082a6fcf947e09 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Fri, 21 Aug 2020 01:15:17 +0200 Subject: [PATCH 48/66] Fix missing init() update in std/build/write_file.zig --- lib/std/build/write_file.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/std/build/write_file.zig b/lib/std/build/write_file.zig index 222de7c79a..17c4b760a1 100644 --- a/lib/std/build/write_file.zig +++ b/lib/std/build/write_file.zig @@ -58,7 +58,7 @@ pub const WriteFileStep = struct { // TODO port the cache system from stage1 to zig std lib. Until then we use blake2b // directly and construct the path, and no "cache hit" detection happens; the files // are always written. - var hash = std.crypto.hash.blake2.Blake2b384.init(); + var hash = std.crypto.hash.blake2.Blake2b384.init(.{}); // Random bytes to make WriteFileStep unique. Refresh this with // new random bytes when WriteFileStep implementation is modified From ebfe723f3cdbb40d2f2280e223b710418abde777 Mon Sep 17 00:00:00 2001 From: Vexu Date: Thu, 20 Aug 2020 12:20:24 +0300 Subject: [PATCH 49/66] stage2: implement rest of simple pointer types --- src-self-hosted/Module.zig | 26 +++-- src-self-hosted/astgen.zig | 27 +++++- src-self-hosted/codegen.zig | 2 +- src-self-hosted/type.zig | 181 ++++++++++++++++++++++++++++++----- src-self-hosted/zir.zig | 19 +++- src-self-hosted/zir_sema.zig | 26 +++-- 6 files changed, 230 insertions(+), 51 deletions(-) diff --git a/src-self-hosted/Module.zig b/src-self-hosted/Module.zig index d08e7f5746..9b27f38fbe 100644 --- a/src-self-hosted/Module.zig +++ b/src-self-hosted/Module.zig @@ -2429,7 +2429,7 @@ pub fn analyzeDeclRef(self: *Module, scope: *Scope, src: usize, decl: *Decl) Inn if (decl_tv.val.tag() == .variable) { return self.analyzeVarRef(scope, src, decl_tv); } - const ty = try self.singlePtrType(scope, src, false, decl_tv.ty); + const ty = try self.simplePtrType(scope, src, decl_tv.ty, false, .One); const val_payload = try scope.arena().create(Value.Payload.DeclRef); val_payload.* = .{ .decl = decl }; @@ -2442,7 +2442,7 @@ pub fn analyzeDeclRef(self: *Module, scope: *Scope, src: usize, decl: *Decl) Inn fn analyzeVarRef(self: *Module, scope: *Scope, src: usize, tv: TypedValue) InnerError!*Inst { const variable = tv.val.cast(Value.Payload.Variable).?.variable; - const ty = try self.singlePtrType(scope, src, variable.is_mutable, tv.ty); + const ty = try self.singlePtrType(scope, src, variable.is_mutable, tv.ty, .One); if (!variable.is_mutable and !variable.is_extern) { const val_payload = try scope.arena().create(Value.Payload.RefVal); val_payload.* = .{ .val = variable.init }; @@ -2766,7 +2766,7 @@ pub fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst // T to ?T if (dest_type.zigTypeTag() == .Optional) { - var buf: Type.Payload.Pointer = undefined; + var buf: Type.Payload.PointerSimple = undefined; const child_type = dest_type.optionalChild(&buf); if (child_type.eql(inst.ty)) { return self.wrapOptional(scope, dest_type, inst); @@ -3145,10 +3145,20 @@ pub fn floatSub(self: *Module, scope: *Scope, float_type: Type, src: usize, lhs: return Value.initPayload(val_payload); } -pub fn singlePtrType(self: *Module, scope: *Scope, src: usize, mutable: bool, elem_ty: Type) Allocator.Error!Type { - const type_payload = try scope.arena().create(Type.Payload.Pointer); +pub fn simplePtrType(self: *Module, scope: *Scope, src: usize, elem_ty: Type, mutable: bool, size: std.builtin.TypeInfo.Pointer.Size) Allocator.Error!Type { + // TODO stage1 type inference bug + const T = Type.Tag; + + const type_payload = try scope.arena().create(Type.Payload.PointerSimple); type_payload.* = .{ - .base = .{ .tag = if (mutable) .single_mut_pointer else .single_const_pointer }, + .base = .{ + .tag = switch (size) { + .One => if (mutable) .single_mut_pointer else T.many_const_pointer, + .Many => if (mutable) T.many_mut_pointer else T.many_const_pointer, + .C => if (mutable) T.c_mut_pointer else T.c_const_pointer, + else => unreachable, + }, + }, .pointee_type = elem_ty, }; return Type.initPayload(&type_payload.base); @@ -3157,7 +3167,7 @@ pub fn singlePtrType(self: *Module, scope: *Scope, src: usize, mutable: bool, el pub fn optionalType(self: *Module, scope: *Scope, child_type: Type) Allocator.Error!Type { return Type.initPayload(switch (child_type.tag()) { .single_const_pointer => blk: { - const payload = try scope.arena().create(Type.Payload.Pointer); + const payload = try scope.arena().create(Type.Payload.PointerSimple); payload.* = .{ .base = .{ .tag = .optional_single_const_pointer }, .pointee_type = child_type.elemType(), @@ -3165,7 +3175,7 @@ pub fn optionalType(self: *Module, scope: *Scope, child_type: Type) Allocator.Er break :blk &payload.base; }, .single_mut_pointer => blk: { - const payload = try scope.arena().create(Type.Payload.Pointer); + const payload = try scope.arena().create(Type.Payload.PointerSimple); payload.* = .{ .base = .{ .tag = .optional_single_mut_pointer }, .pointee_type = child_type.elemType(), diff --git a/src-self-hosted/astgen.zig b/src-self-hosted/astgen.zig index 9f8afa6225..bb42b746ad 100644 --- a/src-self-hosted/astgen.zig +++ b/src-self-hosted/astgen.zig @@ -577,6 +577,17 @@ fn ptrType(mod: *Module, scope: *Scope, node: *ast.Node.PtrType) InnerError!*zir .val = Value.initTag(.type_type), }); + const size: std.builtin.TypeInfo.Pointer.Size = switch (tree.token_ids[node.op_token]) { + .Asterisk, .AsteriskAsterisk => .One, + // TODO stage1 type inference bug + .LBracket => @as(std.builtin.TypeInfo.Pointer.Size, switch (tree.token_ids[node.op_token + 2]) { + .Identifier => .C, + .RBracket => .Many, + else => unreachable, + }), + else => unreachable, + }; + const simple = node.ptr_info.allowzero_token == null and node.ptr_info.align_info == null and node.ptr_info.volatile_token == null and @@ -584,13 +595,19 @@ fn ptrType(mod: *Module, scope: *Scope, node: *ast.Node.PtrType) InnerError!*zir if (simple) { const child_type = try expr(mod, scope, .{ .ty = meta_type }, node.rhs); - return addZIRUnOp(mod, scope, src, if (node.ptr_info.const_token == null) - .single_mut_ptr_type - else - .single_const_ptr_type, child_type); + const mutable = node.ptr_info.const_token == null; + // TODO stage1 type inference bug + const T = zir.Inst.Tag; + return addZIRUnOp(mod, scope, src, switch (size) { + .One => if (mutable) T.single_mut_ptr_type else T.single_const_ptr_type, + .Many => if (mutable) T.many_mut_ptr_type else T.many_const_ptr_type, + .C => if (mutable) T.c_mut_ptr_type else T.c_const_ptr_type, + else => unreachable, + }, child_type); } var kw_args: std.meta.fieldInfo(zir.Inst.PtrType, "kw_args").field_type = .{}; + kw_args.size = size; kw_args.@"allowzero" = node.ptr_info.allowzero_token != null; if (node.ptr_info.align_info) |some| { kw_args.@"align" = try expr(mod, scope, .none, some.node); @@ -1271,7 +1288,7 @@ fn multilineStrLiteral(mod: *Module, scope: *Scope, node: *ast.Node.MultilineStr i += 1; } const slice = tree.tokenSlice(line); - mem.copy(u8, bytes[i..], slice[2..slice.len - 1]); + mem.copy(u8, bytes[i..], slice[2 .. slice.len - 1]); i += slice.len - 3; } diff --git a/src-self-hosted/codegen.zig b/src-self-hosted/codegen.zig index 1bc76f6b05..cc5c51159c 100644 --- a/src-self-hosted/codegen.zig +++ b/src-self-hosted/codegen.zig @@ -2060,7 +2060,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { if (typed_value.val.isNull()) return MCValue{ .immediate = 0 }; - var buf: Type.Payload.Pointer = undefined; + var buf: Type.Payload.PointerSimple = undefined; return self.genTypedValue(src, .{ .ty = typed_value.ty.optionalChild(&buf), .val = typed_value.val, diff --git a/src-self-hosted/type.zig b/src-self-hosted/type.zig index c2762e1f8a..233e479297 100644 --- a/src-self-hosted/type.zig +++ b/src-self-hosted/type.zig @@ -66,10 +66,15 @@ pub const Type = extern union { .function => return .Fn, .array, .array_u8_sentinel_0, .array_u8, .array_sentinel => return .Array, - .single_const_pointer => return .Pointer, - .single_mut_pointer => return .Pointer, - .single_const_pointer_to_comptime_int => return .Pointer, - .const_slice_u8 => return .Pointer, + .single_const_pointer_to_comptime_int, + .const_slice_u8, + .single_const_pointer, + .single_mut_pointer, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, + => return .Pointer, .optional, .optional_single_const_pointer, @@ -108,13 +113,17 @@ pub const Type = extern union { return @fieldParentPtr(T, "base", self.ptr_otherwise); } - pub fn castPointer(self: Type) ?*Payload.Pointer { + pub fn castPointer(self: Type) ?*Payload.PointerSimple { return switch (self.tag()) { .single_const_pointer, .single_mut_pointer, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, .optional_single_const_pointer, .optional_single_mut_pointer, - => @fieldParentPtr(Payload.Pointer, "base", self.ptr_otherwise), + => @fieldParentPtr(Payload.PointerSimple, "base", self.ptr_otherwise), else => null, }; } @@ -198,8 +207,8 @@ pub const Type = extern union { return true; }, .Optional => { - var buf_a: Payload.Pointer = undefined; - var buf_b: Payload.Pointer = undefined; + var buf_a: Payload.PointerSimple = undefined; + var buf_b: Payload.PointerSimple = undefined; return a.optionalChild(&buf_a).eql(b.optionalChild(&buf_b)); }, .Float, @@ -263,7 +272,7 @@ pub const Type = extern union { } }, .Optional => { - var buf: Payload.Pointer = undefined; + var buf: Payload.PointerSimple = undefined; std.hash.autoHash(&hasher, self.optionalChild(&buf).hash()); }, .Float, @@ -374,9 +383,13 @@ pub const Type = extern union { .optional => return self.copyPayloadSingleField(allocator, Payload.Optional, "child_type"), .single_const_pointer, .single_mut_pointer, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, .optional_single_mut_pointer, .optional_single_const_pointer, - => return self.copyPayloadSingleField(allocator, Payload.Pointer, "pointee_type"), + => return self.copyPayloadSingleField(allocator, Payload.PointerSimple, "pointee_type"), } } @@ -482,17 +495,41 @@ pub const Type = extern union { continue; }, .single_const_pointer => { - const payload = @fieldParentPtr(Payload.Pointer, "base", ty.ptr_otherwise); + const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise); try out_stream.writeAll("*const "); ty = payload.pointee_type; continue; }, .single_mut_pointer => { - const payload = @fieldParentPtr(Payload.Pointer, "base", ty.ptr_otherwise); + const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise); try out_stream.writeAll("*"); ty = payload.pointee_type; continue; }, + .many_const_pointer => { + const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise); + try out_stream.writeAll("[*]const "); + ty = payload.pointee_type; + continue; + }, + .many_mut_pointer => { + const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise); + try out_stream.writeAll("[*]"); + ty = payload.pointee_type; + continue; + }, + .c_const_pointer => { + const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise); + try out_stream.writeAll("[*c]const "); + ty = payload.pointee_type; + continue; + }, + .c_mut_pointer => { + const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise); + try out_stream.writeAll("[*c]"); + ty = payload.pointee_type; + continue; + }, .int_signed => { const payload = @fieldParentPtr(Payload.IntSigned, "base", ty.ptr_otherwise); return out_stream.print("i{}", .{payload.bits}); @@ -508,13 +545,13 @@ pub const Type = extern union { continue; }, .optional_single_const_pointer => { - const payload = @fieldParentPtr(Payload.Pointer, "base", ty.ptr_otherwise); + const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise); try out_stream.writeAll("?*const "); ty = payload.pointee_type; continue; }, .optional_single_mut_pointer => { - const payload = @fieldParentPtr(Payload.Pointer, "base", ty.ptr_otherwise); + const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise); try out_stream.writeAll("?*"); ty = payload.pointee_type; continue; @@ -619,6 +656,10 @@ pub const Type = extern union { .array_sentinel => self.elemType().hasCodeGenBits(), .single_const_pointer => self.elemType().hasCodeGenBits(), .single_mut_pointer => self.elemType().hasCodeGenBits(), + .many_const_pointer => self.elemType().hasCodeGenBits(), + .many_mut_pointer => self.elemType().hasCodeGenBits(), + .c_const_pointer => self.elemType().hasCodeGenBits(), + .c_mut_pointer => self.elemType().hasCodeGenBits(), .int_signed => self.cast(Payload.IntSigned).?.bits == 0, .int_unsigned => self.cast(Payload.IntUnsigned).?.bits == 0, @@ -669,6 +710,10 @@ pub const Type = extern union { .const_slice_u8, .single_const_pointer, .single_mut_pointer, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, .optional_single_const_pointer, .optional_single_mut_pointer, => return @divExact(target.cpu.arch.ptrBitWidth(), 8), @@ -704,7 +749,7 @@ pub const Type = extern union { }, .optional => { - var buf: Payload.Pointer = undefined; + var buf: Payload.PointerSimple = undefined; const child_type = self.optionalChild(&buf); if (!child_type.hasCodeGenBits()) return 1; @@ -772,6 +817,10 @@ pub const Type = extern union { .const_slice_u8, .single_const_pointer, .single_mut_pointer, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, .optional_single_const_pointer, .optional_single_mut_pointer, => return @divExact(target.cpu.arch.ptrBitWidth(), 8), @@ -805,7 +854,7 @@ pub const Type = extern union { }, .optional => { - var buf: Payload.Pointer = undefined; + var buf: Payload.PointerSimple = undefined; const child_type = self.optionalChild(&buf); if (!child_type.hasCodeGenBits()) return 1; @@ -872,6 +921,10 @@ pub const Type = extern union { .optional_single_mut_pointer, .optional_single_const_pointer, .enum_literal, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, => false, .single_const_pointer, @@ -922,6 +975,10 @@ pub const Type = extern union { .array_u8_sentinel_0, .single_const_pointer, .single_mut_pointer, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, .single_const_pointer_to_comptime_int, .fn_noreturn_no_args, .fn_void_no_args, @@ -987,6 +1044,8 @@ pub const Type = extern union { .int_unsigned, .int_signed, .single_mut_pointer, + .many_mut_pointer, + .c_mut_pointer, .optional, .optional_single_mut_pointer, .optional_single_const_pointer, @@ -994,6 +1053,8 @@ pub const Type = extern union { => false, .single_const_pointer, + .many_const_pointer, + .c_const_pointer, .single_const_pointer_to_comptime_int, .const_slice_u8, => true, @@ -1048,6 +1109,10 @@ pub const Type = extern union { .int_signed, .single_mut_pointer, .single_const_pointer, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, .single_const_pointer_to_comptime_int, .const_slice_u8, .optional, @@ -1063,7 +1128,7 @@ pub const Type = extern union { switch (self.tag()) { .optional_single_const_pointer, .optional_single_mut_pointer => return true, .optional => { - var buf: Payload.Pointer = undefined; + var buf: Payload.PointerSimple = undefined; const child_type = self.optionalChild(&buf); // optionals of zero sized pointers behave like bools if (!child_type.hasCodeGenBits()) return false; @@ -1101,7 +1166,7 @@ pub const Type = extern union { => return false, .Optional => { - var buf: Payload.Pointer = undefined; + var buf: Payload.PointerSimple = undefined; return ty.optionalChild(&buf).isValidVarType(is_extern); }, .Pointer, .Array => ty = ty.elemType(), @@ -1166,13 +1231,17 @@ pub const Type = extern union { .array_sentinel => self.cast(Payload.ArraySentinel).?.elem_type, .single_const_pointer => self.castPointer().?.pointee_type, .single_mut_pointer => self.castPointer().?.pointee_type, + .many_const_pointer => self.castPointer().?.pointee_type, + .many_mut_pointer => self.castPointer().?.pointee_type, + .c_const_pointer => self.castPointer().?.pointee_type, + .c_mut_pointer => self.castPointer().?.pointee_type, .array_u8, .array_u8_sentinel_0, .const_slice_u8 => Type.initTag(.u8), .single_const_pointer_to_comptime_int => Type.initTag(.comptime_int), }; } /// Asserts that the type is an optional. - pub fn optionalChild(self: Type, buf: *Payload.Pointer) Type { + pub fn optionalChild(self: Type, buf: *Payload.PointerSimple) Type { return switch (self.tag()) { .optional => self.cast(Payload.Optional).?.child_type, .optional_single_mut_pointer => { @@ -1199,7 +1268,7 @@ pub const Type = extern union { return switch (self.tag()) { .optional => self.cast(Payload.Optional).?.child_type, .optional_single_mut_pointer, .optional_single_const_pointer => { - const payload = try allocator.create(Payload.Pointer); + const payload = try allocator.create(Payload.PointerSimple); payload.* = .{ .base = .{ .tag = if (self.tag() == .optional_single_const_pointer) @@ -1258,6 +1327,10 @@ pub const Type = extern union { .function, .single_const_pointer, .single_mut_pointer, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, .single_const_pointer_to_comptime_int, .const_slice_u8, .int_unsigned, @@ -1318,6 +1391,10 @@ pub const Type = extern union { .function, .single_const_pointer, .single_mut_pointer, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, .single_const_pointer_to_comptime_int, .const_slice_u8, .int_unsigned, @@ -1368,6 +1445,10 @@ pub const Type = extern union { .array_u8_sentinel_0, .single_const_pointer, .single_mut_pointer, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, .single_const_pointer_to_comptime_int, .const_slice_u8, .int_unsigned, @@ -1429,6 +1510,10 @@ pub const Type = extern union { .array_u8_sentinel_0, .single_const_pointer, .single_mut_pointer, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, .single_const_pointer_to_comptime_int, .const_slice_u8, .int_signed, @@ -1490,6 +1575,10 @@ pub const Type = extern union { .array_u8_sentinel_0, .single_const_pointer, .single_mut_pointer, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, .single_const_pointer_to_comptime_int, .const_slice_u8, .optional, @@ -1549,6 +1638,10 @@ pub const Type = extern union { .array_u8_sentinel_0, .single_const_pointer, .single_mut_pointer, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, .single_const_pointer_to_comptime_int, .const_slice_u8, .int_unsigned, @@ -1637,6 +1730,10 @@ pub const Type = extern union { .array_u8_sentinel_0, .single_const_pointer, .single_mut_pointer, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, .single_const_pointer_to_comptime_int, .const_slice_u8, .u8, @@ -1701,6 +1798,10 @@ pub const Type = extern union { .array_u8_sentinel_0, .single_const_pointer, .single_mut_pointer, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, .single_const_pointer_to_comptime_int, .const_slice_u8, .u8, @@ -1764,6 +1865,10 @@ pub const Type = extern union { .array_u8_sentinel_0, .single_const_pointer, .single_mut_pointer, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, .single_const_pointer_to_comptime_int, .const_slice_u8, .u8, @@ -1827,6 +1932,10 @@ pub const Type = extern union { .array_u8_sentinel_0, .single_const_pointer, .single_mut_pointer, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, .single_const_pointer_to_comptime_int, .const_slice_u8, .u8, @@ -1887,6 +1996,10 @@ pub const Type = extern union { .array_u8_sentinel_0, .single_const_pointer, .single_mut_pointer, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, .single_const_pointer_to_comptime_int, .const_slice_u8, .u8, @@ -1947,6 +2060,10 @@ pub const Type = extern union { .array_u8_sentinel_0, .single_const_pointer, .single_mut_pointer, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, .single_const_pointer_to_comptime_int, .const_slice_u8, .u8, @@ -2027,6 +2144,10 @@ pub const Type = extern union { .array_u8_sentinel_0, .single_const_pointer, .single_mut_pointer, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, .single_const_pointer_to_comptime_int, .const_slice_u8, .optional, @@ -2109,7 +2230,13 @@ pub const Type = extern union { ty = ty.elemType(); continue; }, - .single_const_pointer, .single_mut_pointer => { + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, + .single_const_pointer, + .single_mut_pointer, + => { const ptr = ty.castPointer().?; ty = ptr.pointee_type; continue; @@ -2167,11 +2294,17 @@ pub const Type = extern union { .array_u8_sentinel_0, .single_const_pointer, .single_mut_pointer, + .many_const_pointer, + .many_mut_pointer, .optional, .optional_single_mut_pointer, .optional_single_const_pointer, .enum_literal, => return false, + + .c_const_pointer, + .c_mut_pointer, + => return true, }; } @@ -2231,6 +2364,10 @@ pub const Type = extern union { array_sentinel, single_const_pointer, single_mut_pointer, + many_const_pointer, + many_mut_pointer, + c_const_pointer, + c_mut_pointer, int_signed, int_unsigned, function, @@ -2272,7 +2409,7 @@ pub const Type = extern union { elem_type: Type, }; - pub const Pointer = struct { + pub const PointerSimple = struct { base: Payload, pointee_type: Type, diff --git a/src-self-hosted/zir.zig b/src-self-hosted/zir.zig index 552e90956b..62c0c73f3f 100644 --- a/src-self-hosted/zir.zig +++ b/src-self-hosted/zir.zig @@ -198,6 +198,14 @@ pub const Inst = struct { single_const_ptr_type, /// Create a mutable pointer type based on the element type. `*T` single_mut_ptr_type, + /// Create a const pointer type based on the element type. `[*]const T` + many_const_ptr_type, + /// Create a mutable pointer type based on the element type. `[*]T` + many_mut_ptr_type, + /// Create a const pointer type based on the element type. `[*c]const T` + c_const_ptr_type, + /// Create a mutable pointer type based on the element type. `[*c]T` + c_mut_ptr_type, /// Create a pointer type with attributes ptr_type, /// Write a value to a pointer. For loading, see `deref`. @@ -262,6 +270,10 @@ pub const Inst = struct { .typeof, .single_const_ptr_type, .single_mut_ptr_type, + .many_const_ptr_type, + .many_mut_ptr_type, + .c_const_ptr_type, + .c_mut_ptr_type, .optional_type, .unwrap_optional_safe, .unwrap_optional_unsafe, @@ -400,6 +412,10 @@ pub const Inst = struct { .shr, .single_const_ptr_type, .single_mut_ptr_type, + .many_const_ptr_type, + .many_mut_ptr_type, + .c_const_ptr_type, + .c_mut_ptr_type, .store, .str, .sub, @@ -859,6 +875,7 @@ pub const Inst = struct { @"const": bool = true, @"volatile": bool = false, sentinel: ?*Inst = null, + size: std.builtin.TypeInfo.Pointer.Size = .One, }, }; @@ -2443,7 +2460,7 @@ const EmitZIR = struct { } }, .Optional => { - var buf: Type.Payload.Pointer = undefined; + var buf: Type.Payload.PointerSimple = undefined; const inst = try self.arena.allocator.create(Inst.UnOp); inst.* = .{ .base = .{ diff --git a/src-self-hosted/zir_sema.zig b/src-self-hosted/zir_sema.zig index cb1ed08d6d..0e331d1979 100644 --- a/src-self-hosted/zir_sema.zig +++ b/src-self-hosted/zir_sema.zig @@ -51,8 +51,12 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError! .ref => return analyzeInstRef(mod, scope, old_inst.castTag(.ref).?), .ret_ptr => return analyzeInstRetPtr(mod, scope, old_inst.castTag(.ret_ptr).?), .ret_type => return analyzeInstRetType(mod, scope, old_inst.castTag(.ret_type).?), - .single_const_ptr_type => return analyzeInstSingleConstPtrType(mod, scope, old_inst.castTag(.single_const_ptr_type).?), - .single_mut_ptr_type => return analyzeInstSingleMutPtrType(mod, scope, old_inst.castTag(.single_mut_ptr_type).?), + .single_const_ptr_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.single_const_ptr_type).?, false, .One), + .single_mut_ptr_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.single_mut_ptr_type).?, true, .One), + .many_const_ptr_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.many_const_ptr_type).?, false, .Many), + .many_mut_ptr_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.many_mut_ptr_type).?, true, .Many), + .c_const_ptr_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.c_const_ptr_type).?, false, .C), + .c_mut_ptr_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.c_mut_ptr_type).?, true, .C), .ptr_type => return analyzeInstPtrType(mod, scope, old_inst.castTag(.ptr_type).?), .store => return analyzeInstStore(mod, scope, old_inst.castTag(.store).?), .str => return analyzeInstStr(mod, scope, old_inst.castTag(.str).?), @@ -324,7 +328,7 @@ fn analyzeInstRetPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerErr fn analyzeInstRef(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { const operand = try resolveInst(mod, scope, inst.positionals.operand); - const ptr_type = try mod.singlePtrType(scope, inst.base.src, false, operand.ty); + const ptr_type = try mod.simplePtrType(scope, inst.base.src, operand.ty, false, .One); if (operand.value()) |val| { const ref_payload = try scope.arena().create(Value.Payload.RefVal); @@ -369,7 +373,7 @@ fn analyzeInstAlloc(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerErro if (!var_type.isValidVarType(false)) { return mod.fail(scope, inst.base.src, "variable of type '{}' must be const or comptime", .{var_type}); } - const ptr_type = try mod.singlePtrType(scope, inst.base.src, true, var_type); + const ptr_type = try mod.simplePtrType(scope, inst.base.src, var_type, true, .One); const b = try mod.requireRuntimeBlock(scope, inst.base.src); return mod.addNoOp(b, inst.base.src, ptr_type, .alloc); } @@ -723,7 +727,7 @@ fn analyzeInstUnwrapOptional(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp } const child_type = try operand.ty.elemType().optionalChildAlloc(scope.arena()); - const child_pointer = try mod.singlePtrType(scope, unwrap.base.src, operand.ty.isConstPtr(), child_type); + const child_pointer = try mod.simplePtrType(scope, unwrap.base.src, child_type, operand.ty.isConstPtr(), .One); if (operand.value()) |val| { if (val.isNull()) { @@ -940,7 +944,7 @@ fn analyzeInstElemPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.ElemPtr) Inne // required a larger index. const elem_ptr = try array_ptr_val.elemPtr(scope.arena(), @intCast(usize, index_u64)); - const type_payload = try scope.arena().create(Type.Payload.Pointer); + const type_payload = try scope.arena().create(Type.Payload.PointerSimple); type_payload.* = .{ .base = .{ .tag = .single_const_pointer }, .pointee_type = array_ptr.ty.elemType().elemType(), @@ -1311,15 +1315,9 @@ fn analyzeDeclVal(mod: *Module, scope: *Scope, inst: *zir.Inst.DeclVal) InnerErr return decl; } -fn analyzeInstSingleConstPtrType(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { +fn analyzeInstSimplePtrType(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp, mutable: bool, size: std.builtin.TypeInfo.Pointer.Size) InnerError!*Inst { const elem_type = try resolveType(mod, scope, inst.positionals.operand); - const ty = try mod.singlePtrType(scope, inst.base.src, false, elem_type); - return mod.constType(scope, inst.base.src, ty); -} - -fn analyzeInstSingleMutPtrType(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { - const elem_type = try resolveType(mod, scope, inst.positionals.operand); - const ty = try mod.singlePtrType(scope, inst.base.src, true, elem_type); + const ty = try mod.simplePtrType(scope, inst.base.src, elem_type, mutable, size); return mod.constType(scope, inst.base.src, ty); } From 95682484503f031efefb2c085cdd4d0b64cf8795 Mon Sep 17 00:00:00 2001 From: Vexu Date: Thu, 20 Aug 2020 13:52:18 +0300 Subject: [PATCH 50/66] stage2: complex pointer types --- src-self-hosted/Module.zig | 34 +++++++++- src-self-hosted/astgen.zig | 5 +- src-self-hosted/type.zig | 126 +++++++++++++++++++++++++++++++++-- src-self-hosted/zir.zig | 2 +- src-self-hosted/zir_sema.zig | 47 ++++++++++++- 5 files changed, 202 insertions(+), 12 deletions(-) diff --git a/src-self-hosted/Module.zig b/src-self-hosted/Module.zig index 9b27f38fbe..2dd64c64bc 100644 --- a/src-self-hosted/Module.zig +++ b/src-self-hosted/Module.zig @@ -3153,7 +3153,7 @@ pub fn simplePtrType(self: *Module, scope: *Scope, src: usize, elem_ty: Type, mu type_payload.* = .{ .base = .{ .tag = switch (size) { - .One => if (mutable) .single_mut_pointer else T.many_const_pointer, + .One => if (mutable) T.single_mut_pointer else T.single_const_pointer, .Many => if (mutable) T.many_mut_pointer else T.many_const_pointer, .C => if (mutable) T.c_mut_pointer else T.c_const_pointer, else => unreachable, @@ -3164,6 +3164,38 @@ pub fn simplePtrType(self: *Module, scope: *Scope, src: usize, elem_ty: Type, mu return Type.initPayload(&type_payload.base); } +pub fn ptrType( + self: *Module, + scope: *Scope, + src: usize, + elem_ty: Type, + sentinel: ?Value, + @"align": u32, + bit_offset: u16, + host_size: u16, + mutable: bool, + @"allowzero": bool, + @"volatile": bool, + size: std.builtin.TypeInfo.Pointer.Size, +) Allocator.Error!Type { + assert(host_size == 0 or bit_offset < host_size * 8); + + // TODO check if type can be represented by simplePtrType + const type_payload = try scope.arena().create(Type.Payload.Pointer); + type_payload.* = .{ + .pointee_type = elem_ty, + .sentinel = sentinel, + .@"align" = @"align", + .bit_offset = bit_offset, + .host_size = host_size, + .@"allowzero" = @"allowzero", + .mutable = mutable, + .@"volatile" = @"volatile", + .size = size, + }; + return Type.initPayload(&type_payload.base); +} + pub fn optionalType(self: *Module, scope: *Scope, child_type: Type) Allocator.Error!Type { return Type.initPayload(switch (child_type.tag()) { .single_const_pointer => blk: { diff --git a/src-self-hosted/astgen.zig b/src-self-hosted/astgen.zig index bb42b746ad..832e6848b3 100644 --- a/src-self-hosted/astgen.zig +++ b/src-self-hosted/astgen.zig @@ -582,8 +582,7 @@ fn ptrType(mod: *Module, scope: *Scope, node: *ast.Node.PtrType) InnerError!*zir // TODO stage1 type inference bug .LBracket => @as(std.builtin.TypeInfo.Pointer.Size, switch (tree.token_ids[node.op_token + 2]) { .Identifier => .C, - .RBracket => .Many, - else => unreachable, + else => .Many, }), else => unreachable, }; @@ -616,7 +615,7 @@ fn ptrType(mod: *Module, scope: *Scope, node: *ast.Node.PtrType) InnerError!*zir kw_args.align_bit_end = try expr(mod, scope, .none, bit_range.end); } } - kw_args.@"const" = node.ptr_info.const_token != null; + kw_args.mutable = node.ptr_info.const_token == null; kw_args.@"volatile" = node.ptr_info.volatile_token != null; if (node.ptr_info.sentinel) |some| { kw_args.sentinel = try expr(mod, scope, .none, some); diff --git a/src-self-hosted/type.zig b/src-self-hosted/type.zig index 233e479297..2c326b9308 100644 --- a/src-self-hosted/type.zig +++ b/src-self-hosted/type.zig @@ -74,6 +74,7 @@ pub const Type = extern union { .many_mut_pointer, .c_const_pointer, .c_mut_pointer, + .pointer, => return .Pointer, .optional, @@ -390,6 +391,25 @@ pub const Type = extern union { .optional_single_mut_pointer, .optional_single_const_pointer, => return self.copyPayloadSingleField(allocator, Payload.PointerSimple, "pointee_type"), + + .pointer => { + const payload = @fieldParentPtr(Payload.Pointer, "base", self.ptr_otherwise); + const new_payload = try allocator.create(Payload.Pointer); + new_payload.* = .{ + .base = payload.base, + + .pointee_type = try payload.pointee_type.copy(allocator), + .sentinel = if (payload.sentinel) |some| try some.copy(allocator) else null, + .@"align" = payload.@"align", + .bit_offset = payload.bit_offset, + .host_size = payload.host_size, + .@"allowzero" = payload.@"allowzero", + .mutable = payload.mutable, + .@"volatile" = payload.@"volatile", + .size = payload.size, + }; + return Type{ .ptr_otherwise = &new_payload.base }; + }, } } @@ -556,6 +576,34 @@ pub const Type = extern union { ty = payload.pointee_type; continue; }, + + .pointer => { + const payload = @fieldParentPtr(Payload.Pointer, "base", ty.ptr_otherwise); + if (payload.sentinel) |some| switch (payload.size) { + .One, .C => unreachable, + .Many => try out_stream.writeAll("[*:{}]"), + .Slice => try out_stream.writeAll("[:{}]"), + } else switch (payload.size) { + .One => try out_stream.writeAll("*"), + .Many => try out_stream.writeAll("[*]"), + .C => try out_stream.writeAll("[*c]"), + .Slice => try out_stream.writeAll("[]"), + } + if (payload.@"align" != 0) { + try out_stream.print("align({}", .{payload.@"align"}); + + if (payload.bit_offset != 0) { + try out_stream.print(":{}:{}", .{ payload.bit_offset, payload.host_size }); + } + try out_stream.writeAll(") "); + } + if (!payload.mutable) try out_stream.writeAll("const "); + if (payload.@"volatile") try out_stream.writeAll("volatile "); + if (payload.@"allowzero") try out_stream.writeAll("allowzero "); + + ty = payload.pointee_type; + continue; + }, } unreachable; } @@ -660,6 +708,7 @@ pub const Type = extern union { .many_mut_pointer => self.elemType().hasCodeGenBits(), .c_const_pointer => self.elemType().hasCodeGenBits(), .c_mut_pointer => self.elemType().hasCodeGenBits(), + .pointer => self.elemType().hasCodeGenBits(), .int_signed => self.cast(Payload.IntSigned).?.bits == 0, .int_unsigned => self.cast(Payload.IntUnsigned).?.bits == 0, @@ -718,6 +767,13 @@ pub const Type = extern union { .optional_single_mut_pointer, => return @divExact(target.cpu.arch.ptrBitWidth(), 8), + .pointer => { + const payload = @fieldParentPtr(Payload.Pointer, "base", self.ptr_otherwise); + + if (payload.@"align" != 0) return payload.@"align"; + return @divExact(target.cpu.arch.ptrBitWidth(), 8); + }, + .c_short => return @divExact(CType.short.sizeInBits(target), 8), .c_ushort => return @divExact(CType.ushort.sizeInBits(target), 8), .c_int => return @divExact(CType.int.sizeInBits(target), 8), @@ -789,6 +845,7 @@ pub const Type = extern union { .@"null" => unreachable, .@"undefined" => unreachable, .enum_literal => unreachable, + .single_const_pointer_to_comptime_int => unreachable, .u8, .i8, @@ -812,18 +869,28 @@ pub const Type = extern union { .i64, .u64 => return 8, .isize, - .usize, - .single_const_pointer_to_comptime_int, - .const_slice_u8, + .usize + => return @divExact(target.cpu.arch.ptrBitWidth(), 8), + .const_slice_u8 => return @divExact(target.cpu.arch.ptrBitWidth(), 8) * 2, + + .optional_single_const_pointer, + .optional_single_mut_pointer, + => { + if (self.elemType().hasCodeGenBits()) return 1; + return @divExact(target.cpu.arch.ptrBitWidth(), 8); + }, + .single_const_pointer, .single_mut_pointer, .many_const_pointer, .many_mut_pointer, .c_const_pointer, .c_mut_pointer, - .optional_single_const_pointer, - .optional_single_mut_pointer, - => return @divExact(target.cpu.arch.ptrBitWidth(), 8), + .pointer, + => { + if (self.elemType().hasCodeGenBits()) return 0; + return @divExact(target.cpu.arch.ptrBitWidth(), 8); + }, .c_short => return @divExact(CType.short.sizeInBits(target), 8), .c_ushort => return @divExact(CType.ushort.sizeInBits(target), 8), @@ -931,6 +998,8 @@ pub const Type = extern union { .single_mut_pointer, .single_const_pointer_to_comptime_int, => true, + + .pointer => self.cast(Payload.Pointer).?.size == .One, }; } @@ -994,6 +1063,8 @@ pub const Type = extern union { => false, .const_slice_u8 => true, + + .pointer => self.cast(Payload.Pointer).?.size == .Slice, }; } @@ -1058,6 +1129,8 @@ pub const Type = extern union { .single_const_pointer_to_comptime_int, .const_slice_u8, => true, + + .pointer => !self.cast(Payload.Pointer).?.mutable, }; } @@ -1120,6 +1193,11 @@ pub const Type = extern union { .optional_single_const_pointer, .enum_literal, => false, + + .pointer => { + const payload = @fieldParentPtr(Payload.Pointer, "base", self.ptr_otherwise); + return payload.@"volatile"; + }, }; } @@ -1237,6 +1315,7 @@ pub const Type = extern union { .c_mut_pointer => self.castPointer().?.pointee_type, .array_u8, .array_u8_sentinel_0, .const_slice_u8 => Type.initTag(.u8), .single_const_pointer_to_comptime_int => Type.initTag(.comptime_int), + .pointer => self.cast(Payload.Pointer).?.pointee_type, }; } @@ -1325,6 +1404,7 @@ pub const Type = extern union { .fn_naked_noreturn_no_args, .fn_ccc_void_no_args, .function, + .pointer, .single_const_pointer, .single_mut_pointer, .many_const_pointer, @@ -1389,6 +1469,7 @@ pub const Type = extern union { .fn_naked_noreturn_no_args, .fn_ccc_void_no_args, .function, + .pointer, .single_const_pointer, .single_mut_pointer, .many_const_pointer, @@ -1443,6 +1524,7 @@ pub const Type = extern union { .array_sentinel, .array_u8, .array_u8_sentinel_0, + .pointer, .single_const_pointer, .single_mut_pointer, .many_const_pointer, @@ -1508,6 +1590,7 @@ pub const Type = extern union { .array_sentinel, .array_u8, .array_u8_sentinel_0, + .pointer, .single_const_pointer, .single_mut_pointer, .many_const_pointer, @@ -1573,6 +1656,7 @@ pub const Type = extern union { .array_sentinel, .array_u8, .array_u8_sentinel_0, + .pointer, .single_const_pointer, .single_mut_pointer, .many_const_pointer, @@ -1636,6 +1720,7 @@ pub const Type = extern union { .array_sentinel, .array_u8, .array_u8_sentinel_0, + .pointer, .single_const_pointer, .single_mut_pointer, .many_const_pointer, @@ -1728,6 +1813,7 @@ pub const Type = extern union { .array_sentinel, .array_u8, .array_u8_sentinel_0, + .pointer, .single_const_pointer, .single_mut_pointer, .many_const_pointer, @@ -1796,6 +1882,7 @@ pub const Type = extern union { .array_sentinel, .array_u8, .array_u8_sentinel_0, + .pointer, .single_const_pointer, .single_mut_pointer, .many_const_pointer, @@ -1863,6 +1950,7 @@ pub const Type = extern union { .array_sentinel, .array_u8, .array_u8_sentinel_0, + .pointer, .single_const_pointer, .single_mut_pointer, .many_const_pointer, @@ -1930,6 +2018,7 @@ pub const Type = extern union { .array_sentinel, .array_u8, .array_u8_sentinel_0, + .pointer, .single_const_pointer, .single_mut_pointer, .many_const_pointer, @@ -1994,6 +2083,7 @@ pub const Type = extern union { .array_sentinel, .array_u8, .array_u8_sentinel_0, + .pointer, .single_const_pointer, .single_mut_pointer, .many_const_pointer, @@ -2058,6 +2148,7 @@ pub const Type = extern union { .array_sentinel, .array_u8, .array_u8_sentinel_0, + .pointer, .single_const_pointer, .single_mut_pointer, .many_const_pointer, @@ -2142,6 +2233,7 @@ pub const Type = extern union { .array_sentinel, .array_u8, .array_u8_sentinel_0, + .pointer, .single_const_pointer, .single_mut_pointer, .many_const_pointer, @@ -2241,6 +2333,10 @@ pub const Type = extern union { ty = ptr.pointee_type; continue; }, + .pointer => { + ty = ty.cast(Payload.Pointer).?.pointee_type; + continue; + }, }; } @@ -2305,6 +2401,8 @@ pub const Type = extern union { .c_const_pointer, .c_mut_pointer, => return true, + + .pointer => self.cast(Payload.Pointer).?.size == .C, }; } @@ -2362,6 +2460,7 @@ pub const Type = extern union { array_u8_sentinel_0, array, array_sentinel, + pointer, single_const_pointer, single_mut_pointer, many_const_pointer, @@ -2440,6 +2539,21 @@ pub const Type = extern union { child_type: Type, }; + + pub const Pointer = struct { + base: Payload = .{ .tag = .pointer }, + + pointee_type: Type, + sentinel: ?Value, + /// If zero use pointee_type.AbiAlign() + @"align": u32, + bit_offset: u16, + host_size: u16, + @"allowzero": bool, + mutable: bool, + @"volatile": bool, + size: std.builtin.TypeInfo.Pointer.Size, + }; }; }; diff --git a/src-self-hosted/zir.zig b/src-self-hosted/zir.zig index 62c0c73f3f..db0ec242cc 100644 --- a/src-self-hosted/zir.zig +++ b/src-self-hosted/zir.zig @@ -872,7 +872,7 @@ pub const Inst = struct { @"align": ?*Inst = null, align_bit_start: ?*Inst = null, align_bit_end: ?*Inst = null, - @"const": bool = true, + mutable: bool = true, @"volatile": bool = false, sentinel: ?*Inst = null, size: std.builtin.TypeInfo.Pointer.Size = .One, diff --git a/src-self-hosted/zir_sema.zig b/src-self-hosted/zir_sema.zig index 0e331d1979..ea3b85b29a 100644 --- a/src-self-hosted/zir_sema.zig +++ b/src-self-hosted/zir_sema.zig @@ -271,6 +271,14 @@ fn resolveType(mod: *Module, scope: *Scope, old_inst: *zir.Inst) !Type { return val.toType(); } +fn resolveInt(mod: *Module, scope: *Scope, old_inst: *zir.Inst, dest_type: Type) !u64 { + const new_inst = try resolveInst(mod, scope, old_inst); + const coerced = try mod.coerce(scope, dest_type, new_inst); + const val = try mod.resolveConstValue(scope, coerced); + + return val.toUnsignedInt(); +} + pub fn resolveInstConst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!TypedValue { const new_inst = try resolveInst(mod, scope, old_inst); const val = try mod.resolveConstValue(scope, new_inst); @@ -1322,5 +1330,42 @@ fn analyzeInstSimplePtrType(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp, m } fn analyzeInstPtrType(mod: *Module, scope: *Scope, inst: *zir.Inst.PtrType) InnerError!*Inst { - return mod.fail(scope, inst.base.src, "TODO implement ptr_type", .{}); + // TODO lazy values + const @"align" = if (inst.kw_args.@"align") |some| + @truncate(u32, try resolveInt(mod, scope, some, Type.initTag(.u32))) + else + 0; + const bit_offset = if (inst.kw_args.align_bit_start) |some| + @truncate(u16, try resolveInt(mod, scope, some, Type.initTag(.u16))) + else + 0; + const host_size = if (inst.kw_args.align_bit_end) |some| + @truncate(u16, try resolveInt(mod, scope, some, Type.initTag(.u16))) + else + 0; + + if (host_size != 0 and bit_offset >= host_size * 8) + return mod.fail(scope, inst.base.src, "bit offset starts after end of host integer", .{}); + + const sentinel = if (inst.kw_args.sentinel) |some| + (try resolveInstConst(mod, scope, some)).val + else + null; + + const elem_type = try resolveType(mod, scope, inst.positionals.child_type); + + const ty = try mod.ptrType( + scope, + inst.base.src, + elem_type, + sentinel, + @"align", + bit_offset, + host_size, + inst.kw_args.mutable, + inst.kw_args.@"allowzero", + inst.kw_args.@"volatile", + inst.kw_args.size, + ); + return mod.constType(scope, inst.base.src, ty); } From d312d64c9aa058293d69b2bf97c51f4caa7a2d9d Mon Sep 17 00:00:00 2001 From: Vexu Date: Thu, 20 Aug 2020 16:37:28 +0300 Subject: [PATCH 51/66] stage2: slice types --- src-self-hosted/Module.zig | 5 +- src-self-hosted/astgen.zig | 50 +++++++++++-------- src-self-hosted/type.zig | 97 +++++++++++++++++++++++++++++------- src-self-hosted/zir.zig | 20 +++++--- src-self-hosted/zir_sema.zig | 2 + 5 files changed, 127 insertions(+), 47 deletions(-) diff --git a/src-self-hosted/Module.zig b/src-self-hosted/Module.zig index 2dd64c64bc..4893aaba7a 100644 --- a/src-self-hosted/Module.zig +++ b/src-self-hosted/Module.zig @@ -3146,6 +3146,9 @@ pub fn floatSub(self: *Module, scope: *Scope, float_type: Type, src: usize, lhs: } pub fn simplePtrType(self: *Module, scope: *Scope, src: usize, elem_ty: Type, mutable: bool, size: std.builtin.TypeInfo.Pointer.Size) Allocator.Error!Type { + if (size == .Slice and elem_ty.eql(Type.initTag(.u8))) { + return Type.initTag(.const_slice_u8); + } // TODO stage1 type inference bug const T = Type.Tag; @@ -3156,7 +3159,7 @@ pub fn simplePtrType(self: *Module, scope: *Scope, src: usize, elem_ty: Type, mu .One => if (mutable) T.single_mut_pointer else T.single_const_pointer, .Many => if (mutable) T.many_mut_pointer else T.many_const_pointer, .C => if (mutable) T.c_mut_pointer else T.c_const_pointer, - else => unreachable, + .Slice => if (mutable) T.mut_slice else T.const_slice, }, }, .pointee_type = elem_ty, diff --git a/src-self-hosted/astgen.zig b/src-self-hosted/astgen.zig index 832e6848b3..8276b191cb 100644 --- a/src-self-hosted/astgen.zig +++ b/src-self-hosted/astgen.zig @@ -262,6 +262,7 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr .EnumLiteral => return rlWrap(mod, scope, rl, try enumLiteral(mod, scope, node.castTag(.EnumLiteral).?)), .MultilineStringLiteral => return rlWrap(mod, scope, rl, try multilineStrLiteral(mod, scope, node.castTag(.MultilineStringLiteral).?)), .CharLiteral => return rlWrap(mod, scope, rl, try charLiteral(mod, scope, node.castTag(.CharLiteral).?)), + .SliceType => return rlWrap(mod, scope, rl, try sliceType(mod, scope, node.castTag(.SliceType).?)), .Defer => return mod.failNode(scope, node, "TODO implement astgen.expr for .Defer", .{}), .Catch => return mod.failNode(scope, node, "TODO implement astgen.expr for .Catch", .{}), @@ -275,7 +276,6 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr .NegationWrap => return mod.failNode(scope, node, "TODO implement astgen.expr for .NegationWrap", .{}), .Resume => return mod.failNode(scope, node, "TODO implement astgen.expr for .Resume", .{}), .Try => return mod.failNode(scope, node, "TODO implement astgen.expr for .Try", .{}), - .SliceType => return mod.failNode(scope, node, "TODO implement astgen.expr for .SliceType", .{}), .Slice => return mod.failNode(scope, node, "TODO implement astgen.expr for .Slice", .{}), .ArrayAccess => return mod.failNode(scope, node, "TODO implement astgen.expr for .ArrayAccess", .{}), .ArrayInitializer => return mod.failNode(scope, node, "TODO implement astgen.expr for .ArrayInitializer", .{}), @@ -569,15 +569,16 @@ fn optionalType(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) Inn return addZIRUnOp(mod, scope, src, .optional_type, operand); } +fn sliceType(mod: *Module, scope: *Scope, node: *ast.Node.SliceType) InnerError!*zir.Inst { + const tree = scope.tree(); + const src = tree.token_locs[node.op_token].start; + return ptrSliceType(mod, scope, src, &node.ptr_info, node.rhs, .Slice); +} + fn ptrType(mod: *Module, scope: *Scope, node: *ast.Node.PtrType) InnerError!*zir.Inst { const tree = scope.tree(); const src = tree.token_locs[node.op_token].start; - const meta_type = try addZIRInstConst(mod, scope, src, .{ - .ty = Type.initTag(.type), - .val = Value.initTag(.type_type), - }); - - const size: std.builtin.TypeInfo.Pointer.Size = switch (tree.token_ids[node.op_token]) { + return ptrSliceType(mod, scope, src, &node.ptr_info, node.rhs, switch (tree.token_ids[node.op_token]) { .Asterisk, .AsteriskAsterisk => .One, // TODO stage1 type inference bug .LBracket => @as(std.builtin.TypeInfo.Pointer.Size, switch (tree.token_ids[node.op_token + 2]) { @@ -585,43 +586,50 @@ fn ptrType(mod: *Module, scope: *Scope, node: *ast.Node.PtrType) InnerError!*zir else => .Many, }), else => unreachable, - }; + }); +} - const simple = node.ptr_info.allowzero_token == null and - node.ptr_info.align_info == null and - node.ptr_info.volatile_token == null and - node.ptr_info.sentinel == null; +fn ptrSliceType(mod: *Module, scope: *Scope, src: usize, ptr_info: *ast.PtrInfo, rhs: *ast.Node, size: std.builtin.TypeInfo.Pointer.Size) InnerError!*zir.Inst { + const meta_type = try addZIRInstConst(mod, scope, src, .{ + .ty = Type.initTag(.type), + .val = Value.initTag(.type_type), + }); + + const simple = ptr_info.allowzero_token == null and + ptr_info.align_info == null and + ptr_info.volatile_token == null and + ptr_info.sentinel == null; if (simple) { - const child_type = try expr(mod, scope, .{ .ty = meta_type }, node.rhs); - const mutable = node.ptr_info.const_token == null; + const child_type = try expr(mod, scope, .{ .ty = meta_type }, rhs); + const mutable = ptr_info.const_token == null; // TODO stage1 type inference bug const T = zir.Inst.Tag; return addZIRUnOp(mod, scope, src, switch (size) { .One => if (mutable) T.single_mut_ptr_type else T.single_const_ptr_type, .Many => if (mutable) T.many_mut_ptr_type else T.many_const_ptr_type, .C => if (mutable) T.c_mut_ptr_type else T.c_const_ptr_type, - else => unreachable, + .Slice => if (mutable) T.mut_slice_type else T.mut_slice_type, }, child_type); } var kw_args: std.meta.fieldInfo(zir.Inst.PtrType, "kw_args").field_type = .{}; kw_args.size = size; - kw_args.@"allowzero" = node.ptr_info.allowzero_token != null; - if (node.ptr_info.align_info) |some| { + kw_args.@"allowzero" = ptr_info.allowzero_token != null; + if (ptr_info.align_info) |some| { kw_args.@"align" = try expr(mod, scope, .none, some.node); if (some.bit_range) |bit_range| { kw_args.align_bit_start = try expr(mod, scope, .none, bit_range.start); kw_args.align_bit_end = try expr(mod, scope, .none, bit_range.end); } } - kw_args.mutable = node.ptr_info.const_token == null; - kw_args.@"volatile" = node.ptr_info.volatile_token != null; - if (node.ptr_info.sentinel) |some| { + kw_args.mutable = ptr_info.const_token == null; + kw_args.@"volatile" = ptr_info.volatile_token != null; + if (ptr_info.sentinel) |some| { kw_args.sentinel = try expr(mod, scope, .none, some); } - const child_type = try expr(mod, scope, .{ .ty = meta_type }, node.rhs); + const child_type = try expr(mod, scope, .{ .ty = meta_type }, rhs); if (kw_args.sentinel) |some| { kw_args.sentinel = try addZIRBinOp(mod, scope, some.src, .as, child_type, some); } diff --git a/src-self-hosted/type.zig b/src-self-hosted/type.zig index 2c326b9308..2218c49200 100644 --- a/src-self-hosted/type.zig +++ b/src-self-hosted/type.zig @@ -74,6 +74,8 @@ pub const Type = extern union { .many_mut_pointer, .c_const_pointer, .c_mut_pointer, + .const_slice, + .mut_slice, .pointer, => return .Pointer, @@ -122,6 +124,8 @@ pub const Type = extern union { .many_mut_pointer, .c_const_pointer, .c_mut_pointer, + .const_slice, + .mut_slice, .optional_single_const_pointer, .optional_single_mut_pointer, => @fieldParentPtr(Payload.PointerSimple, "base", self.ptr_otherwise), @@ -388,6 +392,8 @@ pub const Type = extern union { .many_mut_pointer, .c_const_pointer, .c_mut_pointer, + .const_slice, + .mut_slice, .optional_single_mut_pointer, .optional_single_const_pointer, => return self.copyPayloadSingleField(allocator, Payload.PointerSimple, "pointee_type"), @@ -550,6 +556,18 @@ pub const Type = extern union { ty = payload.pointee_type; continue; }, + .const_slice => { + const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise); + try out_stream.writeAll("[]const "); + ty = payload.pointee_type; + continue; + }, + .mut_slice => { + const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise); + try out_stream.writeAll("[]"); + ty = payload.pointee_type; + continue; + }, .int_signed => { const payload = @fieldParentPtr(Payload.IntSigned, "base", ty.ptr_otherwise); return out_stream.print("i{}", .{payload.bits}); @@ -701,14 +719,7 @@ pub const Type = extern union { // TODO lazy types .array => self.elemType().hasCodeGenBits() and self.arrayLen() != 0, .array_u8 => self.arrayLen() != 0, - .array_sentinel => self.elemType().hasCodeGenBits(), - .single_const_pointer => self.elemType().hasCodeGenBits(), - .single_mut_pointer => self.elemType().hasCodeGenBits(), - .many_const_pointer => self.elemType().hasCodeGenBits(), - .many_mut_pointer => self.elemType().hasCodeGenBits(), - .c_const_pointer => self.elemType().hasCodeGenBits(), - .c_mut_pointer => self.elemType().hasCodeGenBits(), - .pointer => self.elemType().hasCodeGenBits(), + .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(), .int_signed => self.cast(Payload.IntSigned).?.bits == 0, .int_unsigned => self.cast(Payload.IntUnsigned).?.bits == 0, @@ -763,6 +774,8 @@ pub const Type = extern union { .many_mut_pointer, .c_const_pointer, .c_mut_pointer, + .const_slice, + .mut_slice, .optional_single_const_pointer, .optional_single_mut_pointer, => return @divExact(target.cpu.arch.ptrBitWidth(), 8), @@ -868,10 +881,12 @@ pub const Type = extern union { .i32, .u32 => return 4, .i64, .u64 => return 8, - .isize, - .usize - => return @divExact(target.cpu.arch.ptrBitWidth(), 8), - .const_slice_u8 => return @divExact(target.cpu.arch.ptrBitWidth(), 8) * 2, + .isize, .usize => return @divExact(target.cpu.arch.ptrBitWidth(), 8), + + .const_slice, + .mut_slice, + .const_slice_u8, + => return @divExact(target.cpu.arch.ptrBitWidth(), 8) * 2, .optional_single_const_pointer, .optional_single_mut_pointer, @@ -992,6 +1007,8 @@ pub const Type = extern union { .many_mut_pointer, .c_const_pointer, .c_mut_pointer, + .const_slice, + .mut_slice, => false, .single_const_pointer, @@ -1062,7 +1079,10 @@ pub const Type = extern union { .enum_literal, => false, - .const_slice_u8 => true, + .const_slice, + .mut_slice, + .const_slice_u8, + => true, .pointer => self.cast(Payload.Pointer).?.size == .Slice, }; @@ -1121,6 +1141,7 @@ pub const Type = extern union { .optional_single_mut_pointer, .optional_single_const_pointer, .enum_literal, + .mut_slice, => false, .single_const_pointer, @@ -1128,6 +1149,7 @@ pub const Type = extern union { .c_const_pointer, .single_const_pointer_to_comptime_int, .const_slice_u8, + .const_slice, => true, .pointer => !self.cast(Payload.Pointer).?.mutable, @@ -1186,6 +1208,8 @@ pub const Type = extern union { .many_mut_pointer, .c_const_pointer, .c_mut_pointer, + .const_slice, + .mut_slice, .single_const_pointer_to_comptime_int, .const_slice_u8, .optional, @@ -1307,12 +1331,15 @@ pub const Type = extern union { .array => self.cast(Payload.Array).?.elem_type, .array_sentinel => self.cast(Payload.ArraySentinel).?.elem_type, - .single_const_pointer => self.castPointer().?.pointee_type, - .single_mut_pointer => self.castPointer().?.pointee_type, - .many_const_pointer => self.castPointer().?.pointee_type, - .many_mut_pointer => self.castPointer().?.pointee_type, - .c_const_pointer => self.castPointer().?.pointee_type, - .c_mut_pointer => self.castPointer().?.pointee_type, + .single_const_pointer, + .single_mut_pointer, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, + .const_slice, + .mut_slice, + => self.castPointer().?.pointee_type, .array_u8, .array_u8_sentinel_0, .const_slice_u8 => Type.initTag(.u8), .single_const_pointer_to_comptime_int => Type.initTag(.comptime_int), .pointer => self.cast(Payload.Pointer).?.pointee_type, @@ -1411,6 +1438,8 @@ pub const Type = extern union { .many_mut_pointer, .c_const_pointer, .c_mut_pointer, + .const_slice, + .mut_slice, .single_const_pointer_to_comptime_int, .const_slice_u8, .int_unsigned, @@ -1476,6 +1505,8 @@ pub const Type = extern union { .many_mut_pointer, .c_const_pointer, .c_mut_pointer, + .const_slice, + .mut_slice, .single_const_pointer_to_comptime_int, .const_slice_u8, .int_unsigned, @@ -1531,6 +1562,8 @@ pub const Type = extern union { .many_mut_pointer, .c_const_pointer, .c_mut_pointer, + .const_slice, + .mut_slice, .single_const_pointer_to_comptime_int, .const_slice_u8, .int_unsigned, @@ -1597,6 +1630,8 @@ pub const Type = extern union { .many_mut_pointer, .c_const_pointer, .c_mut_pointer, + .const_slice, + .mut_slice, .single_const_pointer_to_comptime_int, .const_slice_u8, .int_signed, @@ -1663,6 +1698,8 @@ pub const Type = extern union { .many_mut_pointer, .c_const_pointer, .c_mut_pointer, + .const_slice, + .mut_slice, .single_const_pointer_to_comptime_int, .const_slice_u8, .optional, @@ -1727,6 +1764,8 @@ pub const Type = extern union { .many_mut_pointer, .c_const_pointer, .c_mut_pointer, + .const_slice, + .mut_slice, .single_const_pointer_to_comptime_int, .const_slice_u8, .int_unsigned, @@ -1820,6 +1859,8 @@ pub const Type = extern union { .many_mut_pointer, .c_const_pointer, .c_mut_pointer, + .const_slice, + .mut_slice, .single_const_pointer_to_comptime_int, .const_slice_u8, .u8, @@ -1889,6 +1930,8 @@ pub const Type = extern union { .many_mut_pointer, .c_const_pointer, .c_mut_pointer, + .const_slice, + .mut_slice, .single_const_pointer_to_comptime_int, .const_slice_u8, .u8, @@ -1957,6 +2000,8 @@ pub const Type = extern union { .many_mut_pointer, .c_const_pointer, .c_mut_pointer, + .const_slice, + .mut_slice, .single_const_pointer_to_comptime_int, .const_slice_u8, .u8, @@ -2025,6 +2070,8 @@ pub const Type = extern union { .many_mut_pointer, .c_const_pointer, .c_mut_pointer, + .const_slice, + .mut_slice, .single_const_pointer_to_comptime_int, .const_slice_u8, .u8, @@ -2090,6 +2137,8 @@ pub const Type = extern union { .many_mut_pointer, .c_const_pointer, .c_mut_pointer, + .const_slice, + .mut_slice, .single_const_pointer_to_comptime_int, .const_slice_u8, .u8, @@ -2155,6 +2204,8 @@ pub const Type = extern union { .many_mut_pointer, .c_const_pointer, .c_mut_pointer, + .const_slice, + .mut_slice, .single_const_pointer_to_comptime_int, .const_slice_u8, .u8, @@ -2240,6 +2291,8 @@ pub const Type = extern union { .many_mut_pointer, .c_const_pointer, .c_mut_pointer, + .const_slice, + .mut_slice, .single_const_pointer_to_comptime_int, .const_slice_u8, .optional, @@ -2290,6 +2343,8 @@ pub const Type = extern union { .array_sentinel, .array_u8_sentinel_0, .const_slice_u8, + .const_slice, + .mut_slice, .c_void, .optional, .optional_single_mut_pointer, @@ -2392,6 +2447,8 @@ pub const Type = extern union { .single_mut_pointer, .many_const_pointer, .many_mut_pointer, + .const_slice, + .mut_slice, .optional, .optional_single_mut_pointer, .optional_single_const_pointer, @@ -2467,6 +2524,8 @@ pub const Type = extern union { many_mut_pointer, c_const_pointer, c_mut_pointer, + const_slice, + mut_slice, int_signed, int_unsigned, function, diff --git a/src-self-hosted/zir.zig b/src-self-hosted/zir.zig index db0ec242cc..a3ea1f11ab 100644 --- a/src-self-hosted/zir.zig +++ b/src-self-hosted/zir.zig @@ -194,18 +194,22 @@ pub const Inst = struct { shl, /// Integer shift-right. Arithmetic or logical depending on the signedness of the integer type. shr, - /// Create a const pointer type based on the element type. `*const T` + /// Create a const pointer type with element type T. `*const T` single_const_ptr_type, - /// Create a mutable pointer type based on the element type. `*T` + /// Create a mutable pointer type with element type T. `*T` single_mut_ptr_type, - /// Create a const pointer type based on the element type. `[*]const T` + /// Create a const pointer type with element type T. `[*]const T` many_const_ptr_type, - /// Create a mutable pointer type based on the element type. `[*]T` + /// Create a mutable pointer type with element type T. `[*]T` many_mut_ptr_type, - /// Create a const pointer type based on the element type. `[*c]const T` + /// Create a const pointer type with element type T. `[*c]const T` c_const_ptr_type, - /// Create a mutable pointer type based on the element type. `[*c]T` + /// Create a mutable pointer type with element type T. `[*c]T` c_mut_ptr_type, + /// Create a mutable slice type with element type T. `[]T` + mut_slice_type, + /// Create a const slice type with element type T. `[]T` + const_slice_type, /// Create a pointer type with attributes ptr_type, /// Write a value to a pointer. For loading, see `deref`. @@ -274,6 +278,8 @@ pub const Inst = struct { .many_mut_ptr_type, .c_const_ptr_type, .c_mut_ptr_type, + .mut_slice_type, + .const_slice_type, .optional_type, .unwrap_optional_safe, .unwrap_optional_unsafe, @@ -416,6 +422,8 @@ pub const Inst = struct { .many_mut_ptr_type, .c_const_ptr_type, .c_mut_ptr_type, + .mut_slice_type, + .const_slice_type, .store, .str, .sub, diff --git a/src-self-hosted/zir_sema.zig b/src-self-hosted/zir_sema.zig index ea3b85b29a..75ec7f6306 100644 --- a/src-self-hosted/zir_sema.zig +++ b/src-self-hosted/zir_sema.zig @@ -57,6 +57,8 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError! .many_mut_ptr_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.many_mut_ptr_type).?, true, .Many), .c_const_ptr_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.c_const_ptr_type).?, false, .C), .c_mut_ptr_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.c_mut_ptr_type).?, true, .C), + .const_slice_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.const_slice_type).?, false, .Slice), + .mut_slice_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.mut_slice_type).?, true, .Slice), .ptr_type => return analyzeInstPtrType(mod, scope, old_inst.castTag(.ptr_type).?), .store => return analyzeInstStore(mod, scope, old_inst.castTag(.store).?), .str => return analyzeInstStr(mod, scope, old_inst.castTag(.str).?), From 6a053ffcc85ce3f2b598be08e5d0587c930b4358 Mon Sep 17 00:00:00 2001 From: Vexu Date: Thu, 20 Aug 2020 18:50:13 +0300 Subject: [PATCH 52/66] stage2: comptime decl --- src-self-hosted/Module.zig | 51 ++++++++++++++++++++++++++++++++-- test/stage2/compare_output.zig | 5 ---- test/stage2/compile_errors.zig | 36 ++++++++---------------- 3 files changed, 60 insertions(+), 32 deletions(-) diff --git a/src-self-hosted/Module.zig b/src-self-hosted/Module.zig index 4893aaba7a..ba39aa8f38 100644 --- a/src-self-hosted/Module.zig +++ b/src-self-hosted/Module.zig @@ -1485,6 +1485,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { const type_node = var_decl.getTrailer("type_node") orelse break :blk null; + // Temporary arena for the zir instructions. var type_scope_arena = std.heap.ArenaAllocator.init(self.gpa); defer type_scope_arena.deinit(); var type_scope: Scope.GenZIR = .{ @@ -1539,7 +1540,8 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { try self.coerce(&inner_block.base, some, ret.operand) else ret.operand; - const val = try self.resolveConstValue(&inner_block.base, coerced); + const val = coerced.value() orelse + return self.fail(&block_scope.base, inst.src, "unable to resolve comptime value", .{}); var_type = explicit_type orelse try ret.operand.ty.copy(block_scope.arena); break :blk try val.copy(block_scope.arena); @@ -1603,7 +1605,41 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { } return type_changed; }, - .Comptime => @panic("TODO comptime decl"), + .Comptime => { + const comptime_decl = @fieldParentPtr(ast.Node.Comptime, "base", ast_node); + + decl.analysis = .in_progress; + + // A comptime decl does not store any value so we can just deinit this arena after analysis is done. + var analysis_arena = std.heap.ArenaAllocator.init(self.gpa); + defer analysis_arena.deinit(); + var gen_scope: Scope.GenZIR = .{ + .decl = decl, + .arena = &analysis_arena.allocator, + .parent = decl.scope, + }; + defer gen_scope.instructions.deinit(self.gpa); + + // TODO comptime scope here + _ = try astgen.expr(self, &gen_scope.base, .none, comptime_decl.expr); + + var block_scope: Scope.Block = .{ + .parent = null, + .func = null, + .decl = decl, + .instructions = .{}, + .arena = &analysis_arena.allocator, + }; + defer block_scope.instructions.deinit(self.gpa); + + _ = try zir_sema.analyzeBody(self, &block_scope.base, .{ + .instructions = gen_scope.instructions.items, + }); + + decl.analysis = .complete; + decl.generation = self.generation; + return true; + }, .Use => @panic("TODO usingnamespace decl"), else => unreachable, } @@ -1794,7 +1830,16 @@ fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void { } } } else if (src_decl.castTag(.Comptime)) |comptime_node| { - log.err("TODO: analyze comptime decl", .{}); + const name_index = self.getNextAnonNameIndex(); + const name = try std.fmt.allocPrint(self.gpa, "__comptime_{}", .{name_index}); + defer self.gpa.free(name); + + const name_hash = root_scope.fullyQualifiedNameHash(name); + const contents_hash = std.zig.hashSrc(tree.getNodeSource(src_decl)); + + const new_decl = try self.createNewDecl(&root_scope.base, name, decl_i, name_hash, contents_hash); + root_scope.decls.appendAssumeCapacity(new_decl); + self.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl }); } else if (src_decl.castTag(.ContainerField)) |container_field| { log.err("TODO: analyze container field", .{}); } else if (src_decl.castTag(.TestDecl)) |test_decl| { diff --git a/test/stage2/compare_output.zig b/test/stage2/compare_output.zig index 6fbc760f26..6c4b9c47e0 100644 --- a/test/stage2/compare_output.zig +++ b/test/stage2/compare_output.zig @@ -23,11 +23,6 @@ pub fn addCases(ctx: *TestContext) !void { case.addError("", &[_][]const u8{":1:1: error: no entry point found"}); - case.addError( - \\export fn _start() noreturn { - \\} - , &[_][]const u8{":2:1: error: expected noreturn, found void"}); - // Regular old hello world case.addCompareOutput( \\export fn _start() noreturn { diff --git a/test/stage2/compile_errors.zig b/test/stage2/compile_errors.zig index 45e60c0741..d90c0c7fae 100644 --- a/test/stage2/compile_errors.zig +++ b/test/stage2/compile_errors.zig @@ -67,6 +67,18 @@ pub fn addCases(ctx: *TestContext) !void { \\fn entry() void {} , &[_][]const u8{":2:4: error: redefinition of 'entry'"}); + ctx.compileError("incorrect return type", linux_x64, + \\export fn _start() noreturn { + \\} + , &[_][]const u8{":2:1: error: expected noreturn, found void"}); + + ctx.compileError("extern variable has no type", linux_x64, + \\comptime { + \\ _ = foo; + \\} + \\extern var foo; + , &[_][]const u8{":4:1: error: unable to infer variable type"}); + //ctx.incrementalFailure("function redefinition", linux_x64, // \\fn entry() void {} // \\fn entry() void {} @@ -108,28 +120,4 @@ pub fn addCases(ctx: *TestContext) !void { // \\ return 36893488147419103232; // \\} //, "1.zig", 2, 12, "integer value '36893488147419103232' cannot be stored in type 'c_int'"); - - //ctx.testCompileError( - // \\comptime { - // \\ var a: *align(4) align(4) i32 = 0; - // \\} - //, "1.zig", 2, 22, "Extra align qualifier"); - - //ctx.testCompileError( - // \\comptime { - // \\ var b: *const const i32 = 0; - // \\} - //, "1.zig", 2, 19, "Extra align qualifier"); - - //ctx.testCompileError( - // \\comptime { - // \\ var c: *volatile volatile i32 = 0; - // \\} - //, "1.zig", 2, 22, "Extra align qualifier"); - - //ctx.testCompileError( - // \\comptime { - // \\ var d: *allowzero allowzero i32 = 0; - // \\} - //, "1.zig", 2, 23, "Extra align qualifier"); } From f54b2e2da6a9ef72a37fae064dc04d951c686298 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 20 Aug 2020 17:08:01 -0700 Subject: [PATCH 53/66] add missing mutability check in simplePtrType --- src-self-hosted/Module.zig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src-self-hosted/Module.zig b/src-self-hosted/Module.zig index ba39aa8f38..c0d1d0d654 100644 --- a/src-self-hosted/Module.zig +++ b/src-self-hosted/Module.zig @@ -2487,7 +2487,7 @@ pub fn analyzeDeclRef(self: *Module, scope: *Scope, src: usize, decl: *Decl) Inn fn analyzeVarRef(self: *Module, scope: *Scope, src: usize, tv: TypedValue) InnerError!*Inst { const variable = tv.val.cast(Value.Payload.Variable).?.variable; - const ty = try self.singlePtrType(scope, src, variable.is_mutable, tv.ty, .One); + const ty = try self.simplePtrType(scope, src, tv.ty, variable.is_mutable, .One); if (!variable.is_mutable and !variable.is_extern) { const val_payload = try scope.arena().create(Value.Payload.RefVal); val_payload.* = .{ .val = variable.init }; @@ -3191,7 +3191,7 @@ pub fn floatSub(self: *Module, scope: *Scope, float_type: Type, src: usize, lhs: } pub fn simplePtrType(self: *Module, scope: *Scope, src: usize, elem_ty: Type, mutable: bool, size: std.builtin.TypeInfo.Pointer.Size) Allocator.Error!Type { - if (size == .Slice and elem_ty.eql(Type.initTag(.u8))) { + if (!mutable and size == .Slice and elem_ty.eql(Type.initTag(.u8))) { return Type.initTag(.const_slice_u8); } // TODO stage1 type inference bug From 7d6d4b1473e7c0c8bc6ee29a3e0ecd03e850e5ee Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 20 Aug 2020 17:15:01 -0700 Subject: [PATCH 54/66] stage2: move all tests to compare_output.zig --- test/stage2/compare_output.zig | 18 +++++++++++ test/stage2/compile_errors.zig | 59 ---------------------------------- 2 files changed, 18 insertions(+), 59 deletions(-) diff --git a/test/stage2/compare_output.zig b/test/stage2/compare_output.zig index 6c4b9c47e0..3e08394b2e 100644 --- a/test/stage2/compare_output.zig +++ b/test/stage2/compare_output.zig @@ -23,6 +23,12 @@ pub fn addCases(ctx: *TestContext) !void { case.addError("", &[_][]const u8{":1:1: error: no entry point found"}); + // Incorrect return type + case.addError( + \\export fn _start() noreturn { + \\} + , &[_][]const u8{":2:1: error: expected noreturn, found void"}); + // Regular old hello world case.addCompareOutput( \\export fn _start() noreturn { @@ -702,4 +708,16 @@ pub fn addCases(ctx: *TestContext) !void { "1109917696\n", ); } + + ctx.compileError("function redefinition", linux_x64, + \\fn entry() void {} + \\fn entry() void {} + , &[_][]const u8{":2:4: error: redefinition of 'entry'"}); + + ctx.compileError("extern variable has no type", linux_x64, + \\comptime { + \\ _ = foo; + \\} + \\extern var foo; + , &[_][]const u8{":4:1: error: unable to infer variable type"}); } diff --git a/test/stage2/compile_errors.zig b/test/stage2/compile_errors.zig index d90c0c7fae..ce53884aca 100644 --- a/test/stage2/compile_errors.zig +++ b/test/stage2/compile_errors.zig @@ -61,63 +61,4 @@ pub fn addCases(ctx: *TestContext) !void { \\@0 = str("_start") \\@1 = export(@0, "start") ); - - ctx.compileError("function redefinition", linux_x64, - \\fn entry() void {} - \\fn entry() void {} - , &[_][]const u8{":2:4: error: redefinition of 'entry'"}); - - ctx.compileError("incorrect return type", linux_x64, - \\export fn _start() noreturn { - \\} - , &[_][]const u8{":2:1: error: expected noreturn, found void"}); - - ctx.compileError("extern variable has no type", linux_x64, - \\comptime { - \\ _ = foo; - \\} - \\extern var foo; - , &[_][]const u8{":4:1: error: unable to infer variable type"}); - - //ctx.incrementalFailure("function redefinition", linux_x64, - // \\fn entry() void {} - // \\fn entry() void {} - //, &[_][]const u8{":2:4: error: redefinition of 'entry'"}, - // \\fn entry() void {} - //); - - //// TODO: need to make sure this works with other variants of export. - //ctx.incrementalFailure("exported symbol collision", linux_x64, - // \\export fn entry() void {} - // \\export fn entry() void {} - //, &[_][]const u8{":2:11: error: redefinition of 'entry'"}, - // \\export fn entry() void {} - //); - - // ctx.incrementalFailure("missing function name", linux_x64, - // \\fn() void {} - // , &[_][]const u8{":1:3: error: missing function name"}, - // \\fn a() void {} - // ); - - // TODO: re-enable these tests. - // https://github.com/ziglang/zig/issues/1364 - - //ctx.testCompileError( - // \\comptime { - // \\ return; - // \\} - //, "1.zig", 2, 5, "return expression outside function definition"); - - //ctx.testCompileError( - // \\export fn entry() void { - // \\ defer return; - // \\} - //, "1.zig", 2, 11, "cannot return from defer expression"); - - //ctx.testCompileError( - // \\export fn entry() c_int { - // \\ return 36893488147419103232; - // \\} - //, "1.zig", 2, 12, "integer value '36893488147419103232' cannot be stored in type 'c_int'"); } From 56ea04cb6d1b2b87e2a2dbde6de8279e035bec73 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 20 Aug 2020 17:19:26 -0700 Subject: [PATCH 55/66] stage2: don't test compile errors of ZIR --- test/stage2/compile_errors.zig | 64 ---------------------------------- test/stage2/test.zig | 1 - 2 files changed, 65 deletions(-) delete mode 100644 test/stage2/compile_errors.zig diff --git a/test/stage2/compile_errors.zig b/test/stage2/compile_errors.zig deleted file mode 100644 index ce53884aca..0000000000 --- a/test/stage2/compile_errors.zig +++ /dev/null @@ -1,64 +0,0 @@ -const TestContext = @import("../../src-self-hosted/test.zig").TestContext; -const std = @import("std"); - -const ErrorMsg = @import("../../src-self-hosted/Module.zig").ErrorMsg; - -const linux_x64 = std.zig.CrossTarget{ - .cpu_arch = .x86_64, - .os_tag = .linux, -}; - -pub fn addCases(ctx: *TestContext) !void { - ctx.compileErrorZIR("call undefined local", linux_x64, - \\@noreturn = primitive(noreturn) - \\ - \\@start_fnty = fntype([], @noreturn, cc=Naked) - \\@start = fn(@start_fnty, { - \\ %0 = call(%test, []) - \\}) - // TODO: address inconsistency in this message and the one in the next test - , &[_][]const u8{":5:13: error: unrecognized identifier: %test"}); - - ctx.compileErrorZIR("call with non-existent target", linux_x64, - \\@noreturn = primitive(noreturn) - \\ - \\@start_fnty = fntype([], @noreturn, cc=Naked) - \\@start = fn(@start_fnty, { - \\ %0 = call(@notafunc, []) - \\}) - \\@0 = str("_start") - \\@1 = export(@0, "start") - , &[_][]const u8{":5:13: error: decl 'notafunc' not found"}); - - // TODO: this error should occur at the call site, not the fntype decl - ctx.compileErrorZIR("call naked function", linux_x64, - \\@noreturn = primitive(noreturn) - \\ - \\@start_fnty = fntype([], @noreturn, cc=Naked) - \\@s = fn(@start_fnty, {}) - \\@start = fn(@start_fnty, { - \\ %0 = call(@s, []) - \\}) - \\@0 = str("_start") - \\@1 = export(@0, "start") - , &[_][]const u8{":4:9: error: unable to call function with naked calling convention"}); - - ctx.incrementalFailureZIR("exported symbol collision", linux_x64, - \\@noreturn = primitive(noreturn) - \\ - \\@start_fnty = fntype([], @noreturn) - \\@start = fn(@start_fnty, {}) - \\ - \\@0 = str("_start") - \\@1 = export(@0, "start") - \\@2 = export(@0, "start") - , &[_][]const u8{":8:13: error: exported symbol collision: _start"}, - \\@noreturn = primitive(noreturn) - \\ - \\@start_fnty = fntype([], @noreturn) - \\@start = fn(@start_fnty, {}) - \\ - \\@0 = str("_start") - \\@1 = export(@0, "start") - ); -} diff --git a/test/stage2/test.zig b/test/stage2/test.zig index f5acc72f93..182bd116e0 100644 --- a/test/stage2/test.zig +++ b/test/stage2/test.zig @@ -1,7 +1,6 @@ const TestContext = @import("../../src-self-hosted/test.zig").TestContext; pub fn addCases(ctx: *TestContext) !void { - try @import("compile_errors.zig").addCases(ctx); try @import("compare_output.zig").addCases(ctx); try @import("zir.zig").addCases(ctx); try @import("cbe.zig").addCases(ctx); From 73d16d015e09c05aecba8a58881cbc429e8126fa Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 20 Aug 2020 17:25:09 -0700 Subject: [PATCH 56/66] stage2: reorganize tests The main test cases are now in `test/stage2/test.zig` which can then call addCases on other files if it wants to organize things differently. --- test/stage2/compare_output.zig | 723 --------------------------------- test/stage2/test.zig | 721 +++++++++++++++++++++++++++++++- 2 files changed, 720 insertions(+), 724 deletions(-) delete mode 100644 test/stage2/compare_output.zig diff --git a/test/stage2/compare_output.zig b/test/stage2/compare_output.zig deleted file mode 100644 index 3e08394b2e..0000000000 --- a/test/stage2/compare_output.zig +++ /dev/null @@ -1,723 +0,0 @@ -const std = @import("std"); -const TestContext = @import("../../src-self-hosted/test.zig").TestContext; -// self-hosted does not yet support PE executable files / COFF object files -// or mach-o files. So we do these test cases cross compiling for x86_64-linux. -const linux_x64 = std.zig.CrossTarget{ - .cpu_arch = .x86_64, - .os_tag = .linux, -}; - -const linux_riscv64 = std.zig.CrossTarget{ - .cpu_arch = .riscv64, - .os_tag = .linux, -}; - -const wasi = std.zig.CrossTarget{ - .cpu_arch = .wasm32, - .os_tag = .wasi, -}; - -pub fn addCases(ctx: *TestContext) !void { - { - var case = ctx.exe("hello world with updates", linux_x64); - - case.addError("", &[_][]const u8{":1:1: error: no entry point found"}); - - // Incorrect return type - case.addError( - \\export fn _start() noreturn { - \\} - , &[_][]const u8{":2:1: error: expected noreturn, found void"}); - - // Regular old hello world - case.addCompareOutput( - \\export fn _start() noreturn { - \\ print(); - \\ - \\ exit(); - \\} - \\ - \\fn print() void { - \\ asm volatile ("syscall" - \\ : - \\ : [number] "{rax}" (1), - \\ [arg1] "{rdi}" (1), - \\ [arg2] "{rsi}" (@ptrToInt("Hello, World!\n")), - \\ [arg3] "{rdx}" (14) - \\ : "rcx", "r11", "memory" - \\ ); - \\ return; - \\} - \\ - \\fn exit() noreturn { - \\ asm volatile ("syscall" - \\ : - \\ : [number] "{rax}" (231), - \\ [arg1] "{rdi}" (0) - \\ : "rcx", "r11", "memory" - \\ ); - \\ unreachable; - \\} - , - "Hello, World!\n", - ); - // Now change the message only - case.addCompareOutput( - \\export fn _start() noreturn { - \\ print(); - \\ - \\ exit(); - \\} - \\ - \\fn print() void { - \\ asm volatile ("syscall" - \\ : - \\ : [number] "{rax}" (1), - \\ [arg1] "{rdi}" (1), - \\ [arg2] "{rsi}" (@ptrToInt("What is up? This is a longer message that will force the data to be relocated in virtual address space.\n")), - \\ [arg3] "{rdx}" (104) - \\ : "rcx", "r11", "memory" - \\ ); - \\ return; - \\} - \\ - \\fn exit() noreturn { - \\ asm volatile ("syscall" - \\ : - \\ : [number] "{rax}" (231), - \\ [arg1] "{rdi}" (0) - \\ : "rcx", "r11", "memory" - \\ ); - \\ unreachable; - \\} - , - "What is up? This is a longer message that will force the data to be relocated in virtual address space.\n", - ); - // Now we print it twice. - case.addCompareOutput( - \\export fn _start() noreturn { - \\ print(); - \\ print(); - \\ - \\ exit(); - \\} - \\ - \\fn print() void { - \\ asm volatile ("syscall" - \\ : - \\ : [number] "{rax}" (1), - \\ [arg1] "{rdi}" (1), - \\ [arg2] "{rsi}" (@ptrToInt("What is up? This is a longer message that will force the data to be relocated in virtual address space.\n")), - \\ [arg3] "{rdx}" (104) - \\ : "rcx", "r11", "memory" - \\ ); - \\ return; - \\} - \\ - \\fn exit() noreturn { - \\ asm volatile ("syscall" - \\ : - \\ : [number] "{rax}" (231), - \\ [arg1] "{rdi}" (0) - \\ : "rcx", "r11", "memory" - \\ ); - \\ unreachable; - \\} - , - \\What is up? This is a longer message that will force the data to be relocated in virtual address space. - \\What is up? This is a longer message that will force the data to be relocated in virtual address space. - \\ - ); - } - - { - var case = ctx.exe("hello world", linux_riscv64); - // Regular old hello world - case.addCompareOutput( - \\export fn _start() noreturn { - \\ print(); - \\ - \\ exit(); - \\} - \\ - \\fn print() void { - \\ asm volatile ("ecall" - \\ : - \\ : [number] "{a7}" (64), - \\ [arg1] "{a0}" (1), - \\ [arg2] "{a1}" (@ptrToInt("Hello, World!\n")), - \\ [arg3] "{a2}" ("Hello, World!\n".len) - \\ : "rcx", "r11", "memory" - \\ ); - \\ return; - \\} - \\ - \\fn exit() noreturn { - \\ asm volatile ("ecall" - \\ : - \\ : [number] "{a7}" (94), - \\ [arg1] "{a0}" (0) - \\ : "rcx", "r11", "memory" - \\ ); - \\ unreachable; - \\} - , - "Hello, World!\n", - ); - } - - { - var case = ctx.exe("adding numbers at comptime", linux_x64); - case.addCompareOutput( - \\export fn _start() noreturn { - \\ asm volatile ("syscall" - \\ : - \\ : [number] "{rax}" (1), - \\ [arg1] "{rdi}" (1), - \\ [arg2] "{rsi}" (@ptrToInt("Hello, World!\n")), - \\ [arg3] "{rdx}" (10 + 4) - \\ : "rcx", "r11", "memory" - \\ ); - \\ asm volatile ("syscall" - \\ : - \\ : [number] "{rax}" (@as(usize, 230) + @as(usize, 1)), - \\ [arg1] "{rdi}" (0) - \\ : "rcx", "r11", "memory" - \\ ); - \\ unreachable; - \\} - , - "Hello, World!\n", - ); - } - - { - var case = ctx.exe("adding numbers at runtime", linux_x64); - case.addCompareOutput( - \\export fn _start() noreturn { - \\ add(3, 4); - \\ - \\ exit(); - \\} - \\ - \\fn add(a: u32, b: u32) void { - \\ if (a + b != 7) unreachable; - \\} - \\ - \\fn exit() noreturn { - \\ asm volatile ("syscall" - \\ : - \\ : [number] "{rax}" (231), - \\ [arg1] "{rdi}" (0) - \\ : "rcx", "r11", "memory" - \\ ); - \\ unreachable; - \\} - , - "", - ); - } - - { - var case = ctx.exe("substracting numbers at runtime", linux_x64); - case.addCompareOutput( - \\export fn _start() noreturn { - \\ sub(7, 4); - \\ - \\ exit(); - \\} - \\ - \\fn sub(a: u32, b: u32) void { - \\ if (a - b != 3) unreachable; - \\} - \\ - \\fn exit() noreturn { - \\ asm volatile ("syscall" - \\ : - \\ : [number] "{rax}" (231), - \\ [arg1] "{rdi}" (0) - \\ : "rcx", "r11", "memory" - \\ ); - \\ unreachable; - \\} - , - "", - ); - } - - { - var case = ctx.exe("assert function", linux_x64); - case.addCompareOutput( - \\export fn _start() noreturn { - \\ add(3, 4); - \\ - \\ exit(); - \\} - \\ - \\fn add(a: u32, b: u32) void { - \\ assert(a + b == 7); - \\} - \\ - \\pub fn assert(ok: bool) void { - \\ if (!ok) unreachable; // assertion failure - \\} - \\ - \\fn exit() noreturn { - \\ asm volatile ("syscall" - \\ : - \\ : [number] "{rax}" (231), - \\ [arg1] "{rdi}" (0) - \\ : "rcx", "r11", "memory" - \\ ); - \\ unreachable; - \\} - , - "", - ); - - // Tests copying a register. For the `c = a + b`, it has to - // preserve both a and b, because they are both used later. - case.addCompareOutput( - \\export fn _start() noreturn { - \\ add(3, 4); - \\ - \\ exit(); - \\} - \\ - \\fn add(a: u32, b: u32) void { - \\ const c = a + b; // 7 - \\ const d = a + c; // 10 - \\ const e = d + b; // 14 - \\ assert(e == 14); - \\} - \\ - \\pub fn assert(ok: bool) void { - \\ if (!ok) unreachable; // assertion failure - \\} - \\ - \\fn exit() noreturn { - \\ asm volatile ("syscall" - \\ : - \\ : [number] "{rax}" (231), - \\ [arg1] "{rdi}" (0) - \\ : "rcx", "r11", "memory" - \\ ); - \\ unreachable; - \\} - , - "", - ); - - // More stress on the liveness detection. - case.addCompareOutput( - \\export fn _start() noreturn { - \\ add(3, 4); - \\ - \\ exit(); - \\} - \\ - \\fn add(a: u32, b: u32) void { - \\ const c = a + b; // 7 - \\ const d = a + c; // 10 - \\ const e = d + b; // 14 - \\ const f = d + e; // 24 - \\ const g = e + f; // 38 - \\ const h = f + g; // 62 - \\ const i = g + h; // 100 - \\ assert(i == 100); - \\} - \\ - \\pub fn assert(ok: bool) void { - \\ if (!ok) unreachable; // assertion failure - \\} - \\ - \\fn exit() noreturn { - \\ asm volatile ("syscall" - \\ : - \\ : [number] "{rax}" (231), - \\ [arg1] "{rdi}" (0) - \\ : "rcx", "r11", "memory" - \\ ); - \\ unreachable; - \\} - , - "", - ); - - // Requires a second move. The register allocator should figure out to re-use rax. - case.addCompareOutput( - \\export fn _start() noreturn { - \\ add(3, 4); - \\ - \\ exit(); - \\} - \\ - \\fn add(a: u32, b: u32) void { - \\ const c = a + b; // 7 - \\ const d = a + c; // 10 - \\ const e = d + b; // 14 - \\ const f = d + e; // 24 - \\ const g = e + f; // 38 - \\ const h = f + g; // 62 - \\ const i = g + h; // 100 - \\ const j = i + d; // 110 - \\ assert(j == 110); - \\} - \\ - \\pub fn assert(ok: bool) void { - \\ if (!ok) unreachable; // assertion failure - \\} - \\ - \\fn exit() noreturn { - \\ asm volatile ("syscall" - \\ : - \\ : [number] "{rax}" (231), - \\ [arg1] "{rdi}" (0) - \\ : "rcx", "r11", "memory" - \\ ); - \\ unreachable; - \\} - , - "", - ); - - // Now we test integer return values. - case.addCompareOutput( - \\export fn _start() noreturn { - \\ assert(add(3, 4) == 7); - \\ assert(add(20, 10) == 30); - \\ - \\ exit(); - \\} - \\ - \\fn add(a: u32, b: u32) u32 { - \\ return a + b; - \\} - \\ - \\pub fn assert(ok: bool) void { - \\ if (!ok) unreachable; // assertion failure - \\} - \\ - \\fn exit() noreturn { - \\ asm volatile ("syscall" - \\ : - \\ : [number] "{rax}" (231), - \\ [arg1] "{rdi}" (0) - \\ : "rcx", "r11", "memory" - \\ ); - \\ unreachable; - \\} - , - "", - ); - - // Local mutable variables. - case.addCompareOutput( - \\export fn _start() noreturn { - \\ assert(add(3, 4) == 7); - \\ assert(add(20, 10) == 30); - \\ - \\ exit(); - \\} - \\ - \\fn add(a: u32, b: u32) u32 { - \\ var x: u32 = undefined; - \\ x = 0; - \\ x += a; - \\ x += b; - \\ return x; - \\} - \\ - \\pub fn assert(ok: bool) void { - \\ if (!ok) unreachable; // assertion failure - \\} - \\ - \\fn exit() noreturn { - \\ asm volatile ("syscall" - \\ : - \\ : [number] "{rax}" (231), - \\ [arg1] "{rdi}" (0) - \\ : "rcx", "r11", "memory" - \\ ); - \\ unreachable; - \\} - , - "", - ); - - // Optionals - case.addCompareOutput( - \\export fn _start() noreturn { - \\ const a: u32 = 2; - \\ const b: ?u32 = a; - \\ const c = b.?; - \\ if (c != 2) unreachable; - \\ - \\ exit(); - \\} - \\ - \\fn exit() noreturn { - \\ asm volatile ("syscall" - \\ : - \\ : [number] "{rax}" (231), - \\ [arg1] "{rdi}" (0) - \\ : "rcx", "r11", "memory" - \\ ); - \\ unreachable; - \\} - , - "", - ); - - // While loops - case.addCompareOutput( - \\export fn _start() noreturn { - \\ var i: u32 = 0; - \\ while (i < 4) : (i += 1) print(); - \\ assert(i == 4); - \\ - \\ exit(); - \\} - \\ - \\fn print() void { - \\ asm volatile ("syscall" - \\ : - \\ : [number] "{rax}" (1), - \\ [arg1] "{rdi}" (1), - \\ [arg2] "{rsi}" (@ptrToInt("hello\n")), - \\ [arg3] "{rdx}" (6) - \\ : "rcx", "r11", "memory" - \\ ); - \\ return; - \\} - \\ - \\pub fn assert(ok: bool) void { - \\ if (!ok) unreachable; // assertion failure - \\} - \\ - \\fn exit() noreturn { - \\ asm volatile ("syscall" - \\ : - \\ : [number] "{rax}" (231), - \\ [arg1] "{rdi}" (0) - \\ : "rcx", "r11", "memory" - \\ ); - \\ unreachable; - \\} - , - "hello\nhello\nhello\nhello\n", - ); - - // Labeled blocks (no conditional branch) - case.addCompareOutput( - \\export fn _start() noreturn { - \\ assert(add(3, 4) == 20); - \\ - \\ exit(); - \\} - \\ - \\fn add(a: u32, b: u32) u32 { - \\ const x: u32 = blk: { - \\ const c = a + b; // 7 - \\ const d = a + c; // 10 - \\ const e = d + b; // 14 - \\ break :blk e; - \\ }; - \\ const y = x + a; // 17 - \\ const z = y + a; // 20 - \\ return z; - \\} - \\ - \\pub fn assert(ok: bool) void { - \\ if (!ok) unreachable; // assertion failure - \\} - \\ - \\fn exit() noreturn { - \\ asm volatile ("syscall" - \\ : - \\ : [number] "{rax}" (231), - \\ [arg1] "{rdi}" (0) - \\ : "rcx", "r11", "memory" - \\ ); - \\ unreachable; - \\} - , - "", - ); - - // This catches a possible bug in the logic for re-using dying operands. - case.addCompareOutput( - \\export fn _start() noreturn { - \\ assert(add(3, 4) == 116); - \\ - \\ exit(); - \\} - \\ - \\fn add(a: u32, b: u32) u32 { - \\ const x: u32 = blk: { - \\ const c = a + b; // 7 - \\ const d = a + c; // 10 - \\ const e = d + b; // 14 - \\ const f = d + e; // 24 - \\ const g = e + f; // 38 - \\ const h = f + g; // 62 - \\ const i = g + h; // 100 - \\ const j = i + d; // 110 - \\ break :blk j; - \\ }; - \\ const y = x + a; // 113 - \\ const z = y + a; // 116 - \\ return z; - \\} - \\ - \\pub fn assert(ok: bool) void { - \\ if (!ok) unreachable; // assertion failure - \\} - \\ - \\fn exit() noreturn { - \\ asm volatile ("syscall" - \\ : - \\ : [number] "{rax}" (231), - \\ [arg1] "{rdi}" (0) - \\ : "rcx", "r11", "memory" - \\ ); - \\ unreachable; - \\} - , - "", - ); - - // Character literals and multiline strings. - case.addCompareOutput( - \\export fn _start() noreturn { - \\ const ignore = - \\ \\ cool thx - \\ \\ - \\ ; - \\ add('ぁ', '\x03'); - \\ - \\ exit(); - \\} - \\ - \\fn add(a: u32, b: u32) void { - \\ assert(a + b == 12356); - \\} - \\ - \\pub fn assert(ok: bool) void { - \\ if (!ok) unreachable; // assertion failure - \\} - \\ - \\fn exit() noreturn { - \\ asm volatile ("syscall" - \\ : - \\ : [number] "{rax}" (231), - \\ [arg1] "{rdi}" (0) - \\ : "rcx", "r11", "memory" - \\ ); - \\ unreachable; - \\} - , - "", - ); - - // Global const. - case.addCompareOutput( - \\export fn _start() noreturn { - \\ add(aa, bb); - \\ - \\ exit(); - \\} - \\ - \\const aa = 'ぁ'; - \\const bb = '\x03'; - \\ - \\fn add(a: u32, b: u32) void { - \\ assert(a + b == 12356); - \\} - \\ - \\pub fn assert(ok: bool) void { - \\ if (!ok) unreachable; // assertion failure - \\} - \\ - \\fn exit() noreturn { - \\ asm volatile ("syscall" - \\ : - \\ : [number] "{rax}" (231), - \\ [arg1] "{rdi}" (0) - \\ : "rcx", "r11", "memory" - \\ ); - \\ unreachable; - \\} - , - "", - ); - } - - { - var case = ctx.exe("wasm function calls", wasi); - - case.addCompareOutput( - \\export fn _start() u32 { - \\ foo(); - \\ bar(); - \\ return 42; - \\} - \\fn foo() void { - \\ bar(); - \\ bar(); - \\} - \\fn bar() void {} - , - "42\n", - ); - - case.addCompareOutput( - \\export fn _start() i64 { - \\ bar(); - \\ foo(); - \\ foo(); - \\ bar(); - \\ foo(); - \\ bar(); - \\ return 42; - \\} - \\fn foo() void { - \\ bar(); - \\} - \\fn bar() void {} - , - "42\n", - ); - - case.addCompareOutput( - \\export fn _start() f32 { - \\ bar(); - \\ foo(); - \\ return 42.0; - \\} - \\fn foo() void { - \\ bar(); - \\ bar(); - \\ bar(); - \\} - \\fn bar() void {} - , - // This is what you get when you take the bits of the IEE-754 - // representation of 42.0 and reinterpret them as an unsigned - // integer. Guess that's a bug in wasmtime. - "1109917696\n", - ); - } - - ctx.compileError("function redefinition", linux_x64, - \\fn entry() void {} - \\fn entry() void {} - , &[_][]const u8{":2:4: error: redefinition of 'entry'"}); - - ctx.compileError("extern variable has no type", linux_x64, - \\comptime { - \\ _ = foo; - \\} - \\extern var foo; - , &[_][]const u8{":4:1: error: unable to infer variable type"}); -} diff --git a/test/stage2/test.zig b/test/stage2/test.zig index 182bd116e0..91257526dd 100644 --- a/test/stage2/test.zig +++ b/test/stage2/test.zig @@ -1,7 +1,726 @@ +const std = @import("std"); const TestContext = @import("../../src-self-hosted/test.zig").TestContext; +// self-hosted does not yet support PE executable files / COFF object files +// or mach-o files. So we do these test cases cross compiling for x86_64-linux. +const linux_x64 = std.zig.CrossTarget{ + .cpu_arch = .x86_64, + .os_tag = .linux, +}; + +const linux_riscv64 = std.zig.CrossTarget{ + .cpu_arch = .riscv64, + .os_tag = .linux, +}; + +const wasi = std.zig.CrossTarget{ + .cpu_arch = .wasm32, + .os_tag = .wasi, +}; + pub fn addCases(ctx: *TestContext) !void { - try @import("compare_output.zig").addCases(ctx); try @import("zir.zig").addCases(ctx); try @import("cbe.zig").addCases(ctx); + { + var case = ctx.exe("hello world with updates", linux_x64); + + case.addError("", &[_][]const u8{":1:1: error: no entry point found"}); + + // Incorrect return type + case.addError( + \\export fn _start() noreturn { + \\} + , &[_][]const u8{":2:1: error: expected noreturn, found void"}); + + // Regular old hello world + case.addCompareOutput( + \\export fn _start() noreturn { + \\ print(); + \\ + \\ exit(); + \\} + \\ + \\fn print() void { + \\ asm volatile ("syscall" + \\ : + \\ : [number] "{rax}" (1), + \\ [arg1] "{rdi}" (1), + \\ [arg2] "{rsi}" (@ptrToInt("Hello, World!\n")), + \\ [arg3] "{rdx}" (14) + \\ : "rcx", "r11", "memory" + \\ ); + \\ return; + \\} + \\ + \\fn exit() noreturn { + \\ asm volatile ("syscall" + \\ : + \\ : [number] "{rax}" (231), + \\ [arg1] "{rdi}" (0) + \\ : "rcx", "r11", "memory" + \\ ); + \\ unreachable; + \\} + , + "Hello, World!\n", + ); + // Now change the message only + case.addCompareOutput( + \\export fn _start() noreturn { + \\ print(); + \\ + \\ exit(); + \\} + \\ + \\fn print() void { + \\ asm volatile ("syscall" + \\ : + \\ : [number] "{rax}" (1), + \\ [arg1] "{rdi}" (1), + \\ [arg2] "{rsi}" (@ptrToInt("What is up? This is a longer message that will force the data to be relocated in virtual address space.\n")), + \\ [arg3] "{rdx}" (104) + \\ : "rcx", "r11", "memory" + \\ ); + \\ return; + \\} + \\ + \\fn exit() noreturn { + \\ asm volatile ("syscall" + \\ : + \\ : [number] "{rax}" (231), + \\ [arg1] "{rdi}" (0) + \\ : "rcx", "r11", "memory" + \\ ); + \\ unreachable; + \\} + , + "What is up? This is a longer message that will force the data to be relocated in virtual address space.\n", + ); + // Now we print it twice. + case.addCompareOutput( + \\export fn _start() noreturn { + \\ print(); + \\ print(); + \\ + \\ exit(); + \\} + \\ + \\fn print() void { + \\ asm volatile ("syscall" + \\ : + \\ : [number] "{rax}" (1), + \\ [arg1] "{rdi}" (1), + \\ [arg2] "{rsi}" (@ptrToInt("What is up? This is a longer message that will force the data to be relocated in virtual address space.\n")), + \\ [arg3] "{rdx}" (104) + \\ : "rcx", "r11", "memory" + \\ ); + \\ return; + \\} + \\ + \\fn exit() noreturn { + \\ asm volatile ("syscall" + \\ : + \\ : [number] "{rax}" (231), + \\ [arg1] "{rdi}" (0) + \\ : "rcx", "r11", "memory" + \\ ); + \\ unreachable; + \\} + , + \\What is up? This is a longer message that will force the data to be relocated in virtual address space. + \\What is up? This is a longer message that will force the data to be relocated in virtual address space. + \\ + ); + } + + { + var case = ctx.exe("hello world", linux_riscv64); + // Regular old hello world + case.addCompareOutput( + \\export fn _start() noreturn { + \\ print(); + \\ + \\ exit(); + \\} + \\ + \\fn print() void { + \\ asm volatile ("ecall" + \\ : + \\ : [number] "{a7}" (64), + \\ [arg1] "{a0}" (1), + \\ [arg2] "{a1}" (@ptrToInt("Hello, World!\n")), + \\ [arg3] "{a2}" ("Hello, World!\n".len) + \\ : "rcx", "r11", "memory" + \\ ); + \\ return; + \\} + \\ + \\fn exit() noreturn { + \\ asm volatile ("ecall" + \\ : + \\ : [number] "{a7}" (94), + \\ [arg1] "{a0}" (0) + \\ : "rcx", "r11", "memory" + \\ ); + \\ unreachable; + \\} + , + "Hello, World!\n", + ); + } + + { + var case = ctx.exe("adding numbers at comptime", linux_x64); + case.addCompareOutput( + \\export fn _start() noreturn { + \\ asm volatile ("syscall" + \\ : + \\ : [number] "{rax}" (1), + \\ [arg1] "{rdi}" (1), + \\ [arg2] "{rsi}" (@ptrToInt("Hello, World!\n")), + \\ [arg3] "{rdx}" (10 + 4) + \\ : "rcx", "r11", "memory" + \\ ); + \\ asm volatile ("syscall" + \\ : + \\ : [number] "{rax}" (@as(usize, 230) + @as(usize, 1)), + \\ [arg1] "{rdi}" (0) + \\ : "rcx", "r11", "memory" + \\ ); + \\ unreachable; + \\} + , + "Hello, World!\n", + ); + } + + { + var case = ctx.exe("adding numbers at runtime", linux_x64); + case.addCompareOutput( + \\export fn _start() noreturn { + \\ add(3, 4); + \\ + \\ exit(); + \\} + \\ + \\fn add(a: u32, b: u32) void { + \\ if (a + b != 7) unreachable; + \\} + \\ + \\fn exit() noreturn { + \\ asm volatile ("syscall" + \\ : + \\ : [number] "{rax}" (231), + \\ [arg1] "{rdi}" (0) + \\ : "rcx", "r11", "memory" + \\ ); + \\ unreachable; + \\} + , + "", + ); + } + + { + var case = ctx.exe("substracting numbers at runtime", linux_x64); + case.addCompareOutput( + \\export fn _start() noreturn { + \\ sub(7, 4); + \\ + \\ exit(); + \\} + \\ + \\fn sub(a: u32, b: u32) void { + \\ if (a - b != 3) unreachable; + \\} + \\ + \\fn exit() noreturn { + \\ asm volatile ("syscall" + \\ : + \\ : [number] "{rax}" (231), + \\ [arg1] "{rdi}" (0) + \\ : "rcx", "r11", "memory" + \\ ); + \\ unreachable; + \\} + , + "", + ); + } + + { + var case = ctx.exe("assert function", linux_x64); + case.addCompareOutput( + \\export fn _start() noreturn { + \\ add(3, 4); + \\ + \\ exit(); + \\} + \\ + \\fn add(a: u32, b: u32) void { + \\ assert(a + b == 7); + \\} + \\ + \\pub fn assert(ok: bool) void { + \\ if (!ok) unreachable; // assertion failure + \\} + \\ + \\fn exit() noreturn { + \\ asm volatile ("syscall" + \\ : + \\ : [number] "{rax}" (231), + \\ [arg1] "{rdi}" (0) + \\ : "rcx", "r11", "memory" + \\ ); + \\ unreachable; + \\} + , + "", + ); + + // Tests copying a register. For the `c = a + b`, it has to + // preserve both a and b, because they are both used later. + case.addCompareOutput( + \\export fn _start() noreturn { + \\ add(3, 4); + \\ + \\ exit(); + \\} + \\ + \\fn add(a: u32, b: u32) void { + \\ const c = a + b; // 7 + \\ const d = a + c; // 10 + \\ const e = d + b; // 14 + \\ assert(e == 14); + \\} + \\ + \\pub fn assert(ok: bool) void { + \\ if (!ok) unreachable; // assertion failure + \\} + \\ + \\fn exit() noreturn { + \\ asm volatile ("syscall" + \\ : + \\ : [number] "{rax}" (231), + \\ [arg1] "{rdi}" (0) + \\ : "rcx", "r11", "memory" + \\ ); + \\ unreachable; + \\} + , + "", + ); + + // More stress on the liveness detection. + case.addCompareOutput( + \\export fn _start() noreturn { + \\ add(3, 4); + \\ + \\ exit(); + \\} + \\ + \\fn add(a: u32, b: u32) void { + \\ const c = a + b; // 7 + \\ const d = a + c; // 10 + \\ const e = d + b; // 14 + \\ const f = d + e; // 24 + \\ const g = e + f; // 38 + \\ const h = f + g; // 62 + \\ const i = g + h; // 100 + \\ assert(i == 100); + \\} + \\ + \\pub fn assert(ok: bool) void { + \\ if (!ok) unreachable; // assertion failure + \\} + \\ + \\fn exit() noreturn { + \\ asm volatile ("syscall" + \\ : + \\ : [number] "{rax}" (231), + \\ [arg1] "{rdi}" (0) + \\ : "rcx", "r11", "memory" + \\ ); + \\ unreachable; + \\} + , + "", + ); + + // Requires a second move. The register allocator should figure out to re-use rax. + case.addCompareOutput( + \\export fn _start() noreturn { + \\ add(3, 4); + \\ + \\ exit(); + \\} + \\ + \\fn add(a: u32, b: u32) void { + \\ const c = a + b; // 7 + \\ const d = a + c; // 10 + \\ const e = d + b; // 14 + \\ const f = d + e; // 24 + \\ const g = e + f; // 38 + \\ const h = f + g; // 62 + \\ const i = g + h; // 100 + \\ const j = i + d; // 110 + \\ assert(j == 110); + \\} + \\ + \\pub fn assert(ok: bool) void { + \\ if (!ok) unreachable; // assertion failure + \\} + \\ + \\fn exit() noreturn { + \\ asm volatile ("syscall" + \\ : + \\ : [number] "{rax}" (231), + \\ [arg1] "{rdi}" (0) + \\ : "rcx", "r11", "memory" + \\ ); + \\ unreachable; + \\} + , + "", + ); + + // Now we test integer return values. + case.addCompareOutput( + \\export fn _start() noreturn { + \\ assert(add(3, 4) == 7); + \\ assert(add(20, 10) == 30); + \\ + \\ exit(); + \\} + \\ + \\fn add(a: u32, b: u32) u32 { + \\ return a + b; + \\} + \\ + \\pub fn assert(ok: bool) void { + \\ if (!ok) unreachable; // assertion failure + \\} + \\ + \\fn exit() noreturn { + \\ asm volatile ("syscall" + \\ : + \\ : [number] "{rax}" (231), + \\ [arg1] "{rdi}" (0) + \\ : "rcx", "r11", "memory" + \\ ); + \\ unreachable; + \\} + , + "", + ); + + // Local mutable variables. + case.addCompareOutput( + \\export fn _start() noreturn { + \\ assert(add(3, 4) == 7); + \\ assert(add(20, 10) == 30); + \\ + \\ exit(); + \\} + \\ + \\fn add(a: u32, b: u32) u32 { + \\ var x: u32 = undefined; + \\ x = 0; + \\ x += a; + \\ x += b; + \\ return x; + \\} + \\ + \\pub fn assert(ok: bool) void { + \\ if (!ok) unreachable; // assertion failure + \\} + \\ + \\fn exit() noreturn { + \\ asm volatile ("syscall" + \\ : + \\ : [number] "{rax}" (231), + \\ [arg1] "{rdi}" (0) + \\ : "rcx", "r11", "memory" + \\ ); + \\ unreachable; + \\} + , + "", + ); + + // Optionals + case.addCompareOutput( + \\export fn _start() noreturn { + \\ const a: u32 = 2; + \\ const b: ?u32 = a; + \\ const c = b.?; + \\ if (c != 2) unreachable; + \\ + \\ exit(); + \\} + \\ + \\fn exit() noreturn { + \\ asm volatile ("syscall" + \\ : + \\ : [number] "{rax}" (231), + \\ [arg1] "{rdi}" (0) + \\ : "rcx", "r11", "memory" + \\ ); + \\ unreachable; + \\} + , + "", + ); + + // While loops + case.addCompareOutput( + \\export fn _start() noreturn { + \\ var i: u32 = 0; + \\ while (i < 4) : (i += 1) print(); + \\ assert(i == 4); + \\ + \\ exit(); + \\} + \\ + \\fn print() void { + \\ asm volatile ("syscall" + \\ : + \\ : [number] "{rax}" (1), + \\ [arg1] "{rdi}" (1), + \\ [arg2] "{rsi}" (@ptrToInt("hello\n")), + \\ [arg3] "{rdx}" (6) + \\ : "rcx", "r11", "memory" + \\ ); + \\ return; + \\} + \\ + \\pub fn assert(ok: bool) void { + \\ if (!ok) unreachable; // assertion failure + \\} + \\ + \\fn exit() noreturn { + \\ asm volatile ("syscall" + \\ : + \\ : [number] "{rax}" (231), + \\ [arg1] "{rdi}" (0) + \\ : "rcx", "r11", "memory" + \\ ); + \\ unreachable; + \\} + , + "hello\nhello\nhello\nhello\n", + ); + + // Labeled blocks (no conditional branch) + case.addCompareOutput( + \\export fn _start() noreturn { + \\ assert(add(3, 4) == 20); + \\ + \\ exit(); + \\} + \\ + \\fn add(a: u32, b: u32) u32 { + \\ const x: u32 = blk: { + \\ const c = a + b; // 7 + \\ const d = a + c; // 10 + \\ const e = d + b; // 14 + \\ break :blk e; + \\ }; + \\ const y = x + a; // 17 + \\ const z = y + a; // 20 + \\ return z; + \\} + \\ + \\pub fn assert(ok: bool) void { + \\ if (!ok) unreachable; // assertion failure + \\} + \\ + \\fn exit() noreturn { + \\ asm volatile ("syscall" + \\ : + \\ : [number] "{rax}" (231), + \\ [arg1] "{rdi}" (0) + \\ : "rcx", "r11", "memory" + \\ ); + \\ unreachable; + \\} + , + "", + ); + + // This catches a possible bug in the logic for re-using dying operands. + case.addCompareOutput( + \\export fn _start() noreturn { + \\ assert(add(3, 4) == 116); + \\ + \\ exit(); + \\} + \\ + \\fn add(a: u32, b: u32) u32 { + \\ const x: u32 = blk: { + \\ const c = a + b; // 7 + \\ const d = a + c; // 10 + \\ const e = d + b; // 14 + \\ const f = d + e; // 24 + \\ const g = e + f; // 38 + \\ const h = f + g; // 62 + \\ const i = g + h; // 100 + \\ const j = i + d; // 110 + \\ break :blk j; + \\ }; + \\ const y = x + a; // 113 + \\ const z = y + a; // 116 + \\ return z; + \\} + \\ + \\pub fn assert(ok: bool) void { + \\ if (!ok) unreachable; // assertion failure + \\} + \\ + \\fn exit() noreturn { + \\ asm volatile ("syscall" + \\ : + \\ : [number] "{rax}" (231), + \\ [arg1] "{rdi}" (0) + \\ : "rcx", "r11", "memory" + \\ ); + \\ unreachable; + \\} + , + "", + ); + + // Character literals and multiline strings. + case.addCompareOutput( + \\export fn _start() noreturn { + \\ const ignore = + \\ \\ cool thx + \\ \\ + \\ ; + \\ add('ぁ', '\x03'); + \\ + \\ exit(); + \\} + \\ + \\fn add(a: u32, b: u32) void { + \\ assert(a + b == 12356); + \\} + \\ + \\pub fn assert(ok: bool) void { + \\ if (!ok) unreachable; // assertion failure + \\} + \\ + \\fn exit() noreturn { + \\ asm volatile ("syscall" + \\ : + \\ : [number] "{rax}" (231), + \\ [arg1] "{rdi}" (0) + \\ : "rcx", "r11", "memory" + \\ ); + \\ unreachable; + \\} + , + "", + ); + + // Global const. + case.addCompareOutput( + \\export fn _start() noreturn { + \\ add(aa, bb); + \\ + \\ exit(); + \\} + \\ + \\const aa = 'ぁ'; + \\const bb = '\x03'; + \\ + \\fn add(a: u32, b: u32) void { + \\ assert(a + b == 12356); + \\} + \\ + \\pub fn assert(ok: bool) void { + \\ if (!ok) unreachable; // assertion failure + \\} + \\ + \\fn exit() noreturn { + \\ asm volatile ("syscall" + \\ : + \\ : [number] "{rax}" (231), + \\ [arg1] "{rdi}" (0) + \\ : "rcx", "r11", "memory" + \\ ); + \\ unreachable; + \\} + , + "", + ); + } + + { + var case = ctx.exe("wasm function calls", wasi); + + case.addCompareOutput( + \\export fn _start() u32 { + \\ foo(); + \\ bar(); + \\ return 42; + \\} + \\fn foo() void { + \\ bar(); + \\ bar(); + \\} + \\fn bar() void {} + , + "42\n", + ); + + case.addCompareOutput( + \\export fn _start() i64 { + \\ bar(); + \\ foo(); + \\ foo(); + \\ bar(); + \\ foo(); + \\ bar(); + \\ return 42; + \\} + \\fn foo() void { + \\ bar(); + \\} + \\fn bar() void {} + , + "42\n", + ); + + case.addCompareOutput( + \\export fn _start() f32 { + \\ bar(); + \\ foo(); + \\ return 42.0; + \\} + \\fn foo() void { + \\ bar(); + \\ bar(); + \\ bar(); + \\} + \\fn bar() void {} + , + // This is what you get when you take the bits of the IEE-754 + // representation of 42.0 and reinterpret them as an unsigned + // integer. Guess that's a bug in wasmtime. + "1109917696\n", + ); + } + + ctx.compileError("function redefinition", linux_x64, + \\fn entry() void {} + \\fn entry() void {} + , &[_][]const u8{":2:4: error: redefinition of 'entry'"}); + + ctx.compileError("extern variable has no type", linux_x64, + \\comptime { + \\ _ = foo; + \\} + \\extern var foo; + , &[_][]const u8{":4:1: error: unable to infer variable type"}); } From e0a38f7f3e2b3dc272cd9ab4f826315590664779 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 20 Aug 2020 23:53:34 -0700 Subject: [PATCH 57/66] stage2: make the cache dir if it doesn't already exist --- src-self-hosted/introspect.zig | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src-self-hosted/introspect.zig b/src-self-hosted/introspect.zig index 8e99c93c60..80f10c8656 100644 --- a/src-self-hosted/introspect.zig +++ b/src-self-hosted/introspect.zig @@ -87,6 +87,13 @@ pub fn resolveGlobalCacheDir(allocator: *mem.Allocator) ![]u8 { return fs.getAppDataDir(allocator, appname); } +pub fn openGlobalCacheDir() !fs.Dir { + var buf: [fs.MAX_PATH_BYTES]u8 = undefined; + var fba = std.heap.FixedBufferAllocator.init(&buf); + const path_name = try resolveGlobalCacheDir(&fba.allocator); + return fs.cwd().makeOpenPath(path_name, .{}); +} + var compiler_id_mutex = std.Mutex{}; var compiler_id: [16]u8 = undefined; var compiler_id_computed = false; @@ -99,11 +106,7 @@ pub fn resolveCompilerId(gpa: *mem.Allocator) ![16]u8 { return compiler_id; compiler_id_computed = true; - const global_cache_dir = try resolveGlobalCacheDir(gpa); - defer gpa.free(global_cache_dir); - - // TODO Introduce openGlobalCacheDir which returns a dir handle rather than a string. - var cache_dir = try fs.cwd().openDir(global_cache_dir, .{}); + var cache_dir = try openGlobalCacheDir(); defer cache_dir.close(); var ch = try CacheHash.init(gpa, cache_dir, "exe"); From 243b5c7a889a3cbc86b5b0720b9ed1cdc6c29835 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Thu, 20 Aug 2020 17:25:39 +0200 Subject: [PATCH 58/66] Add macosx end-to-end smoke test This test case will grow as the linker gets more functionality. Signed-off-by: Jakub Konka --- test/stage2/test.zig | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/stage2/test.zig b/test/stage2/test.zig index 91257526dd..11b1713181 100644 --- a/test/stage2/test.zig +++ b/test/stage2/test.zig @@ -8,6 +8,11 @@ const linux_x64 = std.zig.CrossTarget{ .os_tag = .linux, }; +const macosx_x64 = std.zig.CrossTarget{ + .cpu_arch = .x86_64, + .os_tag = .macosx, +}; + const linux_riscv64 = std.zig.CrossTarget{ .cpu_arch = .riscv64, .os_tag = .linux, @@ -133,6 +138,11 @@ pub fn addCases(ctx: *TestContext) !void { ); } + { + var case = ctx.exe("hello world", macosx_x64); + case.addError("", &[_][]const u8{":1:1: error: no entry point found"}); + } + { var case = ctx.exe("hello world", linux_riscv64); // Regular old hello world From c9218f17197a0d778d9c89787ee0807dc0d00a91 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Fri, 21 Aug 2020 13:56:11 +0200 Subject: [PATCH 59/66] Make poly1305 faster --- lib/std/crypto/poly1305.zig | 375 +++++++++++++++++------------------- 1 file changed, 172 insertions(+), 203 deletions(-) diff --git a/lib/std/crypto/poly1305.zig b/lib/std/crypto/poly1305.zig index 2ed97f4c2e..7f2966f991 100644 --- a/lib/std/crypto/poly1305.zig +++ b/lib/std/crypto/poly1305.zig @@ -3,224 +3,193 @@ // This file is part of [zig](https://ziglang.org/), which is MIT licensed. // The MIT license requires this copyright notice to be included in all copies // and substantial portions of the software. -// Translated from monocypher which is licensed under CC-0/BSD-3. -// -// https://monocypher.org/ - -const std = @import("../std.zig"); -const builtin = std.builtin; - -const Endian = builtin.Endian; -const readIntLittle = std.mem.readIntLittle; -const writeIntLittle = std.mem.writeIntLittle; +const std = @import("std"); +const mem = std.mem; pub const Poly1305 = struct { - const Self = @This(); - + pub const block_size: usize = 16; pub const mac_length = 16; pub const minimum_key_length = 32; // constant multiplier (from the secret key) - r: [4]u32, + r: [3]u64, // accumulated hash - h: [5]u32, - // chunk of the message - c: [5]u32, + h: [3]u64 = [_]u64{ 0, 0, 0 }, // random number added at the end (from the secret key) - pad: [4]u32, - // How many bytes are there in the chunk. - c_idx: usize, + pad: [2]u64, + // how many bytes are waiting to be processed in a partial block + leftover: usize = 0, + // partial block buffer + buf: [block_size]u8 align(16) = undefined, - fn secureZero(self: *Self) void { - std.mem.secureZero(u8, @ptrCast([*]u8, self)[0..@sizeOf(Poly1305)]); + pub fn init(key: []const u8) Poly1305 { + std.debug.assert(key.len >= minimum_key_length); + const t0 = mem.readIntLittle(u64, key[0..8]); + const t1 = mem.readIntLittle(u64, key[8..16]); + return Poly1305{ + .r = [_]u64{ + t0 & 0xffc0fffffff, + ((t0 >> 44) | (t1 << 20)) & 0xfffffc0ffff, + ((t1 >> 24)) & 0x00ffffffc0f, + }, + .pad = [_]u64{ + mem.readIntLittle(u64, key[16..24]), + mem.readIntLittle(u64, key[24..32]), + }, + }; + } + + fn blocks(st: *Poly1305, m: []const u8, last: comptime bool) void { + const hibit: u64 = if (last) 0 else 1 << 40; + const r0 = st.r[0]; + const r1 = st.r[1]; + const r2 = st.r[2]; + const s1 = r1 * (5 << 2); + const s2 = r2 * (5 << 2); + var i: usize = 0; + while (i + block_size <= m.len) : (i += block_size) { + // h += m[i] + const t0 = mem.readIntLittle(u64, m[i..][0..8]); + const t1 = mem.readIntLittle(u64, m[i + 8 ..][0..8]); + st.h[0] += t0 & 0xfffffffffff; + st.h[1] += ((t0 >> 44) | (t1 << 20)) & 0xfffffffffff; + st.h[2] += (((t1 >> 24)) & 0x3ffffffffff) | hibit; + + // h *= r + const d0 = @as(u128, st.h[0]) * @as(u128, r0) + @as(u128, st.h[1]) * @as(u128, s2) + @as(u128, st.h[2]) * @as(u128, s1); + var d1 = @as(u128, st.h[0]) * @as(u128, r1) + @as(u128, st.h[1]) * @as(u128, r0) + @as(u128, st.h[2]) * @as(u128, s2); + var d2 = @as(u128, st.h[0]) * @as(u128, r2) + @as(u128, st.h[1]) * @as(u128, r1) + @as(u128, st.h[2]) * @as(u128, r0); + + // partial reduction + var carry = d0 >> 44; + st.h[0] = @truncate(u64, d0) & 0xfffffffffff; + d1 += carry; + carry = @intCast(u64, d1 >> 44); + st.h[1] = @truncate(u64, d1) & 0xfffffffffff; + d2 += carry; + carry = @intCast(u64, d2 >> 42); + st.h[2] = @truncate(u64, d2) & 0x3ffffffffff; + st.h[0] += @truncate(u64, carry) * 5; + carry = st.h[0] >> 44; + st.h[0] &= 0xfffffffffff; + st.h[1] += @truncate(u64, carry); + } + } + + pub fn update(st: *Poly1305, m: []const u8) void { + var mb = m; + + // handle leftover + if (st.leftover > 0) { + const want = std.math.min(block_size - st.leftover, mb.len); + const mc = mb[0..want]; + for (mc) |x, i| { + st.buf[st.leftover + i] = x; + } + mb = mb[want..]; + st.leftover += want; + if (st.leftover > block_size) { + return; + } + st.blocks(&st.buf, false); + st.leftover = 0; + } + + // process full blocks + if (mb.len >= block_size) { + const want = mb.len & ~(block_size - 1); + st.blocks(mb[0..want], false); + mb = mb[want..]; + } + + // store leftover + if (mb.len > 0) { + for (mb) |x, i| { + st.buf[st.leftover + i] = x; + } + st.leftover += mb.len; + } + } + + pub fn final(st: *Poly1305, out: []u8) void { + std.debug.assert(out.len >= mac_length); + if (st.leftover > 0) { + var i = st.leftover; + st.buf[i] = 1; + i += 1; + while (i < block_size) : (i += 1) { + st.buf[i] = 0; + } + st.blocks(&st.buf, true); + } + // fully carry h + var carry = st.h[1] >> 44; + st.h[1] &= 0xfffffffffff; + st.h[2] += carry; + carry = st.h[2] >> 42; + st.h[2] &= 0x3ffffffffff; + st.h[0] += carry * 5; + carry = st.h[0] >> 44; + st.h[0] &= 0xfffffffffff; + st.h[1] += carry; + carry = st.h[1] >> 44; + st.h[1] &= 0xfffffffffff; + st.h[2] += carry; + carry = st.h[2] >> 42; + st.h[2] &= 0x3ffffffffff; + st.h[0] += carry * 5; + carry = st.h[0] >> 44; + st.h[0] &= 0xfffffffffff; + st.h[1] += carry; + + // compute h + -p + var g0 = st.h[0] + 5; + carry = g0 >> 44; + g0 &= 0xfffffffffff; + var g1 = st.h[1] + carry; + carry = g1 >> 44; + g1 &= 0xfffffffffff; + var g2 = st.h[2] + carry -% (1 << 42); + + // (hopefully) constant-time select h if h < p, or h + -p if h >= p + const mask = (g2 >> 63) -% 1; + g0 &= mask; + g1 &= mask; + g2 &= mask; + const nmask = ~mask; + st.h[0] = (st.h[0] & nmask) | g0; + st.h[1] = (st.h[1] & nmask) | g1; + st.h[2] = (st.h[2] & nmask) | g2; + + // h = (h + pad) + const t0 = st.pad[0]; + const t1 = st.pad[1]; + st.h[0] += (t0 & 0xfffffffffff); + carry = (st.h[0] >> 44); + st.h[0] &= 0xfffffffffff; + st.h[1] += (((t0 >> 44) | (t1 << 20)) & 0xfffffffffff) + carry; + carry = (st.h[1] >> 44); + st.h[1] &= 0xfffffffffff; + st.h[2] += (((t1 >> 24)) & 0x3ffffffffff) + carry; + st.h[2] &= 0x3ffffffffff; + + // mac = h % (2^128) + st.h[0] |= st.h[1] << 44; + st.h[1] = (st.h[1] >> 20) | (st.h[2] << 24); + + mem.writeIntLittle(u64, out[0..8], st.h[0]); + mem.writeIntLittle(u64, out[8..16], st.h[1]); + + mem.secureZero(u64, &st.r); } pub fn create(out: []u8, msg: []const u8, key: []const u8) void { std.debug.assert(out.len >= mac_length); std.debug.assert(key.len >= minimum_key_length); - var ctx = Poly1305.init(key); - ctx.update(msg); - ctx.final(out); - } - - // Initialize the MAC context. - // - key.len is sufficient size. - pub fn init(key: []const u8) Self { - var ctx: Poly1305 = undefined; - - // Initial hash is zero - { - var i: usize = 0; - while (i < 5) : (i += 1) { - ctx.h[i] = 0; - } - } - // add 2^130 to every input block - ctx.c[4] = 1; - polyClearC(&ctx); - - // load r and pad (r has some of its bits cleared) - { - var i: usize = 0; - while (i < 1) : (i += 1) { - ctx.r[0] = readIntLittle(u32, key[0..4]) & 0x0fffffff; - } - } - { - var i: usize = 1; - while (i < 4) : (i += 1) { - ctx.r[i] = readIntLittle(u32, key[i * 4 ..][0..4]) & 0x0ffffffc; - } - } - { - var i: usize = 0; - while (i < 4) : (i += 1) { - ctx.pad[i] = readIntLittle(u32, key[i * 4 + 16 ..][0..4]); - } - } - - return ctx; - } - - // h = (h + c) * r - // preconditions: - // ctx->h <= 4_ffffffff_ffffffff_ffffffff_ffffffff - // ctx->c <= 1_ffffffff_ffffffff_ffffffff_ffffffff - // ctx->r <= 0ffffffc_0ffffffc_0ffffffc_0fffffff - // Postcondition: - // ctx->h <= 4_ffffffff_ffffffff_ffffffff_ffffffff - fn polyBlock(ctx: *Self) void { - // s = h + c, without carry propagation - const s0 = @as(u64, ctx.h[0]) + ctx.c[0]; // s0 <= 1_fffffffe - const s1 = @as(u64, ctx.h[1]) + ctx.c[1]; // s1 <= 1_fffffffe - const s2 = @as(u64, ctx.h[2]) + ctx.c[2]; // s2 <= 1_fffffffe - const s3 = @as(u64, ctx.h[3]) + ctx.c[3]; // s3 <= 1_fffffffe - const s4 = @as(u64, ctx.h[4]) + ctx.c[4]; // s4 <= 5 - - // Local all the things! - const r0 = ctx.r[0]; // r0 <= 0fffffff - const r1 = ctx.r[1]; // r1 <= 0ffffffc - const r2 = ctx.r[2]; // r2 <= 0ffffffc - const r3 = ctx.r[3]; // r3 <= 0ffffffc - const rr0 = (r0 >> 2) * 5; // rr0 <= 13fffffb // lose 2 bits... - const rr1 = (r1 >> 2) + r1; // rr1 <= 13fffffb // rr1 == (r1 >> 2) * 5 - const rr2 = (r2 >> 2) + r2; // rr2 <= 13fffffb // rr1 == (r2 >> 2) * 5 - const rr3 = (r3 >> 2) + r3; // rr3 <= 13fffffb // rr1 == (r3 >> 2) * 5 - - // (h + c) * r, without carry propagation - const x0 = s0 * r0 + s1 * rr3 + s2 * rr2 + s3 * rr1 + s4 * rr0; //<=97ffffe007fffff8 - const x1 = s0 * r1 + s1 * r0 + s2 * rr3 + s3 * rr2 + s4 * rr1; //<=8fffffe20ffffff6 - const x2 = s0 * r2 + s1 * r1 + s2 * r0 + s3 * rr3 + s4 * rr2; //<=87ffffe417fffff4 - const x3 = s0 * r3 + s1 * r2 + s2 * r1 + s3 * r0 + s4 * rr3; //<=7fffffe61ffffff2 - const x4 = s4 * (r0 & 3); // ...recover 2 bits //<= f - - // partial reduction modulo 2^130 - 5 - const _u5 = @truncate(u32, x4 + (x3 >> 32)); // u5 <= 7ffffff5 - const _u0 = (_u5 >> 2) * 5 + (x0 & 0xffffffff); - const _u1 = (_u0 >> 32) + (x1 & 0xffffffff) + (x0 >> 32); - const _u2 = (_u1 >> 32) + (x2 & 0xffffffff) + (x1 >> 32); - const _u3 = (_u2 >> 32) + (x3 & 0xffffffff) + (x2 >> 32); - const _u4 = (_u3 >> 32) + (_u5 & 3); - - // Update the hash - ctx.h[0] = @truncate(u32, _u0); // u0 <= 1_9ffffff0 - ctx.h[1] = @truncate(u32, _u1); // u1 <= 1_97ffffe0 - ctx.h[2] = @truncate(u32, _u2); // u2 <= 1_8fffffe2 - ctx.h[3] = @truncate(u32, _u3); // u3 <= 1_87ffffe4 - ctx.h[4] = @truncate(u32, _u4); // u4 <= 4 - } - - // (re-)initializes the input counter and input buffer - fn polyClearC(ctx: *Self) void { - ctx.c[0] = 0; - ctx.c[1] = 0; - ctx.c[2] = 0; - ctx.c[3] = 0; - ctx.c_idx = 0; - } - - fn polyTakeInput(ctx: *Self, input: u8) void { - const word = ctx.c_idx >> 2; - const byte = ctx.c_idx & 3; - ctx.c[word] |= std.math.shl(u32, input, byte * 8); - ctx.c_idx += 1; - } - - fn polyUpdate(ctx: *Self, msg: []const u8) void { - for (msg) |b| { - polyTakeInput(ctx, b); - if (ctx.c_idx == 16) { - polyBlock(ctx); - polyClearC(ctx); - } - } - } - - fn alignTo(x: usize, block_size: usize) usize { - return ((~x) +% 1) & (block_size - 1); - } - - // Feed data into the MAC context. - pub fn update(ctx: *Self, msg: []const u8) void { - // Align ourselves with block boundaries - const alignm = std.math.min(alignTo(ctx.c_idx, 16), msg.len); - polyUpdate(ctx, msg[0..alignm]); - - var nmsg = msg[alignm..]; - - // Process the msg block by block - const nb_blocks = nmsg.len >> 4; - var i: usize = 0; - while (i < nb_blocks) : (i += 1) { - ctx.c[0] = readIntLittle(u32, nmsg[0..4]); - ctx.c[1] = readIntLittle(u32, nmsg[4..8]); - ctx.c[2] = readIntLittle(u32, nmsg[8..12]); - ctx.c[3] = readIntLittle(u32, nmsg[12..16]); - polyBlock(ctx); - nmsg = nmsg[16..]; - } - if (nb_blocks > 0) { - polyClearC(ctx); - } - - // remaining bytes - polyUpdate(ctx, nmsg[0..]); - } - - // Finalize the MAC and output into buffer provided by caller. - pub fn final(ctx: *Self, out: []u8) void { - // Process the last block (if any) - if (ctx.c_idx != 0) { - // move the final 1 according to remaining input length - // (We may add less than 2^130 to the last input block) - ctx.c[4] = 0; - polyTakeInput(ctx, 1); - // one last hash update - polyBlock(ctx); - } - - // check if we should subtract 2^130-5 by performing the - // corresponding carry propagation. - const _u0 = @as(u64, 5) + ctx.h[0]; // <= 1_00000004 - const _u1 = (_u0 >> 32) + ctx.h[1]; // <= 1_00000000 - const _u2 = (_u1 >> 32) + ctx.h[2]; // <= 1_00000000 - const _u3 = (_u2 >> 32) + ctx.h[3]; // <= 1_00000000 - const _u4 = (_u3 >> 32) + ctx.h[4]; // <= 5 - // u4 indicates how many times we should subtract 2^130-5 (0 or 1) - - // h + pad, minus 2^130-5 if u4 exceeds 3 - const uu0 = (_u4 >> 2) * 5 + ctx.h[0] + ctx.pad[0]; // <= 2_00000003 - const uu1 = (uu0 >> 32) + ctx.h[1] + ctx.pad[1]; // <= 2_00000000 - const uu2 = (uu1 >> 32) + ctx.h[2] + ctx.pad[2]; // <= 2_00000000 - const uu3 = (uu2 >> 32) + ctx.h[3] + ctx.pad[3]; // <= 2_00000000 - - writeIntLittle(u32, out[0..4], @truncate(u32, uu0)); - writeIntLittle(u32, out[4..8], @truncate(u32, uu1)); - writeIntLittle(u32, out[8..12], @truncate(u32, uu2)); - writeIntLittle(u32, out[12..16], @truncate(u32, uu3)); - - ctx.secureZero(); + var st = Poly1305.init(key); + st.update(msg); + st.final(out); } }; From 2fc2ebd920a83e737ebb5f8b3499fd0e48d94043 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Fri, 21 Aug 2020 19:43:06 +0200 Subject: [PATCH 60/66] Force myself to use unusual integer sizes a little bit more :) --- lib/std/crypto/poly1305.zig | 64 ++++++++++++++++++++----------------- 1 file changed, 34 insertions(+), 30 deletions(-) diff --git a/lib/std/crypto/poly1305.zig b/lib/std/crypto/poly1305.zig index 7f2966f991..b401939c5c 100644 --- a/lib/std/crypto/poly1305.zig +++ b/lib/std/crypto/poly1305.zig @@ -44,6 +44,9 @@ pub const Poly1305 = struct { const r0 = st.r[0]; const r1 = st.r[1]; const r2 = st.r[2]; + var h0 = st.h[0]; + var h1 = st.h[1]; + var h2 = st.h[2]; const s1 = r1 * (5 << 2); const s2 = r2 * (5 << 2); var i: usize = 0; @@ -51,29 +54,30 @@ pub const Poly1305 = struct { // h += m[i] const t0 = mem.readIntLittle(u64, m[i..][0..8]); const t1 = mem.readIntLittle(u64, m[i + 8 ..][0..8]); - st.h[0] += t0 & 0xfffffffffff; - st.h[1] += ((t0 >> 44) | (t1 << 20)) & 0xfffffffffff; - st.h[2] += (((t1 >> 24)) & 0x3ffffffffff) | hibit; + h0 += @truncate(u44, t0); + h1 += @truncate(u44, (t0 >> 44) | (t1 << 20)); + h2 += @truncate(u42, t1 >> 24) | hibit; // h *= r - const d0 = @as(u128, st.h[0]) * @as(u128, r0) + @as(u128, st.h[1]) * @as(u128, s2) + @as(u128, st.h[2]) * @as(u128, s1); - var d1 = @as(u128, st.h[0]) * @as(u128, r1) + @as(u128, st.h[1]) * @as(u128, r0) + @as(u128, st.h[2]) * @as(u128, s2); - var d2 = @as(u128, st.h[0]) * @as(u128, r2) + @as(u128, st.h[1]) * @as(u128, r1) + @as(u128, st.h[2]) * @as(u128, r0); + const d0 = @as(u128, h0) * r0 + @as(u128, h1) * s2 + @as(u128, h2) * s1; + var d1 = @as(u128, h0) * r1 + @as(u128, h1) * r0 + @as(u128, h2) * s2; + var d2 = @as(u128, h0) * r2 + @as(u128, h1) * r1 + @as(u128, h2) * r0; // partial reduction var carry = d0 >> 44; - st.h[0] = @truncate(u64, d0) & 0xfffffffffff; + h0 = @truncate(u44, d0); d1 += carry; carry = @intCast(u64, d1 >> 44); - st.h[1] = @truncate(u64, d1) & 0xfffffffffff; + h1 = @truncate(u44, d1); d2 += carry; carry = @intCast(u64, d2 >> 42); - st.h[2] = @truncate(u64, d2) & 0x3ffffffffff; - st.h[0] += @truncate(u64, carry) * 5; - carry = st.h[0] >> 44; - st.h[0] &= 0xfffffffffff; - st.h[1] += @truncate(u64, carry); + h2 = @truncate(u42, d2); + h0 += @truncate(u64, carry) * 5; + carry = h0 >> 44; + h0 = @truncate(u44, h0); + h1 += @truncate(u64, carry); } + st.h = [_]u64{ h0, h1, h2 }; } pub fn update(st: *Poly1305, m: []const u8) void { @@ -124,31 +128,31 @@ pub const Poly1305 = struct { } // fully carry h var carry = st.h[1] >> 44; - st.h[1] &= 0xfffffffffff; + st.h[1] = @truncate(u44, st.h[1]); st.h[2] += carry; carry = st.h[2] >> 42; - st.h[2] &= 0x3ffffffffff; + st.h[2] = @truncate(u42, st.h[2]); st.h[0] += carry * 5; carry = st.h[0] >> 44; - st.h[0] &= 0xfffffffffff; + st.h[0] = @truncate(u44, st.h[0]); st.h[1] += carry; carry = st.h[1] >> 44; - st.h[1] &= 0xfffffffffff; + st.h[1] = @truncate(u44, st.h[1]); st.h[2] += carry; carry = st.h[2] >> 42; - st.h[2] &= 0x3ffffffffff; + st.h[2] = @truncate(u42, st.h[2]); st.h[0] += carry * 5; carry = st.h[0] >> 44; - st.h[0] &= 0xfffffffffff; + st.h[0] = @truncate(u44, st.h[0]); st.h[1] += carry; // compute h + -p var g0 = st.h[0] + 5; carry = g0 >> 44; - g0 &= 0xfffffffffff; + g0 = @truncate(u44, g0); var g1 = st.h[1] + carry; carry = g1 >> 44; - g1 &= 0xfffffffffff; + g1 = @truncate(u44, g1); var g2 = st.h[2] + carry -% (1 << 42); // (hopefully) constant-time select h if h < p, or h + -p if h >= p @@ -164,14 +168,14 @@ pub const Poly1305 = struct { // h = (h + pad) const t0 = st.pad[0]; const t1 = st.pad[1]; - st.h[0] += (t0 & 0xfffffffffff); - carry = (st.h[0] >> 44); - st.h[0] &= 0xfffffffffff; - st.h[1] += (((t0 >> 44) | (t1 << 20)) & 0xfffffffffff) + carry; - carry = (st.h[1] >> 44); - st.h[1] &= 0xfffffffffff; - st.h[2] += (((t1 >> 24)) & 0x3ffffffffff) + carry; - st.h[2] &= 0x3ffffffffff; + st.h[0] += @truncate(u44, t0); + carry = st.h[0] >> 44; + st.h[0] = @truncate(u44, st.h[0]); + st.h[1] += @truncate(u44, (t0 >> 44) | (t1 << 20)) + carry; + carry = st.h[1] >> 44; + st.h[1] = @truncate(u44, st.h[1]); + st.h[2] += @truncate(u42, t1 >> 24) + carry; + st.h[2] = @truncate(u42, st.h[2]); // mac = h % (2^128) st.h[0] |= st.h[1] << 44; @@ -180,7 +184,7 @@ pub const Poly1305 = struct { mem.writeIntLittle(u64, out[0..8], st.h[0]); mem.writeIntLittle(u64, out[8..16], st.h[1]); - mem.secureZero(u64, &st.r); + std.mem.secureZero(u8, @ptrCast([*]u8, st)[0..@sizeOf(Poly1305)]); } pub fn create(out: []u8, msg: []const u8, key: []const u8) void { From 0fe6677736fae205543c6f1c57ea864049bade73 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Fri, 21 Aug 2020 20:33:16 +0200 Subject: [PATCH 61/66] No need to keep a 128-bit carry around --- lib/std/crypto/poly1305.zig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/std/crypto/poly1305.zig b/lib/std/crypto/poly1305.zig index b401939c5c..c0b462c60e 100644 --- a/lib/std/crypto/poly1305.zig +++ b/lib/std/crypto/poly1305.zig @@ -64,7 +64,7 @@ pub const Poly1305 = struct { var d2 = @as(u128, h0) * r2 + @as(u128, h1) * r1 + @as(u128, h2) * r0; // partial reduction - var carry = d0 >> 44; + var carry = @intCast(u64, d0 >> 44); h0 = @truncate(u44, d0); d1 += carry; carry = @intCast(u64, d1 >> 44); @@ -75,7 +75,7 @@ pub const Poly1305 = struct { h0 += @truncate(u64, carry) * 5; carry = h0 >> 44; h0 = @truncate(u44, h0); - h1 += @truncate(u64, carry); + h1 += carry; } st.h = [_]u64{ h0, h1, h2 }; } From 7f1378909b54dec1636920389e60d8dfacb4e614 Mon Sep 17 00:00:00 2001 From: Matt Knight Date: Tue, 18 Aug 2020 22:03:51 -0700 Subject: [PATCH 62/66] moved bpf syscall, added some bpf instructions and tests --- lib/std/os/bits/linux/bpf.zig | 396 ++++++++++++++++++++++++++++++++-- lib/std/os/linux.zig | 4 + 2 files changed, 382 insertions(+), 18 deletions(-) diff --git a/lib/std/os/bits/linux/bpf.zig b/lib/std/os/bits/linux/bpf.zig index e86e082ff7..6baccd4362 100644 --- a/lib/std/os/bits/linux/bpf.zig +++ b/lib/std/os/bits/linux/bpf.zig @@ -5,6 +5,61 @@ // and substantial portions of the software. usingnamespace std.os; const std = @import("../../../std.zig"); +const expectEqual = std.testing.expectEqual; +const fd_t = std.os.fd_t; +const pid_t = std.os.pid_t; + +// instruction classes +pub const LD = 0x00; +pub const LDX = 0x01; +pub const ST = 0x02; +pub const STX = 0x03; +pub const ALU = 0x04; +pub const JMP = 0x05; +pub const RET = 0x06; +pub const MISC = 0x07; + +/// 32-bit +pub const W = 0x00; +/// 16-bit +pub const H = 0x08; +/// 8-bit +pub const B = 0x10; +/// 64-bit +pub const DW = 0x18; + +pub const IMM = 0x00; +pub const ABS = 0x20; +pub const IND = 0x40; +pub const MEM = 0x60; +pub const LEN = 0x80; +pub const MSH = 0xa0; + +// alu fields +pub const ADD = 0x00; +pub const SUB = 0x10; +pub const MUL = 0x20; +pub const DIV = 0x30; +pub const OR = 0x40; +pub const AND = 0x50; +pub const LSH = 0x60; +pub const RSH = 0x70; +pub const NEG = 0x80; +pub const MOD = 0x90; +pub const XOR = 0xa0; + +// jmp fields +pub const JA = 0x00; +pub const JEQ = 0x10; +pub const JGT = 0x20; +pub const JGE = 0x30; +pub const JSET = 0x40; + +//#define BPF_SRC(code) ((code) & 0x08) +pub const K = 0x00; +pub const X = 0x08; + +pub const MAXINSNS = 4096; // instruction classes /// jmp mode in word width @@ -13,8 +68,6 @@ pub const JMP32 = 0x06; pub const ALU64 = 0x07; // ld/ldx fields -/// double word (64-bit) -pub const DW = 0x18; /// exclusive add pub const XADD = 0xc0; @@ -153,6 +206,130 @@ pub const BPF_F_CLONE = 0x200; /// flag for BPF_MAP_CREATE command. Enable memory-mapping BPF map pub const BPF_F_MMAPABLE = 0x400; +/// These values correspond to "syscalls" within the BPF program's environment +pub const Helper = enum(i32) { + unspec, + map_lookup_elem, + map_update_elem, + map_delete_elem, + probe_read, + ktime_get_ns, + trace_printk, + get_prandom_u32, + get_smp_processor_id, + skb_store_bytes, + l3_csum_replace, + l4_csum_replace, + tail_call, + clone_redirect, + get_current_pid_tgid, + get_current_uid_gid, + get_current_comm, + get_cgroup_classid, + skb_vlan_push, + skb_vlan_pop, + skb_get_tunnel_key, + skb_set_tunnel_key, + perf_event_read, + redirect, + get_route_realm, + perf_event_output, + skb_load_bytes, + get_stackid, + csum_diff, + skb_get_tunnel_opt, + skb_set_tunnel_opt, + skb_change_proto, + skb_change_type, + skb_under_cgroup, + get_hash_recalc, + get_current_task, + probe_write_user, + current_task_under_cgroup, + skb_change_tail, + skb_pull_data, + csum_update, + set_hash_invalid, + get_numa_node_id, + skb_change_head, + xdp_adjust_head, + probe_read_str, + get_socket_cookie, + get_socket_uid, + set_hash, + setsockopt, + skb_adjust_room, + redirect_map, + sk_redirect_map, + sock_map_update, + xdp_adjust_meta, + perf_event_read_value, + perf_prog_read_value, + getsockopt, + override_return, + sock_ops_cb_flags_set, + msg_redirect_map, + msg_apply_bytes, + msg_cork_bytes, + msg_pull_data, + bind, + xdp_adjust_tail, + skb_get_xfrm_state, + get_stack, + skb_load_bytes_relative, + fib_lookup, + sock_hash_update, + msg_redirect_hash, + sk_redirect_hash, + lwt_push_encap, + lwt_seg6_store_bytes, + lwt_seg6_adjust_srh, + lwt_seg6_action, + rc_repeat, + rc_keydown, + skb_cgroup_id, + get_current_cgroup_id, + get_local_storage, + sk_select_reuseport, + skb_ancestor_cgroup_id, + sk_lookup_tcp, + sk_lookup_udp, + sk_release, + map_push_elem, + map_pop_elem, + map_peek_elem, + msg_push_data, + msg_pop_data, + rc_pointer_rel, + spin_lock, + spin_unlock, + sk_fullsock, + tcp_sock, + skb_ecn_set_ce, + get_listener_sock, + skc_lookup_tcp, + tcp_check_syncookie, + sysctl_get_name, + sysctl_get_current_value, + sysctl_get_new_value, + sysctl_set_new_value, + strtol, + strtoul, + sk_storage_get, + sk_storage_delete, + send_signal, + tcp_gen_syncookie, + skb_output, + probe_read_user, + probe_read_kernel, + probe_read_user_str, + probe_read_kernel_str, + tcp_send_ack, + send_signal_thread, + jiffies64, + _, +}; + /// a single BPF instruction pub const Insn = packed struct { code: u8, @@ -163,32 +340,163 @@ pub const Insn = packed struct { /// r0 - r9 are general purpose 64-bit registers, r10 points to the stack /// frame - pub const Reg = enum(u4) { - r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10 + pub const Reg = packed enum(u4) { r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10 }; + const Source = packed enum(u1) { reg, imm }; + const AluOp = packed enum(u8) { + add = ADD, + sub = SUB, + mul = MUL, + div = DIV, + op_or = OR, + op_and = AND, + lsh = LSH, + rsh = RSH, + neg = NEG, + mod = MOD, + xor = XOR, + mov = MOV, }; - const alu = 0x04; - const jmp = 0x05; - const mov = 0xb0; - const k = 0; - const exit_code = 0x90; + pub const Size = packed enum(u8) { + byte = B, + half_word = H, + word = W, + double_word = DW, + }; + + const JmpOp = packed enum(u8) { + ja = JA, + jeq = JEQ, + jgt = JGT, + jge = JGE, + jset = JSET, + }; + + const ImmOrReg = union(Source) { + imm: i32, + reg: Reg, + }; + + fn imm_reg(code: u8, dst: Reg, src: anytype, off: i16) Insn { + const imm_or_reg = if (@typeInfo(@TypeOf(src)) == .EnumLiteral) + ImmOrReg{ .reg = @as(Reg, src) } + else + ImmOrReg{ .imm = src }; + + const src_type = switch (imm_or_reg) { + .imm => K, + .reg => X, + }; - // TODO: implement more factory functions for the other instructions - /// load immediate value into a register - pub fn load_imm(dst: Reg, imm: i32) Insn { return Insn{ - .code = alu | mov | k, + .code = code | src_type, .dst = @enumToInt(dst), + .src = switch (imm_or_reg) { + .imm => 0, + .reg => |r| @enumToInt(r), + }, + .off = off, + .imm = switch (imm_or_reg) { + .imm => |i| i, + .reg => 0, + }, + }; + } + + fn alu(comptime width: comptime_int, op: AluOp, dst: Reg, src: anytype) Insn { + const width_bitfield = switch (width) { + 32 => ALU, + 64 => ALU64, + else => @compileError("width must be 32 or 64"), + }; + + return imm_reg(width_bitfield | @enumToInt(op), dst, src, 0); + } + + pub fn mov(dst: Reg, src: anytype) Insn { + return alu(64, .mov, dst, src); + } + + pub fn add(dst: Reg, src: anytype) Insn { + return alu(64, .add, dst, src); + } + + fn jmp(op: JmpOp, dst: Reg, src: anytype, off: i16) Insn { + return imm_reg(JMP | @enumToInt(op), dst, src, off); + } + + pub fn jeq(dst: Reg, src: anytype, off: i16) Insn { + return jmp(.jeq, dst, src, off); + } + + pub fn stx_mem(size: Size, dst: Reg, src: Reg, off: i16) Insn { + return Insn{ + .code = STX | @enumToInt(size) | MEM, + .dst = @enumToInt(dst), + .src = @enumToInt(src), + .off = off, + .imm = 0, + }; + } + + pub fn xadd(dst: Reg, src: Reg) Insn { + return Insn{ + .code = STX | XADD | DW, + .dst = @enumToInt(dst), + .src = @enumToInt(src), + .off = 0, + .imm = 0, + }; + } + + /// direct packet access, R0 = *(uint *)(skb->data + imm32) + pub fn ld_abs(size: Size, imm: i32) Insn { + return Insn{ + .code = LD | @enumToInt(size) | ABS, + .dst = 0, .src = 0, .off = 0, .imm = imm, }; } + fn ld_imm_impl(dst: Reg, src: Reg, imm: u64) [2]Insn { + return [2]Insn{ + Insn{ + .code = LD | DW | IMM, + .dst = @enumToInt(dst), + .src = @enumToInt(src), + .off = 0, + .imm = @intCast(i32, @truncate(u32, imm)), + }, + Insn{ + .code = 0, + .dst = 0, + .src = 0, + .off = 0, + .imm = @intCast(i32, @truncate(u32, imm >> 32)), + }, + }; + } + + pub fn ld_map_fd(dst: Reg, map_fd: fd_t) [2]Insn { + return ld_imm_impl(dst, @intToEnum(Reg, PSEUDO_MAP_FD), @intCast(u64, map_fd)); + } + + pub fn call(helper: Helper) Insn { + return Insn{ + .code = JMP | CALL, + .dst = 0, + .src = 0, + .off = 0, + .imm = @enumToInt(helper), + }; + } + /// exit BPF program pub fn exit() Insn { return Insn{ - .code = jmp | exit_code, + .code = JMP | EXIT, .dst = 0, .src = 0, .off = 0, @@ -197,6 +505,62 @@ pub const Insn = packed struct { } }; +fn expect_insn(insn: Insn, val: u64) void { + expectEqual(@bitCast(u64, insn), val); +} + +test "insn bitsize" { + expectEqual(@bitSizeOf(Insn), 64); +} + +// mov instructions +test "mov imm" { + expect_insn(Insn.mov(.r1, 1), 0x00000001000001b7); +} + +test "mov reg" { + expect_insn(Insn.mov(.r6, .r1), 0x00000000000016bf); +} + +// alu instructions +test "add imm" { + expect_insn(Insn.add(.r2, -4), 0xfffffffc00000207); +} + +// ld instructions +test "ld_abs" { + expect_insn(Insn.ld_abs(.byte, 42), 0x0000002a00000030); +} + +test "ld_map_fd" { + const insns = Insn.ld_map_fd(.r1, 42); + expect_insn(insns[0], 0x0000002a00001118); + expect_insn(insns[1], 0x0000000000000000); +} + +// st instructions +test "stx_mem" { + expect_insn(Insn.stx_mem(.word, .r10, .r0, -4), 0x00000000fffc0a63); +} + +test "xadd" { + expect_insn(Insn.xadd(.r0, .r1), 0x00000000000010db); +} + +// jmp instructions +test "jeq imm" { + expect_insn(Insn.jeq(.r0, 0, 2), 0x0000000000020015); +} + +// other instructions +test "call" { + expect_insn(Insn.call(.map_lookup_elem), 0x0000000100000085); +} + +test "exit" { + expect_insn(Insn.exit(), 0x0000000000000095); +} + pub const Cmd = extern enum(usize) { map_create, map_lookup_elem, @@ -605,7 +969,3 @@ pub const Attr = extern union { enable_stats: EnableStatsAttr, iter_create: IterCreateAttr, }; - -pub fn bpf(cmd: Cmd, attr: *Attr, size: u32) usize { - return syscall3(.bpf, @enumToInt(cmd), @ptrToInt(attr), size); -} diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig index ae66e619c3..f64e7d2add 100644 --- a/lib/std/os/linux.zig +++ b/lib/std/os/linux.zig @@ -1221,6 +1221,10 @@ pub fn copy_file_range(fd_in: fd_t, off_in: ?*i64, fd_out: fd_t, off_out: ?*i64, ); } +pub fn bpf_syscall(cmd: bpf.Cmd, attr: *bpf.Attr, size: u32) usize { + return syscall3(.bpf, @enumToInt(cmd), @ptrToInt(attr), size); +} + test "" { if (builtin.os.tag == .linux) { _ = @import("linux/test.zig"); From bc1536f4bf01e45af80a930b31b9271551de1dc0 Mon Sep 17 00:00:00 2001 From: Matt Knight Date: Tue, 18 Aug 2020 22:18:36 -0700 Subject: [PATCH 63/66] decided to split up loading of 64-bit immediates --- lib/std/os/bits/linux/bpf.zig | 46 +++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/lib/std/os/bits/linux/bpf.zig b/lib/std/os/bits/linux/bpf.zig index 6baccd4362..5517e2ae80 100644 --- a/lib/std/os/bits/linux/bpf.zig +++ b/lib/std/os/bits/linux/bpf.zig @@ -460,27 +460,32 @@ pub const Insn = packed struct { }; } - fn ld_imm_impl(dst: Reg, src: Reg, imm: u64) [2]Insn { - return [2]Insn{ - Insn{ - .code = LD | DW | IMM, - .dst = @enumToInt(dst), - .src = @enumToInt(src), - .off = 0, - .imm = @intCast(i32, @truncate(u32, imm)), - }, - Insn{ - .code = 0, - .dst = 0, - .src = 0, - .off = 0, - .imm = @intCast(i32, @truncate(u32, imm >> 32)), - }, + fn ld_imm_impl1(dst: Reg, src: Reg, imm: u64) Insn { + return Insn{ + .code = LD | DW | IMM, + .dst = @enumToInt(dst), + .src = @enumToInt(src), + .off = 0, + .imm = @intCast(i32, @truncate(u32, imm)), }; } - pub fn ld_map_fd(dst: Reg, map_fd: fd_t) [2]Insn { - return ld_imm_impl(dst, @intToEnum(Reg, PSEUDO_MAP_FD), @intCast(u64, map_fd)); + fn ld_imm_impl2(imm: u64) Insn { + return Insn{ + .code = 0, + .dst = 0, + .src = 0, + .off = 0, + .imm = @intCast(i32, @truncate(u32, imm >> 32)), + }; + } + + pub fn ld_map_fd1(dst: Reg, map_fd: fd_t) Insn { + return ld_imm_impl1(dst, @intToEnum(Reg, PSEUDO_MAP_FD), @intCast(u64, map_fd)); + } + + pub fn ld_map_fd2(map_fd: fd_t) Insn { + return ld_imm_impl2(@intCast(u64, map_fd)); } pub fn call(helper: Helper) Insn { @@ -533,9 +538,8 @@ test "ld_abs" { } test "ld_map_fd" { - const insns = Insn.ld_map_fd(.r1, 42); - expect_insn(insns[0], 0x0000002a00001118); - expect_insn(insns[1], 0x0000000000000000); + expect_insn(Insn.ld_map_fd1(.r1, 42), 0x0000002a00001118); + expect_insn(Insn.ld_map_fd2(42), 0x0000000000000000); } // st instructions From 80fabe18506193978ed60dcd45790ef9486c4eb3 Mon Sep 17 00:00:00 2001 From: Matt Knight Date: Thu, 20 Aug 2020 18:54:41 -0700 Subject: [PATCH 64/66] fixed bpf namespace --- lib/std/os/bits/linux.zig | 2 +- lib/std/os/linux.zig | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/std/os/bits/linux.zig b/lib/std/os/bits/linux.zig index 5c81ee8c06..133b903110 100644 --- a/lib/std/os/bits/linux.zig +++ b/lib/std/os/bits/linux.zig @@ -24,7 +24,7 @@ pub usingnamespace switch (builtin.arch) { }; pub usingnamespace @import("linux/netlink.zig"); -pub const bpf = @import("linux/bpf.zig"); +pub const BPF = @import("linux/bpf.zig"); const is_mips = builtin.arch.isMIPS(); diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig index f64e7d2add..c5edacfab1 100644 --- a/lib/std/os/linux.zig +++ b/lib/std/os/linux.zig @@ -1221,7 +1221,7 @@ pub fn copy_file_range(fd_in: fd_t, off_in: ?*i64, fd_out: fd_t, off_out: ?*i64, ); } -pub fn bpf_syscall(cmd: bpf.Cmd, attr: *bpf.Attr, size: u32) usize { +pub fn bpf(cmd: BPF.Cmd, attr: *BPF.Attr, size: u32) usize { return syscall3(.bpf, @enumToInt(cmd), @ptrToInt(attr), size); } From 37ad9f38dc89b568abddb56a044bdfb36eca7d49 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Fri, 21 Aug 2020 17:54:01 +0200 Subject: [PATCH 65/66] std: sync TailQueue with new SinglyLinkedList API The API of SinglyLinkedList was changed in 93384f7, removing the init function as well as the redundant allocation helper functions. This commit makes parallel changes to the API of TailQueue in order to keep the standard library consistent. --- lib/std/linked_list.zig | 118 ++++++++++------------------------------ 1 file changed, 30 insertions(+), 88 deletions(-) diff --git a/lib/std/linked_list.zig b/lib/std/linked_list.zig index e99f3d8725..00e678e0ac 100644 --- a/lib/std/linked_list.zig +++ b/lib/std/linked_list.zig @@ -183,21 +183,9 @@ pub fn TailQueue(comptime T: type) type { } }; - first: ?*Node, - last: ?*Node, - len: usize, - - /// Initialize a linked list. - /// - /// Returns: - /// An empty linked list. - pub fn init() Self { - return Self{ - .first = null, - .last = null, - .len = 0, - }; - } + first: ?*Node = null, + last: ?*Node = null, + len: usize = 0, /// Insert a new node after an existing one. /// @@ -340,65 +328,24 @@ pub fn TailQueue(comptime T: type) type { list.remove(first); return first; } - - /// Allocate a new node. - /// - /// Arguments: - /// allocator: Dynamic memory allocator. - /// - /// Returns: - /// A pointer to the new node. - pub fn allocateNode(list: *Self, allocator: *Allocator) !*Node { - return allocator.create(Node); - } - - /// Deallocate a node. - /// - /// Arguments: - /// node: Pointer to the node to deallocate. - /// allocator: Dynamic memory allocator. - pub fn destroyNode(list: *Self, node: *Node, allocator: *Allocator) void { - allocator.destroy(node); - } - - /// Allocate and initialize a node and its data. - /// - /// Arguments: - /// data: The data to put inside the node. - /// allocator: Dynamic memory allocator. - /// - /// Returns: - /// A pointer to the new node. - pub fn createNode(list: *Self, data: T, allocator: *Allocator) !*Node { - var node = try list.allocateNode(allocator); - node.* = Node.init(data); - return node; - } }; } test "basic TailQueue test" { - const allocator = testing.allocator; - var list = TailQueue(u32).init(); + const L = TailQueue(u32); + var list = L{}; - var one = try list.createNode(1, allocator); - var two = try list.createNode(2, allocator); - var three = try list.createNode(3, allocator); - var four = try list.createNode(4, allocator); - var five = try list.createNode(5, allocator); - defer { - list.destroyNode(one, allocator); - list.destroyNode(two, allocator); - list.destroyNode(three, allocator); - list.destroyNode(four, allocator); - list.destroyNode(five, allocator); - } + var one = L.Node{ .data = 1 }; + var two = L.Node{ .data = 2 }; + var three = L.Node{ .data = 3 }; + var four = L.Node{ .data = 4 }; + var five = L.Node{ .data = 5 }; - list.append(two); // {2} - list.append(five); // {2, 5} - list.prepend(one); // {1, 2, 5} - list.insertBefore(five, four); // {1, 2, 4, 5} - list.insertAfter(two, three); // {1, 2, 3, 4, 5} + list.append(&two); // {2} + list.append(&five); // {2, 5} + list.prepend(&one); // {1, 2, 5} + list.insertBefore(&five, &four); // {1, 2, 4, 5} + list.insertAfter(&two, &three); // {1, 2, 3, 4, 5} // Traverse forwards. { @@ -422,7 +369,7 @@ test "basic TailQueue test" { var first = list.popFirst(); // {2, 3, 4, 5} var last = list.pop(); // {2, 3, 4} - list.remove(three); // {2, 4} + list.remove(&three); // {2, 4} testing.expect(list.first.?.data == 2); testing.expect(list.last.?.data == 4); @@ -430,30 +377,25 @@ test "basic TailQueue test" { } test "TailQueue concatenation" { - const allocator = testing.allocator; - var list1 = TailQueue(u32).init(); - var list2 = TailQueue(u32).init(); + const L = TailQueue(u32); + var list1 = L{}; + var list2 = L{}; - var one = try list1.createNode(1, allocator); - defer list1.destroyNode(one, allocator); - var two = try list1.createNode(2, allocator); - defer list1.destroyNode(two, allocator); - var three = try list1.createNode(3, allocator); - defer list1.destroyNode(three, allocator); - var four = try list1.createNode(4, allocator); - defer list1.destroyNode(four, allocator); - var five = try list1.createNode(5, allocator); - defer list1.destroyNode(five, allocator); + var one = L.Node{ .data = 1 }; + var two = L.Node{ .data = 2 }; + var three = L.Node{ .data = 3 }; + var four = L.Node{ .data = 4 }; + var five = L.Node{ .data = 5 }; - list1.append(one); - list1.append(two); - list2.append(three); - list2.append(four); - list2.append(five); + list1.append(&one); + list1.append(&two); + list2.append(&three); + list2.append(&four); + list2.append(&five); list1.concatByMoving(&list2); - testing.expect(list1.last == five); + testing.expect(list1.last == &five); testing.expect(list1.len == 5); testing.expect(list2.first == null); testing.expect(list2.last == null); From 89b6c47e042b343fba754ed8f39efa1b385093bb Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 21 Aug 2020 13:24:13 -0700 Subject: [PATCH 66/66] stage2: decouple codegen.zig from ELF See #6113 for an alternate way of doing this that we didn't end up following. Closes #6079. I also took the opportunity here to extract C.zig and Elf.zig from link.zig. --- src-self-hosted/codegen.zig | 197 ++- src-self-hosted/link.zig | 2714 +----------------------------- src-self-hosted/link/C.zig | 101 ++ src-self-hosted/link/Elf.zig | 2583 ++++++++++++++++++++++++++++ src-self-hosted/link/MachO.zig | 6 +- src-self-hosted/{ => link}/cbe.h | 0 src-self-hosted/test.zig | 2 +- 7 files changed, 2824 insertions(+), 2779 deletions(-) create mode 100644 src-self-hosted/link/C.zig create mode 100644 src-self-hosted/link/Elf.zig rename src-self-hosted/{ => link}/cbe.h (100%) diff --git a/src-self-hosted/codegen.zig b/src-self-hosted/codegen.zig index cc5c51159c..36bebe1ca5 100644 --- a/src-self-hosted/codegen.zig +++ b/src-self-hosted/codegen.zig @@ -59,20 +59,20 @@ pub const GenerateSymbolError = error{ }; pub fn generateSymbol( - bin_file: *link.File.Elf, + bin_file: *link.File, src: usize, typed_value: TypedValue, code: *std.ArrayList(u8), dbg_line: *std.ArrayList(u8), dbg_info: *std.ArrayList(u8), - dbg_info_type_relocs: *link.File.Elf.DbgInfoTypeRelocsTable, + dbg_info_type_relocs: *link.File.DbgInfoTypeRelocsTable, ) GenerateSymbolError!Result { const tracy = trace(@src()); defer tracy.end(); switch (typed_value.ty.zigTypeTag()) { .Fn => { - switch (bin_file.base.options.target.cpu.arch) { + switch (bin_file.options.target.cpu.arch) { .wasm32 => unreachable, // has its own code path .wasm64 => unreachable, // has its own code path //.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( } return Result{ .fail = try ErrorMsg.create( - bin_file.base.allocator, + bin_file.allocator, src, "TODO implement generateSymbol for more kinds of arrays", .{}, @@ -164,12 +164,11 @@ pub fn generateSymbol( if (typed_value.val.cast(Value.Payload.DeclRef)) |payload| { const decl = payload.decl; if (decl.analysis != .complete) return error.AnalysisFail; - assert(decl.link.elf.local_sym_index != 0); // TODO handle the dependency of this symbol on the decl's vaddr. // If the decl changes vaddr, then this symbol needs to get regenerated. - const vaddr = bin_file.local_symbols.items[decl.link.elf.local_sym_index].st_value; - const endian = bin_file.base.options.target.cpu.arch.endian(); - switch (bin_file.base.options.target.cpu.arch.ptrBitWidth()) { + const vaddr = bin_file.getDeclVAddr(decl); + const endian = bin_file.options.target.cpu.arch.endian(); + switch (bin_file.options.target.cpu.arch.ptrBitWidth()) { 16 => { try code.resize(2); mem.writeInt(u16, code.items[0..2], @intCast(u16, vaddr), endian); @@ -188,7 +187,7 @@ pub fn generateSymbol( } return Result{ .fail = try ErrorMsg.create( - bin_file.base.allocator, + bin_file.allocator, src, "TODO implement generateSymbol for pointer {}", .{typed_value.val}, @@ -198,7 +197,7 @@ pub fn generateSymbol( .Int => { // TODO populate .debug_info for the integer - const info = typed_value.ty.intInfo(bin_file.base.options.target); + const info = typed_value.ty.intInfo(bin_file.options.target); if (info.bits == 8 and !info.signed) { const x = typed_value.val.toUnsignedInt(); try code.append(@intCast(u8, x)); @@ -206,7 +205,7 @@ pub fn generateSymbol( } return Result{ .fail = try ErrorMsg.create( - bin_file.base.allocator, + bin_file.allocator, src, "TODO implement generateSymbol for int type '{}'", .{typed_value.ty}, @@ -216,7 +215,7 @@ pub fn generateSymbol( else => |t| { return Result{ .fail = try ErrorMsg.create( - bin_file.base.allocator, + bin_file.allocator, src, "TODO implement generateSymbol for type '{}'", .{@tagName(t)}, @@ -234,13 +233,13 @@ const InnerError = error{ fn Function(comptime arch: std.Target.Cpu.Arch) type { return struct { gpa: *Allocator, - bin_file: *link.File.Elf, + bin_file: *link.File, target: *const std.Target, mod_fn: *const Module.Fn, code: *std.ArrayList(u8), dbg_line: *std.ArrayList(u8), dbg_info: *std.ArrayList(u8), - dbg_info_type_relocs: *link.File.Elf.DbgInfoTypeRelocsTable, + dbg_info_type_relocs: *link.File.DbgInfoTypeRelocsTable, err_msg: ?*ErrorMsg, args: []MCValue, ret_mcv: MCValue, @@ -405,22 +404,22 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { const Self = @This(); fn generateSymbol( - bin_file: *link.File.Elf, + bin_file: *link.File, src: usize, typed_value: TypedValue, code: *std.ArrayList(u8), dbg_line: *std.ArrayList(u8), dbg_info: *std.ArrayList(u8), - dbg_info_type_relocs: *link.File.Elf.DbgInfoTypeRelocsTable, + dbg_info_type_relocs: *link.File.DbgInfoTypeRelocsTable, ) GenerateSymbolError!Result { const module_fn = typed_value.val.cast(Value.Payload.Function).?.func; const fn_type = module_fn.owner_decl.typed_value.most_recent.typed_value.ty; - var branch_stack = std.ArrayList(Branch).init(bin_file.base.allocator); + var branch_stack = std.ArrayList(Branch).init(bin_file.allocator); defer { assert(branch_stack.items.len == 1); - branch_stack.items[0].deinit(bin_file.base.allocator); + branch_stack.items[0].deinit(bin_file.allocator); branch_stack.deinit(); } const branch = try branch_stack.addOne(); @@ -443,8 +442,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { }; var function = Self{ - .gpa = bin_file.base.allocator, - .target = &bin_file.base.options.target, + .gpa = bin_file.allocator, + .target = &bin_file.options.target, .bin_file = bin_file, .mod_fn = module_fn, .code = code, @@ -464,7 +463,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { .rbrace_src = src_data.rbrace_src, .source = src_data.source, }; - defer function.exitlude_jump_relocs.deinit(bin_file.base.allocator); + defer function.exitlude_jump_relocs.deinit(bin_file.allocator); var call_info = function.resolveCallingConventionValues(src, fn_type) catch |err| switch (err) { error.CodegenFail => return Result{ .fail = function.err_msg.? }, @@ -1144,80 +1143,88 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { var info = try self.resolveCallingConventionValues(inst.base.src, inst.func.ty); defer info.deinit(self); - switch (arch) { - .x86_64 => { - for (info.args) |mc_arg, arg_i| { - const arg = inst.args[arg_i]; - const arg_mcv = try self.resolveInst(inst.args[arg_i]); - // Here we do not use setRegOrMem even though the logic is similar, because - // the function call will move the stack pointer, so the offsets are different. - switch (mc_arg) { - .none => continue, - .register => |reg| { - try self.genSetReg(arg.src, reg, arg_mcv); - // TODO interact with the register allocator to mark the instruction as moved. - }, - .stack_offset => { - // Here we need to emit instructions like this: - // mov qword ptr [rsp + stack_offset], x - return self.fail(inst.base.src, "TODO implement calling with parameters in memory", .{}); - }, - .ptr_stack_offset => { - return self.fail(inst.base.src, "TODO implement calling with MCValue.ptr_stack_offset arg", .{}); - }, - .ptr_embedded_in_code => { - return self.fail(inst.base.src, "TODO implement calling with MCValue.ptr_embedded_in_code arg", .{}); - }, - .undef => unreachable, - .immediate => unreachable, - .unreach => unreachable, - .dead => unreachable, - .embedded_in_code => unreachable, - .memory => unreachable, - .compare_flags_signed => unreachable, - .compare_flags_unsigned => unreachable, + // Due to incremental compilation, how function calls are generated depends + // on linking. + if (self.bin_file.cast(link.File.Elf)) |elf_file| { + switch (arch) { + .x86_64 => { + for (info.args) |mc_arg, arg_i| { + const arg = inst.args[arg_i]; + const arg_mcv = try self.resolveInst(inst.args[arg_i]); + // Here we do not use setRegOrMem even though the logic is similar, because + // the function call will move the stack pointer, so the offsets are different. + switch (mc_arg) { + .none => continue, + .register => |reg| { + try self.genSetReg(arg.src, reg, arg_mcv); + // TODO interact with the register allocator to mark the instruction as moved. + }, + .stack_offset => { + // Here we need to emit instructions like this: + // mov qword ptr [rsp + stack_offset], x + return self.fail(inst.base.src, "TODO implement calling with parameters in memory", .{}); + }, + .ptr_stack_offset => { + return self.fail(inst.base.src, "TODO implement calling with MCValue.ptr_stack_offset arg", .{}); + }, + .ptr_embedded_in_code => { + return self.fail(inst.base.src, "TODO implement calling with MCValue.ptr_embedded_in_code arg", .{}); + }, + .undef => unreachable, + .immediate => unreachable, + .unreach => unreachable, + .dead => unreachable, + .embedded_in_code => unreachable, + .memory => unreachable, + .compare_flags_signed => unreachable, + .compare_flags_unsigned => unreachable, + } } - } - if (inst.func.cast(ir.Inst.Constant)) |func_inst| { - if (func_inst.val.cast(Value.Payload.Function)) |func_val| { - const func = func_val.func; - const got = &self.bin_file.program_headers.items[self.bin_file.phdr_got_index.?]; - const ptr_bits = self.target.cpu.arch.ptrBitWidth(); - const ptr_bytes: u64 = @divExact(ptr_bits, 8); - const got_addr = @intCast(u32, got.p_vaddr + func.owner_decl.link.elf.offset_table_index * ptr_bytes); - // ff 14 25 xx xx xx xx call [addr] - try self.code.ensureCapacity(self.code.items.len + 7); - self.code.appendSliceAssumeCapacity(&[3]u8{ 0xff, 0x14, 0x25 }); - mem.writeIntLittle(u32, self.code.addManyAsArrayAssumeCapacity(4), got_addr); + if (inst.func.cast(ir.Inst.Constant)) |func_inst| { + if (func_inst.val.cast(Value.Payload.Function)) |func_val| { + const func = func_val.func; + const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?]; + const ptr_bits = self.target.cpu.arch.ptrBitWidth(); + const ptr_bytes: u64 = @divExact(ptr_bits, 8); + const got_addr = @intCast(u32, got.p_vaddr + func.owner_decl.link.elf.offset_table_index * ptr_bytes); + // ff 14 25 xx xx xx xx call [addr] + try self.code.ensureCapacity(self.code.items.len + 7); + self.code.appendSliceAssumeCapacity(&[3]u8{ 0xff, 0x14, 0x25 }); + mem.writeIntLittle(u32, self.code.addManyAsArrayAssumeCapacity(4), got_addr); + } else { + return self.fail(inst.base.src, "TODO implement calling bitcasted functions", .{}); + } } else { - return self.fail(inst.base.src, "TODO implement calling bitcasted functions", .{}); + return self.fail(inst.base.src, "TODO implement calling runtime known function pointer", .{}); } - } else { - return self.fail(inst.base.src, "TODO implement calling runtime known function pointer", .{}); - } - }, - .riscv64 => { - if (info.args.len > 0) return self.fail(inst.base.src, "TODO implement fn args for {}", .{self.target.cpu.arch}); + }, + .riscv64 => { + if (info.args.len > 0) return self.fail(inst.base.src, "TODO implement fn args for {}", .{self.target.cpu.arch}); - if (inst.func.cast(ir.Inst.Constant)) |func_inst| { - if (func_inst.val.cast(Value.Payload.Function)) |func_val| { - const func = func_val.func; - const got = &self.bin_file.program_headers.items[self.bin_file.phdr_got_index.?]; - const ptr_bits = self.target.cpu.arch.ptrBitWidth(); - const ptr_bytes: u64 = @divExact(ptr_bits, 8); - const got_addr = @intCast(u32, got.p_vaddr + func.owner_decl.link.elf.offset_table_index * ptr_bytes); + if (inst.func.cast(ir.Inst.Constant)) |func_inst| { + if (func_inst.val.cast(Value.Payload.Function)) |func_val| { + const func = func_val.func; + const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?]; + const ptr_bits = self.target.cpu.arch.ptrBitWidth(); + const ptr_bytes: u64 = @divExact(ptr_bits, 8); + const got_addr = @intCast(u32, got.p_vaddr + func.owner_decl.link.elf.offset_table_index * ptr_bytes); - try self.genSetReg(inst.base.src, .ra, .{ .memory = got_addr }); - mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.jalr(.ra, 0, .ra).toU32()); + try self.genSetReg(inst.base.src, .ra, .{ .memory = got_addr }); + mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.jalr(.ra, 0, .ra).toU32()); + } else { + return self.fail(inst.base.src, "TODO implement calling bitcasted functions", .{}); + } } else { - return self.fail(inst.base.src, "TODO implement calling bitcasted functions", .{}); + return self.fail(inst.base.src, "TODO implement calling runtime known function pointer", .{}); } - } else { - return self.fail(inst.base.src, "TODO implement calling runtime known function pointer", .{}); - } - }, - else => return self.fail(inst.base.src, "TODO implement call for {}", .{self.target.cpu.arch}), + }, + else => return self.fail(inst.base.src, "TODO implement call for {}", .{self.target.cpu.arch}), + } + } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { + return self.fail(inst.base.src, "TODO implement codegen for call when linking with MachO", .{}); + } else { + unreachable; } return info.return_value; @@ -2036,10 +2043,14 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { switch (typed_value.ty.zigTypeTag()) { .Pointer => { if (typed_value.val.cast(Value.Payload.DeclRef)) |payload| { - const got = &self.bin_file.program_headers.items[self.bin_file.phdr_got_index.?]; - const decl = payload.decl; - const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes; - return MCValue{ .memory = got_addr }; + if (self.bin_file.cast(link.File.Elf)) |elf_file| { + const decl = payload.decl; + const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?]; + const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes; + return MCValue{ .memory = got_addr }; + } else { + return self.fail(src, "TODO codegen non-ELF const Decl pointer", .{}); + } } return self.fail(src, "TODO codegen more kinds of const pointers", .{}); }, @@ -2167,7 +2178,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { /// TODO support scope overrides. Also note this logic is duplicated with `Module.wantSafety`. fn wantSafety(self: *Self) bool { - return switch (self.bin_file.base.options.optimize_mode) { + return switch (self.bin_file.options.optimize_mode) { .Debug => true, .ReleaseSafe => true, .ReleaseFast => false, @@ -2178,7 +2189,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { fn fail(self: *Self, src: usize, comptime format: []const u8, args: anytype) InnerError { @setCold(true); assert(self.err_msg == null); - self.err_msg = try ErrorMsg.create(self.bin_file.base.allocator, src, format, args); + self.err_msg = try ErrorMsg.create(self.bin_file.allocator, src, format, args); return error.CodegenFail; } diff --git a/src-self-hosted/link.zig b/src-self-hosted/link.zig index 39e6d27c58..1e650d5e2c 100644 --- a/src-self-hosted/link.zig +++ b/src-self-hosted/link.zig @@ -1,28 +1,10 @@ const std = @import("std"); -const mem = std.mem; -const assert = std.debug.assert; const Allocator = std.mem.Allocator; -const ir = @import("ir.zig"); const Module = @import("Module.zig"); const fs = std.fs; -const elf = std.elf; -const codegen = @import("codegen.zig"); -const c_codegen = @import("codegen/c.zig"); -const log = std.log.scoped(.link); -const DW = std.dwarf; const trace = @import("tracy.zig").trace; -const leb128 = std.debug.leb; const Package = @import("Package.zig"); -const Value = @import("value.zig").Value; const Type = @import("type.zig").Type; -const build_options = @import("build_options"); - -const producer_string = if (std.builtin.is_test) "zig test" else "zig " ++ build_options.version; - -// TODO Turn back on zig fmt when https://github.com/ziglang/zig/issues/5948 is implemented. -// zig fmt: off - -const default_entry_addr = 0x8000000; pub const Options = struct { target: std.Target, @@ -41,6 +23,11 @@ pub const Options = struct { }; pub const File = struct { + tag: Tag, + options: Options, + file: ?fs.File, + allocator: *Allocator, + pub const LinkBlock = union { elf: Elf.TextBlock, macho: MachO.TextBlock, @@ -55,16 +42,24 @@ pub const File = struct { wasm: ?Wasm.FnData, }; - tag: Tag, - options: Options, - file: ?fs.File, - allocator: *Allocator, + /// For DWARF .debug_info. + pub const DbgInfoTypeRelocsTable = std.HashMapUnmanaged(Type, DbgInfoTypeReloc, Type.hash, Type.eql, true); + + /// For DWARF .debug_info. + pub const DbgInfoTypeReloc = struct { + /// Offset from `TextBlock.dbg_info_off` (the buffer that is local to a Decl). + /// This is where the .debug_info tag for the type is. + off: u32, + /// Offset from `TextBlock.dbg_info_off` (the buffer that is local to a Decl). + /// List of DW.AT_type / DW.FORM_ref4 that points to the type. + relocs: std.ArrayListUnmanaged(u32), + }; /// Attempts incremental linking, if the file already exists. If /// incremental linking fails, falls back to truncating the file and /// rewriting it. A malicious file is detected as incremental link failure /// and does not cause Illegal Behavior. This operation is not atomic. - pub fn openPath(allocator: *Allocator, dir: fs.Dir, sub_path: []const u8, options: Options) !*File { + pub fn openPath(allocator: *Allocator, dir: fs.Dir, sub_path: []const u8, options: Options) !*File { switch (options.object_format) { .unknown => unreachable, .coff => return error.TODOImplementCoff, @@ -219,6 +214,15 @@ pub const File = struct { } } + pub fn getDeclVAddr(base: *File, decl: *const Module.Decl) u64 { + switch (base.tag) { + .elf => return @fieldParentPtr(Elf, "base", base).getDeclVAddr(decl), + .macho => return @fieldParentPtr(MachO, "base", base).getDeclVAddr(decl), + .c => unreachable, + .wasm => unreachable, + } + } + pub const Tag = enum { elf, macho, @@ -230,2670 +234,12 @@ pub const File = struct { no_entry_point_found: bool = false, }; - pub const C = struct { - pub const base_tag: Tag = .c; - - base: File, - - header: std.ArrayList(u8), - constants: std.ArrayList(u8), - main: std.ArrayList(u8), - - called: std.StringHashMap(void), - need_stddef: bool = false, - need_stdint: bool = false, - error_msg: *Module.ErrorMsg = undefined, - - pub fn openPath(allocator: *Allocator, dir: fs.Dir, sub_path: []const u8, options: Options) !*File { - assert(options.object_format == .c); - - const file = try dir.createFile(sub_path, .{ .truncate = true, .read = true, .mode = determineMode(options) }); - errdefer file.close(); - - var c_file = try allocator.create(C); - errdefer allocator.destroy(c_file); - - c_file.* = File.C{ - .base = .{ - .tag = .c, - .options = options, - .file = file, - .allocator = allocator, - }, - .main = std.ArrayList(u8).init(allocator), - .header = std.ArrayList(u8).init(allocator), - .constants = std.ArrayList(u8).init(allocator), - .called = std.StringHashMap(void).init(allocator), - }; - - return &c_file.base; - } - - pub fn fail(self: *C, src: usize, comptime format: []const u8, args: anytype) error{AnalysisFail, OutOfMemory} { - self.error_msg = try Module.ErrorMsg.create(self.base.allocator, src, format, args); - return error.AnalysisFail; - } - - pub fn deinit(self: *File.C) void { - self.main.deinit(); - self.header.deinit(); - self.constants.deinit(); - self.called.deinit(); - } - - pub fn updateDecl(self: *File.C, module: *Module, decl: *Module.Decl) !void { - c_codegen.generate(self, decl) catch |err| { - if (err == error.AnalysisFail) { - try module.failed_decls.put(module.gpa, decl, self.error_msg); - } - return err; - }; - } - - pub fn flush(self: *File.C, module: *Module) !void { - const writer = self.base.file.?.writer(); - try writer.writeAll(@embedFile("cbe.h")); - var includes = false; - if (self.need_stddef) { - try writer.writeAll("#include \n"); - includes = true; - } - if (self.need_stdint) { - try writer.writeAll("#include \n"); - includes = true; - } - if (includes) { - try writer.writeByte('\n'); - } - if (self.header.items.len > 0) { - try writer.print("{}\n", .{self.header.items}); - } - if (self.constants.items.len > 0) { - try writer.print("{}\n", .{self.constants.items}); - } - if (self.main.items.len > 1) { - const last_two = self.main.items[self.main.items.len - 2 ..]; - if (std.mem.eql(u8, last_two, "\n\n")) { - self.main.items.len -= 1; - } - } - try writer.writeAll(self.main.items); - self.base.file.?.close(); - self.base.file = null; - } - }; - - pub const Elf = struct { - pub const base_tag: Tag = .elf; - - base: File, - - ptr_width: enum { p32, p64 }, - - /// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write. - /// Same order as in the file. - sections: std.ArrayListUnmanaged(elf.Elf64_Shdr) = std.ArrayListUnmanaged(elf.Elf64_Shdr){}, - shdr_table_offset: ?u64 = null, - - /// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write. - /// Same order as in the file. - program_headers: std.ArrayListUnmanaged(elf.Elf64_Phdr) = std.ArrayListUnmanaged(elf.Elf64_Phdr){}, - phdr_table_offset: ?u64 = null, - /// The index into the program headers of a PT_LOAD program header with Read and Execute flags - phdr_load_re_index: ?u16 = null, - /// The index into the program headers of the global offset table. - /// It needs PT_LOAD and Read flags. - phdr_got_index: ?u16 = null, - entry_addr: ?u64 = null, - - debug_strtab: std.ArrayListUnmanaged(u8) = std.ArrayListUnmanaged(u8){}, - shstrtab: std.ArrayListUnmanaged(u8) = std.ArrayListUnmanaged(u8){}, - shstrtab_index: ?u16 = null, - - text_section_index: ?u16 = null, - symtab_section_index: ?u16 = null, - got_section_index: ?u16 = null, - debug_info_section_index: ?u16 = null, - debug_abbrev_section_index: ?u16 = null, - debug_str_section_index: ?u16 = null, - debug_aranges_section_index: ?u16 = null, - debug_line_section_index: ?u16 = null, - - debug_abbrev_table_offset: ?u64 = null, - - /// The same order as in the file. ELF requires global symbols to all be after the - /// local symbols, they cannot be mixed. So we must buffer all the global symbols and - /// write them at the end. These are only the local symbols. The length of this array - /// is the value used for sh_info in the .symtab section. - local_symbols: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{}, - global_symbols: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{}, - - local_symbol_free_list: std.ArrayListUnmanaged(u32) = .{}, - global_symbol_free_list: std.ArrayListUnmanaged(u32) = .{}, - offset_table_free_list: std.ArrayListUnmanaged(u32) = .{}, - - /// Same order as in the file. The value is the absolute vaddr value. - /// If the vaddr of the executable program header changes, the entire - /// offset table needs to be rewritten. - offset_table: std.ArrayListUnmanaged(u64) = .{}, - - phdr_table_dirty: bool = false, - shdr_table_dirty: bool = false, - shstrtab_dirty: bool = false, - debug_strtab_dirty: bool = false, - offset_table_count_dirty: bool = false, - debug_abbrev_section_dirty: bool = false, - debug_aranges_section_dirty: bool = false, - - debug_info_header_dirty: bool = false, - debug_line_header_dirty: bool = false, - - error_flags: ErrorFlags = ErrorFlags{}, - - /// A list of text blocks that have surplus capacity. This list can have false - /// positives, as functions grow and shrink over time, only sometimes being added - /// or removed from the freelist. - /// - /// A text block has surplus capacity when its overcapacity value is greater than - /// minimum_text_block_size * alloc_num / alloc_den. That is, when it has so - /// much extra capacity, that we could fit a small new symbol in it, itself with - /// ideal_capacity or more. - /// - /// Ideal capacity is defined by size * alloc_num / alloc_den. - /// - /// Overcapacity is measured by actual_capacity - ideal_capacity. Note that - /// overcapacity can be negative. A simple way to have negative overcapacity is to - /// allocate a fresh text block, which will have ideal capacity, and then grow it - /// by 1 byte. It will then have -1 overcapacity. - text_block_free_list: std.ArrayListUnmanaged(*TextBlock) = .{}, - last_text_block: ?*TextBlock = null, - - /// A list of `SrcFn` whose Line Number Programs have surplus capacity. - /// This is the same concept as `text_block_free_list`; see those doc comments. - dbg_line_fn_free_list: std.AutoHashMapUnmanaged(*SrcFn, void) = .{}, - dbg_line_fn_first: ?*SrcFn = null, - dbg_line_fn_last: ?*SrcFn = null, - - /// A list of `TextBlock` whose corresponding .debug_info tags have surplus capacity. - /// This is the same concept as `text_block_free_list`; see those doc comments. - dbg_info_decl_free_list: std.AutoHashMapUnmanaged(*TextBlock, void) = .{}, - dbg_info_decl_first: ?*TextBlock = null, - dbg_info_decl_last: ?*TextBlock = null, - - /// `alloc_num / alloc_den` is the factor of padding when allocating. - const alloc_num = 4; - const alloc_den = 3; - - /// In order for a slice of bytes to be considered eligible to keep metadata pointing at - /// it as a possible place to put new symbols, it must have enough room for this many bytes - /// (plus extra for reserved capacity). - const minimum_text_block_size = 64; - const min_text_capacity = minimum_text_block_size * alloc_num / alloc_den; - - pub const DbgInfoTypeRelocsTable = std.HashMapUnmanaged(Type, DbgInfoTypeReloc, Type.hash, Type.eql, true); - - const DbgInfoTypeReloc = struct { - /// Offset from `TextBlock.dbg_info_off` (the buffer that is local to a Decl). - /// This is where the .debug_info tag for the type is. - off: u32, - /// Offset from `TextBlock.dbg_info_off` (the buffer that is local to a Decl). - /// List of DW.AT_type / DW.FORM_ref4 that points to the type. - relocs: std.ArrayListUnmanaged(u32), - }; - - pub const TextBlock = struct { - /// Each decl always gets a local symbol with the fully qualified name. - /// The vaddr and size are found here directly. - /// The file offset is found by computing the vaddr offset from the section vaddr - /// the symbol references, and adding that to the file offset of the section. - /// If this field is 0, it means the codegen size = 0 and there is no symbol or - /// offset table entry. - local_sym_index: u32, - /// This field is undefined for symbols with size = 0. - offset_table_index: u32, - /// Points to the previous and next neighbors, based on the `text_offset`. - /// This can be used to find, for example, the capacity of this `TextBlock`. - prev: ?*TextBlock, - next: ?*TextBlock, - - /// Previous/next linked list pointers. This value is `next ^ prev`. - /// This is the linked list node for this Decl's corresponding .debug_info tag. - dbg_info_prev: ?*TextBlock, - dbg_info_next: ?*TextBlock, - /// Offset into .debug_info pointing to the tag for this Decl. - dbg_info_off: u32, - /// Size of the .debug_info tag for this Decl, not including padding. - dbg_info_len: u32, - - pub const empty = TextBlock{ - .local_sym_index = 0, - .offset_table_index = undefined, - .prev = null, - .next = null, - .dbg_info_prev = null, - .dbg_info_next = null, - .dbg_info_off = undefined, - .dbg_info_len = undefined, - }; - - /// Returns how much room there is to grow in virtual address space. - /// File offset relocation happens transparently, so it is not included in - /// this calculation. - fn capacity(self: TextBlock, elf_file: Elf) u64 { - const self_sym = elf_file.local_symbols.items[self.local_sym_index]; - if (self.next) |next| { - const next_sym = elf_file.local_symbols.items[next.local_sym_index]; - return next_sym.st_value - self_sym.st_value; - } else { - // We are the last block. The capacity is limited only by virtual address space. - return std.math.maxInt(u32) - self_sym.st_value; - } - } - - fn freeListEligible(self: TextBlock, elf_file: Elf) bool { - // No need to keep a free list node for the last block. - const next = self.next orelse return false; - const self_sym = elf_file.local_symbols.items[self.local_sym_index]; - const next_sym = elf_file.local_symbols.items[next.local_sym_index]; - const cap = next_sym.st_value - self_sym.st_value; - const ideal_cap = self_sym.st_size * alloc_num / alloc_den; - if (cap <= ideal_cap) return false; - const surplus = cap - ideal_cap; - return surplus >= min_text_capacity; - } - }; - - pub const Export = struct { - sym_index: ?u32 = null, - }; - - pub const SrcFn = struct { - /// Offset from the beginning of the Debug Line Program header that contains this function. - off: u32, - /// Size of the line number program component belonging to this function, not - /// including padding. - len: u32, - - /// Points to the previous and next neighbors, based on the offset from .debug_line. - /// This can be used to find, for example, the capacity of this `SrcFn`. - prev: ?*SrcFn, - next: ?*SrcFn, - - pub const empty: SrcFn = .{ - .off = 0, - .len = 0, - .prev = null, - .next = null, - }; - }; - - pub fn openPath(allocator: *Allocator, dir: fs.Dir, sub_path: []const u8, options: Options) !*File { - assert(options.object_format == .elf); - - const file = try dir.createFile(sub_path, .{ .truncate = false, .read = true, .mode = determineMode(options) }); - errdefer file.close(); - - var elf_file = try allocator.create(Elf); - errdefer allocator.destroy(elf_file); - - elf_file.* = openFile(allocator, file, options) catch |err| switch (err) { - error.IncrFailed => try createFile(allocator, file, options), - else => |e| return e, - }; - - return &elf_file.base; - } - - /// Returns error.IncrFailed if incremental update could not be performed. - fn openFile(allocator: *Allocator, file: fs.File, options: Options) !Elf { - switch (options.output_mode) { - .Exe => {}, - .Obj => {}, - .Lib => return error.IncrFailed, - } - var self: Elf = .{ - .base = .{ - .file = file, - .tag = .elf, - .options = options, - .allocator = allocator, - }, - .ptr_width = switch (options.target.cpu.arch.ptrBitWidth()) { - 32 => .p32, - 64 => .p64, - else => return error.UnsupportedELFArchitecture, - }, - }; - errdefer self.deinit(); - - // TODO implement reading the elf file - return error.IncrFailed; - //try self.populateMissingMetadata(); - //return self; - } - - /// Truncates the existing file contents and overwrites the contents. - /// Returns an error if `file` is not already open with +read +write +seek abilities. - fn createFile(allocator: *Allocator, file: fs.File, options: Options) !Elf { - switch (options.output_mode) { - .Exe => {}, - .Obj => {}, - .Lib => return error.TODOImplementWritingLibFiles, - } - var self: Elf = .{ - .base = .{ - .tag = .elf, - .options = options, - .allocator = allocator, - .file = file, - }, - .ptr_width = switch (options.target.cpu.arch.ptrBitWidth()) { - 32 => .p32, - 64 => .p64, - else => return error.UnsupportedELFArchitecture, - }, - .shdr_table_dirty = true, - }; - errdefer self.deinit(); - - // Index 0 is always a null symbol. - try self.local_symbols.append(allocator, .{ - .st_name = 0, - .st_info = 0, - .st_other = 0, - .st_shndx = 0, - .st_value = 0, - .st_size = 0, - }); - - // There must always be a null section in index 0 - try self.sections.append(allocator, .{ - .sh_name = 0, - .sh_type = elf.SHT_NULL, - .sh_flags = 0, - .sh_addr = 0, - .sh_offset = 0, - .sh_size = 0, - .sh_link = 0, - .sh_info = 0, - .sh_addralign = 0, - .sh_entsize = 0, - }); - - try self.populateMissingMetadata(); - - return self; - } - - pub fn deinit(self: *Elf) void { - self.sections.deinit(self.base.allocator); - self.program_headers.deinit(self.base.allocator); - self.shstrtab.deinit(self.base.allocator); - self.debug_strtab.deinit(self.base.allocator); - self.local_symbols.deinit(self.base.allocator); - self.global_symbols.deinit(self.base.allocator); - self.global_symbol_free_list.deinit(self.base.allocator); - self.local_symbol_free_list.deinit(self.base.allocator); - self.offset_table_free_list.deinit(self.base.allocator); - self.text_block_free_list.deinit(self.base.allocator); - self.dbg_line_fn_free_list.deinit(self.base.allocator); - self.dbg_info_decl_free_list.deinit(self.base.allocator); - self.offset_table.deinit(self.base.allocator); - } - - fn getDebugLineProgramOff(self: Elf) u32 { - return self.dbg_line_fn_first.?.off; - } - - fn getDebugLineProgramEnd(self: Elf) u32 { - return self.dbg_line_fn_last.?.off + self.dbg_line_fn_last.?.len; - } - - /// Returns end pos of collision, if any. - fn detectAllocCollision(self: *Elf, start: u64, size: u64) ?u64 { - const small_ptr = self.base.options.target.cpu.arch.ptrBitWidth() == 32; - const ehdr_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Ehdr) else @sizeOf(elf.Elf64_Ehdr); - if (start < ehdr_size) - return ehdr_size; - - const end = start + satMul(size, alloc_num) / alloc_den; - - if (self.shdr_table_offset) |off| { - const shdr_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Shdr) else @sizeOf(elf.Elf64_Shdr); - const tight_size = self.sections.items.len * shdr_size; - const increased_size = satMul(tight_size, alloc_num) / alloc_den; - const test_end = off + increased_size; - if (end > off and start < test_end) { - return test_end; - } - } - - if (self.phdr_table_offset) |off| { - const phdr_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Phdr) else @sizeOf(elf.Elf64_Phdr); - const tight_size = self.sections.items.len * phdr_size; - const increased_size = satMul(tight_size, alloc_num) / alloc_den; - const test_end = off + increased_size; - if (end > off and start < test_end) { - return test_end; - } - } - - for (self.sections.items) |section| { - const increased_size = satMul(section.sh_size, alloc_num) / alloc_den; - const test_end = section.sh_offset + increased_size; - if (end > section.sh_offset and start < test_end) { - return test_end; - } - } - for (self.program_headers.items) |program_header| { - const increased_size = satMul(program_header.p_filesz, alloc_num) / alloc_den; - const test_end = program_header.p_offset + increased_size; - if (end > program_header.p_offset and start < test_end) { - return test_end; - } - } - return null; - } - - fn allocatedSize(self: *Elf, start: u64) u64 { - if (start == 0) - return 0; - var min_pos: u64 = std.math.maxInt(u64); - if (self.shdr_table_offset) |off| { - if (off > start and off < min_pos) min_pos = off; - } - if (self.phdr_table_offset) |off| { - if (off > start and off < min_pos) min_pos = off; - } - for (self.sections.items) |section| { - if (section.sh_offset <= start) continue; - if (section.sh_offset < min_pos) min_pos = section.sh_offset; - } - for (self.program_headers.items) |program_header| { - if (program_header.p_offset <= start) continue; - if (program_header.p_offset < min_pos) min_pos = program_header.p_offset; - } - return min_pos - start; - } - - fn findFreeSpace(self: *Elf, object_size: u64, min_alignment: u16) u64 { - var start: u64 = 0; - while (self.detectAllocCollision(start, object_size)) |item_end| { - start = mem.alignForwardGeneric(u64, item_end, min_alignment); - } - return start; - } - - /// TODO Improve this to use a table. - fn makeString(self: *Elf, bytes: []const u8) !u32 { - try self.shstrtab.ensureCapacity(self.base.allocator, self.shstrtab.items.len + bytes.len + 1); - const result = self.shstrtab.items.len; - self.shstrtab.appendSliceAssumeCapacity(bytes); - self.shstrtab.appendAssumeCapacity(0); - return @intCast(u32, result); - } - - /// TODO Improve this to use a table. - fn makeDebugString(self: *Elf, bytes: []const u8) !u32 { - try self.debug_strtab.ensureCapacity(self.base.allocator, self.debug_strtab.items.len + bytes.len + 1); - const result = self.debug_strtab.items.len; - self.debug_strtab.appendSliceAssumeCapacity(bytes); - self.debug_strtab.appendAssumeCapacity(0); - return @intCast(u32, result); - } - - fn getString(self: *Elf, str_off: u32) []const u8 { - assert(str_off < self.shstrtab.items.len); - return mem.spanZ(@ptrCast([*:0]const u8, self.shstrtab.items.ptr + str_off)); - } - - fn updateString(self: *Elf, old_str_off: u32, new_name: []const u8) !u32 { - const existing_name = self.getString(old_str_off); - if (mem.eql(u8, existing_name, new_name)) { - return old_str_off; - } - return self.makeString(new_name); - } - - pub fn populateMissingMetadata(self: *Elf) !void { - const small_ptr = switch (self.ptr_width) { - .p32 => true, - .p64 => false, - }; - const ptr_size: u8 = self.ptrWidthBytes(); - if (self.phdr_load_re_index == null) { - self.phdr_load_re_index = @intCast(u16, self.program_headers.items.len); - const file_size = self.base.options.program_code_size_hint; - const p_align = 0x1000; - const off = self.findFreeSpace(file_size, p_align); - log.debug("found PT_LOAD free space 0x{x} to 0x{x}\n", .{ off, off + file_size }); - try self.program_headers.append(self.base.allocator, .{ - .p_type = elf.PT_LOAD, - .p_offset = off, - .p_filesz = file_size, - .p_vaddr = default_entry_addr, - .p_paddr = default_entry_addr, - .p_memsz = file_size, - .p_align = p_align, - .p_flags = elf.PF_X | elf.PF_R, - }); - self.entry_addr = null; - self.phdr_table_dirty = true; - } - if (self.phdr_got_index == null) { - self.phdr_got_index = @intCast(u16, self.program_headers.items.len); - const file_size = @as(u64, ptr_size) * self.base.options.symbol_count_hint; - // We really only need ptr alignment but since we are using PROGBITS, linux requires - // page align. - const p_align = if (self.base.options.target.os.tag == .linux) 0x1000 else @as(u16, ptr_size); - const off = self.findFreeSpace(file_size, p_align); - log.debug("found PT_LOAD free space 0x{x} to 0x{x}\n", .{ off, off + file_size }); - // TODO instead of hard coding the vaddr, make a function to find a vaddr to put things at. - // we'll need to re-use that function anyway, in case the GOT grows and overlaps something - // else in virtual memory. - const default_got_addr = if (ptr_size == 2) @as(u32, 0x8000) else 0x4000000; - try self.program_headers.append(self.base.allocator, .{ - .p_type = elf.PT_LOAD, - .p_offset = off, - .p_filesz = file_size, - .p_vaddr = default_got_addr, - .p_paddr = default_got_addr, - .p_memsz = file_size, - .p_align = p_align, - .p_flags = elf.PF_R, - }); - self.phdr_table_dirty = true; - } - if (self.shstrtab_index == null) { - self.shstrtab_index = @intCast(u16, self.sections.items.len); - assert(self.shstrtab.items.len == 0); - try self.shstrtab.append(self.base.allocator, 0); // need a 0 at position 0 - const off = self.findFreeSpace(self.shstrtab.items.len, 1); - log.debug("found shstrtab free space 0x{x} to 0x{x}\n", .{ off, off + self.shstrtab.items.len }); - try self.sections.append(self.base.allocator, .{ - .sh_name = try self.makeString(".shstrtab"), - .sh_type = elf.SHT_STRTAB, - .sh_flags = 0, - .sh_addr = 0, - .sh_offset = off, - .sh_size = self.shstrtab.items.len, - .sh_link = 0, - .sh_info = 0, - .sh_addralign = 1, - .sh_entsize = 0, - }); - self.shstrtab_dirty = true; - self.shdr_table_dirty = true; - } - if (self.text_section_index == null) { - self.text_section_index = @intCast(u16, self.sections.items.len); - const phdr = &self.program_headers.items[self.phdr_load_re_index.?]; - - try self.sections.append(self.base.allocator, .{ - .sh_name = try self.makeString(".text"), - .sh_type = elf.SHT_PROGBITS, - .sh_flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR, - .sh_addr = phdr.p_vaddr, - .sh_offset = phdr.p_offset, - .sh_size = phdr.p_filesz, - .sh_link = 0, - .sh_info = 0, - .sh_addralign = phdr.p_align, - .sh_entsize = 0, - }); - self.shdr_table_dirty = true; - } - if (self.got_section_index == null) { - self.got_section_index = @intCast(u16, self.sections.items.len); - const phdr = &self.program_headers.items[self.phdr_got_index.?]; - - try self.sections.append(self.base.allocator, .{ - .sh_name = try self.makeString(".got"), - .sh_type = elf.SHT_PROGBITS, - .sh_flags = elf.SHF_ALLOC, - .sh_addr = phdr.p_vaddr, - .sh_offset = phdr.p_offset, - .sh_size = phdr.p_filesz, - .sh_link = 0, - .sh_info = 0, - .sh_addralign = phdr.p_align, - .sh_entsize = 0, - }); - self.shdr_table_dirty = true; - } - if (self.symtab_section_index == null) { - self.symtab_section_index = @intCast(u16, self.sections.items.len); - const min_align: u16 = if (small_ptr) @alignOf(elf.Elf32_Sym) else @alignOf(elf.Elf64_Sym); - const each_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Sym) else @sizeOf(elf.Elf64_Sym); - const file_size = self.base.options.symbol_count_hint * each_size; - const off = self.findFreeSpace(file_size, min_align); - log.debug("found symtab free space 0x{x} to 0x{x}\n", .{ off, off + file_size }); - - try self.sections.append(self.base.allocator, .{ - .sh_name = try self.makeString(".symtab"), - .sh_type = elf.SHT_SYMTAB, - .sh_flags = 0, - .sh_addr = 0, - .sh_offset = off, - .sh_size = file_size, - // The section header index of the associated string table. - .sh_link = self.shstrtab_index.?, - .sh_info = @intCast(u32, self.local_symbols.items.len), - .sh_addralign = min_align, - .sh_entsize = each_size, - }); - self.shdr_table_dirty = true; - try self.writeSymbol(0); - } - if (self.debug_str_section_index == null) { - self.debug_str_section_index = @intCast(u16, self.sections.items.len); - assert(self.debug_strtab.items.len == 0); - try self.sections.append(self.base.allocator, .{ - .sh_name = try self.makeString(".debug_str"), - .sh_type = elf.SHT_PROGBITS, - .sh_flags = elf.SHF_MERGE | elf.SHF_STRINGS, - .sh_addr = 0, - .sh_offset = 0, - .sh_size = self.debug_strtab.items.len, - .sh_link = 0, - .sh_info = 0, - .sh_addralign = 1, - .sh_entsize = 1, - }); - self.debug_strtab_dirty = true; - self.shdr_table_dirty = true; - } - if (self.debug_info_section_index == null) { - self.debug_info_section_index = @intCast(u16, self.sections.items.len); - - const file_size_hint = 200; - const p_align = 1; - const off = self.findFreeSpace(file_size_hint, p_align); - log.debug("found .debug_info free space 0x{x} to 0x{x}\n", .{ - off, - off + file_size_hint, - }); - try self.sections.append(self.base.allocator, .{ - .sh_name = try self.makeString(".debug_info"), - .sh_type = elf.SHT_PROGBITS, - .sh_flags = 0, - .sh_addr = 0, - .sh_offset = off, - .sh_size = file_size_hint, - .sh_link = 0, - .sh_info = 0, - .sh_addralign = p_align, - .sh_entsize = 0, - }); - self.shdr_table_dirty = true; - self.debug_info_header_dirty = true; - } - if (self.debug_abbrev_section_index == null) { - self.debug_abbrev_section_index = @intCast(u16, self.sections.items.len); - - const file_size_hint = 128; - const p_align = 1; - const off = self.findFreeSpace(file_size_hint, p_align); - log.debug("found .debug_abbrev free space 0x{x} to 0x{x}\n", .{ - off, - off + file_size_hint, - }); - try self.sections.append(self.base.allocator, .{ - .sh_name = try self.makeString(".debug_abbrev"), - .sh_type = elf.SHT_PROGBITS, - .sh_flags = 0, - .sh_addr = 0, - .sh_offset = off, - .sh_size = file_size_hint, - .sh_link = 0, - .sh_info = 0, - .sh_addralign = p_align, - .sh_entsize = 0, - }); - self.shdr_table_dirty = true; - self.debug_abbrev_section_dirty = true; - } - if (self.debug_aranges_section_index == null) { - self.debug_aranges_section_index = @intCast(u16, self.sections.items.len); - - const file_size_hint = 160; - const p_align = 16; - const off = self.findFreeSpace(file_size_hint, p_align); - log.debug("found .debug_aranges free space 0x{x} to 0x{x}\n", .{ - off, - off + file_size_hint, - }); - try self.sections.append(self.base.allocator, .{ - .sh_name = try self.makeString(".debug_aranges"), - .sh_type = elf.SHT_PROGBITS, - .sh_flags = 0, - .sh_addr = 0, - .sh_offset = off, - .sh_size = file_size_hint, - .sh_link = 0, - .sh_info = 0, - .sh_addralign = p_align, - .sh_entsize = 0, - }); - self.shdr_table_dirty = true; - self.debug_aranges_section_dirty = true; - } - if (self.debug_line_section_index == null) { - self.debug_line_section_index = @intCast(u16, self.sections.items.len); - - const file_size_hint = 250; - const p_align = 1; - const off = self.findFreeSpace(file_size_hint, p_align); - log.debug("found .debug_line free space 0x{x} to 0x{x}\n", .{ - off, - off + file_size_hint, - }); - try self.sections.append(self.base.allocator, .{ - .sh_name = try self.makeString(".debug_line"), - .sh_type = elf.SHT_PROGBITS, - .sh_flags = 0, - .sh_addr = 0, - .sh_offset = off, - .sh_size = file_size_hint, - .sh_link = 0, - .sh_info = 0, - .sh_addralign = p_align, - .sh_entsize = 0, - }); - self.shdr_table_dirty = true; - self.debug_line_header_dirty = true; - } - const shsize: u64 = switch (self.ptr_width) { - .p32 => @sizeOf(elf.Elf32_Shdr), - .p64 => @sizeOf(elf.Elf64_Shdr), - }; - const shalign: u16 = switch (self.ptr_width) { - .p32 => @alignOf(elf.Elf32_Shdr), - .p64 => @alignOf(elf.Elf64_Shdr), - }; - if (self.shdr_table_offset == null) { - self.shdr_table_offset = self.findFreeSpace(self.sections.items.len * shsize, shalign); - self.shdr_table_dirty = true; - } - const phsize: u64 = switch (self.ptr_width) { - .p32 => @sizeOf(elf.Elf32_Phdr), - .p64 => @sizeOf(elf.Elf64_Phdr), - }; - const phalign: u16 = switch (self.ptr_width) { - .p32 => @alignOf(elf.Elf32_Phdr), - .p64 => @alignOf(elf.Elf64_Phdr), - }; - if (self.phdr_table_offset == null) { - self.phdr_table_offset = self.findFreeSpace(self.program_headers.items.len * phsize, phalign); - self.phdr_table_dirty = true; - } - { - // Iterate over symbols, populating free_list and last_text_block. - if (self.local_symbols.items.len != 1) { - @panic("TODO implement setting up free_list and last_text_block from existing ELF file"); - } - // We are starting with an empty file. The default values are correct, null and empty list. - } - } - - pub const abbrev_compile_unit = 1; - pub const abbrev_subprogram = 2; - pub const abbrev_subprogram_retvoid = 3; - pub const abbrev_base_type = 4; - pub const abbrev_pad1 = 5; - pub const abbrev_parameter = 6; - - /// Commit pending changes and write headers. - pub fn flush(self: *Elf, module: *Module) !void { - const target_endian = self.base.options.target.cpu.arch.endian(); - const foreign_endian = target_endian != std.Target.current.cpu.arch.endian(); - const ptr_width_bytes: u8 = self.ptrWidthBytes(); - const init_len_size: usize = switch (self.ptr_width) { - .p32 => 4, - .p64 => 12, - }; - - // Unfortunately these have to be buffered and done at the end because ELF does not allow - // mixing local and global symbols within a symbol table. - try self.writeAllGlobalSymbols(); - - if (self.debug_abbrev_section_dirty) { - const debug_abbrev_sect = &self.sections.items[self.debug_abbrev_section_index.?]; - - // These are LEB encoded but since the values are all less than 127 - // we can simply append these bytes. - const abbrev_buf = [_]u8{ - abbrev_compile_unit, DW.TAG_compile_unit, DW.CHILDREN_yes, // header - DW.AT_stmt_list, DW.FORM_sec_offset, - DW.AT_low_pc , DW.FORM_addr, - DW.AT_high_pc , DW.FORM_addr, - DW.AT_name , DW.FORM_strp, - DW.AT_comp_dir , DW.FORM_strp, - DW.AT_producer , DW.FORM_strp, - DW.AT_language , DW.FORM_data2, - 0, 0, // table sentinel - - abbrev_subprogram, DW.TAG_subprogram, DW.CHILDREN_yes, // header - DW.AT_low_pc , DW.FORM_addr, - DW.AT_high_pc , DW.FORM_data4, - DW.AT_type , DW.FORM_ref4, - DW.AT_name , DW.FORM_string, - 0, 0, // table sentinel - - abbrev_subprogram_retvoid, DW.TAG_subprogram, DW.CHILDREN_yes, // header - DW.AT_low_pc , DW.FORM_addr, - DW.AT_high_pc , DW.FORM_data4, - DW.AT_name , DW.FORM_string, - 0, 0, // table sentinel - - abbrev_base_type, DW.TAG_base_type, DW.CHILDREN_no, // header - DW.AT_encoding , DW.FORM_data1, - DW.AT_byte_size, DW.FORM_data1, - DW.AT_name , DW.FORM_string, - 0, 0, // table sentinel - - abbrev_pad1, DW.TAG_unspecified_type, DW.CHILDREN_no, // header - 0, 0, // table sentinel - - abbrev_parameter, DW.TAG_formal_parameter, DW.CHILDREN_no, // header - DW.AT_location , DW.FORM_exprloc, - DW.AT_type , DW.FORM_ref4, - DW.AT_name , DW.FORM_string, - 0, 0, // table sentinel - - 0, 0, 0, // section sentinel - }; - - const needed_size = abbrev_buf.len; - const allocated_size = self.allocatedSize(debug_abbrev_sect.sh_offset); - if (needed_size > allocated_size) { - debug_abbrev_sect.sh_size = 0; // free the space - debug_abbrev_sect.sh_offset = self.findFreeSpace(needed_size, 1); - } - debug_abbrev_sect.sh_size = needed_size; - log.debug(".debug_abbrev start=0x{x} end=0x{x}\n", .{ - debug_abbrev_sect.sh_offset, - debug_abbrev_sect.sh_offset + needed_size, - }); - - const abbrev_offset = 0; - self.debug_abbrev_table_offset = abbrev_offset; - try self.base.file.?.pwriteAll(&abbrev_buf, debug_abbrev_sect.sh_offset + abbrev_offset); - if (!self.shdr_table_dirty) { - // Then it won't get written with the others and we need to do it. - try self.writeSectHeader(self.debug_abbrev_section_index.?); - } - - self.debug_abbrev_section_dirty = false; - } - - if (self.debug_info_header_dirty) debug_info: { - // If this value is null it means there is an error in the module; - // leave debug_info_header_dirty=true. - const first_dbg_info_decl = self.dbg_info_decl_first orelse break :debug_info; - const last_dbg_info_decl = self.dbg_info_decl_last.?; - const debug_info_sect = &self.sections.items[self.debug_info_section_index.?]; - - var di_buf = std.ArrayList(u8).init(self.base.allocator); - defer di_buf.deinit(); - - // We have a function to compute the upper bound size, because it's needed - // for determining where to put the offset of the first `LinkBlock`. - try di_buf.ensureCapacity(self.dbgInfoNeededHeaderBytes()); - - // initial length - length of the .debug_info contribution for this compilation unit, - // not including the initial length itself. - // We have to come back and write it later after we know the size. - const after_init_len = di_buf.items.len + init_len_size; - // +1 for the final 0 that ends the compilation unit children. - const dbg_info_end = last_dbg_info_decl.dbg_info_off + last_dbg_info_decl.dbg_info_len + 1; - const init_len = dbg_info_end - after_init_len; - switch (self.ptr_width) { - .p32 => { - mem.writeInt(u32, di_buf.addManyAsArrayAssumeCapacity(4), @intCast(u32, init_len), target_endian); - }, - .p64 => { - di_buf.appendNTimesAssumeCapacity(0xff, 4); - mem.writeInt(u64, di_buf.addManyAsArrayAssumeCapacity(8), init_len, target_endian); - }, - } - mem.writeInt(u16, di_buf.addManyAsArrayAssumeCapacity(2), 4, target_endian); // DWARF version - const abbrev_offset = self.debug_abbrev_table_offset.?; - switch (self.ptr_width) { - .p32 => { - mem.writeInt(u32, di_buf.addManyAsArrayAssumeCapacity(4), @intCast(u32, abbrev_offset), target_endian); - di_buf.appendAssumeCapacity(4); // address size - }, - .p64 => { - mem.writeInt(u64, di_buf.addManyAsArrayAssumeCapacity(8), abbrev_offset, target_endian); - di_buf.appendAssumeCapacity(8); // address size - }, - } - // Write the form for the compile unit, which must match the abbrev table above. - const name_strp = try self.makeDebugString(self.base.options.root_pkg.root_src_path); - const comp_dir_strp = try self.makeDebugString(self.base.options.root_pkg.root_src_dir_path); - const producer_strp = try self.makeDebugString(producer_string); - // Currently only one compilation unit is supported, so the address range is simply - // identical to the main program header virtual address and memory size. - const text_phdr = &self.program_headers.items[self.phdr_load_re_index.?]; - const low_pc = text_phdr.p_vaddr; - const high_pc = text_phdr.p_vaddr + text_phdr.p_memsz; - - di_buf.appendAssumeCapacity(abbrev_compile_unit); - self.writeDwarfAddrAssumeCapacity(&di_buf, 0); // DW.AT_stmt_list, DW.FORM_sec_offset - self.writeDwarfAddrAssumeCapacity(&di_buf, low_pc); - self.writeDwarfAddrAssumeCapacity(&di_buf, high_pc); - self.writeDwarfAddrAssumeCapacity(&di_buf, name_strp); - self.writeDwarfAddrAssumeCapacity(&di_buf, comp_dir_strp); - self.writeDwarfAddrAssumeCapacity(&di_buf, producer_strp); - // We are still waiting on dwarf-std.org to assign DW_LANG_Zig a number: - // http://dwarfstd.org/ShowIssue.php?issue=171115.1 - // Until then we say it is C99. - mem.writeInt(u16, di_buf.addManyAsArrayAssumeCapacity(2), DW.LANG_C99, target_endian); - - if (di_buf.items.len > first_dbg_info_decl.dbg_info_off) { - // Move the first N decls to the end to make more padding for the header. - @panic("TODO: handle .debug_info header exceeding its padding"); - } - const jmp_amt = first_dbg_info_decl.dbg_info_off - di_buf.items.len; - try self.pwriteDbgInfoNops(0, di_buf.items, jmp_amt, false, debug_info_sect.sh_offset); - self.debug_info_header_dirty = false; - } - - if (self.debug_aranges_section_dirty) { - const debug_aranges_sect = &self.sections.items[self.debug_aranges_section_index.?]; - - var di_buf = std.ArrayList(u8).init(self.base.allocator); - defer di_buf.deinit(); - - // Enough for all the data without resizing. When support for more compilation units - // is added, the size of this section will become more variable. - try di_buf.ensureCapacity(100); - - // initial length - length of the .debug_aranges contribution for this compilation unit, - // not including the initial length itself. - // We have to come back and write it later after we know the size. - const init_len_index = di_buf.items.len; - di_buf.items.len += init_len_size; - const after_init_len = di_buf.items.len; - mem.writeInt(u16, di_buf.addManyAsArrayAssumeCapacity(2), 2, target_endian); // version - // When more than one compilation unit is supported, this will be the offset to it. - // For now it is always at offset 0 in .debug_info. - self.writeDwarfAddrAssumeCapacity(&di_buf, 0); // .debug_info offset - di_buf.appendAssumeCapacity(ptr_width_bytes); // address_size - di_buf.appendAssumeCapacity(0); // segment_selector_size - - const end_header_offset = di_buf.items.len; - const begin_entries_offset = mem.alignForward(end_header_offset, ptr_width_bytes * 2); - di_buf.appendNTimesAssumeCapacity(0, begin_entries_offset - end_header_offset); - - // Currently only one compilation unit is supported, so the address range is simply - // identical to the main program header virtual address and memory size. - const text_phdr = &self.program_headers.items[self.phdr_load_re_index.?]; - self.writeDwarfAddrAssumeCapacity(&di_buf, text_phdr.p_vaddr); - self.writeDwarfAddrAssumeCapacity(&di_buf, text_phdr.p_memsz); - - // Sentinel. - self.writeDwarfAddrAssumeCapacity(&di_buf, 0); - self.writeDwarfAddrAssumeCapacity(&di_buf, 0); - - // Go back and populate the initial length. - const init_len = di_buf.items.len - after_init_len; - switch (self.ptr_width) { - .p32 => { - mem.writeInt(u32, di_buf.items[init_len_index..][0..4], @intCast(u32, init_len), target_endian); - }, - .p64 => { - // initial length - length of the .debug_aranges contribution for this compilation unit, - // not including the initial length itself. - di_buf.items[init_len_index..][0..4].* = [_]u8{ 0xff, 0xff, 0xff, 0xff }; - mem.writeInt(u64, di_buf.items[init_len_index + 4..][0..8], init_len, target_endian); - }, - } - - const needed_size = di_buf.items.len; - const allocated_size = self.allocatedSize(debug_aranges_sect.sh_offset); - if (needed_size > allocated_size) { - debug_aranges_sect.sh_size = 0; // free the space - debug_aranges_sect.sh_offset = self.findFreeSpace(needed_size, 16); - } - debug_aranges_sect.sh_size = needed_size; - log.debug(".debug_aranges start=0x{x} end=0x{x}\n", .{ - debug_aranges_sect.sh_offset, - debug_aranges_sect.sh_offset + needed_size, - }); - - try self.base.file.?.pwriteAll(di_buf.items, debug_aranges_sect.sh_offset); - if (!self.shdr_table_dirty) { - // Then it won't get written with the others and we need to do it. - try self.writeSectHeader(self.debug_aranges_section_index.?); - } - - self.debug_aranges_section_dirty = false; - } - if (self.debug_line_header_dirty) debug_line: { - if (self.dbg_line_fn_first == null) { - break :debug_line; // Error in module; leave debug_line_header_dirty=true. - } - const dbg_line_prg_off = self.getDebugLineProgramOff(); - const dbg_line_prg_end = self.getDebugLineProgramEnd(); - assert(dbg_line_prg_end != 0); - - const debug_line_sect = &self.sections.items[self.debug_line_section_index.?]; - - var di_buf = std.ArrayList(u8).init(self.base.allocator); - defer di_buf.deinit(); - - // The size of this header is variable, depending on the number of directories, - // files, and padding. We have a function to compute the upper bound size, however, - // because it's needed for determining where to put the offset of the first `SrcFn`. - try di_buf.ensureCapacity(self.dbgLineNeededHeaderBytes()); - - // initial length - length of the .debug_line contribution for this compilation unit, - // not including the initial length itself. - const after_init_len = di_buf.items.len + init_len_size; - const init_len = dbg_line_prg_end - after_init_len; - switch (self.ptr_width) { - .p32 => { - mem.writeInt(u32, di_buf.addManyAsArrayAssumeCapacity(4), @intCast(u32, init_len), target_endian); - }, - .p64 => { - di_buf.appendNTimesAssumeCapacity(0xff, 4); - mem.writeInt(u64, di_buf.addManyAsArrayAssumeCapacity(8), init_len, target_endian); - }, - } - - mem.writeInt(u16, di_buf.addManyAsArrayAssumeCapacity(2), 4, target_endian); // version - - // Empirically, debug info consumers do not respect this field, or otherwise - // consider it to be an error when it does not point exactly to the end of the header. - // Therefore we rely on the NOP jump at the beginning of the Line Number Program for - // padding rather than this field. - const before_header_len = di_buf.items.len; - di_buf.items.len += ptr_width_bytes; // We will come back and write this. - const after_header_len = di_buf.items.len; - - const opcode_base = DW.LNS_set_isa + 1; - di_buf.appendSliceAssumeCapacity(&[_]u8{ - 1, // minimum_instruction_length - 1, // maximum_operations_per_instruction - 1, // default_is_stmt - 1, // line_base (signed) - 1, // line_range - opcode_base, - - // Standard opcode lengths. The number of items here is based on `opcode_base`. - // The value is the number of LEB128 operands the instruction takes. - 0, // `DW.LNS_copy` - 1, // `DW.LNS_advance_pc` - 1, // `DW.LNS_advance_line` - 1, // `DW.LNS_set_file` - 1, // `DW.LNS_set_column` - 0, // `DW.LNS_negate_stmt` - 0, // `DW.LNS_set_basic_block` - 0, // `DW.LNS_const_add_pc` - 1, // `DW.LNS_fixed_advance_pc` - 0, // `DW.LNS_set_prologue_end` - 0, // `DW.LNS_set_epilogue_begin` - 1, // `DW.LNS_set_isa` - - 0, // include_directories (none except the compilation unit cwd) - }); - // file_names[0] - di_buf.appendSliceAssumeCapacity(self.base.options.root_pkg.root_src_path); // relative path name - di_buf.appendSliceAssumeCapacity(&[_]u8{ - 0, // null byte for the relative path name - 0, // directory_index - 0, // mtime (TODO supply this) - 0, // file size bytes (TODO supply this) - 0, // file_names sentinel - }); - - const header_len = di_buf.items.len - after_header_len; - switch (self.ptr_width) { - .p32 => { - mem.writeInt(u32, di_buf.items[before_header_len..][0..4], @intCast(u32, header_len), target_endian); - }, - .p64 => { - mem.writeInt(u64, di_buf.items[before_header_len..][0..8], header_len, target_endian); - }, - } - - // We use NOPs because consumers empirically do not respect the header length field. - if (di_buf.items.len > dbg_line_prg_off) { - // Move the first N files to the end to make more padding for the header. - @panic("TODO: handle .debug_line header exceeding its padding"); - } - const jmp_amt = dbg_line_prg_off - di_buf.items.len; - try self.pwriteDbgLineNops(0, di_buf.items, jmp_amt, debug_line_sect.sh_offset); - self.debug_line_header_dirty = false; - } - - if (self.phdr_table_dirty) { - const phsize: u64 = switch (self.ptr_width) { - .p32 => @sizeOf(elf.Elf32_Phdr), - .p64 => @sizeOf(elf.Elf64_Phdr), - }; - const phalign: u16 = switch (self.ptr_width) { - .p32 => @alignOf(elf.Elf32_Phdr), - .p64 => @alignOf(elf.Elf64_Phdr), - }; - const allocated_size = self.allocatedSize(self.phdr_table_offset.?); - const needed_size = self.program_headers.items.len * phsize; - - if (needed_size > allocated_size) { - self.phdr_table_offset = null; // free the space - self.phdr_table_offset = self.findFreeSpace(needed_size, phalign); - } - - switch (self.ptr_width) { - .p32 => { - const buf = try self.base.allocator.alloc(elf.Elf32_Phdr, self.program_headers.items.len); - defer self.base.allocator.free(buf); - - for (buf) |*phdr, i| { - phdr.* = progHeaderTo32(self.program_headers.items[i]); - if (foreign_endian) { - bswapAllFields(elf.Elf32_Phdr, phdr); - } - } - try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), self.phdr_table_offset.?); - }, - .p64 => { - const buf = try self.base.allocator.alloc(elf.Elf64_Phdr, self.program_headers.items.len); - defer self.base.allocator.free(buf); - - for (buf) |*phdr, i| { - phdr.* = self.program_headers.items[i]; - if (foreign_endian) { - bswapAllFields(elf.Elf64_Phdr, phdr); - } - } - try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), self.phdr_table_offset.?); - }, - } - self.phdr_table_dirty = false; - } - - { - const shstrtab_sect = &self.sections.items[self.shstrtab_index.?]; - if (self.shstrtab_dirty or self.shstrtab.items.len != shstrtab_sect.sh_size) { - const allocated_size = self.allocatedSize(shstrtab_sect.sh_offset); - const needed_size = self.shstrtab.items.len; - - if (needed_size > allocated_size) { - shstrtab_sect.sh_size = 0; // free the space - shstrtab_sect.sh_offset = self.findFreeSpace(needed_size, 1); - } - shstrtab_sect.sh_size = needed_size; - log.debug("writing shstrtab start=0x{x} end=0x{x}\n", .{ shstrtab_sect.sh_offset, shstrtab_sect.sh_offset + needed_size }); - - try self.base.file.?.pwriteAll(self.shstrtab.items, shstrtab_sect.sh_offset); - if (!self.shdr_table_dirty) { - // Then it won't get written with the others and we need to do it. - try self.writeSectHeader(self.shstrtab_index.?); - } - self.shstrtab_dirty = false; - } - } - { - const debug_strtab_sect = &self.sections.items[self.debug_str_section_index.?]; - if (self.debug_strtab_dirty or self.debug_strtab.items.len != debug_strtab_sect.sh_size) { - const allocated_size = self.allocatedSize(debug_strtab_sect.sh_offset); - const needed_size = self.debug_strtab.items.len; - - if (needed_size > allocated_size) { - debug_strtab_sect.sh_size = 0; // free the space - debug_strtab_sect.sh_offset = self.findFreeSpace(needed_size, 1); - } - debug_strtab_sect.sh_size = needed_size; - log.debug("debug_strtab start=0x{x} end=0x{x}\n", .{ debug_strtab_sect.sh_offset, debug_strtab_sect.sh_offset + needed_size }); - - try self.base.file.?.pwriteAll(self.debug_strtab.items, debug_strtab_sect.sh_offset); - if (!self.shdr_table_dirty) { - // Then it won't get written with the others and we need to do it. - try self.writeSectHeader(self.debug_str_section_index.?); - } - self.debug_strtab_dirty = false; - } - } - if (self.shdr_table_dirty) { - const shsize: u64 = switch (self.ptr_width) { - .p32 => @sizeOf(elf.Elf32_Shdr), - .p64 => @sizeOf(elf.Elf64_Shdr), - }; - const shalign: u16 = switch (self.ptr_width) { - .p32 => @alignOf(elf.Elf32_Shdr), - .p64 => @alignOf(elf.Elf64_Shdr), - }; - const allocated_size = self.allocatedSize(self.shdr_table_offset.?); - const needed_size = self.sections.items.len * shsize; - - if (needed_size > allocated_size) { - self.shdr_table_offset = null; // free the space - self.shdr_table_offset = self.findFreeSpace(needed_size, shalign); - } - - switch (self.ptr_width) { - .p32 => { - const buf = try self.base.allocator.alloc(elf.Elf32_Shdr, self.sections.items.len); - defer self.base.allocator.free(buf); - - for (buf) |*shdr, i| { - shdr.* = sectHeaderTo32(self.sections.items[i]); - log.debug("writing section {}\n", .{shdr.*}); - if (foreign_endian) { - bswapAllFields(elf.Elf32_Shdr, shdr); - } - } - try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), self.shdr_table_offset.?); - }, - .p64 => { - const buf = try self.base.allocator.alloc(elf.Elf64_Shdr, self.sections.items.len); - defer self.base.allocator.free(buf); - - for (buf) |*shdr, i| { - shdr.* = self.sections.items[i]; - log.debug("writing section {}\n", .{shdr.*}); - if (foreign_endian) { - bswapAllFields(elf.Elf64_Shdr, shdr); - } - } - try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), self.shdr_table_offset.?); - }, - } - self.shdr_table_dirty = false; - } - if (self.entry_addr == null and self.base.options.output_mode == .Exe) { - log.debug("flushing. no_entry_point_found = true\n", .{}); - self.error_flags.no_entry_point_found = true; - } else { - log.debug("flushing. no_entry_point_found = false\n", .{}); - self.error_flags.no_entry_point_found = false; - try self.writeElfHeader(); - } - - // The point of flush() is to commit changes, so in theory, nothing should - // be dirty after this. However, it is possible for some things to remain - // dirty because they fail to be written in the event of compile errors, - // such as debug_line_header_dirty and debug_info_header_dirty. - assert(!self.debug_abbrev_section_dirty); - assert(!self.debug_aranges_section_dirty); - assert(!self.phdr_table_dirty); - assert(!self.shdr_table_dirty); - assert(!self.shstrtab_dirty); - assert(!self.debug_strtab_dirty); - } - - fn writeDwarfAddrAssumeCapacity(self: *Elf, buf: *std.ArrayList(u8), addr: u64) void { - const target_endian = self.base.options.target.cpu.arch.endian(); - switch (self.ptr_width) { - .p32 => mem.writeInt(u32, buf.addManyAsArrayAssumeCapacity(4), @intCast(u32, addr), target_endian), - .p64 => mem.writeInt(u64, buf.addManyAsArrayAssumeCapacity(8), addr, target_endian), - } - } - - fn writeElfHeader(self: *Elf) !void { - var hdr_buf: [@sizeOf(elf.Elf64_Ehdr)]u8 = undefined; - - var index: usize = 0; - hdr_buf[0..4].* = "\x7fELF".*; - index += 4; - - hdr_buf[index] = switch (self.ptr_width) { - .p32 => elf.ELFCLASS32, - .p64 => elf.ELFCLASS64, - }; - index += 1; - - const endian = self.base.options.target.cpu.arch.endian(); - hdr_buf[index] = switch (endian) { - .Little => elf.ELFDATA2LSB, - .Big => elf.ELFDATA2MSB, - }; - index += 1; - - hdr_buf[index] = 1; // ELF version - index += 1; - - // OS ABI, often set to 0 regardless of target platform - // ABI Version, possibly used by glibc but not by static executables - // padding - mem.set(u8, hdr_buf[index..][0..9], 0); - index += 9; - - assert(index == 16); - - const elf_type = switch (self.base.options.output_mode) { - .Exe => elf.ET.EXEC, - .Obj => elf.ET.REL, - .Lib => switch (self.base.options.link_mode) { - .Static => elf.ET.REL, - .Dynamic => elf.ET.DYN, - }, - }; - mem.writeInt(u16, hdr_buf[index..][0..2], @enumToInt(elf_type), endian); - index += 2; - - const machine = self.base.options.target.cpu.arch.toElfMachine(); - mem.writeInt(u16, hdr_buf[index..][0..2], @enumToInt(machine), endian); - index += 2; - - // ELF Version, again - mem.writeInt(u32, hdr_buf[index..][0..4], 1, endian); - index += 4; - - const e_entry = if (elf_type == .REL) 0 else self.entry_addr.?; - - switch (self.ptr_width) { - .p32 => { - mem.writeInt(u32, hdr_buf[index..][0..4], @intCast(u32, e_entry), endian); - index += 4; - - // e_phoff - mem.writeInt(u32, hdr_buf[index..][0..4], @intCast(u32, self.phdr_table_offset.?), endian); - index += 4; - - // e_shoff - mem.writeInt(u32, hdr_buf[index..][0..4], @intCast(u32, self.shdr_table_offset.?), endian); - index += 4; - }, - .p64 => { - // e_entry - mem.writeInt(u64, hdr_buf[index..][0..8], e_entry, endian); - index += 8; - - // e_phoff - mem.writeInt(u64, hdr_buf[index..][0..8], self.phdr_table_offset.?, endian); - index += 8; - - // e_shoff - mem.writeInt(u64, hdr_buf[index..][0..8], self.shdr_table_offset.?, endian); - index += 8; - }, - } - - const e_flags = 0; - mem.writeInt(u32, hdr_buf[index..][0..4], e_flags, endian); - index += 4; - - const e_ehsize: u16 = switch (self.ptr_width) { - .p32 => @sizeOf(elf.Elf32_Ehdr), - .p64 => @sizeOf(elf.Elf64_Ehdr), - }; - mem.writeInt(u16, hdr_buf[index..][0..2], e_ehsize, endian); - index += 2; - - const e_phentsize: u16 = switch (self.ptr_width) { - .p32 => @sizeOf(elf.Elf32_Phdr), - .p64 => @sizeOf(elf.Elf64_Phdr), - }; - mem.writeInt(u16, hdr_buf[index..][0..2], e_phentsize, endian); - index += 2; - - const e_phnum = @intCast(u16, self.program_headers.items.len); - mem.writeInt(u16, hdr_buf[index..][0..2], e_phnum, endian); - index += 2; - - const e_shentsize: u16 = switch (self.ptr_width) { - .p32 => @sizeOf(elf.Elf32_Shdr), - .p64 => @sizeOf(elf.Elf64_Shdr), - }; - mem.writeInt(u16, hdr_buf[index..][0..2], e_shentsize, endian); - index += 2; - - const e_shnum = @intCast(u16, self.sections.items.len); - mem.writeInt(u16, hdr_buf[index..][0..2], e_shnum, endian); - index += 2; - - mem.writeInt(u16, hdr_buf[index..][0..2], self.shstrtab_index.?, endian); - index += 2; - - assert(index == e_ehsize); - - try self.base.file.?.pwriteAll(hdr_buf[0..index], 0); - } - - fn freeTextBlock(self: *Elf, text_block: *TextBlock) void { - var already_have_free_list_node = false; - { - var i: usize = 0; - while (i < self.text_block_free_list.items.len) { - if (self.text_block_free_list.items[i] == text_block) { - _ = self.text_block_free_list.swapRemove(i); - continue; - } - if (self.text_block_free_list.items[i] == text_block.prev) { - already_have_free_list_node = true; - } - i += 1; - } - } - - if (self.last_text_block == text_block) { - // TODO shrink the .text section size here - self.last_text_block = text_block.prev; - } - - if (text_block.prev) |prev| { - prev.next = text_block.next; - - if (!already_have_free_list_node and prev.freeListEligible(self.*)) { - // The free list is heuristics, it doesn't have to be perfect, so we can - // ignore the OOM here. - self.text_block_free_list.append(self.base.allocator, prev) catch {}; - } - } else { - text_block.prev = null; - } - - if (text_block.next) |next| { - next.prev = text_block.prev; - } else { - text_block.next = null; - } - } - - fn shrinkTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64) void { - // TODO check the new capacity, and if it crosses the size threshold into a big enough - // capacity, insert a free list node for it. - } - - fn growTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, alignment: u64) !u64 { - const sym = self.local_symbols.items[text_block.local_sym_index]; - const align_ok = mem.alignBackwardGeneric(u64, sym.st_value, alignment) == sym.st_value; - const need_realloc = !align_ok or new_block_size > text_block.capacity(self.*); - if (!need_realloc) return sym.st_value; - return self.allocateTextBlock(text_block, new_block_size, alignment); - } - - fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, alignment: u64) !u64 { - const phdr = &self.program_headers.items[self.phdr_load_re_index.?]; - const shdr = &self.sections.items[self.text_section_index.?]; - const new_block_ideal_capacity = new_block_size * alloc_num / alloc_den; - - // We use these to indicate our intention to update metadata, placing the new block, - // and possibly removing a free list node. - // It would be simpler to do it inside the for loop below, but that would cause a - // problem if an error was returned later in the function. So this action - // is actually carried out at the end of the function, when errors are no longer possible. - var block_placement: ?*TextBlock = null; - var free_list_removal: ?usize = null; - - // First we look for an appropriately sized free list node. - // The list is unordered. We'll just take the first thing that works. - const vaddr = blk: { - var i: usize = 0; - while (i < self.text_block_free_list.items.len) { - const big_block = self.text_block_free_list.items[i]; - // We now have a pointer to a live text block that has too much capacity. - // Is it enough that we could fit this new text block? - const sym = self.local_symbols.items[big_block.local_sym_index]; - const capacity = big_block.capacity(self.*); - const ideal_capacity = capacity * alloc_num / alloc_den; - const ideal_capacity_end_vaddr = sym.st_value + ideal_capacity; - const capacity_end_vaddr = sym.st_value + capacity; - const new_start_vaddr_unaligned = capacity_end_vaddr - new_block_ideal_capacity; - const new_start_vaddr = mem.alignBackwardGeneric(u64, new_start_vaddr_unaligned, alignment); - if (new_start_vaddr < ideal_capacity_end_vaddr) { - // Additional bookkeeping here to notice if this free list node - // should be deleted because the block that it points to has grown to take up - // more of the extra capacity. - if (!big_block.freeListEligible(self.*)) { - _ = self.text_block_free_list.swapRemove(i); - } else { - i += 1; - } - continue; - } - // At this point we know that we will place the new block here. But the - // remaining question is whether there is still yet enough capacity left - // over for there to still be a free list node. - const remaining_capacity = new_start_vaddr - ideal_capacity_end_vaddr; - const keep_free_list_node = remaining_capacity >= min_text_capacity; - - // Set up the metadata to be updated, after errors are no longer possible. - block_placement = big_block; - if (!keep_free_list_node) { - free_list_removal = i; - } - break :blk new_start_vaddr; - } else if (self.last_text_block) |last| { - const sym = self.local_symbols.items[last.local_sym_index]; - const ideal_capacity = sym.st_size * alloc_num / alloc_den; - const ideal_capacity_end_vaddr = sym.st_value + ideal_capacity; - const new_start_vaddr = mem.alignForwardGeneric(u64, ideal_capacity_end_vaddr, alignment); - // Set up the metadata to be updated, after errors are no longer possible. - block_placement = last; - break :blk new_start_vaddr; - } else { - break :blk phdr.p_vaddr; - } - }; - - const expand_text_section = block_placement == null or block_placement.?.next == null; - if (expand_text_section) { - const text_capacity = self.allocatedSize(shdr.sh_offset); - const needed_size = (vaddr + new_block_size) - phdr.p_vaddr; - if (needed_size > text_capacity) { - // Must move the entire text section. - const new_offset = self.findFreeSpace(needed_size, 0x1000); - const text_size = if (self.last_text_block) |last| blk: { - const sym = self.local_symbols.items[last.local_sym_index]; - break :blk (sym.st_value + sym.st_size) - phdr.p_vaddr; - } else 0; - const amt = try self.base.file.?.copyRangeAll(shdr.sh_offset, self.base.file.?, new_offset, text_size); - if (amt != text_size) return error.InputOutput; - shdr.sh_offset = new_offset; - phdr.p_offset = new_offset; - } - self.last_text_block = text_block; - - shdr.sh_size = needed_size; - phdr.p_memsz = needed_size; - phdr.p_filesz = needed_size; - - // The .debug_info section has `low_pc` and `high_pc` values which is the virtual address - // range of the compilation unit. When we expand the text section, this range changes, - // so the DW_TAG_compile_unit tag of the .debug_info section becomes dirty. - self.debug_info_header_dirty = true; - // This becomes dirty for the same reason. We could potentially make this more - // fine-grained with the addition of support for more compilation units. It is planned to - // model each package as a different compilation unit. - self.debug_aranges_section_dirty = true; - - self.phdr_table_dirty = true; // TODO look into making only the one program header dirty - self.shdr_table_dirty = true; // TODO look into making only the one section dirty - } - - // This function can also reallocate a text block. - // In this case we need to "unplug" it from its previous location before - // plugging it in to its new location. - if (text_block.prev) |prev| { - prev.next = text_block.next; - } - if (text_block.next) |next| { - next.prev = text_block.prev; - } - - if (block_placement) |big_block| { - text_block.prev = big_block; - text_block.next = big_block.next; - big_block.next = text_block; - } else { - text_block.prev = null; - text_block.next = null; - } - if (free_list_removal) |i| { - _ = self.text_block_free_list.swapRemove(i); - } - return vaddr; - } - - pub fn allocateDeclIndexes(self: *Elf, decl: *Module.Decl) !void { - if (decl.link.elf.local_sym_index != 0) return; - - try self.local_symbols.ensureCapacity(self.base.allocator, self.local_symbols.items.len + 1); - try self.offset_table.ensureCapacity(self.base.allocator, self.offset_table.items.len + 1); - - if (self.local_symbol_free_list.popOrNull()) |i| { - log.debug("reusing symbol index {} for {}\n", .{ i, decl.name }); - decl.link.elf.local_sym_index = i; - } else { - log.debug("allocating symbol index {} for {}\n", .{ self.local_symbols.items.len, decl.name }); - decl.link.elf.local_sym_index = @intCast(u32, self.local_symbols.items.len); - _ = self.local_symbols.addOneAssumeCapacity(); - } - - if (self.offset_table_free_list.popOrNull()) |i| { - decl.link.elf.offset_table_index = i; - } else { - decl.link.elf.offset_table_index = @intCast(u32, self.offset_table.items.len); - _ = self.offset_table.addOneAssumeCapacity(); - self.offset_table_count_dirty = true; - } - - const phdr = &self.program_headers.items[self.phdr_load_re_index.?]; - - self.local_symbols.items[decl.link.elf.local_sym_index] = .{ - .st_name = 0, - .st_info = 0, - .st_other = 0, - .st_shndx = 0, - .st_value = phdr.p_vaddr, - .st_size = 0, - }; - self.offset_table.items[decl.link.elf.offset_table_index] = 0; - } - - pub fn freeDecl(self: *Elf, decl: *Module.Decl) void { - // Appending to free lists is allowed to fail because the free lists are heuristics based anyway. - self.freeTextBlock(&decl.link.elf); - if (decl.link.elf.local_sym_index != 0) { - self.local_symbol_free_list.append(self.base.allocator, decl.link.elf.local_sym_index) catch {}; - self.offset_table_free_list.append(self.base.allocator, decl.link.elf.offset_table_index) catch {}; - - self.local_symbols.items[decl.link.elf.local_sym_index].st_info = 0; - - decl.link.elf.local_sym_index = 0; - } - // TODO make this logic match freeTextBlock. Maybe abstract the logic out since the same thing - // is desired for both. - _ = self.dbg_line_fn_free_list.remove(&decl.fn_link.elf); - if (decl.fn_link.elf.prev) |prev| { - _ = self.dbg_line_fn_free_list.put(self.base.allocator, prev, {}) catch {}; - prev.next = decl.fn_link.elf.next; - if (decl.fn_link.elf.next) |next| { - next.prev = prev; - } else { - self.dbg_line_fn_last = prev; - } - } else if (decl.fn_link.elf.next) |next| { - self.dbg_line_fn_first = next; - next.prev = null; - } - if (self.dbg_line_fn_first == &decl.fn_link.elf) { - self.dbg_line_fn_first = null; - } - if (self.dbg_line_fn_last == &decl.fn_link.elf) { - self.dbg_line_fn_last = null; - } - } - - pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void { - const tracy = trace(@src()); - defer tracy.end(); - - var code_buffer = std.ArrayList(u8).init(self.base.allocator); - defer code_buffer.deinit(); - - var dbg_line_buffer = std.ArrayList(u8).init(self.base.allocator); - defer dbg_line_buffer.deinit(); - - var dbg_info_buffer = std.ArrayList(u8).init(self.base.allocator); - defer dbg_info_buffer.deinit(); - - var dbg_info_type_relocs: DbgInfoTypeRelocsTable = .{}; - defer { - for (dbg_info_type_relocs.items()) |*entry| { - entry.value.relocs.deinit(self.base.allocator); - } - dbg_info_type_relocs.deinit(self.base.allocator); - } - - const typed_value = decl.typed_value.most_recent.typed_value; - const is_fn: bool = switch (typed_value.ty.zigTypeTag()) { - .Fn => true, - else => false, - }; - if (is_fn) { - //if (mem.eql(u8, mem.spanZ(decl.name), "add")) { - // typed_value.val.cast(Value.Payload.Function).?.func.dump(module.*); - //} - - // For functions we need to add a prologue to the debug line program. - try dbg_line_buffer.ensureCapacity(26); - - const line_off: u28 = blk: { - if (decl.scope.cast(Module.Scope.File)) |scope_file| { - const tree = scope_file.contents.tree; - const file_ast_decls = tree.root_node.decls(); - // TODO Look into improving the performance here by adding a token-index-to-line - // lookup table. Currently this involves scanning over the source code for newlines. - const fn_proto = file_ast_decls[decl.src_index].castTag(.FnProto).?; - const block = fn_proto.body().?.castTag(.Block).?; - const line_delta = std.zig.lineDelta(tree.source, 0, tree.token_locs[block.lbrace].start); - break :blk @intCast(u28, line_delta); - } else if (decl.scope.cast(Module.Scope.ZIRModule)) |zir_module| { - const byte_off = zir_module.contents.module.decls[decl.src_index].inst.src; - const line_delta = std.zig.lineDelta(zir_module.source.bytes, 0, byte_off); - break :blk @intCast(u28, line_delta); - } else { - unreachable; - } - }; - - const ptr_width_bytes = self.ptrWidthBytes(); - dbg_line_buffer.appendSliceAssumeCapacity(&[_]u8{ - DW.LNS_extended_op, - ptr_width_bytes + 1, - DW.LNE_set_address, - }); - // This is the "relocatable" vaddr, corresponding to `code_buffer` index `0`. - assert(dbg_line_vaddr_reloc_index == dbg_line_buffer.items.len); - dbg_line_buffer.items.len += ptr_width_bytes; - - dbg_line_buffer.appendAssumeCapacity(DW.LNS_advance_line); - // This is the "relocatable" relative line offset from the previous function's end curly - // to this function's begin curly. - assert(self.getRelocDbgLineOff() == dbg_line_buffer.items.len); - // Here we use a ULEB128-fixed-4 to make sure this field can be overwritten later. - leb128.writeUnsignedFixed(4, dbg_line_buffer.addManyAsArrayAssumeCapacity(4), line_off); - - dbg_line_buffer.appendAssumeCapacity(DW.LNS_set_file); - assert(self.getRelocDbgFileIndex() == dbg_line_buffer.items.len); - // Once we support more than one source file, this will have the ability to be more - // than one possible value. - const file_index = 1; - leb128.writeUnsignedFixed(4, dbg_line_buffer.addManyAsArrayAssumeCapacity(4), file_index); - - // Emit a line for the begin curly with prologue_end=false. The codegen will - // do the work of setting prologue_end=true and epilogue_begin=true. - dbg_line_buffer.appendAssumeCapacity(DW.LNS_copy); - - // .debug_info subprogram - const decl_name_with_null = decl.name[0..mem.lenZ(decl.name) + 1]; - try dbg_info_buffer.ensureCapacity(dbg_info_buffer.items.len + 25 + decl_name_with_null.len); - - const fn_ret_type = typed_value.ty.fnReturnType(); - const fn_ret_has_bits = fn_ret_type.hasCodeGenBits(); - if (fn_ret_has_bits) { - dbg_info_buffer.appendAssumeCapacity(abbrev_subprogram); - } else { - dbg_info_buffer.appendAssumeCapacity(abbrev_subprogram_retvoid); - } - // These get overwritten after generating the machine code. These values are - // "relocations" and have to be in this fixed place so that functions can be - // moved in virtual address space. - assert(dbg_info_low_pc_reloc_index == dbg_info_buffer.items.len); - dbg_info_buffer.items.len += ptr_width_bytes; // DW.AT_low_pc, DW.FORM_addr - assert(self.getRelocDbgInfoSubprogramHighPC() == dbg_info_buffer.items.len); - dbg_info_buffer.items.len += 4; // DW.AT_high_pc, DW.FORM_data4 - if (fn_ret_has_bits) { - const gop = try dbg_info_type_relocs.getOrPut(self.base.allocator, fn_ret_type); - if (!gop.found_existing) { - gop.entry.value = .{ - .off = undefined, - .relocs = .{}, - }; - } - try gop.entry.value.relocs.append(self.base.allocator, @intCast(u32, dbg_info_buffer.items.len)); - dbg_info_buffer.items.len += 4; // DW.AT_type, DW.FORM_ref4 - } - dbg_info_buffer.appendSliceAssumeCapacity(decl_name_with_null); // DW.AT_name, DW.FORM_string - } else { - // TODO implement .debug_info for global variables - } - const res = try codegen.generateSymbol(self, decl.src(), typed_value, &code_buffer, &dbg_line_buffer, &dbg_info_buffer, &dbg_info_type_relocs); - const code = switch (res) { - .externally_managed => |x| x, - .appended => code_buffer.items, - .fail => |em| { - decl.analysis = .codegen_failure; - try module.failed_decls.put(module.gpa, decl, em); - return; - }, - }; - - const required_alignment = typed_value.ty.abiAlignment(self.base.options.target); - - const stt_bits: u8 = if (is_fn) elf.STT_FUNC else elf.STT_OBJECT; - - assert(decl.link.elf.local_sym_index != 0); // Caller forgot to allocateDeclIndexes() - const local_sym = &self.local_symbols.items[decl.link.elf.local_sym_index]; - if (local_sym.st_size != 0) { - const capacity = decl.link.elf.capacity(self.*); - const need_realloc = code.len > capacity or - !mem.isAlignedGeneric(u64, local_sym.st_value, required_alignment); - if (need_realloc) { - const vaddr = try self.growTextBlock(&decl.link.elf, code.len, required_alignment); - log.debug("growing {} from 0x{x} to 0x{x}\n", .{ decl.name, local_sym.st_value, vaddr }); - if (vaddr != local_sym.st_value) { - local_sym.st_value = vaddr; - - log.debug(" (writing new offset table entry)\n", .{}); - self.offset_table.items[decl.link.elf.offset_table_index] = vaddr; - try self.writeOffsetTableEntry(decl.link.elf.offset_table_index); - } - } else if (code.len < local_sym.st_size) { - self.shrinkTextBlock(&decl.link.elf, code.len); - } - local_sym.st_size = code.len; - local_sym.st_name = try self.updateString(local_sym.st_name, mem.spanZ(decl.name)); - local_sym.st_info = (elf.STB_LOCAL << 4) | stt_bits; - local_sym.st_other = 0; - local_sym.st_shndx = self.text_section_index.?; - // TODO this write could be avoided if no fields of the symbol were changed. - try self.writeSymbol(decl.link.elf.local_sym_index); - } else { - const decl_name = mem.spanZ(decl.name); - const name_str_index = try self.makeString(decl_name); - const vaddr = try self.allocateTextBlock(&decl.link.elf, code.len, required_alignment); - log.debug("allocated text block for {} at 0x{x}\n", .{ decl_name, vaddr }); - errdefer self.freeTextBlock(&decl.link.elf); - - local_sym.* = .{ - .st_name = name_str_index, - .st_info = (elf.STB_LOCAL << 4) | stt_bits, - .st_other = 0, - .st_shndx = self.text_section_index.?, - .st_value = vaddr, - .st_size = code.len, - }; - self.offset_table.items[decl.link.elf.offset_table_index] = vaddr; - - try self.writeSymbol(decl.link.elf.local_sym_index); - try self.writeOffsetTableEntry(decl.link.elf.offset_table_index); - } - - const section_offset = local_sym.st_value - self.program_headers.items[self.phdr_load_re_index.?].p_vaddr; - const file_offset = self.sections.items[self.text_section_index.?].sh_offset + section_offset; - try self.base.file.?.pwriteAll(code, file_offset); - - const target_endian = self.base.options.target.cpu.arch.endian(); - - const text_block = &decl.link.elf; - - // If the Decl is a function, we need to update the .debug_line program. - if (is_fn) { - // Perform the relocations based on vaddr. - switch (self.ptr_width) { - .p32 => { - { - const ptr = dbg_line_buffer.items[dbg_line_vaddr_reloc_index..][0..4]; - mem.writeInt(u32, ptr, @intCast(u32, local_sym.st_value), target_endian); - } - { - const ptr = dbg_info_buffer.items[dbg_info_low_pc_reloc_index..][0..4]; - mem.writeInt(u32, ptr, @intCast(u32, local_sym.st_value), target_endian); - } - }, - .p64 => { - { - const ptr = dbg_line_buffer.items[dbg_line_vaddr_reloc_index..][0..8]; - mem.writeInt(u64, ptr, local_sym.st_value, target_endian); - } - { - const ptr = dbg_info_buffer.items[dbg_info_low_pc_reloc_index..][0..8]; - mem.writeInt(u64, ptr, local_sym.st_value, target_endian); - } - }, - } - { - const ptr = dbg_info_buffer.items[self.getRelocDbgInfoSubprogramHighPC()..][0..4]; - mem.writeInt(u32, ptr, @intCast(u32, local_sym.st_size), target_endian); - } - - try dbg_line_buffer.appendSlice(&[_]u8{ DW.LNS_extended_op, 1, DW.LNE_end_sequence }); - - // Now we have the full contents and may allocate a region to store it. - - // This logic is nearly identical to the logic below in `updateDeclDebugInfo` for - // `TextBlock` and the .debug_info. If you are editing this logic, you - // probably need to edit that logic too. - - const debug_line_sect = &self.sections.items[self.debug_line_section_index.?]; - const src_fn = &decl.fn_link.elf; - src_fn.len = @intCast(u32, dbg_line_buffer.items.len); - if (self.dbg_line_fn_last) |last| { - if (src_fn.next) |next| { - // Update existing function - non-last item. - if (src_fn.off + src_fn.len + min_nop_size > next.off) { - // It grew too big, so we move it to a new location. - if (src_fn.prev) |prev| { - _ = self.dbg_line_fn_free_list.put(self.base.allocator, prev, {}) catch {}; - prev.next = src_fn.next; - } - next.prev = src_fn.prev; - src_fn.next = null; - // Populate where it used to be with NOPs. - const file_pos = debug_line_sect.sh_offset + src_fn.off; - try self.pwriteDbgLineNops(0, &[0]u8{}, src_fn.len, file_pos); - // TODO Look at the free list before appending at the end. - src_fn.prev = last; - last.next = src_fn; - self.dbg_line_fn_last = src_fn; - - src_fn.off = last.off + (last.len * alloc_num / alloc_den); - } - } else if (src_fn.prev == null) { - // Append new function. - // TODO Look at the free list before appending at the end. - src_fn.prev = last; - last.next = src_fn; - self.dbg_line_fn_last = src_fn; - - src_fn.off = last.off + (last.len * alloc_num / alloc_den); - } - } else { - // This is the first function of the Line Number Program. - self.dbg_line_fn_first = src_fn; - self.dbg_line_fn_last = src_fn; - - src_fn.off = self.dbgLineNeededHeaderBytes() * alloc_num / alloc_den; - } - - const last_src_fn = self.dbg_line_fn_last.?; - const needed_size = last_src_fn.off + last_src_fn.len; - if (needed_size != debug_line_sect.sh_size) { - if (needed_size > self.allocatedSize(debug_line_sect.sh_offset)) { - const new_offset = self.findFreeSpace(needed_size, 1); - const existing_size = last_src_fn.off; - log.debug("moving .debug_line section: {} bytes from 0x{x} to 0x{x}\n", .{ - existing_size, - debug_line_sect.sh_offset, - new_offset, - }); - const amt = try self.base.file.?.copyRangeAll(debug_line_sect.sh_offset, self.base.file.?, new_offset, existing_size); - if (amt != existing_size) return error.InputOutput; - debug_line_sect.sh_offset = new_offset; - } - debug_line_sect.sh_size = needed_size; - self.shdr_table_dirty = true; // TODO look into making only the one section dirty - self.debug_line_header_dirty = true; - } - const prev_padding_size: u32 = if (src_fn.prev) |prev| src_fn.off - (prev.off + prev.len) else 0; - const next_padding_size: u32 = if (src_fn.next) |next| next.off - (src_fn.off + src_fn.len) else 0; - - // We only have support for one compilation unit so far, so the offsets are directly - // from the .debug_line section. - const file_pos = debug_line_sect.sh_offset + src_fn.off; - try self.pwriteDbgLineNops(prev_padding_size, dbg_line_buffer.items, next_padding_size, file_pos); - - // .debug_info - End the TAG_subprogram children. - try dbg_info_buffer.append(0); - } - - // Now we emit the .debug_info types of the Decl. These will count towards the size of - // the buffer, so we have to do it before computing the offset, and we can't perform the actual - // relocations yet. - for (dbg_info_type_relocs.items()) |*entry| { - entry.value.off = @intCast(u32, dbg_info_buffer.items.len); - try self.addDbgInfoType(entry.key, &dbg_info_buffer); - } - - try self.updateDeclDebugInfoAllocation(text_block, @intCast(u32, dbg_info_buffer.items.len)); - - // Now that we have the offset assigned we can finally perform type relocations. - for (dbg_info_type_relocs.items()) |entry| { - for (entry.value.relocs.items) |off| { - mem.writeInt( - u32, - dbg_info_buffer.items[off..][0..4], - text_block.dbg_info_off + entry.value.off, - target_endian, - ); - } - } - - try self.writeDeclDebugInfo(text_block, dbg_info_buffer.items); - - // Since we updated the vaddr and the size, each corresponding export symbol also needs to be updated. - const decl_exports = module.decl_exports.get(decl) orelse &[0]*Module.Export{}; - return self.updateDeclExports(module, decl, decl_exports); - } - - /// Asserts the type has codegen bits. - fn addDbgInfoType(self: *Elf, ty: Type, dbg_info_buffer: *std.ArrayList(u8)) !void { - switch (ty.zigTypeTag()) { - .Void => unreachable, - .NoReturn => unreachable, - .Bool => { - try dbg_info_buffer.appendSlice(&[_]u8{ - abbrev_base_type, - DW.ATE_boolean, // DW.AT_encoding , DW.FORM_data1 - 1, // DW.AT_byte_size, DW.FORM_data1 - 'b', 'o', 'o', 'l', 0, // DW.AT_name, DW.FORM_string - }); - }, - .Int => { - const info = ty.intInfo(self.base.options.target); - try dbg_info_buffer.ensureCapacity(dbg_info_buffer.items.len + 12); - dbg_info_buffer.appendAssumeCapacity(abbrev_base_type); - // DW.AT_encoding, DW.FORM_data1 - dbg_info_buffer.appendAssumeCapacity(if (info.signed) DW.ATE_signed else DW.ATE_unsigned); - // DW.AT_byte_size, DW.FORM_data1 - dbg_info_buffer.appendAssumeCapacity(@intCast(u8, ty.abiSize(self.base.options.target))); - // DW.AT_name, DW.FORM_string - try dbg_info_buffer.writer().print("{}\x00", .{ty}); - }, - else => { - std.log.scoped(.compiler).err("TODO implement .debug_info for type '{}'", .{ty}); - try dbg_info_buffer.append(abbrev_pad1); - }, - } - } - - fn updateDeclDebugInfoAllocation(self: *Elf, text_block: *TextBlock, len: u32) !void { - const tracy = trace(@src()); - defer tracy.end(); - - // This logic is nearly identical to the logic above in `updateDecl` for - // `SrcFn` and the line number programs. If you are editing this logic, you - // probably need to edit that logic too. - - const debug_info_sect = &self.sections.items[self.debug_info_section_index.?]; - text_block.dbg_info_len = len; - if (self.dbg_info_decl_last) |last| { - if (text_block.dbg_info_next) |next| { - // Update existing Decl - non-last item. - if (text_block.dbg_info_off + text_block.dbg_info_len + min_nop_size > next.dbg_info_off) { - // It grew too big, so we move it to a new location. - if (text_block.dbg_info_prev) |prev| { - _ = self.dbg_info_decl_free_list.put(self.base.allocator, prev, {}) catch {}; - prev.dbg_info_next = text_block.dbg_info_next; - } - next.dbg_info_prev = text_block.dbg_info_prev; - text_block.dbg_info_next = null; - // Populate where it used to be with NOPs. - const file_pos = debug_info_sect.sh_offset + text_block.dbg_info_off; - try self.pwriteDbgInfoNops(0, &[0]u8{}, text_block.dbg_info_len, false, file_pos); - // TODO Look at the free list before appending at the end. - text_block.dbg_info_prev = last; - last.dbg_info_next = text_block; - self.dbg_info_decl_last = text_block; - - text_block.dbg_info_off = last.dbg_info_off + (last.dbg_info_len * alloc_num / alloc_den); - } - } else if (text_block.dbg_info_prev == null) { - // Append new Decl. - // TODO Look at the free list before appending at the end. - text_block.dbg_info_prev = last; - last.dbg_info_next = text_block; - self.dbg_info_decl_last = text_block; - - text_block.dbg_info_off = last.dbg_info_off + (last.dbg_info_len * alloc_num / alloc_den); - } - } else { - // This is the first Decl of the .debug_info - self.dbg_info_decl_first = text_block; - self.dbg_info_decl_last = text_block; - - text_block.dbg_info_off = self.dbgInfoNeededHeaderBytes() * alloc_num / alloc_den; - } - } - - fn writeDeclDebugInfo(self: *Elf, text_block: *TextBlock, dbg_info_buf: []const u8) !void { - const tracy = trace(@src()); - defer tracy.end(); - - // This logic is nearly identical to the logic above in `updateDecl` for - // `SrcFn` and the line number programs. If you are editing this logic, you - // probably need to edit that logic too. - - const debug_info_sect = &self.sections.items[self.debug_info_section_index.?]; - - const last_decl = self.dbg_info_decl_last.?; - // +1 for a trailing zero to end the children of the decl tag. - const needed_size = last_decl.dbg_info_off + last_decl.dbg_info_len + 1; - if (needed_size != debug_info_sect.sh_size) { - if (needed_size > self.allocatedSize(debug_info_sect.sh_offset)) { - const new_offset = self.findFreeSpace(needed_size, 1); - const existing_size = last_decl.dbg_info_off; - log.debug("moving .debug_info section: {} bytes from 0x{x} to 0x{x}\n", .{ - existing_size, - debug_info_sect.sh_offset, - new_offset, - }); - const amt = try self.base.file.?.copyRangeAll(debug_info_sect.sh_offset, self.base.file.?, new_offset, existing_size); - if (amt != existing_size) return error.InputOutput; - debug_info_sect.sh_offset = new_offset; - } - debug_info_sect.sh_size = needed_size; - self.shdr_table_dirty = true; // TODO look into making only the one section dirty - self.debug_info_header_dirty = true; - } - const prev_padding_size: u32 = if (text_block.dbg_info_prev) |prev| - text_block.dbg_info_off - (prev.dbg_info_off + prev.dbg_info_len) - else - 0; - const next_padding_size: u32 = if (text_block.dbg_info_next) |next| - next.dbg_info_off - (text_block.dbg_info_off + text_block.dbg_info_len) - else - 0; - - // To end the children of the decl tag. - const trailing_zero = text_block.dbg_info_next == null; - - // We only have support for one compilation unit so far, so the offsets are directly - // from the .debug_info section. - const file_pos = debug_info_sect.sh_offset + text_block.dbg_info_off; - try self.pwriteDbgInfoNops(prev_padding_size, dbg_info_buf, next_padding_size, trailing_zero, file_pos); - } - - pub fn updateDeclExports( - self: *Elf, - module: *Module, - decl: *const Module.Decl, - exports: []const *Module.Export, - ) !void { - const tracy = trace(@src()); - defer tracy.end(); - - try self.global_symbols.ensureCapacity(self.base.allocator, self.global_symbols.items.len + exports.len); - const typed_value = decl.typed_value.most_recent.typed_value; - if (decl.link.elf.local_sym_index == 0) return; - const decl_sym = self.local_symbols.items[decl.link.elf.local_sym_index]; - - for (exports) |exp| { - if (exp.options.section) |section_name| { - if (!mem.eql(u8, section_name, ".text")) { - try module.failed_exports.ensureCapacity(module.gpa, module.failed_exports.items().len + 1); - module.failed_exports.putAssumeCapacityNoClobber( - exp, - try Module.ErrorMsg.create(self.base.allocator, 0, "Unimplemented: ExportOptions.section", .{}), - ); - continue; - } - } - const stb_bits: u8 = switch (exp.options.linkage) { - .Internal => elf.STB_LOCAL, - .Strong => blk: { - if (mem.eql(u8, exp.options.name, "_start")) { - self.entry_addr = decl_sym.st_value; - } - break :blk elf.STB_GLOBAL; - }, - .Weak => elf.STB_WEAK, - .LinkOnce => { - try module.failed_exports.ensureCapacity(module.gpa, module.failed_exports.items().len + 1); - module.failed_exports.putAssumeCapacityNoClobber( - exp, - try Module.ErrorMsg.create(self.base.allocator, 0, "Unimplemented: GlobalLinkage.LinkOnce", .{}), - ); - continue; - }, - }; - const stt_bits: u8 = @truncate(u4, decl_sym.st_info); - if (exp.link.sym_index) |i| { - const sym = &self.global_symbols.items[i]; - sym.* = .{ - .st_name = try self.updateString(sym.st_name, exp.options.name), - .st_info = (stb_bits << 4) | stt_bits, - .st_other = 0, - .st_shndx = self.text_section_index.?, - .st_value = decl_sym.st_value, - .st_size = decl_sym.st_size, - }; - } else { - const name = try self.makeString(exp.options.name); - const i = if (self.global_symbol_free_list.popOrNull()) |i| i else blk: { - _ = self.global_symbols.addOneAssumeCapacity(); - break :blk self.global_symbols.items.len - 1; - }; - self.global_symbols.items[i] = .{ - .st_name = name, - .st_info = (stb_bits << 4) | stt_bits, - .st_other = 0, - .st_shndx = self.text_section_index.?, - .st_value = decl_sym.st_value, - .st_size = decl_sym.st_size, - }; - - exp.link.sym_index = @intCast(u32, i); - } - } - } - - /// Must be called only after a successful call to `updateDecl`. - pub fn updateDeclLineNumber(self: *Elf, module: *Module, decl: *const Module.Decl) !void { - const tracy = trace(@src()); - defer tracy.end(); - - const scope_file = decl.scope.cast(Module.Scope.File).?; - const tree = scope_file.contents.tree; - const file_ast_decls = tree.root_node.decls(); - // TODO Look into improving the performance here by adding a token-index-to-line - // lookup table. Currently this involves scanning over the source code for newlines. - const fn_proto = file_ast_decls[decl.src_index].castTag(.FnProto).?; - const block = fn_proto.body().?.castTag(.Block).?; - const line_delta = std.zig.lineDelta(tree.source, 0, tree.token_locs[block.lbrace].start); - const casted_line_off = @intCast(u28, line_delta); - - const shdr = &self.sections.items[self.debug_line_section_index.?]; - const file_pos = shdr.sh_offset + decl.fn_link.elf.off + self.getRelocDbgLineOff(); - var data: [4]u8 = undefined; - leb128.writeUnsignedFixed(4, &data, casted_line_off); - try self.base.file.?.pwriteAll(&data, file_pos); - } - - pub fn deleteExport(self: *Elf, exp: Export) void { - const sym_index = exp.sym_index orelse return; - self.global_symbol_free_list.append(self.base.allocator, sym_index) catch {}; - self.global_symbols.items[sym_index].st_info = 0; - } - - fn writeProgHeader(self: *Elf, index: usize) !void { - const foreign_endian = self.base.options.target.cpu.arch.endian() != std.Target.current.cpu.arch.endian(); - const offset = self.program_headers.items[index].p_offset; - switch (self.base.options.target.cpu.arch.ptrBitWidth()) { - 32 => { - var phdr = [1]elf.Elf32_Phdr{progHeaderTo32(self.program_headers.items[index])}; - if (foreign_endian) { - bswapAllFields(elf.Elf32_Phdr, &phdr[0]); - } - return self.base.file.?.pwriteAll(mem.sliceAsBytes(&phdr), offset); - }, - 64 => { - var phdr = [1]elf.Elf64_Phdr{self.program_headers.items[index]}; - if (foreign_endian) { - bswapAllFields(elf.Elf64_Phdr, &phdr[0]); - } - return self.base.file.?.pwriteAll(mem.sliceAsBytes(&phdr), offset); - }, - else => return error.UnsupportedArchitecture, - } - } - - fn writeSectHeader(self: *Elf, index: usize) !void { - const foreign_endian = self.base.options.target.cpu.arch.endian() != std.Target.current.cpu.arch.endian(); - switch (self.base.options.target.cpu.arch.ptrBitWidth()) { - 32 => { - var shdr: [1]elf.Elf32_Shdr = undefined; - shdr[0] = sectHeaderTo32(self.sections.items[index]); - if (foreign_endian) { - bswapAllFields(elf.Elf32_Shdr, &shdr[0]); - } - const offset = self.shdr_table_offset.? + index * @sizeOf(elf.Elf32_Shdr); - return self.base.file.?.pwriteAll(mem.sliceAsBytes(&shdr), offset); - }, - 64 => { - var shdr = [1]elf.Elf64_Shdr{self.sections.items[index]}; - if (foreign_endian) { - bswapAllFields(elf.Elf64_Shdr, &shdr[0]); - } - const offset = self.shdr_table_offset.? + index * @sizeOf(elf.Elf64_Shdr); - return self.base.file.?.pwriteAll(mem.sliceAsBytes(&shdr), offset); - }, - else => return error.UnsupportedArchitecture, - } - } - - fn writeOffsetTableEntry(self: *Elf, index: usize) !void { - const shdr = &self.sections.items[self.got_section_index.?]; - const phdr = &self.program_headers.items[self.phdr_got_index.?]; - const entry_size: u16 = self.ptrWidthBytes(); - if (self.offset_table_count_dirty) { - // TODO Also detect virtual address collisions. - const allocated_size = self.allocatedSize(shdr.sh_offset); - const needed_size = self.local_symbols.items.len * entry_size; - if (needed_size > allocated_size) { - // Must move the entire got section. - const new_offset = self.findFreeSpace(needed_size, entry_size); - const amt = try self.base.file.?.copyRangeAll(shdr.sh_offset, self.base.file.?, new_offset, shdr.sh_size); - if (amt != shdr.sh_size) return error.InputOutput; - shdr.sh_offset = new_offset; - phdr.p_offset = new_offset; - } - shdr.sh_size = needed_size; - phdr.p_memsz = needed_size; - phdr.p_filesz = needed_size; - - self.shdr_table_dirty = true; // TODO look into making only the one section dirty - self.phdr_table_dirty = true; // TODO look into making only the one program header dirty - - self.offset_table_count_dirty = false; - } - const endian = self.base.options.target.cpu.arch.endian(); - const off = shdr.sh_offset + @as(u64, entry_size) * index; - switch (self.ptr_width) { - .p32 => { - var buf: [4]u8 = undefined; - mem.writeInt(u32, &buf, @intCast(u32, self.offset_table.items[index]), endian); - try self.base.file.?.pwriteAll(&buf, off); - }, - .p64 => { - var buf: [8]u8 = undefined; - mem.writeInt(u64, &buf, self.offset_table.items[index], endian); - try self.base.file.?.pwriteAll(&buf, off); - }, - } - } - - fn writeSymbol(self: *Elf, index: usize) !void { - const tracy = trace(@src()); - defer tracy.end(); - - const syms_sect = &self.sections.items[self.symtab_section_index.?]; - // Make sure we are not pointlessly writing symbol data that will have to get relocated - // due to running out of space. - if (self.local_symbols.items.len != syms_sect.sh_info) { - const sym_size: u64 = switch (self.ptr_width) { - .p32 => @sizeOf(elf.Elf32_Sym), - .p64 => @sizeOf(elf.Elf64_Sym), - }; - const sym_align: u16 = switch (self.ptr_width) { - .p32 => @alignOf(elf.Elf32_Sym), - .p64 => @alignOf(elf.Elf64_Sym), - }; - const needed_size = (self.local_symbols.items.len + self.global_symbols.items.len) * sym_size; - if (needed_size > self.allocatedSize(syms_sect.sh_offset)) { - // Move all the symbols to a new file location. - const new_offset = self.findFreeSpace(needed_size, sym_align); - const existing_size = @as(u64, syms_sect.sh_info) * sym_size; - const amt = try self.base.file.?.copyRangeAll(syms_sect.sh_offset, self.base.file.?, new_offset, existing_size); - if (amt != existing_size) return error.InputOutput; - syms_sect.sh_offset = new_offset; - } - syms_sect.sh_info = @intCast(u32, self.local_symbols.items.len); - syms_sect.sh_size = needed_size; // anticipating adding the global symbols later - self.shdr_table_dirty = true; // TODO look into only writing one section - } - const foreign_endian = self.base.options.target.cpu.arch.endian() != std.Target.current.cpu.arch.endian(); - switch (self.ptr_width) { - .p32 => { - var sym = [1]elf.Elf32_Sym{ - .{ - .st_name = self.local_symbols.items[index].st_name, - .st_value = @intCast(u32, self.local_symbols.items[index].st_value), - .st_size = @intCast(u32, self.local_symbols.items[index].st_size), - .st_info = self.local_symbols.items[index].st_info, - .st_other = self.local_symbols.items[index].st_other, - .st_shndx = self.local_symbols.items[index].st_shndx, - }, - }; - if (foreign_endian) { - bswapAllFields(elf.Elf32_Sym, &sym[0]); - } - const off = syms_sect.sh_offset + @sizeOf(elf.Elf32_Sym) * index; - try self.base.file.?.pwriteAll(mem.sliceAsBytes(sym[0..1]), off); - }, - .p64 => { - var sym = [1]elf.Elf64_Sym{self.local_symbols.items[index]}; - if (foreign_endian) { - bswapAllFields(elf.Elf64_Sym, &sym[0]); - } - const off = syms_sect.sh_offset + @sizeOf(elf.Elf64_Sym) * index; - try self.base.file.?.pwriteAll(mem.sliceAsBytes(sym[0..1]), off); - }, - } - } - - fn writeAllGlobalSymbols(self: *Elf) !void { - const syms_sect = &self.sections.items[self.symtab_section_index.?]; - const sym_size: u64 = switch (self.ptr_width) { - .p32 => @sizeOf(elf.Elf32_Sym), - .p64 => @sizeOf(elf.Elf64_Sym), - }; - const foreign_endian = self.base.options.target.cpu.arch.endian() != std.Target.current.cpu.arch.endian(); - const global_syms_off = syms_sect.sh_offset + self.local_symbols.items.len * sym_size; - switch (self.ptr_width) { - .p32 => { - const buf = try self.base.allocator.alloc(elf.Elf32_Sym, self.global_symbols.items.len); - defer self.base.allocator.free(buf); - - for (buf) |*sym, i| { - sym.* = .{ - .st_name = self.global_symbols.items[i].st_name, - .st_value = @intCast(u32, self.global_symbols.items[i].st_value), - .st_size = @intCast(u32, self.global_symbols.items[i].st_size), - .st_info = self.global_symbols.items[i].st_info, - .st_other = self.global_symbols.items[i].st_other, - .st_shndx = self.global_symbols.items[i].st_shndx, - }; - if (foreign_endian) { - bswapAllFields(elf.Elf32_Sym, sym); - } - } - try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), global_syms_off); - }, - .p64 => { - const buf = try self.base.allocator.alloc(elf.Elf64_Sym, self.global_symbols.items.len); - defer self.base.allocator.free(buf); - - for (buf) |*sym, i| { - sym.* = .{ - .st_name = self.global_symbols.items[i].st_name, - .st_value = self.global_symbols.items[i].st_value, - .st_size = self.global_symbols.items[i].st_size, - .st_info = self.global_symbols.items[i].st_info, - .st_other = self.global_symbols.items[i].st_other, - .st_shndx = self.global_symbols.items[i].st_shndx, - }; - if (foreign_endian) { - bswapAllFields(elf.Elf64_Sym, sym); - } - } - try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), global_syms_off); - }, - } - } - - fn ptrWidthBytes(self: Elf) u8 { - return switch (self.ptr_width) { - .p32 => 4, - .p64 => 8, - }; - } - - /// The reloc offset for the virtual address of a function in its Line Number Program. - /// Size is a virtual address integer. - const dbg_line_vaddr_reloc_index = 3; - /// The reloc offset for the virtual address of a function in its .debug_info TAG_subprogram. - /// Size is a virtual address integer. - const dbg_info_low_pc_reloc_index = 1; - - /// The reloc offset for the line offset of a function from the previous function's line. - /// It's a fixed-size 4-byte ULEB128. - fn getRelocDbgLineOff(self: Elf) usize { - return dbg_line_vaddr_reloc_index + self.ptrWidthBytes() + 1; - } - - fn getRelocDbgFileIndex(self: Elf) usize { - return self.getRelocDbgLineOff() + 5; - } - - fn getRelocDbgInfoSubprogramHighPC(self: Elf) u32 { - return dbg_info_low_pc_reloc_index + self.ptrWidthBytes(); - } - - fn dbgLineNeededHeaderBytes(self: Elf) u32 { - const directory_entry_format_count = 1; - const file_name_entry_format_count = 1; - const directory_count = 1; - const file_name_count = 1; - return @intCast(u32, 53 + directory_entry_format_count * 2 + file_name_entry_format_count * 2 + - directory_count * 8 + file_name_count * 8 + - // These are encoded as DW.FORM_string rather than DW.FORM_strp as we would like - // because of a workaround for readelf and gdb failing to understand DWARFv5 correctly. - self.base.options.root_pkg.root_src_dir_path.len + - self.base.options.root_pkg.root_src_path.len); - - } - - fn dbgInfoNeededHeaderBytes(self: Elf) u32 { - return 120; - } - - const min_nop_size = 2; - - /// Writes to the file a buffer, prefixed and suffixed by the specified number of - /// bytes of NOPs. Asserts each padding size is at least `min_nop_size` and total padding bytes - /// are less than 126,976 bytes (if this limit is ever reached, this function can be - /// improved to make more than one pwritev call, or the limit can be raised by a fixed - /// amount by increasing the length of `vecs`). - fn pwriteDbgLineNops( - self: *Elf, - prev_padding_size: usize, - buf: []const u8, - next_padding_size: usize, - offset: usize, - ) !void { - const tracy = trace(@src()); - defer tracy.end(); - - const page_of_nops = [1]u8{DW.LNS_negate_stmt} ** 4096; - const three_byte_nop = [3]u8{DW.LNS_advance_pc, 0b1000_0000, 0}; - var vecs: [32]std.os.iovec_const = undefined; - var vec_index: usize = 0; - { - var padding_left = prev_padding_size; - if (padding_left % 2 != 0) { - vecs[vec_index] = .{ - .iov_base = &three_byte_nop, - .iov_len = three_byte_nop.len, - }; - vec_index += 1; - padding_left -= three_byte_nop.len; - } - while (padding_left > page_of_nops.len) { - vecs[vec_index] = .{ - .iov_base = &page_of_nops, - .iov_len = page_of_nops.len, - }; - vec_index += 1; - padding_left -= page_of_nops.len; - } - if (padding_left > 0) { - vecs[vec_index] = .{ - .iov_base = &page_of_nops, - .iov_len = padding_left, - }; - vec_index += 1; - } - } - - vecs[vec_index] = .{ - .iov_base = buf.ptr, - .iov_len = buf.len, - }; - vec_index += 1; - - { - var padding_left = next_padding_size; - if (padding_left % 2 != 0) { - vecs[vec_index] = .{ - .iov_base = &three_byte_nop, - .iov_len = three_byte_nop.len, - }; - vec_index += 1; - padding_left -= three_byte_nop.len; - } - while (padding_left > page_of_nops.len) { - vecs[vec_index] = .{ - .iov_base = &page_of_nops, - .iov_len = page_of_nops.len, - }; - vec_index += 1; - padding_left -= page_of_nops.len; - } - if (padding_left > 0) { - vecs[vec_index] = .{ - .iov_base = &page_of_nops, - .iov_len = padding_left, - }; - vec_index += 1; - } - } - try self.base.file.?.pwritevAll(vecs[0..vec_index], offset - prev_padding_size); - } - - /// Writes to the file a buffer, prefixed and suffixed by the specified number of - /// bytes of padding. - fn pwriteDbgInfoNops( - self: *Elf, - prev_padding_size: usize, - buf: []const u8, - next_padding_size: usize, - trailing_zero: bool, - offset: usize, - ) !void { - const tracy = trace(@src()); - defer tracy.end(); - - const page_of_nops = [1]u8{abbrev_pad1} ** 4096; - var vecs: [32]std.os.iovec_const = undefined; - var vec_index: usize = 0; - { - var padding_left = prev_padding_size; - while (padding_left > page_of_nops.len) { - vecs[vec_index] = .{ - .iov_base = &page_of_nops, - .iov_len = page_of_nops.len, - }; - vec_index += 1; - padding_left -= page_of_nops.len; - } - if (padding_left > 0) { - vecs[vec_index] = .{ - .iov_base = &page_of_nops, - .iov_len = padding_left, - }; - vec_index += 1; - } - } - - vecs[vec_index] = .{ - .iov_base = buf.ptr, - .iov_len = buf.len, - }; - vec_index += 1; - - { - var padding_left = next_padding_size; - while (padding_left > page_of_nops.len) { - vecs[vec_index] = .{ - .iov_base = &page_of_nops, - .iov_len = page_of_nops.len, - }; - vec_index += 1; - padding_left -= page_of_nops.len; - } - if (padding_left > 0) { - vecs[vec_index] = .{ - .iov_base = &page_of_nops, - .iov_len = padding_left, - }; - vec_index += 1; - } - } - - if (trailing_zero) { - var zbuf = [1]u8{0}; - vecs[vec_index] = .{ - .iov_base = &zbuf, - .iov_len = zbuf.len, - }; - vec_index += 1; - } - - try self.base.file.?.pwritevAll(vecs[0..vec_index], offset - prev_padding_size); - } - - }; - + pub const C = @import("link/C.zig"); + pub const Elf = @import("link/Elf.zig"); pub const MachO = @import("link/MachO.zig"); - const Wasm = @import("link/Wasm.zig"); + pub const Wasm = @import("link/Wasm.zig"); }; -/// Saturating multiplication -fn satMul(a: anytype, b: anytype) @TypeOf(a, b) { - const T = @TypeOf(a, b); - return std.math.mul(T, a, b) catch std.math.maxInt(T); -} - -fn bswapAllFields(comptime S: type, ptr: *S) void { - @panic("TODO implement bswapAllFields"); -} - -fn progHeaderTo32(phdr: elf.Elf64_Phdr) elf.Elf32_Phdr { - return .{ - .p_type = phdr.p_type, - .p_flags = phdr.p_flags, - .p_offset = @intCast(u32, phdr.p_offset), - .p_vaddr = @intCast(u32, phdr.p_vaddr), - .p_paddr = @intCast(u32, phdr.p_paddr), - .p_filesz = @intCast(u32, phdr.p_filesz), - .p_memsz = @intCast(u32, phdr.p_memsz), - .p_align = @intCast(u32, phdr.p_align), - }; -} - -fn sectHeaderTo32(shdr: elf.Elf64_Shdr) elf.Elf32_Shdr { - return .{ - .sh_name = shdr.sh_name, - .sh_type = shdr.sh_type, - .sh_flags = @intCast(u32, shdr.sh_flags), - .sh_addr = @intCast(u32, shdr.sh_addr), - .sh_offset = @intCast(u32, shdr.sh_offset), - .sh_size = @intCast(u32, shdr.sh_size), - .sh_link = shdr.sh_link, - .sh_info = shdr.sh_info, - .sh_addralign = @intCast(u32, shdr.sh_addralign), - .sh_entsize = @intCast(u32, shdr.sh_entsize), - }; -} - pub fn determineMode(options: Options) fs.File.Mode { // On common systems with a 0o022 umask, 0o777 will still result in a file created // with 0o755 permissions, but it works appropriately if the system is configured diff --git a/src-self-hosted/link/C.zig b/src-self-hosted/link/C.zig new file mode 100644 index 0000000000..69eabd1f8b --- /dev/null +++ b/src-self-hosted/link/C.zig @@ -0,0 +1,101 @@ +const std = @import("std"); +const mem = std.mem; +const assert = std.debug.assert; +const Allocator = std.mem.Allocator; +const Module = @import("../Module.zig"); +const fs = std.fs; +const codegen = @import("../codegen/c.zig"); +const link = @import("../link.zig"); +const File = link.File; +const C = @This(); + +pub const base_tag: File.Tag = .c; + +base: File, + +header: std.ArrayList(u8), +constants: std.ArrayList(u8), +main: std.ArrayList(u8), + +called: std.StringHashMap(void), +need_stddef: bool = false, +need_stdint: bool = false, +error_msg: *Module.ErrorMsg = undefined, + +pub fn openPath(allocator: *Allocator, dir: fs.Dir, sub_path: []const u8, options: link.Options) !*File { + assert(options.object_format == .c); + + const file = try dir.createFile(sub_path, .{ .truncate = true, .read = true, .mode = link.determineMode(options) }); + errdefer file.close(); + + var c_file = try allocator.create(C); + errdefer allocator.destroy(c_file); + + c_file.* = C{ + .base = .{ + .tag = .c, + .options = options, + .file = file, + .allocator = allocator, + }, + .main = std.ArrayList(u8).init(allocator), + .header = std.ArrayList(u8).init(allocator), + .constants = std.ArrayList(u8).init(allocator), + .called = std.StringHashMap(void).init(allocator), + }; + + return &c_file.base; +} + +pub fn fail(self: *C, src: usize, comptime format: []const u8, args: anytype) error{ AnalysisFail, OutOfMemory } { + self.error_msg = try Module.ErrorMsg.create(self.base.allocator, src, format, args); + return error.AnalysisFail; +} + +pub fn deinit(self: *C) void { + self.main.deinit(); + self.header.deinit(); + self.constants.deinit(); + self.called.deinit(); +} + +pub fn updateDecl(self: *C, module: *Module, decl: *Module.Decl) !void { + codegen.generate(self, decl) catch |err| { + if (err == error.AnalysisFail) { + try module.failed_decls.put(module.gpa, decl, self.error_msg); + } + return err; + }; +} + +pub fn flush(self: *C, module: *Module) !void { + const writer = self.base.file.?.writer(); + try writer.writeAll(@embedFile("cbe.h")); + var includes = false; + if (self.need_stddef) { + try writer.writeAll("#include \n"); + includes = true; + } + if (self.need_stdint) { + try writer.writeAll("#include \n"); + includes = true; + } + if (includes) { + try writer.writeByte('\n'); + } + if (self.header.items.len > 0) { + try writer.print("{}\n", .{self.header.items}); + } + if (self.constants.items.len > 0) { + try writer.print("{}\n", .{self.constants.items}); + } + if (self.main.items.len > 1) { + const last_two = self.main.items[self.main.items.len - 2 ..]; + if (std.mem.eql(u8, last_two, "\n\n")) { + self.main.items.len -= 1; + } + } + try writer.writeAll(self.main.items); + self.base.file.?.close(); + self.base.file = null; +} diff --git a/src-self-hosted/link/Elf.zig b/src-self-hosted/link/Elf.zig new file mode 100644 index 0000000000..3751411297 --- /dev/null +++ b/src-self-hosted/link/Elf.zig @@ -0,0 +1,2583 @@ +const std = @import("std"); +const mem = std.mem; +const assert = std.debug.assert; +const Allocator = std.mem.Allocator; +const ir = @import("../ir.zig"); +const Module = @import("../Module.zig"); +const fs = std.fs; +const elf = std.elf; +const codegen = @import("../codegen.zig"); +const log = std.log.scoped(.link); +const DW = std.dwarf; +const trace = @import("../tracy.zig").trace; +const leb128 = std.debug.leb; +const Package = @import("../Package.zig"); +const Value = @import("../value.zig").Value; +const Type = @import("../type.zig").Type; +const build_options = @import("build_options"); +const link = @import("../link.zig"); +const File = link.File; +const Elf = @This(); + +const producer_string = if (std.builtin.is_test) "zig test" else "zig " ++ build_options.version; +const default_entry_addr = 0x8000000; + +// TODO Turn back on zig fmt when https://github.com/ziglang/zig/issues/5948 is implemented. +// zig fmt: off + +pub const base_tag: File.Tag = .elf; + +base: File, + +ptr_width: enum { p32, p64 }, + +/// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write. +/// Same order as in the file. +sections: std.ArrayListUnmanaged(elf.Elf64_Shdr) = std.ArrayListUnmanaged(elf.Elf64_Shdr){}, +shdr_table_offset: ?u64 = null, + +/// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write. +/// Same order as in the file. +program_headers: std.ArrayListUnmanaged(elf.Elf64_Phdr) = std.ArrayListUnmanaged(elf.Elf64_Phdr){}, +phdr_table_offset: ?u64 = null, +/// The index into the program headers of a PT_LOAD program header with Read and Execute flags +phdr_load_re_index: ?u16 = null, +/// The index into the program headers of the global offset table. +/// It needs PT_LOAD and Read flags. +phdr_got_index: ?u16 = null, +entry_addr: ?u64 = null, + +debug_strtab: std.ArrayListUnmanaged(u8) = std.ArrayListUnmanaged(u8){}, +shstrtab: std.ArrayListUnmanaged(u8) = std.ArrayListUnmanaged(u8){}, +shstrtab_index: ?u16 = null, + +text_section_index: ?u16 = null, +symtab_section_index: ?u16 = null, +got_section_index: ?u16 = null, +debug_info_section_index: ?u16 = null, +debug_abbrev_section_index: ?u16 = null, +debug_str_section_index: ?u16 = null, +debug_aranges_section_index: ?u16 = null, +debug_line_section_index: ?u16 = null, + +debug_abbrev_table_offset: ?u64 = null, + +/// The same order as in the file. ELF requires global symbols to all be after the +/// local symbols, they cannot be mixed. So we must buffer all the global symbols and +/// write them at the end. These are only the local symbols. The length of this array +/// is the value used for sh_info in the .symtab section. +local_symbols: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{}, +global_symbols: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{}, + +local_symbol_free_list: std.ArrayListUnmanaged(u32) = .{}, +global_symbol_free_list: std.ArrayListUnmanaged(u32) = .{}, +offset_table_free_list: std.ArrayListUnmanaged(u32) = .{}, + +/// Same order as in the file. The value is the absolute vaddr value. +/// If the vaddr of the executable program header changes, the entire +/// offset table needs to be rewritten. +offset_table: std.ArrayListUnmanaged(u64) = .{}, + +phdr_table_dirty: bool = false, +shdr_table_dirty: bool = false, +shstrtab_dirty: bool = false, +debug_strtab_dirty: bool = false, +offset_table_count_dirty: bool = false, +debug_abbrev_section_dirty: bool = false, +debug_aranges_section_dirty: bool = false, + +debug_info_header_dirty: bool = false, +debug_line_header_dirty: bool = false, + +error_flags: File.ErrorFlags = File.ErrorFlags{}, + +/// A list of text blocks that have surplus capacity. This list can have false +/// positives, as functions grow and shrink over time, only sometimes being added +/// or removed from the freelist. +/// +/// A text block has surplus capacity when its overcapacity value is greater than +/// minimum_text_block_size * alloc_num / alloc_den. That is, when it has so +/// much extra capacity, that we could fit a small new symbol in it, itself with +/// ideal_capacity or more. +/// +/// Ideal capacity is defined by size * alloc_num / alloc_den. +/// +/// Overcapacity is measured by actual_capacity - ideal_capacity. Note that +/// overcapacity can be negative. A simple way to have negative overcapacity is to +/// allocate a fresh text block, which will have ideal capacity, and then grow it +/// by 1 byte. It will then have -1 overcapacity. +text_block_free_list: std.ArrayListUnmanaged(*TextBlock) = .{}, +last_text_block: ?*TextBlock = null, + +/// A list of `SrcFn` whose Line Number Programs have surplus capacity. +/// This is the same concept as `text_block_free_list`; see those doc comments. +dbg_line_fn_free_list: std.AutoHashMapUnmanaged(*SrcFn, void) = .{}, +dbg_line_fn_first: ?*SrcFn = null, +dbg_line_fn_last: ?*SrcFn = null, + +/// A list of `TextBlock` whose corresponding .debug_info tags have surplus capacity. +/// This is the same concept as `text_block_free_list`; see those doc comments. +dbg_info_decl_free_list: std.AutoHashMapUnmanaged(*TextBlock, void) = .{}, +dbg_info_decl_first: ?*TextBlock = null, +dbg_info_decl_last: ?*TextBlock = null, + +/// `alloc_num / alloc_den` is the factor of padding when allocating. +const alloc_num = 4; +const alloc_den = 3; + +/// In order for a slice of bytes to be considered eligible to keep metadata pointing at +/// it as a possible place to put new symbols, it must have enough room for this many bytes +/// (plus extra for reserved capacity). +const minimum_text_block_size = 64; +const min_text_capacity = minimum_text_block_size * alloc_num / alloc_den; + +pub const TextBlock = struct { + /// Each decl always gets a local symbol with the fully qualified name. + /// The vaddr and size are found here directly. + /// The file offset is found by computing the vaddr offset from the section vaddr + /// the symbol references, and adding that to the file offset of the section. + /// If this field is 0, it means the codegen size = 0 and there is no symbol or + /// offset table entry. + local_sym_index: u32, + /// This field is undefined for symbols with size = 0. + offset_table_index: u32, + /// Points to the previous and next neighbors, based on the `text_offset`. + /// This can be used to find, for example, the capacity of this `TextBlock`. + prev: ?*TextBlock, + next: ?*TextBlock, + + /// Previous/next linked list pointers. This value is `next ^ prev`. + /// This is the linked list node for this Decl's corresponding .debug_info tag. + dbg_info_prev: ?*TextBlock, + dbg_info_next: ?*TextBlock, + /// Offset into .debug_info pointing to the tag for this Decl. + dbg_info_off: u32, + /// Size of the .debug_info tag for this Decl, not including padding. + dbg_info_len: u32, + + pub const empty = TextBlock{ + .local_sym_index = 0, + .offset_table_index = undefined, + .prev = null, + .next = null, + .dbg_info_prev = null, + .dbg_info_next = null, + .dbg_info_off = undefined, + .dbg_info_len = undefined, + }; + + /// Returns how much room there is to grow in virtual address space. + /// File offset relocation happens transparently, so it is not included in + /// this calculation. + fn capacity(self: TextBlock, elf_file: Elf) u64 { + const self_sym = elf_file.local_symbols.items[self.local_sym_index]; + if (self.next) |next| { + const next_sym = elf_file.local_symbols.items[next.local_sym_index]; + return next_sym.st_value - self_sym.st_value; + } else { + // We are the last block. The capacity is limited only by virtual address space. + return std.math.maxInt(u32) - self_sym.st_value; + } + } + + fn freeListEligible(self: TextBlock, elf_file: Elf) bool { + // No need to keep a free list node for the last block. + const next = self.next orelse return false; + const self_sym = elf_file.local_symbols.items[self.local_sym_index]; + const next_sym = elf_file.local_symbols.items[next.local_sym_index]; + const cap = next_sym.st_value - self_sym.st_value; + const ideal_cap = self_sym.st_size * alloc_num / alloc_den; + if (cap <= ideal_cap) return false; + const surplus = cap - ideal_cap; + return surplus >= min_text_capacity; + } +}; + +pub const Export = struct { + sym_index: ?u32 = null, +}; + +pub const SrcFn = struct { + /// Offset from the beginning of the Debug Line Program header that contains this function. + off: u32, + /// Size of the line number program component belonging to this function, not + /// including padding. + len: u32, + + /// Points to the previous and next neighbors, based on the offset from .debug_line. + /// This can be used to find, for example, the capacity of this `SrcFn`. + prev: ?*SrcFn, + next: ?*SrcFn, + + pub const empty: SrcFn = .{ + .off = 0, + .len = 0, + .prev = null, + .next = null, + }; +}; + +pub fn openPath(allocator: *Allocator, dir: fs.Dir, sub_path: []const u8, options: link.Options) !*File { + assert(options.object_format == .elf); + + const file = try dir.createFile(sub_path, .{ .truncate = false, .read = true, .mode = link.determineMode(options) }); + errdefer file.close(); + + var elf_file = try allocator.create(Elf); + errdefer allocator.destroy(elf_file); + + elf_file.* = openFile(allocator, file, options) catch |err| switch (err) { + error.IncrFailed => try createFile(allocator, file, options), + else => |e| return e, + }; + + return &elf_file.base; +} + +/// Returns error.IncrFailed if incremental update could not be performed. +fn openFile(allocator: *Allocator, file: fs.File, options: link.Options) !Elf { + switch (options.output_mode) { + .Exe => {}, + .Obj => {}, + .Lib => return error.IncrFailed, + } + var self: Elf = .{ + .base = .{ + .file = file, + .tag = .elf, + .options = options, + .allocator = allocator, + }, + .ptr_width = switch (options.target.cpu.arch.ptrBitWidth()) { + 32 => .p32, + 64 => .p64, + else => return error.UnsupportedELFArchitecture, + }, + }; + errdefer self.deinit(); + + // TODO implement reading the elf file + return error.IncrFailed; + //try self.populateMissingMetadata(); + //return self; +} + +/// Truncates the existing file contents and overwrites the contents. +/// Returns an error if `file` is not already open with +read +write +seek abilities. +fn createFile(allocator: *Allocator, file: fs.File, options: link.Options) !Elf { + switch (options.output_mode) { + .Exe => {}, + .Obj => {}, + .Lib => return error.TODOImplementWritingLibFiles, + } + var self: Elf = .{ + .base = .{ + .tag = .elf, + .options = options, + .allocator = allocator, + .file = file, + }, + .ptr_width = switch (options.target.cpu.arch.ptrBitWidth()) { + 32 => .p32, + 64 => .p64, + else => return error.UnsupportedELFArchitecture, + }, + .shdr_table_dirty = true, + }; + errdefer self.deinit(); + + // Index 0 is always a null symbol. + try self.local_symbols.append(allocator, .{ + .st_name = 0, + .st_info = 0, + .st_other = 0, + .st_shndx = 0, + .st_value = 0, + .st_size = 0, + }); + + // There must always be a null section in index 0 + try self.sections.append(allocator, .{ + .sh_name = 0, + .sh_type = elf.SHT_NULL, + .sh_flags = 0, + .sh_addr = 0, + .sh_offset = 0, + .sh_size = 0, + .sh_link = 0, + .sh_info = 0, + .sh_addralign = 0, + .sh_entsize = 0, + }); + + try self.populateMissingMetadata(); + + return self; +} + +pub fn deinit(self: *Elf) void { + self.sections.deinit(self.base.allocator); + self.program_headers.deinit(self.base.allocator); + self.shstrtab.deinit(self.base.allocator); + self.debug_strtab.deinit(self.base.allocator); + self.local_symbols.deinit(self.base.allocator); + self.global_symbols.deinit(self.base.allocator); + self.global_symbol_free_list.deinit(self.base.allocator); + self.local_symbol_free_list.deinit(self.base.allocator); + self.offset_table_free_list.deinit(self.base.allocator); + self.text_block_free_list.deinit(self.base.allocator); + self.dbg_line_fn_free_list.deinit(self.base.allocator); + self.dbg_info_decl_free_list.deinit(self.base.allocator); + self.offset_table.deinit(self.base.allocator); +} + +pub fn getDeclVAddr(self: *Elf, decl: *const Module.Decl) u64 { + assert(decl.link.elf.local_sym_index != 0); + return self.local_symbols.items[decl.link.elf.local_sym_index].st_value; +} + +fn getDebugLineProgramOff(self: Elf) u32 { + return self.dbg_line_fn_first.?.off; +} + +fn getDebugLineProgramEnd(self: Elf) u32 { + return self.dbg_line_fn_last.?.off + self.dbg_line_fn_last.?.len; +} + +/// Returns end pos of collision, if any. +fn detectAllocCollision(self: *Elf, start: u64, size: u64) ?u64 { + const small_ptr = self.base.options.target.cpu.arch.ptrBitWidth() == 32; + const ehdr_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Ehdr) else @sizeOf(elf.Elf64_Ehdr); + if (start < ehdr_size) + return ehdr_size; + + const end = start + satMul(size, alloc_num) / alloc_den; + + if (self.shdr_table_offset) |off| { + const shdr_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Shdr) else @sizeOf(elf.Elf64_Shdr); + const tight_size = self.sections.items.len * shdr_size; + const increased_size = satMul(tight_size, alloc_num) / alloc_den; + const test_end = off + increased_size; + if (end > off and start < test_end) { + return test_end; + } + } + + if (self.phdr_table_offset) |off| { + const phdr_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Phdr) else @sizeOf(elf.Elf64_Phdr); + const tight_size = self.sections.items.len * phdr_size; + const increased_size = satMul(tight_size, alloc_num) / alloc_den; + const test_end = off + increased_size; + if (end > off and start < test_end) { + return test_end; + } + } + + for (self.sections.items) |section| { + const increased_size = satMul(section.sh_size, alloc_num) / alloc_den; + const test_end = section.sh_offset + increased_size; + if (end > section.sh_offset and start < test_end) { + return test_end; + } + } + for (self.program_headers.items) |program_header| { + const increased_size = satMul(program_header.p_filesz, alloc_num) / alloc_den; + const test_end = program_header.p_offset + increased_size; + if (end > program_header.p_offset and start < test_end) { + return test_end; + } + } + return null; +} + +fn allocatedSize(self: *Elf, start: u64) u64 { + if (start == 0) + return 0; + var min_pos: u64 = std.math.maxInt(u64); + if (self.shdr_table_offset) |off| { + if (off > start and off < min_pos) min_pos = off; + } + if (self.phdr_table_offset) |off| { + if (off > start and off < min_pos) min_pos = off; + } + for (self.sections.items) |section| { + if (section.sh_offset <= start) continue; + if (section.sh_offset < min_pos) min_pos = section.sh_offset; + } + for (self.program_headers.items) |program_header| { + if (program_header.p_offset <= start) continue; + if (program_header.p_offset < min_pos) min_pos = program_header.p_offset; + } + return min_pos - start; +} + +fn findFreeSpace(self: *Elf, object_size: u64, min_alignment: u16) u64 { + var start: u64 = 0; + while (self.detectAllocCollision(start, object_size)) |item_end| { + start = mem.alignForwardGeneric(u64, item_end, min_alignment); + } + return start; +} + +/// TODO Improve this to use a table. +fn makeString(self: *Elf, bytes: []const u8) !u32 { + try self.shstrtab.ensureCapacity(self.base.allocator, self.shstrtab.items.len + bytes.len + 1); + const result = self.shstrtab.items.len; + self.shstrtab.appendSliceAssumeCapacity(bytes); + self.shstrtab.appendAssumeCapacity(0); + return @intCast(u32, result); +} + +/// TODO Improve this to use a table. +fn makeDebugString(self: *Elf, bytes: []const u8) !u32 { + try self.debug_strtab.ensureCapacity(self.base.allocator, self.debug_strtab.items.len + bytes.len + 1); + const result = self.debug_strtab.items.len; + self.debug_strtab.appendSliceAssumeCapacity(bytes); + self.debug_strtab.appendAssumeCapacity(0); + return @intCast(u32, result); +} + +fn getString(self: *Elf, str_off: u32) []const u8 { + assert(str_off < self.shstrtab.items.len); + return mem.spanZ(@ptrCast([*:0]const u8, self.shstrtab.items.ptr + str_off)); +} + +fn updateString(self: *Elf, old_str_off: u32, new_name: []const u8) !u32 { + const existing_name = self.getString(old_str_off); + if (mem.eql(u8, existing_name, new_name)) { + return old_str_off; + } + return self.makeString(new_name); +} + +pub fn populateMissingMetadata(self: *Elf) !void { + const small_ptr = switch (self.ptr_width) { + .p32 => true, + .p64 => false, + }; + const ptr_size: u8 = self.ptrWidthBytes(); + if (self.phdr_load_re_index == null) { + self.phdr_load_re_index = @intCast(u16, self.program_headers.items.len); + const file_size = self.base.options.program_code_size_hint; + const p_align = 0x1000; + const off = self.findFreeSpace(file_size, p_align); + log.debug("found PT_LOAD free space 0x{x} to 0x{x}\n", .{ off, off + file_size }); + try self.program_headers.append(self.base.allocator, .{ + .p_type = elf.PT_LOAD, + .p_offset = off, + .p_filesz = file_size, + .p_vaddr = default_entry_addr, + .p_paddr = default_entry_addr, + .p_memsz = file_size, + .p_align = p_align, + .p_flags = elf.PF_X | elf.PF_R, + }); + self.entry_addr = null; + self.phdr_table_dirty = true; + } + if (self.phdr_got_index == null) { + self.phdr_got_index = @intCast(u16, self.program_headers.items.len); + const file_size = @as(u64, ptr_size) * self.base.options.symbol_count_hint; + // We really only need ptr alignment but since we are using PROGBITS, linux requires + // page align. + const p_align = if (self.base.options.target.os.tag == .linux) 0x1000 else @as(u16, ptr_size); + const off = self.findFreeSpace(file_size, p_align); + log.debug("found PT_LOAD free space 0x{x} to 0x{x}\n", .{ off, off + file_size }); + // TODO instead of hard coding the vaddr, make a function to find a vaddr to put things at. + // we'll need to re-use that function anyway, in case the GOT grows and overlaps something + // else in virtual memory. + const default_got_addr = if (ptr_size == 2) @as(u32, 0x8000) else 0x4000000; + try self.program_headers.append(self.base.allocator, .{ + .p_type = elf.PT_LOAD, + .p_offset = off, + .p_filesz = file_size, + .p_vaddr = default_got_addr, + .p_paddr = default_got_addr, + .p_memsz = file_size, + .p_align = p_align, + .p_flags = elf.PF_R, + }); + self.phdr_table_dirty = true; + } + if (self.shstrtab_index == null) { + self.shstrtab_index = @intCast(u16, self.sections.items.len); + assert(self.shstrtab.items.len == 0); + try self.shstrtab.append(self.base.allocator, 0); // need a 0 at position 0 + const off = self.findFreeSpace(self.shstrtab.items.len, 1); + log.debug("found shstrtab free space 0x{x} to 0x{x}\n", .{ off, off + self.shstrtab.items.len }); + try self.sections.append(self.base.allocator, .{ + .sh_name = try self.makeString(".shstrtab"), + .sh_type = elf.SHT_STRTAB, + .sh_flags = 0, + .sh_addr = 0, + .sh_offset = off, + .sh_size = self.shstrtab.items.len, + .sh_link = 0, + .sh_info = 0, + .sh_addralign = 1, + .sh_entsize = 0, + }); + self.shstrtab_dirty = true; + self.shdr_table_dirty = true; + } + if (self.text_section_index == null) { + self.text_section_index = @intCast(u16, self.sections.items.len); + const phdr = &self.program_headers.items[self.phdr_load_re_index.?]; + + try self.sections.append(self.base.allocator, .{ + .sh_name = try self.makeString(".text"), + .sh_type = elf.SHT_PROGBITS, + .sh_flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR, + .sh_addr = phdr.p_vaddr, + .sh_offset = phdr.p_offset, + .sh_size = phdr.p_filesz, + .sh_link = 0, + .sh_info = 0, + .sh_addralign = phdr.p_align, + .sh_entsize = 0, + }); + self.shdr_table_dirty = true; + } + if (self.got_section_index == null) { + self.got_section_index = @intCast(u16, self.sections.items.len); + const phdr = &self.program_headers.items[self.phdr_got_index.?]; + + try self.sections.append(self.base.allocator, .{ + .sh_name = try self.makeString(".got"), + .sh_type = elf.SHT_PROGBITS, + .sh_flags = elf.SHF_ALLOC, + .sh_addr = phdr.p_vaddr, + .sh_offset = phdr.p_offset, + .sh_size = phdr.p_filesz, + .sh_link = 0, + .sh_info = 0, + .sh_addralign = phdr.p_align, + .sh_entsize = 0, + }); + self.shdr_table_dirty = true; + } + if (self.symtab_section_index == null) { + self.symtab_section_index = @intCast(u16, self.sections.items.len); + const min_align: u16 = if (small_ptr) @alignOf(elf.Elf32_Sym) else @alignOf(elf.Elf64_Sym); + const each_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Sym) else @sizeOf(elf.Elf64_Sym); + const file_size = self.base.options.symbol_count_hint * each_size; + const off = self.findFreeSpace(file_size, min_align); + log.debug("found symtab free space 0x{x} to 0x{x}\n", .{ off, off + file_size }); + + try self.sections.append(self.base.allocator, .{ + .sh_name = try self.makeString(".symtab"), + .sh_type = elf.SHT_SYMTAB, + .sh_flags = 0, + .sh_addr = 0, + .sh_offset = off, + .sh_size = file_size, + // The section header index of the associated string table. + .sh_link = self.shstrtab_index.?, + .sh_info = @intCast(u32, self.local_symbols.items.len), + .sh_addralign = min_align, + .sh_entsize = each_size, + }); + self.shdr_table_dirty = true; + try self.writeSymbol(0); + } + if (self.debug_str_section_index == null) { + self.debug_str_section_index = @intCast(u16, self.sections.items.len); + assert(self.debug_strtab.items.len == 0); + try self.sections.append(self.base.allocator, .{ + .sh_name = try self.makeString(".debug_str"), + .sh_type = elf.SHT_PROGBITS, + .sh_flags = elf.SHF_MERGE | elf.SHF_STRINGS, + .sh_addr = 0, + .sh_offset = 0, + .sh_size = self.debug_strtab.items.len, + .sh_link = 0, + .sh_info = 0, + .sh_addralign = 1, + .sh_entsize = 1, + }); + self.debug_strtab_dirty = true; + self.shdr_table_dirty = true; + } + if (self.debug_info_section_index == null) { + self.debug_info_section_index = @intCast(u16, self.sections.items.len); + + const file_size_hint = 200; + const p_align = 1; + const off = self.findFreeSpace(file_size_hint, p_align); + log.debug("found .debug_info free space 0x{x} to 0x{x}\n", .{ + off, + off + file_size_hint, + }); + try self.sections.append(self.base.allocator, .{ + .sh_name = try self.makeString(".debug_info"), + .sh_type = elf.SHT_PROGBITS, + .sh_flags = 0, + .sh_addr = 0, + .sh_offset = off, + .sh_size = file_size_hint, + .sh_link = 0, + .sh_info = 0, + .sh_addralign = p_align, + .sh_entsize = 0, + }); + self.shdr_table_dirty = true; + self.debug_info_header_dirty = true; + } + if (self.debug_abbrev_section_index == null) { + self.debug_abbrev_section_index = @intCast(u16, self.sections.items.len); + + const file_size_hint = 128; + const p_align = 1; + const off = self.findFreeSpace(file_size_hint, p_align); + log.debug("found .debug_abbrev free space 0x{x} to 0x{x}\n", .{ + off, + off + file_size_hint, + }); + try self.sections.append(self.base.allocator, .{ + .sh_name = try self.makeString(".debug_abbrev"), + .sh_type = elf.SHT_PROGBITS, + .sh_flags = 0, + .sh_addr = 0, + .sh_offset = off, + .sh_size = file_size_hint, + .sh_link = 0, + .sh_info = 0, + .sh_addralign = p_align, + .sh_entsize = 0, + }); + self.shdr_table_dirty = true; + self.debug_abbrev_section_dirty = true; + } + if (self.debug_aranges_section_index == null) { + self.debug_aranges_section_index = @intCast(u16, self.sections.items.len); + + const file_size_hint = 160; + const p_align = 16; + const off = self.findFreeSpace(file_size_hint, p_align); + log.debug("found .debug_aranges free space 0x{x} to 0x{x}\n", .{ + off, + off + file_size_hint, + }); + try self.sections.append(self.base.allocator, .{ + .sh_name = try self.makeString(".debug_aranges"), + .sh_type = elf.SHT_PROGBITS, + .sh_flags = 0, + .sh_addr = 0, + .sh_offset = off, + .sh_size = file_size_hint, + .sh_link = 0, + .sh_info = 0, + .sh_addralign = p_align, + .sh_entsize = 0, + }); + self.shdr_table_dirty = true; + self.debug_aranges_section_dirty = true; + } + if (self.debug_line_section_index == null) { + self.debug_line_section_index = @intCast(u16, self.sections.items.len); + + const file_size_hint = 250; + const p_align = 1; + const off = self.findFreeSpace(file_size_hint, p_align); + log.debug("found .debug_line free space 0x{x} to 0x{x}\n", .{ + off, + off + file_size_hint, + }); + try self.sections.append(self.base.allocator, .{ + .sh_name = try self.makeString(".debug_line"), + .sh_type = elf.SHT_PROGBITS, + .sh_flags = 0, + .sh_addr = 0, + .sh_offset = off, + .sh_size = file_size_hint, + .sh_link = 0, + .sh_info = 0, + .sh_addralign = p_align, + .sh_entsize = 0, + }); + self.shdr_table_dirty = true; + self.debug_line_header_dirty = true; + } + const shsize: u64 = switch (self.ptr_width) { + .p32 => @sizeOf(elf.Elf32_Shdr), + .p64 => @sizeOf(elf.Elf64_Shdr), + }; + const shalign: u16 = switch (self.ptr_width) { + .p32 => @alignOf(elf.Elf32_Shdr), + .p64 => @alignOf(elf.Elf64_Shdr), + }; + if (self.shdr_table_offset == null) { + self.shdr_table_offset = self.findFreeSpace(self.sections.items.len * shsize, shalign); + self.shdr_table_dirty = true; + } + const phsize: u64 = switch (self.ptr_width) { + .p32 => @sizeOf(elf.Elf32_Phdr), + .p64 => @sizeOf(elf.Elf64_Phdr), + }; + const phalign: u16 = switch (self.ptr_width) { + .p32 => @alignOf(elf.Elf32_Phdr), + .p64 => @alignOf(elf.Elf64_Phdr), + }; + if (self.phdr_table_offset == null) { + self.phdr_table_offset = self.findFreeSpace(self.program_headers.items.len * phsize, phalign); + self.phdr_table_dirty = true; + } + { + // Iterate over symbols, populating free_list and last_text_block. + if (self.local_symbols.items.len != 1) { + @panic("TODO implement setting up free_list and last_text_block from existing ELF file"); + } + // We are starting with an empty file. The default values are correct, null and empty list. + } +} + +pub const abbrev_compile_unit = 1; +pub const abbrev_subprogram = 2; +pub const abbrev_subprogram_retvoid = 3; +pub const abbrev_base_type = 4; +pub const abbrev_pad1 = 5; +pub const abbrev_parameter = 6; + +/// Commit pending changes and write headers. +pub fn flush(self: *Elf, module: *Module) !void { + const target_endian = self.base.options.target.cpu.arch.endian(); + const foreign_endian = target_endian != std.Target.current.cpu.arch.endian(); + const ptr_width_bytes: u8 = self.ptrWidthBytes(); + const init_len_size: usize = switch (self.ptr_width) { + .p32 => 4, + .p64 => 12, + }; + + // Unfortunately these have to be buffered and done at the end because ELF does not allow + // mixing local and global symbols within a symbol table. + try self.writeAllGlobalSymbols(); + + if (self.debug_abbrev_section_dirty) { + const debug_abbrev_sect = &self.sections.items[self.debug_abbrev_section_index.?]; + + // These are LEB encoded but since the values are all less than 127 + // we can simply append these bytes. + const abbrev_buf = [_]u8{ + abbrev_compile_unit, DW.TAG_compile_unit, DW.CHILDREN_yes, // header + DW.AT_stmt_list, DW.FORM_sec_offset, DW.AT_low_pc, + DW.FORM_addr, DW.AT_high_pc, DW.FORM_addr, + DW.AT_name, DW.FORM_strp, DW.AT_comp_dir, + DW.FORM_strp, DW.AT_producer, DW.FORM_strp, + DW.AT_language, DW.FORM_data2, 0, + 0, // table sentinel + abbrev_subprogram, DW.TAG_subprogram, + DW.CHILDREN_yes, // header + DW.AT_low_pc, DW.FORM_addr, + DW.AT_high_pc, DW.FORM_data4, DW.AT_type, + DW.FORM_ref4, DW.AT_name, DW.FORM_string, + 0, 0, // table sentinel + abbrev_subprogram_retvoid, + DW.TAG_subprogram, DW.CHILDREN_yes, // header + DW.AT_low_pc, + DW.FORM_addr, DW.AT_high_pc, DW.FORM_data4, + DW.AT_name, DW.FORM_string, 0, + 0, // table sentinel + abbrev_base_type, DW.TAG_base_type, + DW.CHILDREN_no, // header + DW.AT_encoding, DW.FORM_data1, + DW.AT_byte_size, DW.FORM_data1, DW.AT_name, + DW.FORM_string, 0, 0, // table sentinel + + abbrev_pad1, DW.TAG_unspecified_type, DW.CHILDREN_no, // header + 0, 0, // table sentinel + abbrev_parameter, + DW.TAG_formal_parameter, DW.CHILDREN_no, // header + DW.AT_location, + DW.FORM_exprloc, DW.AT_type, DW.FORM_ref4, + DW.AT_name, DW.FORM_string, 0, + 0, // table sentinel + 0, 0, + 0, // section sentinel + }; + + const needed_size = abbrev_buf.len; + const allocated_size = self.allocatedSize(debug_abbrev_sect.sh_offset); + if (needed_size > allocated_size) { + debug_abbrev_sect.sh_size = 0; // free the space + debug_abbrev_sect.sh_offset = self.findFreeSpace(needed_size, 1); + } + debug_abbrev_sect.sh_size = needed_size; + log.debug(".debug_abbrev start=0x{x} end=0x{x}\n", .{ + debug_abbrev_sect.sh_offset, + debug_abbrev_sect.sh_offset + needed_size, + }); + + const abbrev_offset = 0; + self.debug_abbrev_table_offset = abbrev_offset; + try self.base.file.?.pwriteAll(&abbrev_buf, debug_abbrev_sect.sh_offset + abbrev_offset); + if (!self.shdr_table_dirty) { + // Then it won't get written with the others and we need to do it. + try self.writeSectHeader(self.debug_abbrev_section_index.?); + } + + self.debug_abbrev_section_dirty = false; + } + + if (self.debug_info_header_dirty) debug_info: { + // If this value is null it means there is an error in the module; + // leave debug_info_header_dirty=true. + const first_dbg_info_decl = self.dbg_info_decl_first orelse break :debug_info; + const last_dbg_info_decl = self.dbg_info_decl_last.?; + const debug_info_sect = &self.sections.items[self.debug_info_section_index.?]; + + var di_buf = std.ArrayList(u8).init(self.base.allocator); + defer di_buf.deinit(); + + // We have a function to compute the upper bound size, because it's needed + // for determining where to put the offset of the first `LinkBlock`. + try di_buf.ensureCapacity(self.dbgInfoNeededHeaderBytes()); + + // initial length - length of the .debug_info contribution for this compilation unit, + // not including the initial length itself. + // We have to come back and write it later after we know the size. + const after_init_len = di_buf.items.len + init_len_size; + // +1 for the final 0 that ends the compilation unit children. + const dbg_info_end = last_dbg_info_decl.dbg_info_off + last_dbg_info_decl.dbg_info_len + 1; + const init_len = dbg_info_end - after_init_len; + switch (self.ptr_width) { + .p32 => { + mem.writeInt(u32, di_buf.addManyAsArrayAssumeCapacity(4), @intCast(u32, init_len), target_endian); + }, + .p64 => { + di_buf.appendNTimesAssumeCapacity(0xff, 4); + mem.writeInt(u64, di_buf.addManyAsArrayAssumeCapacity(8), init_len, target_endian); + }, + } + mem.writeInt(u16, di_buf.addManyAsArrayAssumeCapacity(2), 4, target_endian); // DWARF version + const abbrev_offset = self.debug_abbrev_table_offset.?; + switch (self.ptr_width) { + .p32 => { + mem.writeInt(u32, di_buf.addManyAsArrayAssumeCapacity(4), @intCast(u32, abbrev_offset), target_endian); + di_buf.appendAssumeCapacity(4); // address size + }, + .p64 => { + mem.writeInt(u64, di_buf.addManyAsArrayAssumeCapacity(8), abbrev_offset, target_endian); + di_buf.appendAssumeCapacity(8); // address size + }, + } + // Write the form for the compile unit, which must match the abbrev table above. + const name_strp = try self.makeDebugString(self.base.options.root_pkg.root_src_path); + const comp_dir_strp = try self.makeDebugString(self.base.options.root_pkg.root_src_dir_path); + const producer_strp = try self.makeDebugString(producer_string); + // Currently only one compilation unit is supported, so the address range is simply + // identical to the main program header virtual address and memory size. + const text_phdr = &self.program_headers.items[self.phdr_load_re_index.?]; + const low_pc = text_phdr.p_vaddr; + const high_pc = text_phdr.p_vaddr + text_phdr.p_memsz; + + di_buf.appendAssumeCapacity(abbrev_compile_unit); + self.writeDwarfAddrAssumeCapacity(&di_buf, 0); // DW.AT_stmt_list, DW.FORM_sec_offset + self.writeDwarfAddrAssumeCapacity(&di_buf, low_pc); + self.writeDwarfAddrAssumeCapacity(&di_buf, high_pc); + self.writeDwarfAddrAssumeCapacity(&di_buf, name_strp); + self.writeDwarfAddrAssumeCapacity(&di_buf, comp_dir_strp); + self.writeDwarfAddrAssumeCapacity(&di_buf, producer_strp); + // We are still waiting on dwarf-std.org to assign DW_LANG_Zig a number: + // http://dwarfstd.org/ShowIssue.php?issue=171115.1 + // Until then we say it is C99. + mem.writeInt(u16, di_buf.addManyAsArrayAssumeCapacity(2), DW.LANG_C99, target_endian); + + if (di_buf.items.len > first_dbg_info_decl.dbg_info_off) { + // Move the first N decls to the end to make more padding for the header. + @panic("TODO: handle .debug_info header exceeding its padding"); + } + const jmp_amt = first_dbg_info_decl.dbg_info_off - di_buf.items.len; + try self.pwriteDbgInfoNops(0, di_buf.items, jmp_amt, false, debug_info_sect.sh_offset); + self.debug_info_header_dirty = false; + } + + if (self.debug_aranges_section_dirty) { + const debug_aranges_sect = &self.sections.items[self.debug_aranges_section_index.?]; + + var di_buf = std.ArrayList(u8).init(self.base.allocator); + defer di_buf.deinit(); + + // Enough for all the data without resizing. When support for more compilation units + // is added, the size of this section will become more variable. + try di_buf.ensureCapacity(100); + + // initial length - length of the .debug_aranges contribution for this compilation unit, + // not including the initial length itself. + // We have to come back and write it later after we know the size. + const init_len_index = di_buf.items.len; + di_buf.items.len += init_len_size; + const after_init_len = di_buf.items.len; + mem.writeInt(u16, di_buf.addManyAsArrayAssumeCapacity(2), 2, target_endian); // version + // When more than one compilation unit is supported, this will be the offset to it. + // For now it is always at offset 0 in .debug_info. + self.writeDwarfAddrAssumeCapacity(&di_buf, 0); // .debug_info offset + di_buf.appendAssumeCapacity(ptr_width_bytes); // address_size + di_buf.appendAssumeCapacity(0); // segment_selector_size + + const end_header_offset = di_buf.items.len; + const begin_entries_offset = mem.alignForward(end_header_offset, ptr_width_bytes * 2); + di_buf.appendNTimesAssumeCapacity(0, begin_entries_offset - end_header_offset); + + // Currently only one compilation unit is supported, so the address range is simply + // identical to the main program header virtual address and memory size. + const text_phdr = &self.program_headers.items[self.phdr_load_re_index.?]; + self.writeDwarfAddrAssumeCapacity(&di_buf, text_phdr.p_vaddr); + self.writeDwarfAddrAssumeCapacity(&di_buf, text_phdr.p_memsz); + + // Sentinel. + self.writeDwarfAddrAssumeCapacity(&di_buf, 0); + self.writeDwarfAddrAssumeCapacity(&di_buf, 0); + + // Go back and populate the initial length. + const init_len = di_buf.items.len - after_init_len; + switch (self.ptr_width) { + .p32 => { + mem.writeInt(u32, di_buf.items[init_len_index..][0..4], @intCast(u32, init_len), target_endian); + }, + .p64 => { + // initial length - length of the .debug_aranges contribution for this compilation unit, + // not including the initial length itself. + di_buf.items[init_len_index..][0..4].* = [_]u8{ 0xff, 0xff, 0xff, 0xff }; + mem.writeInt(u64, di_buf.items[init_len_index + 4 ..][0..8], init_len, target_endian); + }, + } + + const needed_size = di_buf.items.len; + const allocated_size = self.allocatedSize(debug_aranges_sect.sh_offset); + if (needed_size > allocated_size) { + debug_aranges_sect.sh_size = 0; // free the space + debug_aranges_sect.sh_offset = self.findFreeSpace(needed_size, 16); + } + debug_aranges_sect.sh_size = needed_size; + log.debug(".debug_aranges start=0x{x} end=0x{x}\n", .{ + debug_aranges_sect.sh_offset, + debug_aranges_sect.sh_offset + needed_size, + }); + + try self.base.file.?.pwriteAll(di_buf.items, debug_aranges_sect.sh_offset); + if (!self.shdr_table_dirty) { + // Then it won't get written with the others and we need to do it. + try self.writeSectHeader(self.debug_aranges_section_index.?); + } + + self.debug_aranges_section_dirty = false; + } + if (self.debug_line_header_dirty) debug_line: { + if (self.dbg_line_fn_first == null) { + break :debug_line; // Error in module; leave debug_line_header_dirty=true. + } + const dbg_line_prg_off = self.getDebugLineProgramOff(); + const dbg_line_prg_end = self.getDebugLineProgramEnd(); + assert(dbg_line_prg_end != 0); + + const debug_line_sect = &self.sections.items[self.debug_line_section_index.?]; + + var di_buf = std.ArrayList(u8).init(self.base.allocator); + defer di_buf.deinit(); + + // The size of this header is variable, depending on the number of directories, + // files, and padding. We have a function to compute the upper bound size, however, + // because it's needed for determining where to put the offset of the first `SrcFn`. + try di_buf.ensureCapacity(self.dbgLineNeededHeaderBytes()); + + // initial length - length of the .debug_line contribution for this compilation unit, + // not including the initial length itself. + const after_init_len = di_buf.items.len + init_len_size; + const init_len = dbg_line_prg_end - after_init_len; + switch (self.ptr_width) { + .p32 => { + mem.writeInt(u32, di_buf.addManyAsArrayAssumeCapacity(4), @intCast(u32, init_len), target_endian); + }, + .p64 => { + di_buf.appendNTimesAssumeCapacity(0xff, 4); + mem.writeInt(u64, di_buf.addManyAsArrayAssumeCapacity(8), init_len, target_endian); + }, + } + + mem.writeInt(u16, di_buf.addManyAsArrayAssumeCapacity(2), 4, target_endian); // version + + // Empirically, debug info consumers do not respect this field, or otherwise + // consider it to be an error when it does not point exactly to the end of the header. + // Therefore we rely on the NOP jump at the beginning of the Line Number Program for + // padding rather than this field. + const before_header_len = di_buf.items.len; + di_buf.items.len += ptr_width_bytes; // We will come back and write this. + const after_header_len = di_buf.items.len; + + const opcode_base = DW.LNS_set_isa + 1; + di_buf.appendSliceAssumeCapacity(&[_]u8{ + 1, // minimum_instruction_length + 1, // maximum_operations_per_instruction + 1, // default_is_stmt + 1, // line_base (signed) + 1, // line_range + opcode_base, + + // Standard opcode lengths. The number of items here is based on `opcode_base`. + // The value is the number of LEB128 operands the instruction takes. + 0, // `DW.LNS_copy` + 1, // `DW.LNS_advance_pc` + 1, // `DW.LNS_advance_line` + 1, // `DW.LNS_set_file` + 1, // `DW.LNS_set_column` + 0, // `DW.LNS_negate_stmt` + 0, // `DW.LNS_set_basic_block` + 0, // `DW.LNS_const_add_pc` + 1, // `DW.LNS_fixed_advance_pc` + 0, // `DW.LNS_set_prologue_end` + 0, // `DW.LNS_set_epilogue_begin` + 1, // `DW.LNS_set_isa` + + 0, // include_directories (none except the compilation unit cwd) + }); + // file_names[0] + di_buf.appendSliceAssumeCapacity(self.base.options.root_pkg.root_src_path); // relative path name + di_buf.appendSliceAssumeCapacity(&[_]u8{ + 0, // null byte for the relative path name + 0, // directory_index + 0, // mtime (TODO supply this) + 0, // file size bytes (TODO supply this) + 0, // file_names sentinel + }); + + const header_len = di_buf.items.len - after_header_len; + switch (self.ptr_width) { + .p32 => { + mem.writeInt(u32, di_buf.items[before_header_len..][0..4], @intCast(u32, header_len), target_endian); + }, + .p64 => { + mem.writeInt(u64, di_buf.items[before_header_len..][0..8], header_len, target_endian); + }, + } + + // We use NOPs because consumers empirically do not respect the header length field. + if (di_buf.items.len > dbg_line_prg_off) { + // Move the first N files to the end to make more padding for the header. + @panic("TODO: handle .debug_line header exceeding its padding"); + } + const jmp_amt = dbg_line_prg_off - di_buf.items.len; + try self.pwriteDbgLineNops(0, di_buf.items, jmp_amt, debug_line_sect.sh_offset); + self.debug_line_header_dirty = false; + } + + if (self.phdr_table_dirty) { + const phsize: u64 = switch (self.ptr_width) { + .p32 => @sizeOf(elf.Elf32_Phdr), + .p64 => @sizeOf(elf.Elf64_Phdr), + }; + const phalign: u16 = switch (self.ptr_width) { + .p32 => @alignOf(elf.Elf32_Phdr), + .p64 => @alignOf(elf.Elf64_Phdr), + }; + const allocated_size = self.allocatedSize(self.phdr_table_offset.?); + const needed_size = self.program_headers.items.len * phsize; + + if (needed_size > allocated_size) { + self.phdr_table_offset = null; // free the space + self.phdr_table_offset = self.findFreeSpace(needed_size, phalign); + } + + switch (self.ptr_width) { + .p32 => { + const buf = try self.base.allocator.alloc(elf.Elf32_Phdr, self.program_headers.items.len); + defer self.base.allocator.free(buf); + + for (buf) |*phdr, i| { + phdr.* = progHeaderTo32(self.program_headers.items[i]); + if (foreign_endian) { + bswapAllFields(elf.Elf32_Phdr, phdr); + } + } + try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), self.phdr_table_offset.?); + }, + .p64 => { + const buf = try self.base.allocator.alloc(elf.Elf64_Phdr, self.program_headers.items.len); + defer self.base.allocator.free(buf); + + for (buf) |*phdr, i| { + phdr.* = self.program_headers.items[i]; + if (foreign_endian) { + bswapAllFields(elf.Elf64_Phdr, phdr); + } + } + try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), self.phdr_table_offset.?); + }, + } + self.phdr_table_dirty = false; + } + + { + const shstrtab_sect = &self.sections.items[self.shstrtab_index.?]; + if (self.shstrtab_dirty or self.shstrtab.items.len != shstrtab_sect.sh_size) { + const allocated_size = self.allocatedSize(shstrtab_sect.sh_offset); + const needed_size = self.shstrtab.items.len; + + if (needed_size > allocated_size) { + shstrtab_sect.sh_size = 0; // free the space + shstrtab_sect.sh_offset = self.findFreeSpace(needed_size, 1); + } + shstrtab_sect.sh_size = needed_size; + log.debug("writing shstrtab start=0x{x} end=0x{x}\n", .{ shstrtab_sect.sh_offset, shstrtab_sect.sh_offset + needed_size }); + + try self.base.file.?.pwriteAll(self.shstrtab.items, shstrtab_sect.sh_offset); + if (!self.shdr_table_dirty) { + // Then it won't get written with the others and we need to do it. + try self.writeSectHeader(self.shstrtab_index.?); + } + self.shstrtab_dirty = false; + } + } + { + const debug_strtab_sect = &self.sections.items[self.debug_str_section_index.?]; + if (self.debug_strtab_dirty or self.debug_strtab.items.len != debug_strtab_sect.sh_size) { + const allocated_size = self.allocatedSize(debug_strtab_sect.sh_offset); + const needed_size = self.debug_strtab.items.len; + + if (needed_size > allocated_size) { + debug_strtab_sect.sh_size = 0; // free the space + debug_strtab_sect.sh_offset = self.findFreeSpace(needed_size, 1); + } + debug_strtab_sect.sh_size = needed_size; + log.debug("debug_strtab start=0x{x} end=0x{x}\n", .{ debug_strtab_sect.sh_offset, debug_strtab_sect.sh_offset + needed_size }); + + try self.base.file.?.pwriteAll(self.debug_strtab.items, debug_strtab_sect.sh_offset); + if (!self.shdr_table_dirty) { + // Then it won't get written with the others and we need to do it. + try self.writeSectHeader(self.debug_str_section_index.?); + } + self.debug_strtab_dirty = false; + } + } + if (self.shdr_table_dirty) { + const shsize: u64 = switch (self.ptr_width) { + .p32 => @sizeOf(elf.Elf32_Shdr), + .p64 => @sizeOf(elf.Elf64_Shdr), + }; + const shalign: u16 = switch (self.ptr_width) { + .p32 => @alignOf(elf.Elf32_Shdr), + .p64 => @alignOf(elf.Elf64_Shdr), + }; + const allocated_size = self.allocatedSize(self.shdr_table_offset.?); + const needed_size = self.sections.items.len * shsize; + + if (needed_size > allocated_size) { + self.shdr_table_offset = null; // free the space + self.shdr_table_offset = self.findFreeSpace(needed_size, shalign); + } + + switch (self.ptr_width) { + .p32 => { + const buf = try self.base.allocator.alloc(elf.Elf32_Shdr, self.sections.items.len); + defer self.base.allocator.free(buf); + + for (buf) |*shdr, i| { + shdr.* = sectHeaderTo32(self.sections.items[i]); + log.debug("writing section {}\n", .{shdr.*}); + if (foreign_endian) { + bswapAllFields(elf.Elf32_Shdr, shdr); + } + } + try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), self.shdr_table_offset.?); + }, + .p64 => { + const buf = try self.base.allocator.alloc(elf.Elf64_Shdr, self.sections.items.len); + defer self.base.allocator.free(buf); + + for (buf) |*shdr, i| { + shdr.* = self.sections.items[i]; + log.debug("writing section {}\n", .{shdr.*}); + if (foreign_endian) { + bswapAllFields(elf.Elf64_Shdr, shdr); + } + } + try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), self.shdr_table_offset.?); + }, + } + self.shdr_table_dirty = false; + } + if (self.entry_addr == null and self.base.options.output_mode == .Exe) { + log.debug("flushing. no_entry_point_found = true\n", .{}); + self.error_flags.no_entry_point_found = true; + } else { + log.debug("flushing. no_entry_point_found = false\n", .{}); + self.error_flags.no_entry_point_found = false; + try self.writeElfHeader(); + } + + // The point of flush() is to commit changes, so in theory, nothing should + // be dirty after this. However, it is possible for some things to remain + // dirty because they fail to be written in the event of compile errors, + // such as debug_line_header_dirty and debug_info_header_dirty. + assert(!self.debug_abbrev_section_dirty); + assert(!self.debug_aranges_section_dirty); + assert(!self.phdr_table_dirty); + assert(!self.shdr_table_dirty); + assert(!self.shstrtab_dirty); + assert(!self.debug_strtab_dirty); +} + +fn writeDwarfAddrAssumeCapacity(self: *Elf, buf: *std.ArrayList(u8), addr: u64) void { + const target_endian = self.base.options.target.cpu.arch.endian(); + switch (self.ptr_width) { + .p32 => mem.writeInt(u32, buf.addManyAsArrayAssumeCapacity(4), @intCast(u32, addr), target_endian), + .p64 => mem.writeInt(u64, buf.addManyAsArrayAssumeCapacity(8), addr, target_endian), + } +} + +fn writeElfHeader(self: *Elf) !void { + var hdr_buf: [@sizeOf(elf.Elf64_Ehdr)]u8 = undefined; + + var index: usize = 0; + hdr_buf[0..4].* = "\x7fELF".*; + index += 4; + + hdr_buf[index] = switch (self.ptr_width) { + .p32 => elf.ELFCLASS32, + .p64 => elf.ELFCLASS64, + }; + index += 1; + + const endian = self.base.options.target.cpu.arch.endian(); + hdr_buf[index] = switch (endian) { + .Little => elf.ELFDATA2LSB, + .Big => elf.ELFDATA2MSB, + }; + index += 1; + + hdr_buf[index] = 1; // ELF version + index += 1; + + // OS ABI, often set to 0 regardless of target platform + // ABI Version, possibly used by glibc but not by static executables + // padding + mem.set(u8, hdr_buf[index..][0..9], 0); + index += 9; + + assert(index == 16); + + const elf_type = switch (self.base.options.output_mode) { + .Exe => elf.ET.EXEC, + .Obj => elf.ET.REL, + .Lib => switch (self.base.options.link_mode) { + .Static => elf.ET.REL, + .Dynamic => elf.ET.DYN, + }, + }; + mem.writeInt(u16, hdr_buf[index..][0..2], @enumToInt(elf_type), endian); + index += 2; + + const machine = self.base.options.target.cpu.arch.toElfMachine(); + mem.writeInt(u16, hdr_buf[index..][0..2], @enumToInt(machine), endian); + index += 2; + + // ELF Version, again + mem.writeInt(u32, hdr_buf[index..][0..4], 1, endian); + index += 4; + + const e_entry = if (elf_type == .REL) 0 else self.entry_addr.?; + + switch (self.ptr_width) { + .p32 => { + mem.writeInt(u32, hdr_buf[index..][0..4], @intCast(u32, e_entry), endian); + index += 4; + + // e_phoff + mem.writeInt(u32, hdr_buf[index..][0..4], @intCast(u32, self.phdr_table_offset.?), endian); + index += 4; + + // e_shoff + mem.writeInt(u32, hdr_buf[index..][0..4], @intCast(u32, self.shdr_table_offset.?), endian); + index += 4; + }, + .p64 => { + // e_entry + mem.writeInt(u64, hdr_buf[index..][0..8], e_entry, endian); + index += 8; + + // e_phoff + mem.writeInt(u64, hdr_buf[index..][0..8], self.phdr_table_offset.?, endian); + index += 8; + + // e_shoff + mem.writeInt(u64, hdr_buf[index..][0..8], self.shdr_table_offset.?, endian); + index += 8; + }, + } + + const e_flags = 0; + mem.writeInt(u32, hdr_buf[index..][0..4], e_flags, endian); + index += 4; + + const e_ehsize: u16 = switch (self.ptr_width) { + .p32 => @sizeOf(elf.Elf32_Ehdr), + .p64 => @sizeOf(elf.Elf64_Ehdr), + }; + mem.writeInt(u16, hdr_buf[index..][0..2], e_ehsize, endian); + index += 2; + + const e_phentsize: u16 = switch (self.ptr_width) { + .p32 => @sizeOf(elf.Elf32_Phdr), + .p64 => @sizeOf(elf.Elf64_Phdr), + }; + mem.writeInt(u16, hdr_buf[index..][0..2], e_phentsize, endian); + index += 2; + + const e_phnum = @intCast(u16, self.program_headers.items.len); + mem.writeInt(u16, hdr_buf[index..][0..2], e_phnum, endian); + index += 2; + + const e_shentsize: u16 = switch (self.ptr_width) { + .p32 => @sizeOf(elf.Elf32_Shdr), + .p64 => @sizeOf(elf.Elf64_Shdr), + }; + mem.writeInt(u16, hdr_buf[index..][0..2], e_shentsize, endian); + index += 2; + + const e_shnum = @intCast(u16, self.sections.items.len); + mem.writeInt(u16, hdr_buf[index..][0..2], e_shnum, endian); + index += 2; + + mem.writeInt(u16, hdr_buf[index..][0..2], self.shstrtab_index.?, endian); + index += 2; + + assert(index == e_ehsize); + + try self.base.file.?.pwriteAll(hdr_buf[0..index], 0); +} + +fn freeTextBlock(self: *Elf, text_block: *TextBlock) void { + var already_have_free_list_node = false; + { + var i: usize = 0; + while (i < self.text_block_free_list.items.len) { + if (self.text_block_free_list.items[i] == text_block) { + _ = self.text_block_free_list.swapRemove(i); + continue; + } + if (self.text_block_free_list.items[i] == text_block.prev) { + already_have_free_list_node = true; + } + i += 1; + } + } + + if (self.last_text_block == text_block) { + // TODO shrink the .text section size here + self.last_text_block = text_block.prev; + } + + if (text_block.prev) |prev| { + prev.next = text_block.next; + + if (!already_have_free_list_node and prev.freeListEligible(self.*)) { + // The free list is heuristics, it doesn't have to be perfect, so we can + // ignore the OOM here. + self.text_block_free_list.append(self.base.allocator, prev) catch {}; + } + } else { + text_block.prev = null; + } + + if (text_block.next) |next| { + next.prev = text_block.prev; + } else { + text_block.next = null; + } +} + +fn shrinkTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64) void { + // TODO check the new capacity, and if it crosses the size threshold into a big enough + // capacity, insert a free list node for it. +} + +fn growTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, alignment: u64) !u64 { + const sym = self.local_symbols.items[text_block.local_sym_index]; + const align_ok = mem.alignBackwardGeneric(u64, sym.st_value, alignment) == sym.st_value; + const need_realloc = !align_ok or new_block_size > text_block.capacity(self.*); + if (!need_realloc) return sym.st_value; + return self.allocateTextBlock(text_block, new_block_size, alignment); +} + +fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, alignment: u64) !u64 { + const phdr = &self.program_headers.items[self.phdr_load_re_index.?]; + const shdr = &self.sections.items[self.text_section_index.?]; + const new_block_ideal_capacity = new_block_size * alloc_num / alloc_den; + + // We use these to indicate our intention to update metadata, placing the new block, + // and possibly removing a free list node. + // It would be simpler to do it inside the for loop below, but that would cause a + // problem if an error was returned later in the function. So this action + // is actually carried out at the end of the function, when errors are no longer possible. + var block_placement: ?*TextBlock = null; + var free_list_removal: ?usize = null; + + // First we look for an appropriately sized free list node. + // The list is unordered. We'll just take the first thing that works. + const vaddr = blk: { + var i: usize = 0; + while (i < self.text_block_free_list.items.len) { + const big_block = self.text_block_free_list.items[i]; + // We now have a pointer to a live text block that has too much capacity. + // Is it enough that we could fit this new text block? + const sym = self.local_symbols.items[big_block.local_sym_index]; + const capacity = big_block.capacity(self.*); + const ideal_capacity = capacity * alloc_num / alloc_den; + const ideal_capacity_end_vaddr = sym.st_value + ideal_capacity; + const capacity_end_vaddr = sym.st_value + capacity; + const new_start_vaddr_unaligned = capacity_end_vaddr - new_block_ideal_capacity; + const new_start_vaddr = mem.alignBackwardGeneric(u64, new_start_vaddr_unaligned, alignment); + if (new_start_vaddr < ideal_capacity_end_vaddr) { + // Additional bookkeeping here to notice if this free list node + // should be deleted because the block that it points to has grown to take up + // more of the extra capacity. + if (!big_block.freeListEligible(self.*)) { + _ = self.text_block_free_list.swapRemove(i); + } else { + i += 1; + } + continue; + } + // At this point we know that we will place the new block here. But the + // remaining question is whether there is still yet enough capacity left + // over for there to still be a free list node. + const remaining_capacity = new_start_vaddr - ideal_capacity_end_vaddr; + const keep_free_list_node = remaining_capacity >= min_text_capacity; + + // Set up the metadata to be updated, after errors are no longer possible. + block_placement = big_block; + if (!keep_free_list_node) { + free_list_removal = i; + } + break :blk new_start_vaddr; + } else if (self.last_text_block) |last| { + const sym = self.local_symbols.items[last.local_sym_index]; + const ideal_capacity = sym.st_size * alloc_num / alloc_den; + const ideal_capacity_end_vaddr = sym.st_value + ideal_capacity; + const new_start_vaddr = mem.alignForwardGeneric(u64, ideal_capacity_end_vaddr, alignment); + // Set up the metadata to be updated, after errors are no longer possible. + block_placement = last; + break :blk new_start_vaddr; + } else { + break :blk phdr.p_vaddr; + } + }; + + const expand_text_section = block_placement == null or block_placement.?.next == null; + if (expand_text_section) { + const text_capacity = self.allocatedSize(shdr.sh_offset); + const needed_size = (vaddr + new_block_size) - phdr.p_vaddr; + if (needed_size > text_capacity) { + // Must move the entire text section. + const new_offset = self.findFreeSpace(needed_size, 0x1000); + const text_size = if (self.last_text_block) |last| blk: { + const sym = self.local_symbols.items[last.local_sym_index]; + break :blk (sym.st_value + sym.st_size) - phdr.p_vaddr; + } else 0; + const amt = try self.base.file.?.copyRangeAll(shdr.sh_offset, self.base.file.?, new_offset, text_size); + if (amt != text_size) return error.InputOutput; + shdr.sh_offset = new_offset; + phdr.p_offset = new_offset; + } + self.last_text_block = text_block; + + shdr.sh_size = needed_size; + phdr.p_memsz = needed_size; + phdr.p_filesz = needed_size; + + // The .debug_info section has `low_pc` and `high_pc` values which is the virtual address + // range of the compilation unit. When we expand the text section, this range changes, + // so the DW_TAG_compile_unit tag of the .debug_info section becomes dirty. + self.debug_info_header_dirty = true; + // This becomes dirty for the same reason. We could potentially make this more + // fine-grained with the addition of support for more compilation units. It is planned to + // model each package as a different compilation unit. + self.debug_aranges_section_dirty = true; + + self.phdr_table_dirty = true; // TODO look into making only the one program header dirty + self.shdr_table_dirty = true; // TODO look into making only the one section dirty + } + + // This function can also reallocate a text block. + // In this case we need to "unplug" it from its previous location before + // plugging it in to its new location. + if (text_block.prev) |prev| { + prev.next = text_block.next; + } + if (text_block.next) |next| { + next.prev = text_block.prev; + } + + if (block_placement) |big_block| { + text_block.prev = big_block; + text_block.next = big_block.next; + big_block.next = text_block; + } else { + text_block.prev = null; + text_block.next = null; + } + if (free_list_removal) |i| { + _ = self.text_block_free_list.swapRemove(i); + } + return vaddr; +} + +pub fn allocateDeclIndexes(self: *Elf, decl: *Module.Decl) !void { + if (decl.link.elf.local_sym_index != 0) return; + + try self.local_symbols.ensureCapacity(self.base.allocator, self.local_symbols.items.len + 1); + try self.offset_table.ensureCapacity(self.base.allocator, self.offset_table.items.len + 1); + + if (self.local_symbol_free_list.popOrNull()) |i| { + log.debug("reusing symbol index {} for {}\n", .{ i, decl.name }); + decl.link.elf.local_sym_index = i; + } else { + log.debug("allocating symbol index {} for {}\n", .{ self.local_symbols.items.len, decl.name }); + decl.link.elf.local_sym_index = @intCast(u32, self.local_symbols.items.len); + _ = self.local_symbols.addOneAssumeCapacity(); + } + + if (self.offset_table_free_list.popOrNull()) |i| { + decl.link.elf.offset_table_index = i; + } else { + decl.link.elf.offset_table_index = @intCast(u32, self.offset_table.items.len); + _ = self.offset_table.addOneAssumeCapacity(); + self.offset_table_count_dirty = true; + } + + const phdr = &self.program_headers.items[self.phdr_load_re_index.?]; + + self.local_symbols.items[decl.link.elf.local_sym_index] = .{ + .st_name = 0, + .st_info = 0, + .st_other = 0, + .st_shndx = 0, + .st_value = phdr.p_vaddr, + .st_size = 0, + }; + self.offset_table.items[decl.link.elf.offset_table_index] = 0; +} + +pub fn freeDecl(self: *Elf, decl: *Module.Decl) void { + // Appending to free lists is allowed to fail because the free lists are heuristics based anyway. + self.freeTextBlock(&decl.link.elf); + if (decl.link.elf.local_sym_index != 0) { + self.local_symbol_free_list.append(self.base.allocator, decl.link.elf.local_sym_index) catch {}; + self.offset_table_free_list.append(self.base.allocator, decl.link.elf.offset_table_index) catch {}; + + self.local_symbols.items[decl.link.elf.local_sym_index].st_info = 0; + + decl.link.elf.local_sym_index = 0; + } + // TODO make this logic match freeTextBlock. Maybe abstract the logic out since the same thing + // is desired for both. + _ = self.dbg_line_fn_free_list.remove(&decl.fn_link.elf); + if (decl.fn_link.elf.prev) |prev| { + _ = self.dbg_line_fn_free_list.put(self.base.allocator, prev, {}) catch {}; + prev.next = decl.fn_link.elf.next; + if (decl.fn_link.elf.next) |next| { + next.prev = prev; + } else { + self.dbg_line_fn_last = prev; + } + } else if (decl.fn_link.elf.next) |next| { + self.dbg_line_fn_first = next; + next.prev = null; + } + if (self.dbg_line_fn_first == &decl.fn_link.elf) { + self.dbg_line_fn_first = null; + } + if (self.dbg_line_fn_last == &decl.fn_link.elf) { + self.dbg_line_fn_last = null; + } +} + +pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void { + const tracy = trace(@src()); + defer tracy.end(); + + var code_buffer = std.ArrayList(u8).init(self.base.allocator); + defer code_buffer.deinit(); + + var dbg_line_buffer = std.ArrayList(u8).init(self.base.allocator); + defer dbg_line_buffer.deinit(); + + var dbg_info_buffer = std.ArrayList(u8).init(self.base.allocator); + defer dbg_info_buffer.deinit(); + + var dbg_info_type_relocs: File.DbgInfoTypeRelocsTable = .{}; + defer { + for (dbg_info_type_relocs.items()) |*entry| { + entry.value.relocs.deinit(self.base.allocator); + } + dbg_info_type_relocs.deinit(self.base.allocator); + } + + const typed_value = decl.typed_value.most_recent.typed_value; + const is_fn: bool = switch (typed_value.ty.zigTypeTag()) { + .Fn => true, + else => false, + }; + if (is_fn) { + //if (mem.eql(u8, mem.spanZ(decl.name), "add")) { + // typed_value.val.cast(Value.Payload.Function).?.func.dump(module.*); + //} + + // For functions we need to add a prologue to the debug line program. + try dbg_line_buffer.ensureCapacity(26); + + const line_off: u28 = blk: { + if (decl.scope.cast(Module.Scope.File)) |scope_file| { + const tree = scope_file.contents.tree; + const file_ast_decls = tree.root_node.decls(); + // TODO Look into improving the performance here by adding a token-index-to-line + // lookup table. Currently this involves scanning over the source code for newlines. + const fn_proto = file_ast_decls[decl.src_index].castTag(.FnProto).?; + const block = fn_proto.body().?.castTag(.Block).?; + const line_delta = std.zig.lineDelta(tree.source, 0, tree.token_locs[block.lbrace].start); + break :blk @intCast(u28, line_delta); + } else if (decl.scope.cast(Module.Scope.ZIRModule)) |zir_module| { + const byte_off = zir_module.contents.module.decls[decl.src_index].inst.src; + const line_delta = std.zig.lineDelta(zir_module.source.bytes, 0, byte_off); + break :blk @intCast(u28, line_delta); + } else { + unreachable; + } + }; + + const ptr_width_bytes = self.ptrWidthBytes(); + dbg_line_buffer.appendSliceAssumeCapacity(&[_]u8{ + DW.LNS_extended_op, + ptr_width_bytes + 1, + DW.LNE_set_address, + }); + // This is the "relocatable" vaddr, corresponding to `code_buffer` index `0`. + assert(dbg_line_vaddr_reloc_index == dbg_line_buffer.items.len); + dbg_line_buffer.items.len += ptr_width_bytes; + + dbg_line_buffer.appendAssumeCapacity(DW.LNS_advance_line); + // This is the "relocatable" relative line offset from the previous function's end curly + // to this function's begin curly. + assert(self.getRelocDbgLineOff() == dbg_line_buffer.items.len); + // Here we use a ULEB128-fixed-4 to make sure this field can be overwritten later. + leb128.writeUnsignedFixed(4, dbg_line_buffer.addManyAsArrayAssumeCapacity(4), line_off); + + dbg_line_buffer.appendAssumeCapacity(DW.LNS_set_file); + assert(self.getRelocDbgFileIndex() == dbg_line_buffer.items.len); + // Once we support more than one source file, this will have the ability to be more + // than one possible value. + const file_index = 1; + leb128.writeUnsignedFixed(4, dbg_line_buffer.addManyAsArrayAssumeCapacity(4), file_index); + + // Emit a line for the begin curly with prologue_end=false. The codegen will + // do the work of setting prologue_end=true and epilogue_begin=true. + dbg_line_buffer.appendAssumeCapacity(DW.LNS_copy); + + // .debug_info subprogram + const decl_name_with_null = decl.name[0 .. mem.lenZ(decl.name) + 1]; + try dbg_info_buffer.ensureCapacity(dbg_info_buffer.items.len + 25 + decl_name_with_null.len); + + const fn_ret_type = typed_value.ty.fnReturnType(); + const fn_ret_has_bits = fn_ret_type.hasCodeGenBits(); + if (fn_ret_has_bits) { + dbg_info_buffer.appendAssumeCapacity(abbrev_subprogram); + } else { + dbg_info_buffer.appendAssumeCapacity(abbrev_subprogram_retvoid); + } + // These get overwritten after generating the machine code. These values are + // "relocations" and have to be in this fixed place so that functions can be + // moved in virtual address space. + assert(dbg_info_low_pc_reloc_index == dbg_info_buffer.items.len); + dbg_info_buffer.items.len += ptr_width_bytes; // DW.AT_low_pc, DW.FORM_addr + assert(self.getRelocDbgInfoSubprogramHighPC() == dbg_info_buffer.items.len); + dbg_info_buffer.items.len += 4; // DW.AT_high_pc, DW.FORM_data4 + if (fn_ret_has_bits) { + const gop = try dbg_info_type_relocs.getOrPut(self.base.allocator, fn_ret_type); + if (!gop.found_existing) { + gop.entry.value = .{ + .off = undefined, + .relocs = .{}, + }; + } + try gop.entry.value.relocs.append(self.base.allocator, @intCast(u32, dbg_info_buffer.items.len)); + dbg_info_buffer.items.len += 4; // DW.AT_type, DW.FORM_ref4 + } + dbg_info_buffer.appendSliceAssumeCapacity(decl_name_with_null); // DW.AT_name, DW.FORM_string + } else { + // TODO implement .debug_info for global variables + } + const res = try codegen.generateSymbol(&self.base, decl.src(), typed_value, &code_buffer, &dbg_line_buffer, &dbg_info_buffer, &dbg_info_type_relocs); + const code = switch (res) { + .externally_managed => |x| x, + .appended => code_buffer.items, + .fail => |em| { + decl.analysis = .codegen_failure; + try module.failed_decls.put(module.gpa, decl, em); + return; + }, + }; + + const required_alignment = typed_value.ty.abiAlignment(self.base.options.target); + + const stt_bits: u8 = if (is_fn) elf.STT_FUNC else elf.STT_OBJECT; + + assert(decl.link.elf.local_sym_index != 0); // Caller forgot to allocateDeclIndexes() + const local_sym = &self.local_symbols.items[decl.link.elf.local_sym_index]; + if (local_sym.st_size != 0) { + const capacity = decl.link.elf.capacity(self.*); + const need_realloc = code.len > capacity or + !mem.isAlignedGeneric(u64, local_sym.st_value, required_alignment); + if (need_realloc) { + const vaddr = try self.growTextBlock(&decl.link.elf, code.len, required_alignment); + log.debug("growing {} from 0x{x} to 0x{x}\n", .{ decl.name, local_sym.st_value, vaddr }); + if (vaddr != local_sym.st_value) { + local_sym.st_value = vaddr; + + log.debug(" (writing new offset table entry)\n", .{}); + self.offset_table.items[decl.link.elf.offset_table_index] = vaddr; + try self.writeOffsetTableEntry(decl.link.elf.offset_table_index); + } + } else if (code.len < local_sym.st_size) { + self.shrinkTextBlock(&decl.link.elf, code.len); + } + local_sym.st_size = code.len; + local_sym.st_name = try self.updateString(local_sym.st_name, mem.spanZ(decl.name)); + local_sym.st_info = (elf.STB_LOCAL << 4) | stt_bits; + local_sym.st_other = 0; + local_sym.st_shndx = self.text_section_index.?; + // TODO this write could be avoided if no fields of the symbol were changed. + try self.writeSymbol(decl.link.elf.local_sym_index); + } else { + const decl_name = mem.spanZ(decl.name); + const name_str_index = try self.makeString(decl_name); + const vaddr = try self.allocateTextBlock(&decl.link.elf, code.len, required_alignment); + log.debug("allocated text block for {} at 0x{x}\n", .{ decl_name, vaddr }); + errdefer self.freeTextBlock(&decl.link.elf); + + local_sym.* = .{ + .st_name = name_str_index, + .st_info = (elf.STB_LOCAL << 4) | stt_bits, + .st_other = 0, + .st_shndx = self.text_section_index.?, + .st_value = vaddr, + .st_size = code.len, + }; + self.offset_table.items[decl.link.elf.offset_table_index] = vaddr; + + try self.writeSymbol(decl.link.elf.local_sym_index); + try self.writeOffsetTableEntry(decl.link.elf.offset_table_index); + } + + const section_offset = local_sym.st_value - self.program_headers.items[self.phdr_load_re_index.?].p_vaddr; + const file_offset = self.sections.items[self.text_section_index.?].sh_offset + section_offset; + try self.base.file.?.pwriteAll(code, file_offset); + + const target_endian = self.base.options.target.cpu.arch.endian(); + + const text_block = &decl.link.elf; + + // If the Decl is a function, we need to update the .debug_line program. + if (is_fn) { + // Perform the relocations based on vaddr. + switch (self.ptr_width) { + .p32 => { + { + const ptr = dbg_line_buffer.items[dbg_line_vaddr_reloc_index..][0..4]; + mem.writeInt(u32, ptr, @intCast(u32, local_sym.st_value), target_endian); + } + { + const ptr = dbg_info_buffer.items[dbg_info_low_pc_reloc_index..][0..4]; + mem.writeInt(u32, ptr, @intCast(u32, local_sym.st_value), target_endian); + } + }, + .p64 => { + { + const ptr = dbg_line_buffer.items[dbg_line_vaddr_reloc_index..][0..8]; + mem.writeInt(u64, ptr, local_sym.st_value, target_endian); + } + { + const ptr = dbg_info_buffer.items[dbg_info_low_pc_reloc_index..][0..8]; + mem.writeInt(u64, ptr, local_sym.st_value, target_endian); + } + }, + } + { + const ptr = dbg_info_buffer.items[self.getRelocDbgInfoSubprogramHighPC()..][0..4]; + mem.writeInt(u32, ptr, @intCast(u32, local_sym.st_size), target_endian); + } + + try dbg_line_buffer.appendSlice(&[_]u8{ DW.LNS_extended_op, 1, DW.LNE_end_sequence }); + + // Now we have the full contents and may allocate a region to store it. + + // This logic is nearly identical to the logic below in `updateDeclDebugInfo` for + // `TextBlock` and the .debug_info. If you are editing this logic, you + // probably need to edit that logic too. + + const debug_line_sect = &self.sections.items[self.debug_line_section_index.?]; + const src_fn = &decl.fn_link.elf; + src_fn.len = @intCast(u32, dbg_line_buffer.items.len); + if (self.dbg_line_fn_last) |last| { + if (src_fn.next) |next| { + // Update existing function - non-last item. + if (src_fn.off + src_fn.len + min_nop_size > next.off) { + // It grew too big, so we move it to a new location. + if (src_fn.prev) |prev| { + _ = self.dbg_line_fn_free_list.put(self.base.allocator, prev, {}) catch {}; + prev.next = src_fn.next; + } + next.prev = src_fn.prev; + src_fn.next = null; + // Populate where it used to be with NOPs. + const file_pos = debug_line_sect.sh_offset + src_fn.off; + try self.pwriteDbgLineNops(0, &[0]u8{}, src_fn.len, file_pos); + // TODO Look at the free list before appending at the end. + src_fn.prev = last; + last.next = src_fn; + self.dbg_line_fn_last = src_fn; + + src_fn.off = last.off + (last.len * alloc_num / alloc_den); + } + } else if (src_fn.prev == null) { + // Append new function. + // TODO Look at the free list before appending at the end. + src_fn.prev = last; + last.next = src_fn; + self.dbg_line_fn_last = src_fn; + + src_fn.off = last.off + (last.len * alloc_num / alloc_den); + } + } else { + // This is the first function of the Line Number Program. + self.dbg_line_fn_first = src_fn; + self.dbg_line_fn_last = src_fn; + + src_fn.off = self.dbgLineNeededHeaderBytes() * alloc_num / alloc_den; + } + + const last_src_fn = self.dbg_line_fn_last.?; + const needed_size = last_src_fn.off + last_src_fn.len; + if (needed_size != debug_line_sect.sh_size) { + if (needed_size > self.allocatedSize(debug_line_sect.sh_offset)) { + const new_offset = self.findFreeSpace(needed_size, 1); + const existing_size = last_src_fn.off; + log.debug("moving .debug_line section: {} bytes from 0x{x} to 0x{x}\n", .{ + existing_size, + debug_line_sect.sh_offset, + new_offset, + }); + const amt = try self.base.file.?.copyRangeAll(debug_line_sect.sh_offset, self.base.file.?, new_offset, existing_size); + if (amt != existing_size) return error.InputOutput; + debug_line_sect.sh_offset = new_offset; + } + debug_line_sect.sh_size = needed_size; + self.shdr_table_dirty = true; // TODO look into making only the one section dirty + self.debug_line_header_dirty = true; + } + const prev_padding_size: u32 = if (src_fn.prev) |prev| src_fn.off - (prev.off + prev.len) else 0; + const next_padding_size: u32 = if (src_fn.next) |next| next.off - (src_fn.off + src_fn.len) else 0; + + // We only have support for one compilation unit so far, so the offsets are directly + // from the .debug_line section. + const file_pos = debug_line_sect.sh_offset + src_fn.off; + try self.pwriteDbgLineNops(prev_padding_size, dbg_line_buffer.items, next_padding_size, file_pos); + + // .debug_info - End the TAG_subprogram children. + try dbg_info_buffer.append(0); + } + + // Now we emit the .debug_info types of the Decl. These will count towards the size of + // the buffer, so we have to do it before computing the offset, and we can't perform the actual + // relocations yet. + for (dbg_info_type_relocs.items()) |*entry| { + entry.value.off = @intCast(u32, dbg_info_buffer.items.len); + try self.addDbgInfoType(entry.key, &dbg_info_buffer); + } + + try self.updateDeclDebugInfoAllocation(text_block, @intCast(u32, dbg_info_buffer.items.len)); + + // Now that we have the offset assigned we can finally perform type relocations. + for (dbg_info_type_relocs.items()) |entry| { + for (entry.value.relocs.items) |off| { + mem.writeInt( + u32, + dbg_info_buffer.items[off..][0..4], + text_block.dbg_info_off + entry.value.off, + target_endian, + ); + } + } + + try self.writeDeclDebugInfo(text_block, dbg_info_buffer.items); + + // Since we updated the vaddr and the size, each corresponding export symbol also needs to be updated. + const decl_exports = module.decl_exports.get(decl) orelse &[0]*Module.Export{}; + return self.updateDeclExports(module, decl, decl_exports); +} + +/// Asserts the type has codegen bits. +fn addDbgInfoType(self: *Elf, ty: Type, dbg_info_buffer: *std.ArrayList(u8)) !void { + switch (ty.zigTypeTag()) { + .Void => unreachable, + .NoReturn => unreachable, + .Bool => { + try dbg_info_buffer.appendSlice(&[_]u8{ + abbrev_base_type, + DW.ATE_boolean, // DW.AT_encoding , DW.FORM_data1 + 1, // DW.AT_byte_size, DW.FORM_data1 + 'b', + 'o', + 'o', + 'l', + 0, // DW.AT_name, DW.FORM_string + }); + }, + .Int => { + const info = ty.intInfo(self.base.options.target); + try dbg_info_buffer.ensureCapacity(dbg_info_buffer.items.len + 12); + dbg_info_buffer.appendAssumeCapacity(abbrev_base_type); + // DW.AT_encoding, DW.FORM_data1 + dbg_info_buffer.appendAssumeCapacity(if (info.signed) DW.ATE_signed else DW.ATE_unsigned); + // DW.AT_byte_size, DW.FORM_data1 + dbg_info_buffer.appendAssumeCapacity(@intCast(u8, ty.abiSize(self.base.options.target))); + // DW.AT_name, DW.FORM_string + try dbg_info_buffer.writer().print("{}\x00", .{ty}); + }, + else => { + std.log.scoped(.compiler).err("TODO implement .debug_info for type '{}'", .{ty}); + try dbg_info_buffer.append(abbrev_pad1); + }, + } +} + +fn updateDeclDebugInfoAllocation(self: *Elf, text_block: *TextBlock, len: u32) !void { + const tracy = trace(@src()); + defer tracy.end(); + + // This logic is nearly identical to the logic above in `updateDecl` for + // `SrcFn` and the line number programs. If you are editing this logic, you + // probably need to edit that logic too. + + const debug_info_sect = &self.sections.items[self.debug_info_section_index.?]; + text_block.dbg_info_len = len; + if (self.dbg_info_decl_last) |last| { + if (text_block.dbg_info_next) |next| { + // Update existing Decl - non-last item. + if (text_block.dbg_info_off + text_block.dbg_info_len + min_nop_size > next.dbg_info_off) { + // It grew too big, so we move it to a new location. + if (text_block.dbg_info_prev) |prev| { + _ = self.dbg_info_decl_free_list.put(self.base.allocator, prev, {}) catch {}; + prev.dbg_info_next = text_block.dbg_info_next; + } + next.dbg_info_prev = text_block.dbg_info_prev; + text_block.dbg_info_next = null; + // Populate where it used to be with NOPs. + const file_pos = debug_info_sect.sh_offset + text_block.dbg_info_off; + try self.pwriteDbgInfoNops(0, &[0]u8{}, text_block.dbg_info_len, false, file_pos); + // TODO Look at the free list before appending at the end. + text_block.dbg_info_prev = last; + last.dbg_info_next = text_block; + self.dbg_info_decl_last = text_block; + + text_block.dbg_info_off = last.dbg_info_off + (last.dbg_info_len * alloc_num / alloc_den); + } + } else if (text_block.dbg_info_prev == null) { + // Append new Decl. + // TODO Look at the free list before appending at the end. + text_block.dbg_info_prev = last; + last.dbg_info_next = text_block; + self.dbg_info_decl_last = text_block; + + text_block.dbg_info_off = last.dbg_info_off + (last.dbg_info_len * alloc_num / alloc_den); + } + } else { + // This is the first Decl of the .debug_info + self.dbg_info_decl_first = text_block; + self.dbg_info_decl_last = text_block; + + text_block.dbg_info_off = self.dbgInfoNeededHeaderBytes() * alloc_num / alloc_den; + } +} + +fn writeDeclDebugInfo(self: *Elf, text_block: *TextBlock, dbg_info_buf: []const u8) !void { + const tracy = trace(@src()); + defer tracy.end(); + + // This logic is nearly identical to the logic above in `updateDecl` for + // `SrcFn` and the line number programs. If you are editing this logic, you + // probably need to edit that logic too. + + const debug_info_sect = &self.sections.items[self.debug_info_section_index.?]; + + const last_decl = self.dbg_info_decl_last.?; + // +1 for a trailing zero to end the children of the decl tag. + const needed_size = last_decl.dbg_info_off + last_decl.dbg_info_len + 1; + if (needed_size != debug_info_sect.sh_size) { + if (needed_size > self.allocatedSize(debug_info_sect.sh_offset)) { + const new_offset = self.findFreeSpace(needed_size, 1); + const existing_size = last_decl.dbg_info_off; + log.debug("moving .debug_info section: {} bytes from 0x{x} to 0x{x}\n", .{ + existing_size, + debug_info_sect.sh_offset, + new_offset, + }); + const amt = try self.base.file.?.copyRangeAll(debug_info_sect.sh_offset, self.base.file.?, new_offset, existing_size); + if (amt != existing_size) return error.InputOutput; + debug_info_sect.sh_offset = new_offset; + } + debug_info_sect.sh_size = needed_size; + self.shdr_table_dirty = true; // TODO look into making only the one section dirty + self.debug_info_header_dirty = true; + } + const prev_padding_size: u32 = if (text_block.dbg_info_prev) |prev| + text_block.dbg_info_off - (prev.dbg_info_off + prev.dbg_info_len) + else + 0; + const next_padding_size: u32 = if (text_block.dbg_info_next) |next| + next.dbg_info_off - (text_block.dbg_info_off + text_block.dbg_info_len) + else + 0; + + // To end the children of the decl tag. + const trailing_zero = text_block.dbg_info_next == null; + + // We only have support for one compilation unit so far, so the offsets are directly + // from the .debug_info section. + const file_pos = debug_info_sect.sh_offset + text_block.dbg_info_off; + try self.pwriteDbgInfoNops(prev_padding_size, dbg_info_buf, next_padding_size, trailing_zero, file_pos); +} + +pub fn updateDeclExports( + self: *Elf, + module: *Module, + decl: *const Module.Decl, + exports: []const *Module.Export, +) !void { + const tracy = trace(@src()); + defer tracy.end(); + + try self.global_symbols.ensureCapacity(self.base.allocator, self.global_symbols.items.len + exports.len); + const typed_value = decl.typed_value.most_recent.typed_value; + if (decl.link.elf.local_sym_index == 0) return; + const decl_sym = self.local_symbols.items[decl.link.elf.local_sym_index]; + + for (exports) |exp| { + if (exp.options.section) |section_name| { + if (!mem.eql(u8, section_name, ".text")) { + try module.failed_exports.ensureCapacity(module.gpa, module.failed_exports.items().len + 1); + module.failed_exports.putAssumeCapacityNoClobber( + exp, + try Module.ErrorMsg.create(self.base.allocator, 0, "Unimplemented: ExportOptions.section", .{}), + ); + continue; + } + } + const stb_bits: u8 = switch (exp.options.linkage) { + .Internal => elf.STB_LOCAL, + .Strong => blk: { + if (mem.eql(u8, exp.options.name, "_start")) { + self.entry_addr = decl_sym.st_value; + } + break :blk elf.STB_GLOBAL; + }, + .Weak => elf.STB_WEAK, + .LinkOnce => { + try module.failed_exports.ensureCapacity(module.gpa, module.failed_exports.items().len + 1); + module.failed_exports.putAssumeCapacityNoClobber( + exp, + try Module.ErrorMsg.create(self.base.allocator, 0, "Unimplemented: GlobalLinkage.LinkOnce", .{}), + ); + continue; + }, + }; + const stt_bits: u8 = @truncate(u4, decl_sym.st_info); + if (exp.link.sym_index) |i| { + const sym = &self.global_symbols.items[i]; + sym.* = .{ + .st_name = try self.updateString(sym.st_name, exp.options.name), + .st_info = (stb_bits << 4) | stt_bits, + .st_other = 0, + .st_shndx = self.text_section_index.?, + .st_value = decl_sym.st_value, + .st_size = decl_sym.st_size, + }; + } else { + const name = try self.makeString(exp.options.name); + const i = if (self.global_symbol_free_list.popOrNull()) |i| i else blk: { + _ = self.global_symbols.addOneAssumeCapacity(); + break :blk self.global_symbols.items.len - 1; + }; + self.global_symbols.items[i] = .{ + .st_name = name, + .st_info = (stb_bits << 4) | stt_bits, + .st_other = 0, + .st_shndx = self.text_section_index.?, + .st_value = decl_sym.st_value, + .st_size = decl_sym.st_size, + }; + + exp.link.sym_index = @intCast(u32, i); + } + } +} + +/// Must be called only after a successful call to `updateDecl`. +pub fn updateDeclLineNumber(self: *Elf, module: *Module, decl: *const Module.Decl) !void { + const tracy = trace(@src()); + defer tracy.end(); + + const scope_file = decl.scope.cast(Module.Scope.File).?; + const tree = scope_file.contents.tree; + const file_ast_decls = tree.root_node.decls(); + // TODO Look into improving the performance here by adding a token-index-to-line + // lookup table. Currently this involves scanning over the source code for newlines. + const fn_proto = file_ast_decls[decl.src_index].castTag(.FnProto).?; + const block = fn_proto.body().?.castTag(.Block).?; + const line_delta = std.zig.lineDelta(tree.source, 0, tree.token_locs[block.lbrace].start); + const casted_line_off = @intCast(u28, line_delta); + + const shdr = &self.sections.items[self.debug_line_section_index.?]; + const file_pos = shdr.sh_offset + decl.fn_link.elf.off + self.getRelocDbgLineOff(); + var data: [4]u8 = undefined; + leb128.writeUnsignedFixed(4, &data, casted_line_off); + try self.base.file.?.pwriteAll(&data, file_pos); +} + +pub fn deleteExport(self: *Elf, exp: Export) void { + const sym_index = exp.sym_index orelse return; + self.global_symbol_free_list.append(self.base.allocator, sym_index) catch {}; + self.global_symbols.items[sym_index].st_info = 0; +} + +fn writeProgHeader(self: *Elf, index: usize) !void { + const foreign_endian = self.base.options.target.cpu.arch.endian() != std.Target.current.cpu.arch.endian(); + const offset = self.program_headers.items[index].p_offset; + switch (self.base.options.target.cpu.arch.ptrBitWidth()) { + 32 => { + var phdr = [1]elf.Elf32_Phdr{progHeaderTo32(self.program_headers.items[index])}; + if (foreign_endian) { + bswapAllFields(elf.Elf32_Phdr, &phdr[0]); + } + return self.base.file.?.pwriteAll(mem.sliceAsBytes(&phdr), offset); + }, + 64 => { + var phdr = [1]elf.Elf64_Phdr{self.program_headers.items[index]}; + if (foreign_endian) { + bswapAllFields(elf.Elf64_Phdr, &phdr[0]); + } + return self.base.file.?.pwriteAll(mem.sliceAsBytes(&phdr), offset); + }, + else => return error.UnsupportedArchitecture, + } +} + +fn writeSectHeader(self: *Elf, index: usize) !void { + const foreign_endian = self.base.options.target.cpu.arch.endian() != std.Target.current.cpu.arch.endian(); + switch (self.base.options.target.cpu.arch.ptrBitWidth()) { + 32 => { + var shdr: [1]elf.Elf32_Shdr = undefined; + shdr[0] = sectHeaderTo32(self.sections.items[index]); + if (foreign_endian) { + bswapAllFields(elf.Elf32_Shdr, &shdr[0]); + } + const offset = self.shdr_table_offset.? + index * @sizeOf(elf.Elf32_Shdr); + return self.base.file.?.pwriteAll(mem.sliceAsBytes(&shdr), offset); + }, + 64 => { + var shdr = [1]elf.Elf64_Shdr{self.sections.items[index]}; + if (foreign_endian) { + bswapAllFields(elf.Elf64_Shdr, &shdr[0]); + } + const offset = self.shdr_table_offset.? + index * @sizeOf(elf.Elf64_Shdr); + return self.base.file.?.pwriteAll(mem.sliceAsBytes(&shdr), offset); + }, + else => return error.UnsupportedArchitecture, + } +} + +fn writeOffsetTableEntry(self: *Elf, index: usize) !void { + const shdr = &self.sections.items[self.got_section_index.?]; + const phdr = &self.program_headers.items[self.phdr_got_index.?]; + const entry_size: u16 = self.ptrWidthBytes(); + if (self.offset_table_count_dirty) { + // TODO Also detect virtual address collisions. + const allocated_size = self.allocatedSize(shdr.sh_offset); + const needed_size = self.local_symbols.items.len * entry_size; + if (needed_size > allocated_size) { + // Must move the entire got section. + const new_offset = self.findFreeSpace(needed_size, entry_size); + const amt = try self.base.file.?.copyRangeAll(shdr.sh_offset, self.base.file.?, new_offset, shdr.sh_size); + if (amt != shdr.sh_size) return error.InputOutput; + shdr.sh_offset = new_offset; + phdr.p_offset = new_offset; + } + shdr.sh_size = needed_size; + phdr.p_memsz = needed_size; + phdr.p_filesz = needed_size; + + self.shdr_table_dirty = true; // TODO look into making only the one section dirty + self.phdr_table_dirty = true; // TODO look into making only the one program header dirty + + self.offset_table_count_dirty = false; + } + const endian = self.base.options.target.cpu.arch.endian(); + const off = shdr.sh_offset + @as(u64, entry_size) * index; + switch (self.ptr_width) { + .p32 => { + var buf: [4]u8 = undefined; + mem.writeInt(u32, &buf, @intCast(u32, self.offset_table.items[index]), endian); + try self.base.file.?.pwriteAll(&buf, off); + }, + .p64 => { + var buf: [8]u8 = undefined; + mem.writeInt(u64, &buf, self.offset_table.items[index], endian); + try self.base.file.?.pwriteAll(&buf, off); + }, + } +} + +fn writeSymbol(self: *Elf, index: usize) !void { + const tracy = trace(@src()); + defer tracy.end(); + + const syms_sect = &self.sections.items[self.symtab_section_index.?]; + // Make sure we are not pointlessly writing symbol data that will have to get relocated + // due to running out of space. + if (self.local_symbols.items.len != syms_sect.sh_info) { + const sym_size: u64 = switch (self.ptr_width) { + .p32 => @sizeOf(elf.Elf32_Sym), + .p64 => @sizeOf(elf.Elf64_Sym), + }; + const sym_align: u16 = switch (self.ptr_width) { + .p32 => @alignOf(elf.Elf32_Sym), + .p64 => @alignOf(elf.Elf64_Sym), + }; + const needed_size = (self.local_symbols.items.len + self.global_symbols.items.len) * sym_size; + if (needed_size > self.allocatedSize(syms_sect.sh_offset)) { + // Move all the symbols to a new file location. + const new_offset = self.findFreeSpace(needed_size, sym_align); + const existing_size = @as(u64, syms_sect.sh_info) * sym_size; + const amt = try self.base.file.?.copyRangeAll(syms_sect.sh_offset, self.base.file.?, new_offset, existing_size); + if (amt != existing_size) return error.InputOutput; + syms_sect.sh_offset = new_offset; + } + syms_sect.sh_info = @intCast(u32, self.local_symbols.items.len); + syms_sect.sh_size = needed_size; // anticipating adding the global symbols later + self.shdr_table_dirty = true; // TODO look into only writing one section + } + const foreign_endian = self.base.options.target.cpu.arch.endian() != std.Target.current.cpu.arch.endian(); + switch (self.ptr_width) { + .p32 => { + var sym = [1]elf.Elf32_Sym{ + .{ + .st_name = self.local_symbols.items[index].st_name, + .st_value = @intCast(u32, self.local_symbols.items[index].st_value), + .st_size = @intCast(u32, self.local_symbols.items[index].st_size), + .st_info = self.local_symbols.items[index].st_info, + .st_other = self.local_symbols.items[index].st_other, + .st_shndx = self.local_symbols.items[index].st_shndx, + }, + }; + if (foreign_endian) { + bswapAllFields(elf.Elf32_Sym, &sym[0]); + } + const off = syms_sect.sh_offset + @sizeOf(elf.Elf32_Sym) * index; + try self.base.file.?.pwriteAll(mem.sliceAsBytes(sym[0..1]), off); + }, + .p64 => { + var sym = [1]elf.Elf64_Sym{self.local_symbols.items[index]}; + if (foreign_endian) { + bswapAllFields(elf.Elf64_Sym, &sym[0]); + } + const off = syms_sect.sh_offset + @sizeOf(elf.Elf64_Sym) * index; + try self.base.file.?.pwriteAll(mem.sliceAsBytes(sym[0..1]), off); + }, + } +} + +fn writeAllGlobalSymbols(self: *Elf) !void { + const syms_sect = &self.sections.items[self.symtab_section_index.?]; + const sym_size: u64 = switch (self.ptr_width) { + .p32 => @sizeOf(elf.Elf32_Sym), + .p64 => @sizeOf(elf.Elf64_Sym), + }; + const foreign_endian = self.base.options.target.cpu.arch.endian() != std.Target.current.cpu.arch.endian(); + const global_syms_off = syms_sect.sh_offset + self.local_symbols.items.len * sym_size; + switch (self.ptr_width) { + .p32 => { + const buf = try self.base.allocator.alloc(elf.Elf32_Sym, self.global_symbols.items.len); + defer self.base.allocator.free(buf); + + for (buf) |*sym, i| { + sym.* = .{ + .st_name = self.global_symbols.items[i].st_name, + .st_value = @intCast(u32, self.global_symbols.items[i].st_value), + .st_size = @intCast(u32, self.global_symbols.items[i].st_size), + .st_info = self.global_symbols.items[i].st_info, + .st_other = self.global_symbols.items[i].st_other, + .st_shndx = self.global_symbols.items[i].st_shndx, + }; + if (foreign_endian) { + bswapAllFields(elf.Elf32_Sym, sym); + } + } + try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), global_syms_off); + }, + .p64 => { + const buf = try self.base.allocator.alloc(elf.Elf64_Sym, self.global_symbols.items.len); + defer self.base.allocator.free(buf); + + for (buf) |*sym, i| { + sym.* = .{ + .st_name = self.global_symbols.items[i].st_name, + .st_value = self.global_symbols.items[i].st_value, + .st_size = self.global_symbols.items[i].st_size, + .st_info = self.global_symbols.items[i].st_info, + .st_other = self.global_symbols.items[i].st_other, + .st_shndx = self.global_symbols.items[i].st_shndx, + }; + if (foreign_endian) { + bswapAllFields(elf.Elf64_Sym, sym); + } + } + try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), global_syms_off); + }, + } +} + +fn ptrWidthBytes(self: Elf) u8 { + return switch (self.ptr_width) { + .p32 => 4, + .p64 => 8, + }; +} + +/// The reloc offset for the virtual address of a function in its Line Number Program. +/// Size is a virtual address integer. +const dbg_line_vaddr_reloc_index = 3; +/// The reloc offset for the virtual address of a function in its .debug_info TAG_subprogram. +/// Size is a virtual address integer. +const dbg_info_low_pc_reloc_index = 1; + +/// The reloc offset for the line offset of a function from the previous function's line. +/// It's a fixed-size 4-byte ULEB128. +fn getRelocDbgLineOff(self: Elf) usize { + return dbg_line_vaddr_reloc_index + self.ptrWidthBytes() + 1; +} + +fn getRelocDbgFileIndex(self: Elf) usize { + return self.getRelocDbgLineOff() + 5; +} + +fn getRelocDbgInfoSubprogramHighPC(self: Elf) u32 { + return dbg_info_low_pc_reloc_index + self.ptrWidthBytes(); +} + +fn dbgLineNeededHeaderBytes(self: Elf) u32 { + const directory_entry_format_count = 1; + const file_name_entry_format_count = 1; + const directory_count = 1; + const file_name_count = 1; + return @intCast(u32, 53 + directory_entry_format_count * 2 + file_name_entry_format_count * 2 + + directory_count * 8 + file_name_count * 8 + + // These are encoded as DW.FORM_string rather than DW.FORM_strp as we would like + // because of a workaround for readelf and gdb failing to understand DWARFv5 correctly. + self.base.options.root_pkg.root_src_dir_path.len + + self.base.options.root_pkg.root_src_path.len); +} + +fn dbgInfoNeededHeaderBytes(self: Elf) u32 { + return 120; +} + +const min_nop_size = 2; + +/// Writes to the file a buffer, prefixed and suffixed by the specified number of +/// bytes of NOPs. Asserts each padding size is at least `min_nop_size` and total padding bytes +/// are less than 126,976 bytes (if this limit is ever reached, this function can be +/// improved to make more than one pwritev call, or the limit can be raised by a fixed +/// amount by increasing the length of `vecs`). +fn pwriteDbgLineNops( + self: *Elf, + prev_padding_size: usize, + buf: []const u8, + next_padding_size: usize, + offset: usize, +) !void { + const tracy = trace(@src()); + defer tracy.end(); + + const page_of_nops = [1]u8{DW.LNS_negate_stmt} ** 4096; + const three_byte_nop = [3]u8{ DW.LNS_advance_pc, 0b1000_0000, 0 }; + var vecs: [32]std.os.iovec_const = undefined; + var vec_index: usize = 0; + { + var padding_left = prev_padding_size; + if (padding_left % 2 != 0) { + vecs[vec_index] = .{ + .iov_base = &three_byte_nop, + .iov_len = three_byte_nop.len, + }; + vec_index += 1; + padding_left -= three_byte_nop.len; + } + while (padding_left > page_of_nops.len) { + vecs[vec_index] = .{ + .iov_base = &page_of_nops, + .iov_len = page_of_nops.len, + }; + vec_index += 1; + padding_left -= page_of_nops.len; + } + if (padding_left > 0) { + vecs[vec_index] = .{ + .iov_base = &page_of_nops, + .iov_len = padding_left, + }; + vec_index += 1; + } + } + + vecs[vec_index] = .{ + .iov_base = buf.ptr, + .iov_len = buf.len, + }; + vec_index += 1; + + { + var padding_left = next_padding_size; + if (padding_left % 2 != 0) { + vecs[vec_index] = .{ + .iov_base = &three_byte_nop, + .iov_len = three_byte_nop.len, + }; + vec_index += 1; + padding_left -= three_byte_nop.len; + } + while (padding_left > page_of_nops.len) { + vecs[vec_index] = .{ + .iov_base = &page_of_nops, + .iov_len = page_of_nops.len, + }; + vec_index += 1; + padding_left -= page_of_nops.len; + } + if (padding_left > 0) { + vecs[vec_index] = .{ + .iov_base = &page_of_nops, + .iov_len = padding_left, + }; + vec_index += 1; + } + } + try self.base.file.?.pwritevAll(vecs[0..vec_index], offset - prev_padding_size); +} + +/// Writes to the file a buffer, prefixed and suffixed by the specified number of +/// bytes of padding. +fn pwriteDbgInfoNops( + self: *Elf, + prev_padding_size: usize, + buf: []const u8, + next_padding_size: usize, + trailing_zero: bool, + offset: usize, +) !void { + const tracy = trace(@src()); + defer tracy.end(); + + const page_of_nops = [1]u8{abbrev_pad1} ** 4096; + var vecs: [32]std.os.iovec_const = undefined; + var vec_index: usize = 0; + { + var padding_left = prev_padding_size; + while (padding_left > page_of_nops.len) { + vecs[vec_index] = .{ + .iov_base = &page_of_nops, + .iov_len = page_of_nops.len, + }; + vec_index += 1; + padding_left -= page_of_nops.len; + } + if (padding_left > 0) { + vecs[vec_index] = .{ + .iov_base = &page_of_nops, + .iov_len = padding_left, + }; + vec_index += 1; + } + } + + vecs[vec_index] = .{ + .iov_base = buf.ptr, + .iov_len = buf.len, + }; + vec_index += 1; + + { + var padding_left = next_padding_size; + while (padding_left > page_of_nops.len) { + vecs[vec_index] = .{ + .iov_base = &page_of_nops, + .iov_len = page_of_nops.len, + }; + vec_index += 1; + padding_left -= page_of_nops.len; + } + if (padding_left > 0) { + vecs[vec_index] = .{ + .iov_base = &page_of_nops, + .iov_len = padding_left, + }; + vec_index += 1; + } + } + + if (trailing_zero) { + var zbuf = [1]u8{0}; + vecs[vec_index] = .{ + .iov_base = &zbuf, + .iov_len = zbuf.len, + }; + vec_index += 1; + } + + try self.base.file.?.pwritevAll(vecs[0..vec_index], offset - prev_padding_size); +} + +/// Saturating multiplication +fn satMul(a: anytype, b: anytype) @TypeOf(a, b) { + const T = @TypeOf(a, b); + return std.math.mul(T, a, b) catch std.math.maxInt(T); +} + +fn bswapAllFields(comptime S: type, ptr: *S) void { + @panic("TODO implement bswapAllFields"); +} + +fn progHeaderTo32(phdr: elf.Elf64_Phdr) elf.Elf32_Phdr { + return .{ + .p_type = phdr.p_type, + .p_flags = phdr.p_flags, + .p_offset = @intCast(u32, phdr.p_offset), + .p_vaddr = @intCast(u32, phdr.p_vaddr), + .p_paddr = @intCast(u32, phdr.p_paddr), + .p_filesz = @intCast(u32, phdr.p_filesz), + .p_memsz = @intCast(u32, phdr.p_memsz), + .p_align = @intCast(u32, phdr.p_align), + }; +} + +fn sectHeaderTo32(shdr: elf.Elf64_Shdr) elf.Elf32_Shdr { + return .{ + .sh_name = shdr.sh_name, + .sh_type = shdr.sh_type, + .sh_flags = @intCast(u32, shdr.sh_flags), + .sh_addr = @intCast(u32, shdr.sh_addr), + .sh_offset = @intCast(u32, shdr.sh_offset), + .sh_size = @intCast(u32, shdr.sh_size), + .sh_link = shdr.sh_link, + .sh_info = shdr.sh_info, + .sh_addralign = @intCast(u32, shdr.sh_addralign), + .sh_entsize = @intCast(u32, shdr.sh_entsize), + }; +} diff --git a/src-self-hosted/link/MachO.zig b/src-self-hosted/link/MachO.zig index 9947530398..4bcea9cfa8 100644 --- a/src-self-hosted/link/MachO.zig +++ b/src-self-hosted/link/MachO.zig @@ -13,7 +13,7 @@ const Module = @import("../Module.zig"); const link = @import("../link.zig"); const File = link.File; -pub const base_tag: Tag = File.Tag.macho; +pub const base_tag: File.Tag = File.Tag.macho; base: File, @@ -210,3 +210,7 @@ pub fn updateDeclExports( ) !void {} pub fn freeDecl(self: *MachO, decl: *Module.Decl) void {} + +pub fn getDeclVAddr(self: *MachO, decl: *const Module.Decl) u64 { + @panic("TODO implement getDeclVAddr for MachO"); +} diff --git a/src-self-hosted/cbe.h b/src-self-hosted/link/cbe.h similarity index 100% rename from src-self-hosted/cbe.h rename to src-self-hosted/link/cbe.h diff --git a/src-self-hosted/test.zig b/src-self-hosted/test.zig index b51cb313f8..9e88466cf7 100644 --- a/src-self-hosted/test.zig +++ b/src-self-hosted/test.zig @@ -10,7 +10,7 @@ const enable_wine: bool = build_options.enable_wine; const enable_wasmtime: bool = build_options.enable_wasmtime; const glibc_multi_install_dir: ?[]const u8 = build_options.glibc_multi_install_dir; -const cheader = @embedFile("cbe.h"); +const cheader = @embedFile("link/cbe.h"); test "self-hosted" { var ctx = TestContext.init();