From 4983da40d02632217e606098fd8a94bd7732bf0c Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Wed, 25 Jan 2023 10:10:50 +0100 Subject: [PATCH 01/84] self-hosted: remove unused `externally_managed` prong for Decls code --- src/arch/aarch64/CodeGen.zig | 18 ++++----- src/arch/arm/CodeGen.zig | 18 ++++----- src/arch/riscv64/CodeGen.zig | 18 ++++----- src/arch/sparc64/CodeGen.zig | 18 ++++----- src/arch/wasm/CodeGen.zig | 13 ++----- src/arch/x86_64/CodeGen.zig | 18 ++++----- src/codegen.zig | 75 +----------------------------------- src/link/Coff.zig | 2 - src/link/Elf.zig | 2 - src/link/MachO.zig | 2 - src/link/Plan9.zig | 2 - src/link/Wasm.zig | 2 - 12 files changed, 49 insertions(+), 139 deletions(-) diff --git a/src/arch/aarch64/CodeGen.zig b/src/arch/aarch64/CodeGen.zig index b333ffc6661f1c7db36781a7170ad3f517a00de4..532bfcb9bf53fe90cc5f6f09e9b5f28670342171 100644 --- a/src/arch/aarch64/CodeGen.zig +++ b/src/arch/aarch64/CodeGen.zig @@ -24,7 +24,7 @@ const log = std.log.scoped(.codegen); const build_options = @import("build_options"); const GenerateSymbolError = codegen.GenerateSymbolError; -const FnResult = codegen.FnResult; +const Result = codegen.Result; const DebugInfoOutput = codegen.DebugInfoOutput; const bits = @import("bits.zig"); @@ -349,7 +349,7 @@ pub fn generate( liveness: Liveness, code: *std.ArrayList(u8), debug_output: DebugInfoOutput, -) GenerateSymbolError!FnResult { +) GenerateSymbolError!Result { if (build_options.skip_non_native and builtin.cpu.arch != bin_file.options.target.cpu.arch) { @panic("Attempted to compile for architecture that was disabled by build configuration"); } @@ -392,8 +392,8 @@ pub fn generate( defer function.dbg_info_relocs.deinit(bin_file.allocator); var call_info = function.resolveCallingConventionValues(fn_type) catch |err| switch (err) { - error.CodegenFail => return FnResult{ .fail = function.err_msg.? }, - error.OutOfRegisters => return FnResult{ + error.CodegenFail => return Result{ .fail = function.err_msg.? }, + error.OutOfRegisters => return Result{ .fail = try ErrorMsg.create(bin_file.allocator, src_loc, "CodeGen ran out of registers. This is a bug in the Zig compiler.", .{}), }, else => |e| return e, @@ -406,8 +406,8 @@ pub fn generate( function.max_end_stack = call_info.stack_byte_count; function.gen() catch |err| switch (err) { - error.CodegenFail => return FnResult{ .fail = function.err_msg.? }, - error.OutOfRegisters => return FnResult{ + error.CodegenFail => return Result{ .fail = function.err_msg.? }, + error.OutOfRegisters => return Result{ .fail = try ErrorMsg.create(bin_file.allocator, src_loc, "CodeGen ran out of registers. This is a bug in the Zig compiler.", .{}), }, else => |e| return e, @@ -439,14 +439,14 @@ pub fn generate( defer emit.deinit(); emit.emitMir() catch |err| switch (err) { - error.EmitFail => return FnResult{ .fail = emit.err_msg.? }, + error.EmitFail => return Result{ .fail = emit.err_msg.? }, else => |e| return e, }; if (function.err_msg) |em| { - return FnResult{ .fail = em }; + return Result{ .fail = em }; } else { - return FnResult{ .appended = {} }; + return Result{ .appended = {} }; } } diff --git a/src/arch/arm/CodeGen.zig b/src/arch/arm/CodeGen.zig index fec844a8673b46a7c67de28233ea24c8e2a6d9a2..38cf86c758580534bb6389aecd20d26bc5390486 100644 --- a/src/arch/arm/CodeGen.zig +++ b/src/arch/arm/CodeGen.zig @@ -23,7 +23,7 @@ const leb128 = std.leb; const log = std.log.scoped(.codegen); const build_options = @import("build_options"); -const FnResult = codegen.FnResult; +const Result = codegen.Result; const GenerateSymbolError = codegen.GenerateSymbolError; const DebugInfoOutput = codegen.DebugInfoOutput; @@ -356,7 +356,7 @@ pub fn generate( liveness: Liveness, code: *std.ArrayList(u8), debug_output: DebugInfoOutput, -) GenerateSymbolError!FnResult { +) GenerateSymbolError!Result { if (build_options.skip_non_native and builtin.cpu.arch != bin_file.options.target.cpu.arch) { @panic("Attempted to compile for architecture that was disabled by build configuration"); } @@ -399,8 +399,8 @@ pub fn generate( defer function.dbg_info_relocs.deinit(bin_file.allocator); var call_info = function.resolveCallingConventionValues(fn_type) catch |err| switch (err) { - error.CodegenFail => return FnResult{ .fail = function.err_msg.? }, - error.OutOfRegisters => return FnResult{ + error.CodegenFail => return Result{ .fail = function.err_msg.? }, + error.OutOfRegisters => return Result{ .fail = try ErrorMsg.create(bin_file.allocator, src_loc, "CodeGen ran out of registers. This is a bug in the Zig compiler.", .{}), }, else => |e| return e, @@ -413,8 +413,8 @@ pub fn generate( function.max_end_stack = call_info.stack_byte_count; function.gen() catch |err| switch (err) { - error.CodegenFail => return FnResult{ .fail = function.err_msg.? }, - error.OutOfRegisters => return FnResult{ + error.CodegenFail => return Result{ .fail = function.err_msg.? }, + error.OutOfRegisters => return Result{ .fail = try ErrorMsg.create(bin_file.allocator, src_loc, "CodeGen ran out of registers. This is a bug in the Zig compiler.", .{}), }, else => |e| return e, @@ -446,14 +446,14 @@ pub fn generate( defer emit.deinit(); emit.emitMir() catch |err| switch (err) { - error.EmitFail => return FnResult{ .fail = emit.err_msg.? }, + error.EmitFail => return Result{ .fail = emit.err_msg.? }, else => |e| return e, }; if (function.err_msg) |em| { - return FnResult{ .fail = em }; + return Result{ .fail = em }; } else { - return FnResult{ .appended = {} }; + return Result{ .appended = {} }; } } diff --git a/src/arch/riscv64/CodeGen.zig b/src/arch/riscv64/CodeGen.zig index 2c63f171addc2c96c8ca4cdd40f3bdc136bb9724..71dcfef35e39b89213c3dff320e492d27c278cb0 100644 --- a/src/arch/riscv64/CodeGen.zig +++ b/src/arch/riscv64/CodeGen.zig @@ -22,7 +22,7 @@ const leb128 = std.leb; const log = std.log.scoped(.codegen); const build_options = @import("build_options"); -const FnResult = @import("../../codegen.zig").FnResult; +const Result = @import("../../codegen.zig").Result; const GenerateSymbolError = @import("../../codegen.zig").GenerateSymbolError; const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput; @@ -225,7 +225,7 @@ pub fn generate( liveness: Liveness, code: *std.ArrayList(u8), debug_output: DebugInfoOutput, -) GenerateSymbolError!FnResult { +) GenerateSymbolError!Result { if (build_options.skip_non_native and builtin.cpu.arch != bin_file.options.target.cpu.arch) { @panic("Attempted to compile for architecture that was disabled by build configuration"); } @@ -268,8 +268,8 @@ pub fn generate( defer function.exitlude_jump_relocs.deinit(bin_file.allocator); var call_info = function.resolveCallingConventionValues(fn_type) catch |err| switch (err) { - error.CodegenFail => return FnResult{ .fail = function.err_msg.? }, - error.OutOfRegisters => return FnResult{ + error.CodegenFail => return Result{ .fail = function.err_msg.? }, + error.OutOfRegisters => return Result{ .fail = try ErrorMsg.create(bin_file.allocator, src_loc, "CodeGen ran out of registers. This is a bug in the Zig compiler.", .{}), }, else => |e| return e, @@ -282,8 +282,8 @@ pub fn generate( function.max_end_stack = call_info.stack_byte_count; function.gen() catch |err| switch (err) { - error.CodegenFail => return FnResult{ .fail = function.err_msg.? }, - error.OutOfRegisters => return FnResult{ + error.CodegenFail => return Result{ .fail = function.err_msg.? }, + error.OutOfRegisters => return Result{ .fail = try ErrorMsg.create(bin_file.allocator, src_loc, "CodeGen ran out of registers. This is a bug in the Zig compiler.", .{}), }, else => |e| return e, @@ -309,14 +309,14 @@ pub fn generate( defer emit.deinit(); emit.emitMir() catch |err| switch (err) { - error.EmitFail => return FnResult{ .fail = emit.err_msg.? }, + error.EmitFail => return Result{ .fail = emit.err_msg.? }, else => |e| return e, }; if (function.err_msg) |em| { - return FnResult{ .fail = em }; + return Result{ .fail = em }; } else { - return FnResult{ .appended = {} }; + return Result{ .appended = {} }; } } diff --git a/src/arch/sparc64/CodeGen.zig b/src/arch/sparc64/CodeGen.zig index 943d21c47b01bcc8bd1c9f8f830f460894b7202c..a5ae985442f14a885c738a2fdc4ead04c13b5a6e 100644 --- a/src/arch/sparc64/CodeGen.zig +++ b/src/arch/sparc64/CodeGen.zig @@ -20,7 +20,7 @@ const Emit = @import("Emit.zig"); const Liveness = @import("../../Liveness.zig"); const Type = @import("../../type.zig").Type; const GenerateSymbolError = @import("../../codegen.zig").GenerateSymbolError; -const FnResult = @import("../../codegen.zig").FnResult; +const Result = @import("../../codegen.zig").Result; const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput; const build_options = @import("build_options"); @@ -265,7 +265,7 @@ pub fn generate( liveness: Liveness, code: *std.ArrayList(u8), debug_output: DebugInfoOutput, -) GenerateSymbolError!FnResult { +) GenerateSymbolError!Result { if (build_options.skip_non_native and builtin.cpu.arch != bin_file.options.target.cpu.arch) { @panic("Attempted to compile for architecture that was disabled by build configuration"); } @@ -310,8 +310,8 @@ pub fn generate( defer function.exitlude_jump_relocs.deinit(bin_file.allocator); var call_info = function.resolveCallingConventionValues(fn_type, .callee) catch |err| switch (err) { - error.CodegenFail => return FnResult{ .fail = function.err_msg.? }, - error.OutOfRegisters => return FnResult{ + error.CodegenFail => return Result{ .fail = function.err_msg.? }, + error.OutOfRegisters => return Result{ .fail = try ErrorMsg.create(bin_file.allocator, src_loc, "CodeGen ran out of registers. This is a bug in the Zig compiler.", .{}), }, else => |e| return e, @@ -324,8 +324,8 @@ pub fn generate( function.max_end_stack = call_info.stack_byte_count; function.gen() catch |err| switch (err) { - error.CodegenFail => return FnResult{ .fail = function.err_msg.? }, - error.OutOfRegisters => return FnResult{ + error.CodegenFail => return Result{ .fail = function.err_msg.? }, + error.OutOfRegisters => return Result{ .fail = try ErrorMsg.create(bin_file.allocator, src_loc, "CodeGen ran out of registers. This is a bug in the Zig compiler.", .{}), }, else => |e| return e, @@ -351,14 +351,14 @@ pub fn generate( defer emit.deinit(); emit.emitMir() catch |err| switch (err) { - error.EmitFail => return FnResult{ .fail = emit.err_msg.? }, + error.EmitFail => return Result{ .fail = emit.err_msg.? }, else => |e| return e, }; if (function.err_msg) |em| { - return FnResult{ .fail = em }; + return Result{ .fail = em }; } else { - return FnResult{ .appended = {} }; + return Result{ .appended = {} }; } } diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index c27639e14a07e07c63b01b55e110824de306d5a5..55cfc1096a5ac1083d265e36aa24b87a5ec4a6f5 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -627,13 +627,6 @@ test "Wasm - buildOpcode" { try testing.expectEqual(@as(wasm.Opcode, .f64_reinterpret_i64), f64_reinterpret_i64); } -pub const Result = union(enum) { - /// The codegen bytes have been appended to `Context.code` - appended: void, - /// The data is managed externally and are part of the `Result` - externally_managed: []const u8, -}; - /// Hashmap to store generated `WValue` for each `Air.Inst.Ref` pub const ValueTable = std.AutoArrayHashMapUnmanaged(Air.Inst.Ref, WValue); @@ -1171,7 +1164,7 @@ pub fn generate( liveness: Liveness, code: *std.ArrayList(u8), debug_output: codegen.DebugInfoOutput, -) codegen.GenerateSymbolError!codegen.FnResult { +) codegen.GenerateSymbolError!codegen.Result { _ = src_loc; var code_gen: CodeGen = .{ .gpa = bin_file.allocator, @@ -1190,11 +1183,11 @@ pub fn generate( defer code_gen.deinit(); genFunc(&code_gen) catch |err| switch (err) { - error.CodegenFail => return codegen.FnResult{ .fail = code_gen.err_msg }, + error.CodegenFail => return codegen.Result{ .fail = code_gen.err_msg }, else => |e| return e, }; - return codegen.FnResult{ .appended = {} }; + return codegen.Result{ .appended = {} }; } fn genFunc(func: *CodeGen) InnerError!void { diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 2ad31bf7baf8aaa732294ae0545f7a55d2f3673a..d68aa81cacec23b721fe0f3d7d86d29e146e5960 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -16,7 +16,7 @@ const Compilation = @import("../../Compilation.zig"); const DebugInfoOutput = codegen.DebugInfoOutput; const DW = std.dwarf; const ErrorMsg = Module.ErrorMsg; -const FnResult = codegen.FnResult; +const Result = codegen.Result; const GenerateSymbolError = codegen.GenerateSymbolError; const Emit = @import("Emit.zig"); const Liveness = @import("../../Liveness.zig"); @@ -257,7 +257,7 @@ pub fn generate( liveness: Liveness, code: *std.ArrayList(u8), debug_output: DebugInfoOutput, -) GenerateSymbolError!FnResult { +) GenerateSymbolError!Result { if (build_options.skip_non_native and builtin.cpu.arch != bin_file.options.target.cpu.arch) { @panic("Attempted to compile for architecture that was disabled by build configuration"); } @@ -305,8 +305,8 @@ pub fn generate( defer if (builtin.mode == .Debug) function.mir_to_air_map.deinit(); var call_info = function.resolveCallingConventionValues(fn_type) catch |err| switch (err) { - error.CodegenFail => return FnResult{ .fail = function.err_msg.? }, - error.OutOfRegisters => return FnResult{ + error.CodegenFail => return Result{ .fail = function.err_msg.? }, + error.OutOfRegisters => return Result{ .fail = try ErrorMsg.create(bin_file.allocator, src_loc, "CodeGen ran out of registers. This is a bug in the Zig compiler.", .{}), }, else => |e| return e, @@ -319,8 +319,8 @@ pub fn generate( function.max_end_stack = call_info.stack_byte_count; function.gen() catch |err| switch (err) { - error.CodegenFail => return FnResult{ .fail = function.err_msg.? }, - error.OutOfRegisters => return FnResult{ + error.CodegenFail => return Result{ .fail = function.err_msg.? }, + error.OutOfRegisters => return Result{ .fail = try ErrorMsg.create(bin_file.allocator, src_loc, "CodeGen ran out of registers. This is a bug in the Zig compiler.", .{}), }, else => |e| return e, @@ -345,14 +345,14 @@ pub fn generate( }; defer emit.deinit(); emit.lowerMir() catch |err| switch (err) { - error.EmitFail => return FnResult{ .fail = emit.err_msg.? }, + error.EmitFail => return Result{ .fail = emit.err_msg.? }, else => |e| return e, }; if (function.err_msg) |em| { - return FnResult{ .fail = em }; + return Result{ .fail = em }; } else { - return FnResult{ .appended = {} }; + return Result{ .appended = {} }; } } diff --git a/src/codegen.zig b/src/codegen.zig index e8dd6616848efff909f9080a25aa4ff82a610e6e..1bb0d390e6827c9cf55184765f69f5955afc1b17 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -21,16 +21,9 @@ const TypedValue = @import("TypedValue.zig"); const Value = @import("value.zig").Value; const Zir = @import("Zir.zig"); -pub const FnResult = union(enum) { - /// The `code` parameter passed to `generateSymbol` has the value appended. - appended: void, - fail: *ErrorMsg, -}; pub const Result = union(enum) { /// The `code` parameter passed to `generateSymbol` has the value appended. appended: void, - /// The value is available externally, `code` is unused. - externally_managed: []const u8, fail: *ErrorMsg, }; @@ -89,7 +82,7 @@ pub fn generateFunction( liveness: Liveness, code: *std.ArrayList(u8), debug_output: DebugInfoOutput, -) GenerateSymbolError!FnResult { +) GenerateSymbolError!Result { switch (bin_file.options.target.cpu.arch) { .arm, .armeb, @@ -209,9 +202,6 @@ pub fn generateSymbol( .val = elem_val, }, code, debug_output, reloc_info)) { .appended => {}, - .externally_managed => |slice| { - code.appendSliceAssumeCapacity(slice); - }, .fail => |em| return Result{ .fail = em }, } } @@ -230,9 +220,6 @@ pub fn generateSymbol( .val = array, }, code, debug_output, reloc_info)) { .appended => {}, - .externally_managed => |slice| { - code.appendSliceAssumeCapacity(slice); - }, .fail => |em| return Result{ .fail = em }, } } @@ -243,9 +230,6 @@ pub fn generateSymbol( .val = sentinel_val, }, code, debug_output, reloc_info)) { .appended => {}, - .externally_managed => |slice| { - code.appendSliceAssumeCapacity(slice); - }, .fail => |em| return Result{ .fail = em }, } } @@ -260,9 +244,6 @@ pub fn generateSymbol( .val = sentinel_val, }, code, debug_output, reloc_info)) { .appended => {}, - .externally_managed => |slice| { - code.appendSliceAssumeCapacity(slice); - }, .fail => |em| return Result{ .fail = em }, } return Result{ .appended = {} }; @@ -310,9 +291,6 @@ pub fn generateSymbol( .val = slice.ptr, }, code, debug_output, reloc_info)) { .appended => {}, - .externally_managed => |external_slice| { - code.appendSliceAssumeCapacity(external_slice); - }, .fail => |em| return Result{ .fail = em }, } @@ -322,9 +300,6 @@ pub fn generateSymbol( .val = slice.len, }, code, debug_output, reloc_info)) { .appended => {}, - .externally_managed => |external_slice| { - code.appendSliceAssumeCapacity(external_slice); - }, .fail => |em| return Result{ .fail = em }, } @@ -376,9 +351,6 @@ pub fn generateSymbol( .val = container_ptr, }, code, debug_output, reloc_info)) { .appended => {}, - .externally_managed => |external_slice| { - code.appendSliceAssumeCapacity(external_slice); - }, .fail => |em| return Result{ .fail = em }, } return Result{ .appended = {} }; @@ -552,9 +524,6 @@ pub fn generateSymbol( .appended => { mem.copy(u8, code.items[current_pos..], tmp_list.items); }, - .externally_managed => |external_slice| { - mem.copy(u8, code.items[current_pos..], external_slice); - }, .fail => |em| return Result{ .fail = em }, } } else { @@ -577,9 +546,6 @@ pub fn generateSymbol( .val = field_val, }, code, debug_output, reloc_info)) { .appended => {}, - .externally_managed => |external_slice| { - code.appendSliceAssumeCapacity(external_slice); - }, .fail => |em| return Result{ .fail = em }, } const unpadded_field_end = code.items.len - struct_begin; @@ -613,9 +579,6 @@ pub fn generateSymbol( .val = union_obj.tag, }, code, debug_output, reloc_info)) { .appended => {}, - .externally_managed => |external_slice| { - code.appendSliceAssumeCapacity(external_slice); - }, .fail => |em| return Result{ .fail = em }, } } @@ -633,9 +596,6 @@ pub fn generateSymbol( .val = union_obj.val, }, code, debug_output, reloc_info)) { .appended => {}, - .externally_managed => |external_slice| { - code.appendSliceAssumeCapacity(external_slice); - }, .fail => |em| return Result{ .fail = em }, } @@ -651,9 +611,6 @@ pub fn generateSymbol( .val = union_obj.tag, }, code, debug_output, reloc_info)) { .appended => {}, - .externally_managed => |external_slice| { - code.appendSliceAssumeCapacity(external_slice); - }, .fail => |em| return Result{ .fail = em }, } } @@ -679,9 +636,6 @@ pub fn generateSymbol( .val = payload.data, }, code, debug_output, reloc_info)) { .appended => {}, - .externally_managed => |external_slice| { - code.appendSliceAssumeCapacity(external_slice); - }, .fail => |em| return Result{ .fail = em }, } } else if (!typed_value.val.isNull()) { @@ -690,9 +644,6 @@ pub fn generateSymbol( .val = typed_value.val, }, code, debug_output, reloc_info)) { .appended => {}, - .externally_managed => |external_slice| { - code.appendSliceAssumeCapacity(external_slice); - }, .fail => |em| return Result{ .fail = em }, } } else { @@ -709,9 +660,6 @@ pub fn generateSymbol( .val = value, }, code, debug_output, reloc_info)) { .appended => {}, - .externally_managed => |external_slice| { - code.appendSliceAssumeCapacity(external_slice); - }, .fail => |em| return Result{ .fail = em }, } @@ -741,9 +689,6 @@ pub fn generateSymbol( .val = if (is_payload) Value.initTag(.zero) else typed_value.val, }, code, debug_output, reloc_info)) { .appended => {}, - .externally_managed => |external_slice| { - code.appendSliceAssumeCapacity(external_slice); - }, .fail => |em| return Result{ .fail = em }, } } @@ -757,9 +702,6 @@ pub fn generateSymbol( .val = payload_val, }, code, debug_output, reloc_info)) { .appended => {}, - .externally_managed => |external_slice| { - code.appendSliceAssumeCapacity(external_slice); - }, .fail => |em| return Result{ .fail = em }, } const unpadded_end = code.items.len - begin; @@ -779,9 +721,6 @@ pub fn generateSymbol( .val = if (is_payload) Value.initTag(.zero) else typed_value.val, }, code, debug_output, reloc_info)) { .appended => {}, - .externally_managed => |external_slice| { - code.appendSliceAssumeCapacity(external_slice); - }, .fail => |em| return Result{ .fail = em }, } const unpadded_end = code.items.len - begin; @@ -826,9 +765,6 @@ pub fn generateSymbol( .val = elem_val, }, code, debug_output, reloc_info)) { .appended => {}, - .externally_managed => |slice| { - code.appendSliceAssumeCapacity(slice); - }, .fail => |em| return Result{ .fail = em }, } } @@ -846,9 +782,6 @@ pub fn generateSymbol( .val = array, }, code, debug_output, reloc_info)) { .appended => {}, - .externally_managed => |slice| { - code.appendSliceAssumeCapacity(slice); - }, .fail => |em| return Result{ .fail = em }, } } @@ -902,9 +835,6 @@ fn lowerDeclRef( .val = typed_value.val, }, code, debug_output, reloc_info)) { .appended => {}, - .externally_managed => |external_slice| { - code.appendSliceAssumeCapacity(external_slice); - }, .fail => |em| return Result{ .fail = em }, } @@ -918,9 +848,6 @@ fn lowerDeclRef( .val = Value.initPayload(&slice_len.base), }, code, debug_output, reloc_info)) { .appended => {}, - .externally_managed => |external_slice| { - code.appendSliceAssumeCapacity(external_slice); - }, .fail => |em| return Result{ .fail = em }, } diff --git a/src/link/Coff.zig b/src/link/Coff.zig index 9c05114a1f13816ef3ce451c26a1203ffae034ac..90073cf5aeeb4a5e1934e19094fa429660ae8269 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -981,7 +981,6 @@ pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.In .parent_atom_index = atom.sym_index, }); const code = switch (res) { - .externally_managed => |x| x, .appended => code_buffer.items, .fail => |em| { decl.analysis = .codegen_failure; @@ -1042,7 +1041,6 @@ pub fn updateDecl(self: *Coff, module: *Module, decl_index: Module.Decl.Index) ! .parent_atom_index = decl.link.coff.sym_index, }); const code = switch (res) { - .externally_managed => |x| x, .appended => code_buffer.items, .fail => |em| { decl.analysis = .codegen_failure; diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 48e0320dc60ace6cc0c8a871a8cb0e44c07d5be8..db84cc38f722db28661fb87c9618d95bc642de26 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -2553,7 +2553,6 @@ pub fn updateDecl(self: *Elf, module: *Module, decl_index: Module.Decl.Index) !v }); const code = switch (res) { - .externally_managed => |x| x, .appended => code_buffer.items, .fail => |em| { decl.analysis = .codegen_failure; @@ -2618,7 +2617,6 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module .parent_atom_index = atom.local_sym_index, }); const code = switch (res) { - .externally_managed => |x| x, .appended => code_buffer.items, .fail => |em| { decl.analysis = .codegen_failure; diff --git a/src/link/MachO.zig b/src/link/MachO.zig index e6924a6717fcf58c101f2d90cd52ca2c1cf97193..252df865d0a831e93ea76d4dec466350b537c6b2 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -2082,7 +2082,6 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Modu .parent_atom_index = atom.sym_index, }); const code = switch (res) { - .externally_managed => |x| x, .appended => code_buffer.items, .fail => |em| { decl.analysis = .codegen_failure; @@ -2167,7 +2166,6 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index) }); const code = switch (res) { - .externally_managed => |x| x, .appended => code_buffer.items, .fail => |em| { decl.analysis = .codegen_failure; diff --git a/src/link/Plan9.zig b/src/link/Plan9.zig index 5423269bf06bcc533288261ab76e7e30a4d0acf5..3a76139fe10d425662bf3064a899e3b8cf46abbc 100644 --- a/src/link/Plan9.zig +++ b/src/link/Plan9.zig @@ -358,7 +358,6 @@ pub fn lowerUnnamedConst(self: *Plan9, tv: TypedValue, decl_index: Module.Decl.I .parent_atom_index = @enumToInt(decl_index), }); const code = switch (res) { - .externally_managed => |x| x, .appended => code_buffer.items, .fail => |em| { decl.analysis = .codegen_failure; @@ -403,7 +402,6 @@ pub fn updateDecl(self: *Plan9, module: *Module, decl_index: Module.Decl.Index) .parent_atom_index = @enumToInt(decl_index), }); const code = switch (res) { - .externally_managed => |x| x, .appended => code_buffer.items, .fail => |em| { decl.analysis = .codegen_failure; diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index 7154cd7bc1758bd0b1de9f4e332ab3f4f286923b..f11a052f4563c81a73ecb6027ea39ba23d71ecd4 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -1113,7 +1113,6 @@ pub fn updateDecl(wasm: *Wasm, mod: *Module, decl_index: Module.Decl.Index) !voi ); const code = switch (res) { - .externally_managed => |x| x, .appended => code_writer.items, .fail => |em| { decl.analysis = .codegen_failure; @@ -1250,7 +1249,6 @@ pub fn lowerUnnamedConst(wasm: *Wasm, tv: TypedValue, decl_index: Module.Decl.In }, ); const code = switch (result) { - .externally_managed => |x| x, .appended => value_bytes.items, .fail => |em| { decl.analysis = .codegen_failure; -- 2.54.0 From a95d58caf289ecc2ab36cdb30437f634c07b64e4 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Wed, 25 Jan 2023 10:28:18 +0100 Subject: [PATCH 02/84] self-hosted: rename codegen Result.appended to Result.ok --- src/arch/aarch64/CodeGen.zig | 2 +- src/arch/arm/CodeGen.zig | 2 +- src/arch/riscv64/CodeGen.zig | 2 +- src/arch/sparc64/CodeGen.zig | 2 +- src/arch/wasm/CodeGen.zig | 2 +- src/arch/x86_64/CodeGen.zig | 2 +- src/codegen.zig | 114 +++++++++++++++++------------------ src/link/Coff.zig | 6 +- src/link/Elf.zig | 6 +- src/link/MachO.zig | 6 +- src/link/Plan9.zig | 6 +- src/link/Wasm.zig | 6 +- 12 files changed, 78 insertions(+), 78 deletions(-) diff --git a/src/arch/aarch64/CodeGen.zig b/src/arch/aarch64/CodeGen.zig index 532bfcb9bf53fe90cc5f6f09e9b5f28670342171..53841a83a8a2cef573bf2a5671a479271d0362ee 100644 --- a/src/arch/aarch64/CodeGen.zig +++ b/src/arch/aarch64/CodeGen.zig @@ -446,7 +446,7 @@ pub fn generate( if (function.err_msg) |em| { return Result{ .fail = em }; } else { - return Result{ .appended = {} }; + return Result.ok; } } diff --git a/src/arch/arm/CodeGen.zig b/src/arch/arm/CodeGen.zig index 38cf86c758580534bb6389aecd20d26bc5390486..6a7986a7a8a41e39e5abba49566b628f7db40921 100644 --- a/src/arch/arm/CodeGen.zig +++ b/src/arch/arm/CodeGen.zig @@ -453,7 +453,7 @@ pub fn generate( if (function.err_msg) |em| { return Result{ .fail = em }; } else { - return Result{ .appended = {} }; + return Result.ok; } } diff --git a/src/arch/riscv64/CodeGen.zig b/src/arch/riscv64/CodeGen.zig index 71dcfef35e39b89213c3dff320e492d27c278cb0..f9ef52e8d589b137913fc5e3cde7946ad57875c2 100644 --- a/src/arch/riscv64/CodeGen.zig +++ b/src/arch/riscv64/CodeGen.zig @@ -316,7 +316,7 @@ pub fn generate( if (function.err_msg) |em| { return Result{ .fail = em }; } else { - return Result{ .appended = {} }; + return Result.ok; } } diff --git a/src/arch/sparc64/CodeGen.zig b/src/arch/sparc64/CodeGen.zig index a5ae985442f14a885c738a2fdc4ead04c13b5a6e..4fa1695948440728313f4c7d4e18ce33bca2a32f 100644 --- a/src/arch/sparc64/CodeGen.zig +++ b/src/arch/sparc64/CodeGen.zig @@ -358,7 +358,7 @@ pub fn generate( if (function.err_msg) |em| { return Result{ .fail = em }; } else { - return Result{ .appended = {} }; + return Result.ok; } } diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index 55cfc1096a5ac1083d265e36aa24b87a5ec4a6f5..a7d90a8bf9f24b1997fac978853404a2f3869066 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -1187,7 +1187,7 @@ pub fn generate( else => |e| return e, }; - return codegen.Result{ .appended = {} }; + return codegen.Result.ok; } fn genFunc(func: *CodeGen) InnerError!void { diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index d68aa81cacec23b721fe0f3d7d86d29e146e5960..2de358fee89becf37add42bf7d50dd9dfb4adeea 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -352,7 +352,7 @@ pub fn generate( if (function.err_msg) |em| { return Result{ .fail = em }; } else { - return Result{ .appended = {} }; + return Result.ok; } } diff --git a/src/codegen.zig b/src/codegen.zig index 1bb0d390e6827c9cf55184765f69f5955afc1b17..c0a04765b0381bce86f2d063f38a892bfde1975e 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -22,8 +22,10 @@ const Value = @import("value.zig").Value; const Zir = @import("Zir.zig"); pub const Result = union(enum) { - /// The `code` parameter passed to `generateSymbol` has the value appended. - appended: void, + /// The `code` parameter passed to `generateSymbol` has the value ok. + ok: void, + + /// There was a codegen error. fail: *ErrorMsg, }; @@ -138,7 +140,7 @@ pub fn generateSymbol( if (typed_value.val.isUndefDeep()) { const abi_size = math.cast(usize, typed_value.ty.abiSize(target)) orelse return error.Overflow; try code.appendNTimes(0xaa, abi_size); - return Result{ .appended = {} }; + return Result.ok; } switch (typed_value.ty.zigTypeTag()) { @@ -169,7 +171,7 @@ pub fn generateSymbol( 128 => writeFloat(f128, typed_value.val.toFloat(f128), target, endian, try code.addManyAsArray(16)), else => unreachable, } - return Result{ .appended = {} }; + return Result.ok; }, .Array => switch (typed_value.val.tag()) { .bytes => { @@ -178,7 +180,7 @@ pub fn generateSymbol( // The bytes payload already includes the sentinel, if any try code.ensureUnusedCapacity(len); code.appendSliceAssumeCapacity(bytes[0..len]); - return Result{ .appended = {} }; + return Result.ok; }, .str_lit => { const str_lit = typed_value.val.castTag(.str_lit).?.data; @@ -190,7 +192,7 @@ pub fn generateSymbol( const byte = @intCast(u8, sent_val.toUnsignedInt(target)); code.appendAssumeCapacity(byte); } - return Result{ .appended = {} }; + return Result.ok; }, .aggregate => { const elem_vals = typed_value.val.castTag(.aggregate).?.data; @@ -201,11 +203,11 @@ pub fn generateSymbol( .ty = elem_ty, .val = elem_val, }, code, debug_output, reloc_info)) { - .appended => {}, + .ok => {}, .fail => |em| return Result{ .fail = em }, } } - return Result{ .appended = {} }; + return Result.ok; }, .repeated => { const array = typed_value.val.castTag(.repeated).?.data; @@ -219,7 +221,7 @@ pub fn generateSymbol( .ty = elem_ty, .val = array, }, code, debug_output, reloc_info)) { - .appended => {}, + .ok => {}, .fail => |em| return Result{ .fail = em }, } } @@ -229,12 +231,12 @@ pub fn generateSymbol( .ty = elem_ty, .val = sentinel_val, }, code, debug_output, reloc_info)) { - .appended => {}, + .ok => {}, .fail => |em| return Result{ .fail = em }, } } - return Result{ .appended = {} }; + return Result.ok; }, .empty_array_sentinel => { const elem_ty = typed_value.ty.childType(); @@ -243,10 +245,10 @@ pub fn generateSymbol( .ty = elem_ty, .val = sentinel_val, }, code, debug_output, reloc_info)) { - .appended => {}, + .ok => {}, .fail => |em| return Result{ .fail = em }, } - return Result{ .appended = {} }; + return Result.ok; }, else => return Result{ .fail = try ErrorMsg.create( @@ -270,7 +272,7 @@ pub fn generateSymbol( }, else => unreachable, } - return Result{ .appended = {} }; + return Result.ok; }, .variable => { const decl = typed_value.val.castTag(.variable).?.data.owner_decl; @@ -290,7 +292,7 @@ pub fn generateSymbol( .ty = slice_ptr_field_type, .val = slice.ptr, }, code, debug_output, reloc_info)) { - .appended => {}, + .ok => {}, .fail => |em| return Result{ .fail = em }, } @@ -299,11 +301,11 @@ pub fn generateSymbol( .ty = Type.initTag(.usize), .val = slice.len, }, code, debug_output, reloc_info)) { - .appended => {}, + .ok => {}, .fail => |em| return Result{ .fail = em }, } - return Result{ .appended = {} }; + return Result.ok; }, .field_ptr => { const field_ptr = typed_value.val.castTag(.field_ptr).?.data; @@ -350,10 +352,10 @@ pub fn generateSymbol( .ty = typed_value.ty, .val = container_ptr, }, code, debug_output, reloc_info)) { - .appended => {}, + .ok => {}, .fail => |em| return Result{ .fail = em }, } - return Result{ .appended = {} }; + return Result.ok; }, else => return Result{ .fail = try ErrorMsg.create( @@ -406,7 +408,7 @@ pub fn generateSymbol( .signed => @bitCast(u8, @intCast(i8, typed_value.val.toSignedInt(target))), }; try code.append(x); - return Result{ .appended = {} }; + return Result.ok; } if (info.bits > 64) { var bigint_buffer: Value.BigIntSpace = undefined; @@ -415,7 +417,7 @@ pub fn generateSymbol( const start = code.items.len; try code.resize(start + abi_size); bigint.writeTwosComplement(code.items[start..][0..abi_size], endian); - return Result{ .appended = {} }; + return Result.ok; } switch (info.signedness) { .unsigned => { @@ -443,7 +445,7 @@ pub fn generateSymbol( } }, } - return Result{ .appended = {} }; + return Result.ok; }, .Enum => { var int_buffer: Value.Payload.U64 = undefined; @@ -453,7 +455,7 @@ pub fn generateSymbol( if (info.bits <= 8) { const x = @intCast(u8, int_val.toUnsignedInt(target)); try code.append(x); - return Result{ .appended = {} }; + return Result.ok; } if (info.bits > 64) { return Result{ @@ -491,12 +493,12 @@ pub fn generateSymbol( } }, } - return Result{ .appended = {} }; + return Result.ok; }, .Bool => { const x: u8 = @boolToInt(typed_value.val.toBool()); try code.append(x); - return Result{ .appended = {} }; + return Result.ok; }, .Struct => { if (typed_value.ty.containerLayout() == .Packed) { @@ -521,9 +523,7 @@ pub fn generateSymbol( .ty = field_ty, .val = field_val, }, &tmp_list, debug_output, reloc_info)) { - .appended => { - mem.copy(u8, code.items[current_pos..], tmp_list.items); - }, + .ok => mem.copy(u8, code.items[current_pos..], tmp_list.items), .fail => |em| return Result{ .fail = em }, } } else { @@ -532,7 +532,7 @@ pub fn generateSymbol( bits += @intCast(u16, field_ty.bitSize(target)); } - return Result{ .appended = {} }; + return Result.ok; } const struct_begin = code.items.len; @@ -545,7 +545,7 @@ pub fn generateSymbol( .ty = field_ty, .val = field_val, }, code, debug_output, reloc_info)) { - .appended => {}, + .ok => {}, .fail => |em| return Result{ .fail = em }, } const unpadded_field_end = code.items.len - struct_begin; @@ -559,7 +559,7 @@ pub fn generateSymbol( } } - return Result{ .appended = {} }; + return Result.ok; }, .Union => { const union_obj = typed_value.val.castTag(.@"union").?.data; @@ -578,7 +578,7 @@ pub fn generateSymbol( .ty = typed_value.ty.unionTagType().?, .val = union_obj.tag, }, code, debug_output, reloc_info)) { - .appended => {}, + .ok => {}, .fail => |em| return Result{ .fail = em }, } } @@ -595,7 +595,7 @@ pub fn generateSymbol( .ty = field_ty, .val = union_obj.val, }, code, debug_output, reloc_info)) { - .appended => {}, + .ok => {}, .fail => |em| return Result{ .fail = em }, } @@ -610,12 +610,12 @@ pub fn generateSymbol( .ty = union_ty.tag_ty, .val = union_obj.tag, }, code, debug_output, reloc_info)) { - .appended => {}, + .ok => {}, .fail => |em| return Result{ .fail = em }, } } - return Result{ .appended = {} }; + return Result.ok; }, .Optional => { var opt_buf: Type.Payload.ElemType = undefined; @@ -626,7 +626,7 @@ pub fn generateSymbol( if (!payload_type.hasRuntimeBits()) { try code.writer().writeByteNTimes(@boolToInt(is_pl), abi_size); - return Result{ .appended = {} }; + return Result.ok; } if (typed_value.ty.optionalReprIsPayload()) { @@ -635,7 +635,7 @@ pub fn generateSymbol( .ty = payload_type, .val = payload.data, }, code, debug_output, reloc_info)) { - .appended => {}, + .ok => {}, .fail => |em| return Result{ .fail = em }, } } else if (!typed_value.val.isNull()) { @@ -643,14 +643,14 @@ pub fn generateSymbol( .ty = payload_type, .val = typed_value.val, }, code, debug_output, reloc_info)) { - .appended => {}, + .ok => {}, .fail => |em| return Result{ .fail = em }, } } else { try code.writer().writeByteNTimes(0, abi_size); } - return Result{ .appended = {} }; + return Result.ok; } const value = if (typed_value.val.castTag(.opt_payload)) |payload| payload.data else Value.initTag(.undef); @@ -659,11 +659,11 @@ pub fn generateSymbol( .ty = payload_type, .val = value, }, code, debug_output, reloc_info)) { - .appended => {}, + .ok => {}, .fail => |em| return Result{ .fail = em }, } - return Result{ .appended = {} }; + return Result.ok; }, .ErrorUnion => { const error_ty = typed_value.ty.errorUnionSet(); @@ -688,7 +688,7 @@ pub fn generateSymbol( .ty = error_ty, .val = if (is_payload) Value.initTag(.zero) else typed_value.val, }, code, debug_output, reloc_info)) { - .appended => {}, + .ok => {}, .fail => |em| return Result{ .fail = em }, } } @@ -701,7 +701,7 @@ pub fn generateSymbol( .ty = payload_ty, .val = payload_val, }, code, debug_output, reloc_info)) { - .appended => {}, + .ok => {}, .fail => |em| return Result{ .fail = em }, } const unpadded_end = code.items.len - begin; @@ -720,7 +720,7 @@ pub fn generateSymbol( .ty = error_ty, .val = if (is_payload) Value.initTag(.zero) else typed_value.val, }, code, debug_output, reloc_info)) { - .appended => {}, + .ok => {}, .fail => |em| return Result{ .fail = em }, } const unpadded_end = code.items.len - begin; @@ -732,7 +732,7 @@ pub fn generateSymbol( } } - return Result{ .appended = {} }; + return Result.ok; }, .ErrorSet => { switch (typed_value.val.tag()) { @@ -745,7 +745,7 @@ pub fn generateSymbol( try code.writer().writeByteNTimes(0, @intCast(usize, Type.anyerror.abiSize(target))); }, } - return Result{ .appended = {} }; + return Result.ok; }, .Vector => switch (typed_value.val.tag()) { .bytes => { @@ -753,7 +753,7 @@ pub fn generateSymbol( const len = @intCast(usize, typed_value.ty.arrayLen()); try code.ensureUnusedCapacity(len); code.appendSliceAssumeCapacity(bytes[0..len]); - return Result{ .appended = {} }; + return Result.ok; }, .aggregate => { const elem_vals = typed_value.val.castTag(.aggregate).?.data; @@ -764,11 +764,11 @@ pub fn generateSymbol( .ty = elem_ty, .val = elem_val, }, code, debug_output, reloc_info)) { - .appended => {}, + .ok => {}, .fail => |em| return Result{ .fail = em }, } } - return Result{ .appended = {} }; + return Result.ok; }, .repeated => { const array = typed_value.val.castTag(.repeated).?.data; @@ -781,11 +781,11 @@ pub fn generateSymbol( .ty = elem_ty, .val = array, }, code, debug_output, reloc_info)) { - .appended => {}, + .ok => {}, .fail => |em| return Result{ .fail = em }, } } - return Result{ .appended = {} }; + return Result.ok; }, .str_lit => { const str_lit = typed_value.val.castTag(.str_lit).?.data; @@ -793,7 +793,7 @@ pub fn generateSymbol( const bytes = mod.string_literal_bytes.items[str_lit.index..][0..str_lit.len]; try code.ensureUnusedCapacity(str_lit.len); code.appendSliceAssumeCapacity(bytes); - return Result{ .appended = {} }; + return Result.ok; }, else => unreachable, }, @@ -834,7 +834,7 @@ fn lowerDeclRef( .ty = slice_ptr_field_type, .val = typed_value.val, }, code, debug_output, reloc_info)) { - .appended => {}, + .ok => {}, .fail => |em| return Result{ .fail = em }, } @@ -847,11 +847,11 @@ fn lowerDeclRef( .ty = Type.usize, .val = Value.initPayload(&slice_len.base), }, code, debug_output, reloc_info)) { - .appended => {}, + .ok => {}, .fail => |em| return Result{ .fail = em }, } - return Result{ .appended = {} }; + return Result.ok; } const ptr_width = target.cpu.arch.ptrBitWidth(); @@ -859,7 +859,7 @@ fn lowerDeclRef( const is_fn_body = decl.ty.zigTypeTag() == .Fn; if (!is_fn_body and !decl.ty.hasRuntimeBits()) { try code.writer().writeByteNTimes(0xaa, @divExact(ptr_width, 8)); - return Result{ .appended = {} }; + return Result.ok; } module.markDeclAlive(decl); @@ -877,7 +877,7 @@ fn lowerDeclRef( else => unreachable, } - return Result{ .appended = {} }; + return Result.ok; } pub fn errUnionPayloadOffset(payload_ty: Type, target: std.Target) u64 { diff --git a/src/link/Coff.zig b/src/link/Coff.zig index 90073cf5aeeb4a5e1934e19094fa429660ae8269..65aee010fd34bb8746a3615a9433d5f51e636e8e 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -928,7 +928,7 @@ pub fn updateFunc(self: *Coff, module: *Module, func: *Module.Fn, air: Air, live .none, ); const code = switch (res) { - .appended => code_buffer.items, + .ok => code_buffer.items, .fail => |em| { decl.analysis = .codegen_failure; try module.failed_decls.put(module.gpa, decl_index, em); @@ -981,7 +981,7 @@ pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.In .parent_atom_index = atom.sym_index, }); const code = switch (res) { - .appended => code_buffer.items, + .ok => code_buffer.items, .fail => |em| { decl.analysis = .codegen_failure; try mod.failed_decls.put(mod.gpa, decl_index, em); @@ -1041,7 +1041,7 @@ pub fn updateDecl(self: *Coff, module: *Module, decl_index: Module.Decl.Index) ! .parent_atom_index = decl.link.coff.sym_index, }); const code = switch (res) { - .appended => code_buffer.items, + .ok => code_buffer.items, .fail => |em| { decl.analysis = .codegen_failure; try module.failed_decls.put(module.gpa, decl_index, em); diff --git a/src/link/Elf.zig b/src/link/Elf.zig index db84cc38f722db28661fb87c9618d95bc642de26..b0acef368a4d2751796860d738687b4a0bc69606 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -2479,7 +2479,7 @@ pub fn updateFunc(self: *Elf, module: *Module, func: *Module.Fn, air: Air, liven try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .none); const code = switch (res) { - .appended => code_buffer.items, + .ok => code_buffer.items, .fail => |em| { decl.analysis = .codegen_failure; try module.failed_decls.put(module.gpa, decl_index, em); @@ -2553,7 +2553,7 @@ pub fn updateDecl(self: *Elf, module: *Module, decl_index: Module.Decl.Index) !v }); const code = switch (res) { - .appended => code_buffer.items, + .ok => code_buffer.items, .fail => |em| { decl.analysis = .codegen_failure; try module.failed_decls.put(module.gpa, decl_index, em); @@ -2617,7 +2617,7 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module .parent_atom_index = atom.local_sym_index, }); const code = switch (res) { - .appended => code_buffer.items, + .ok => code_buffer.items, .fail => |em| { decl.analysis = .codegen_failure; try mod.failed_decls.put(mod.gpa, decl_index, em); diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 252df865d0a831e93ea76d4dec466350b537c6b2..caf9a91e1a8f8c65ee6d6245472bbb35e0e978a0 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -2017,7 +2017,7 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .none); const code = switch (res) { - .appended => code_buffer.items, + .ok => code_buffer.items, .fail => |em| { decl.analysis = .codegen_failure; try module.failed_decls.put(module.gpa, decl_index, em); @@ -2082,7 +2082,7 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Modu .parent_atom_index = atom.sym_index, }); const code = switch (res) { - .appended => code_buffer.items, + .ok => code_buffer.items, .fail => |em| { decl.analysis = .codegen_failure; try module.failed_decls.put(module.gpa, decl_index, em); @@ -2166,7 +2166,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index) }); const code = switch (res) { - .appended => code_buffer.items, + .ok => code_buffer.items, .fail => |em| { decl.analysis = .codegen_failure; try module.failed_decls.put(module.gpa, decl_index, em); diff --git a/src/link/Plan9.zig b/src/link/Plan9.zig index 3a76139fe10d425662bf3064a899e3b8cf46abbc..e412c78f7fdfa0a0c1624bf0c3cfbe276460dbe3 100644 --- a/src/link/Plan9.zig +++ b/src/link/Plan9.zig @@ -299,7 +299,7 @@ pub fn updateFunc(self: *Plan9, module: *Module, func: *Module.Fn, air: Air, liv }, ); const code = switch (res) { - .appended => try code_buffer.toOwnedSlice(), + .ok => try code_buffer.toOwnedSlice(), .fail => |em| { decl.analysis = .codegen_failure; try module.failed_decls.put(module.gpa, decl_index, em); @@ -358,7 +358,7 @@ pub fn lowerUnnamedConst(self: *Plan9, tv: TypedValue, decl_index: Module.Decl.I .parent_atom_index = @enumToInt(decl_index), }); const code = switch (res) { - .appended => code_buffer.items, + .ok => code_buffer.items, .fail => |em| { decl.analysis = .codegen_failure; try mod.failed_decls.put(mod.gpa, decl_index, em); @@ -402,7 +402,7 @@ pub fn updateDecl(self: *Plan9, module: *Module, decl_index: Module.Decl.Index) .parent_atom_index = @enumToInt(decl_index), }); const code = switch (res) { - .appended => code_buffer.items, + .ok => code_buffer.items, .fail => |em| { decl.analysis = .codegen_failure; try module.failed_decls.put(module.gpa, decl_index, em); diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index f11a052f4563c81a73ecb6027ea39ba23d71ecd4..7129722d16bd9e03c8653e1307da211473469470 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -1046,7 +1046,7 @@ pub fn updateFunc(wasm: *Wasm, mod: *Module, func: *Module.Fn, air: Air, livenes ); const code = switch (result) { - .appended => code_writer.items, + .ok => code_writer.items, .fail => |em| { decl.analysis = .codegen_failure; try mod.failed_decls.put(mod.gpa, decl_index, em); @@ -1113,7 +1113,7 @@ pub fn updateDecl(wasm: *Wasm, mod: *Module, decl_index: Module.Decl.Index) !voi ); const code = switch (res) { - .appended => code_writer.items, + .ok => code_writer.items, .fail => |em| { decl.analysis = .codegen_failure; try mod.failed_decls.put(mod.gpa, decl_index, em); @@ -1249,7 +1249,7 @@ pub fn lowerUnnamedConst(wasm: *Wasm, tv: TypedValue, decl_index: Module.Decl.In }, ); const code = switch (result) { - .appended => value_bytes.items, + .ok => value_bytes.items, .fail => |em| { decl.analysis = .codegen_failure; try mod.failed_decls.put(mod.gpa, decl_index, em); -- 2.54.0 From 4d804c1b239e45a0a28f4caf1f9748dac44ddce2 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Tue, 24 Jan 2023 17:55:10 +0100 Subject: [PATCH 03/84] macho: completely remove allocateDeclIndexes in favor of linker tracking --- src/Module.zig | 2 +- src/arch/aarch64/CodeGen.zig | 19 ++--- src/arch/x86_64/CodeGen.zig | 13 ++-- src/link.zig | 4 +- src/link/MachO.zig | 135 +++++++++++++++++++---------------- src/link/MachO/Atom.zig | 30 +++++--- 6 files changed, 115 insertions(+), 88 deletions(-) diff --git a/src/Module.zig b/src/Module.zig index b17c140231176cacdb5518accfc391d6b631d887..2d85399baf72e31bf3b8c86ad639caa9479e7509 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -5324,7 +5324,7 @@ pub fn deleteUnusedDecl(mod: *Module, decl_index: Decl.Index) void { // Until then, we did call `allocateDeclIndexes` on this anonymous Decl and so we // must call `freeDecl` in the linker backend now. switch (mod.comp.bin_file.tag) { - .c => {}, // this linker backend has already migrated to the new API + .macho, .c => {}, // this linker backend has already migrated to the new API else => if (decl.has_tv) { if (decl.ty.isFnOrHasRuntimeBits()) { mod.comp.bin_file.freeDecl(decl_index); diff --git a/src/arch/aarch64/CodeGen.zig b/src/arch/aarch64/CodeGen.zig index 53841a83a8a2cef573bf2a5671a479271d0362ee..b509e36f3a8543efc4e3ea5c0b97128255e829b2 100644 --- a/src/arch/aarch64/CodeGen.zig +++ b/src/arch/aarch64/CodeGen.zig @@ -3999,7 +3999,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type const mod = self.bin_file.options.module.?; const owner_decl = mod.declPtr(self.mod_fn.owner_decl); const atom_index = switch (self.bin_file.tag) { - .macho => owner_decl.link.macho.sym_index, + .macho => owner_decl.link.macho.getSymbolIndex().?, .coff => owner_decl.link.coff.sym_index, else => unreachable, // unsupported target format }; @@ -4328,10 +4328,11 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier if (func_value.castTag(.function)) |func_payload| { const func = func_payload.data; const fn_owner_decl = mod.declPtr(func.owner_decl); + try fn_owner_decl.link.macho.ensureInitialized(macho_file); try self.genSetReg(Type.initTag(.u64), .x30, .{ .linker_load = .{ .type = .got, - .sym_index = fn_owner_decl.link.macho.sym_index, + .sym_index = fn_owner_decl.link.macho.getSymbolIndex().?, }, }); // blr x30 @@ -4354,7 +4355,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier .tag = .call_extern, .data = .{ .relocation = .{ - .atom_index = mod.declPtr(self.mod_fn.owner_decl).link.macho.sym_index, + .atom_index = mod.declPtr(self.mod_fn.owner_decl).link.macho.getSymbolIndex().?, .sym_index = sym_index, }, }, @@ -5537,7 +5538,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro const mod = self.bin_file.options.module.?; const owner_decl = mod.declPtr(self.mod_fn.owner_decl); const atom_index = switch (self.bin_file.tag) { - .macho => owner_decl.link.macho.sym_index, + .macho => owner_decl.link.macho.getSymbolIndex().?, .coff => owner_decl.link.coff.sym_index, else => unreachable, // unsupported target format }; @@ -5651,7 +5652,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void const mod = self.bin_file.options.module.?; const owner_decl = mod.declPtr(self.mod_fn.owner_decl); const atom_index = switch (self.bin_file.tag) { - .macho => owner_decl.link.macho.sym_index, + .macho => owner_decl.link.macho.getSymbolIndex().?, .coff => owner_decl.link.coff.sym_index, else => unreachable, // unsupported target format }; @@ -5845,7 +5846,7 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I const mod = self.bin_file.options.module.?; const owner_decl = mod.declPtr(self.mod_fn.owner_decl); const atom_index = switch (self.bin_file.tag) { - .macho => owner_decl.link.macho.sym_index, + .macho => owner_decl.link.macho.getSymbolIndex().?, .coff => owner_decl.link.coff.sym_index, else => unreachable, // unsupported target format }; @@ -6168,13 +6169,13 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne 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 if (self.bin_file.cast(link.File.MachO)) |_| { + } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { // Because MachO is PIE-always-on, we defer memory address resolution until // the linker has enough info to perform relocations. - assert(decl.link.macho.sym_index != 0); + try decl.link.macho.ensureInitialized(macho_file); return MCValue{ .linker_load = .{ .type = .got, - .sym_index = decl.link.macho.sym_index, + .sym_index = decl.link.macho.getSymbolIndex().?, } }; } else if (self.bin_file.cast(link.File.Coff)) |_| { // Because COFF is PIE-always-on, we defer memory address resolution until diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 2de358fee89becf37add42bf7d50dd9dfb4adeea..635c5d8d325ba9ef9ce3dc0d8f03f8f4833fd68d 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -2671,7 +2671,7 @@ fn loadMemPtrIntoRegister(self: *Self, reg: Register, ptr_ty: Type, ptr: MCValue const mod = self.bin_file.options.module.?; const fn_owner_decl = mod.declPtr(self.mod_fn.owner_decl); const atom_index = if (self.bin_file.tag == link.File.MachO.base_tag) - fn_owner_decl.link.macho.sym_index + fn_owner_decl.link.macho.getSymbolIndex().? else fn_owner_decl.link.coff.sym_index; const flags: u2 = switch (load_struct.type) { @@ -4090,7 +4090,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier if (func_value.castTag(.function)) |func_payload| { const func = func_payload.data; const fn_owner_decl = mod.declPtr(func.owner_decl); - const sym_index = fn_owner_decl.link.macho.sym_index; + try fn_owner_decl.link.macho.ensureInitialized(macho_file); + const sym_index = fn_owner_decl.link.macho.getSymbolIndex().?; try self.genSetReg(Type.initTag(.usize), .rax, .{ .linker_load = .{ .type = .got, @@ -4121,7 +4122,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier .ops = undefined, .data = .{ .relocation = .{ - .atom_index = mod.declPtr(self.mod_fn.owner_decl).link.macho.sym_index, + .atom_index = mod.declPtr(self.mod_fn.owner_decl).link.macho.getSymbolIndex().?, .sym_index = sym_index, }, }, @@ -6784,11 +6785,11 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne 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 if (self.bin_file.cast(link.File.MachO)) |_| { - assert(decl.link.macho.sym_index != 0); + } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { + try decl.link.macho.ensureInitialized(macho_file); return MCValue{ .linker_load = .{ .type = .got, - .sym_index = decl.link.macho.sym_index, + .sym_index = decl.link.macho.getSymbolIndex().?, } }; } else if (self.bin_file.cast(link.File.Coff)) |_| { assert(decl.link.coff.sym_index != 0); diff --git a/src/link.zig b/src/link.zig index 976debb72be04909d5cf75e3d124db88fde8fdd6..1eee9cad7ca04d7ca78b18b929118913ede6a937 100644 --- a/src/link.zig +++ b/src/link.zig @@ -617,7 +617,7 @@ pub const File = struct { switch (base.tag) { .coff => return @fieldParentPtr(Coff, "base", base).allocateDeclIndexes(decl_index), .elf => return @fieldParentPtr(Elf, "base", base).allocateDeclIndexes(decl_index), - .macho => return @fieldParentPtr(MachO, "base", base).allocateDeclIndexes(decl_index), + .macho => {}, // no-op .wasm => return @fieldParentPtr(Wasm, "base", base).allocateDeclIndexes(decl_index), .plan9 => return @fieldParentPtr(Plan9, "base", base).allocateDeclIndexes(decl_index), .c, .spirv, .nvptx => {}, @@ -911,6 +911,8 @@ pub const File = struct { /// The linker is passed information about the containing atom, `parent_atom_index`, and offset within it's /// memory buffer, `offset`, so that it can make a note of potential relocation sites, should the /// `Decl`'s address was not yet resolved, or the containing atom gets moved in virtual memory. + /// May be called before or after updateFunc/updateDecl therefore it is up to the linker to allocate + /// the block/atom. pub fn getDeclVAddr(base: *File, decl_index: Module.Decl.Index, reloc_info: RelocInfo) !u64 { if (build_options.only_c) unreachable; switch (base.tag) { diff --git a/src/link/MachO.zig b/src/link/MachO.zig index caf9a91e1a8f8c65ee6d6245472bbb35e0e978a0..1ec8ecaaf8627847e8da9c4aa791a754610bc87b 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -1811,6 +1811,8 @@ pub fn deinit(self: *MachO) void { fn freeAtom(self: *MachO, atom: *Atom) void { log.debug("freeAtom {*}", .{atom}); + const gpa = self.base.allocator; + // Remove any relocs and base relocs associated with this Atom self.freeRelocationsForAtom(atom); @@ -1850,7 +1852,7 @@ fn freeAtom(self: *MachO, atom: *Atom) void { 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. - free_list.append(self.base.allocator, prev) catch {}; + free_list.append(gpa, prev) catch {}; } } else { atom.prev = null; @@ -1862,6 +1864,33 @@ fn freeAtom(self: *MachO, atom: *Atom) void { atom.next = null; } + // Appending to free lists is allowed to fail because the free lists are heuristics based anyway. + const sym_index = atom.getSymbolIndex().?; + + self.locals_free_list.append(gpa, sym_index) catch {}; + + // Try freeing GOT atom if this decl had one + const got_target = SymbolWithLoc{ .sym_index = sym_index, .file = null }; + if (self.got_entries_table.get(got_target)) |got_index| { + self.got_entries_free_list.append(gpa, @intCast(u32, got_index)) catch {}; + self.got_entries.items[got_index] = .{ + .target = .{ .sym_index = 0, .file = null }, + .sym_index = 0, + }; + _ = self.got_entries_table.remove(got_target); + + if (self.d_sym) |*d_sym| { + d_sym.swapRemoveRelocs(sym_index); + } + + log.debug(" adding GOT index {d} to free list (target local@{d})", .{ got_index, sym_index }); + } + + self.locals.items[sym_index].n_type = 0; + _ = self.atom_by_index_table.remove(sym_index); + log.debug(" adding local symbol index {d} to free list", .{sym_index}); + atom.sym_index = 0; + if (self.d_sym) |*d_sym| { d_sym.dwarf.freeAtom(&atom.dbg_info_atom); } @@ -1883,7 +1912,7 @@ fn growAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64) !u64 return self.allocateAtom(atom, new_atom_size, alignment); } -fn allocateSymbol(self: *MachO) !u32 { +pub fn allocateSymbol(self: *MachO) !u32 { try self.locals.ensureUnusedCapacity(self.base.allocator, 1); const index = blk: { @@ -1975,16 +2004,6 @@ pub fn allocateStubEntry(self: *MachO, target: SymbolWithLoc) !u32 { return index; } -pub fn allocateDeclIndexes(self: *MachO, decl_index: Module.Decl.Index) !void { - if (self.llvm_object) |_| return; - const decl = self.base.options.module.?.declPtr(decl_index); - if (decl.link.macho.sym_index != 0) return; - - decl.link.macho.sym_index = try self.allocateSymbol(); - try self.atom_by_index_table.putNoClobber(self.base.allocator, decl.link.macho.sym_index, &decl.link.macho); - try self.decls.putNoClobber(self.base.allocator, decl_index, null); -} - pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void { if (build_options.skip_non_native and builtin.object_format != .macho) { @panic("Attempted to compile for object format that was disabled by build configuration"); @@ -1997,8 +2016,15 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv const decl_index = func.owner_decl; const decl = module.declPtr(decl_index); - self.freeUnnamedConsts(decl_index); - self.freeRelocationsForAtom(&decl.link.macho); + const atom = &decl.link.macho; + try atom.ensureInitialized(self); + const gop = try self.decls.getOrPut(self.base.allocator, decl_index); + if (gop.found_existing) { + self.freeUnnamedConsts(decl_index); + self.freeRelocationsForAtom(atom); + } else { + gop.value_ptr.* = null; + } var code_buffer = std.ArrayList(u8).init(self.base.allocator); defer code_buffer.deinit(); @@ -2136,7 +2162,14 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index) } } - self.freeRelocationsForAtom(&decl.link.macho); + const atom = &decl.link.macho; + try atom.ensureInitialized(self); + const gop = try self.decls.getOrPut(self.base.allocator, decl_index); + if (gop.found_existing) { + self.freeRelocationsForAtom(atom); + } else { + gop.value_ptr.* = null; + } var code_buffer = std.ArrayList(u8).init(self.base.allocator); defer code_buffer.deinit(); @@ -2337,12 +2370,12 @@ fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []const u8) const decl = mod.declPtr(decl_index); const required_alignment = decl.getAlignment(self.base.options.target); - assert(decl.link.macho.sym_index != 0); // Caller forgot to call allocateDeclIndexes() const sym_name = try decl.getFullyQualifiedName(mod); defer self.base.allocator.free(sym_name); const atom = &decl.link.macho; + const sym_index = atom.getSymbolIndex().?; // Atom was not initialized const decl_ptr = self.decls.getPtr(decl_index).?; if (decl_ptr.* == null) { decl_ptr.* = self.getDeclOutputSection(decl); @@ -2368,7 +2401,7 @@ fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []const u8) if (vaddr != sym.n_value) { sym.n_value = vaddr; log.debug(" (updating GOT entry)", .{}); - const got_target = SymbolWithLoc{ .sym_index = atom.sym_index, .file = null }; + const got_target = SymbolWithLoc{ .sym_index = sym_index, .file = null }; const got_atom = self.getGotAtomForSymbol(got_target).?; self.markRelocsDirtyByTarget(got_target); try self.writePtrWidthAtom(got_atom); @@ -2399,10 +2432,10 @@ fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []const u8) atom.size = code_len; sym.n_value = vaddr; - const got_target = SymbolWithLoc{ .sym_index = atom.sym_index, .file = null }; + const got_target = SymbolWithLoc{ .sym_index = sym_index, .file = null }; const got_index = try self.allocateGotEntry(got_target); const got_atom = try self.createGotAtom(got_target); - self.got_entries.items[got_index].sym_index = got_atom.sym_index; + self.got_entries.items[got_index].sym_index = got_atom.getSymbolIndex().?; try self.writePtrWidthAtom(got_atom); } @@ -2438,7 +2471,14 @@ pub fn updateDeclExports( const gpa = self.base.allocator; const decl = module.declPtr(decl_index); - if (decl.link.macho.sym_index == 0) return; + const atom = &decl.link.macho; + try atom.ensureInitialized(self); + + const gop = try self.decls.getOrPut(gpa, decl_index); + if (!gop.found_existing) { + gop.value_ptr.* = null; + } + const decl_sym = decl.link.macho.getSymbol(self); for (exports) |exp| { @@ -2573,11 +2613,6 @@ fn freeUnnamedConsts(self: *MachO, decl_index: Module.Decl.Index) void { const unnamed_consts = self.unnamed_const_atoms.getPtr(decl_index) orelse return; for (unnamed_consts.items) |atom| { self.freeAtom(atom); - self.locals_free_list.append(gpa, atom.sym_index) catch {}; - self.locals.items[atom.sym_index].n_type = 0; - _ = self.atom_by_index_table.remove(atom.sym_index); - log.debug(" adding local symbol index {d} to free list", .{atom.sym_index}); - atom.sym_index = 0; } unnamed_consts.clearAndFree(gpa); } @@ -2591,39 +2626,11 @@ pub fn freeDecl(self: *MachO, decl_index: Module.Decl.Index) void { log.debug("freeDecl {*}", .{decl}); - const kv = self.decls.fetchSwapRemove(decl_index); - if (kv.?.value) |_| { - self.freeAtom(&decl.link.macho); - self.freeUnnamedConsts(decl_index); - } - - // Appending to free lists is allowed to fail because the free lists are heuristics based anyway. - const gpa = self.base.allocator; - const sym_index = decl.link.macho.sym_index; - if (sym_index != 0) { - self.locals_free_list.append(gpa, sym_index) catch {}; - - // Try freeing GOT atom if this decl had one - const got_target = SymbolWithLoc{ .sym_index = sym_index, .file = null }; - if (self.got_entries_table.get(got_target)) |got_index| { - self.got_entries_free_list.append(gpa, @intCast(u32, got_index)) catch {}; - self.got_entries.items[got_index] = .{ - .target = .{ .sym_index = 0, .file = null }, - .sym_index = 0, - }; - _ = self.got_entries_table.remove(got_target); - - if (self.d_sym) |*d_sym| { - d_sym.swapRemoveRelocs(sym_index); - } - - log.debug(" adding GOT index {d} to free list (target local@{d})", .{ got_index, sym_index }); + if (self.decls.fetchSwapRemove(decl_index)) |kv| { + if (kv.value) |_| { + self.freeAtom(&decl.link.macho); + self.freeUnnamedConsts(decl_index); } - - self.locals.items[sym_index].n_type = 0; - _ = self.atom_by_index_table.remove(sym_index); - log.debug(" adding local symbol index {d} to free list", .{sym_index}); - decl.link.macho.sym_index = 0; } if (self.d_sym) |*d_sym| { @@ -2636,7 +2643,9 @@ pub fn getDeclVAddr(self: *MachO, decl_index: Module.Decl.Index, reloc_info: Fil const decl = mod.declPtr(decl_index); assert(self.llvm_object == null); - assert(decl.link.macho.sym_index != 0); + + try decl.link.macho.ensureInitialized(self); + const sym_index = decl.link.macho.getSymbolIndex().?; const atom = self.getAtomForSymbol(.{ .sym_index = reloc_info.parent_atom_index, .file = null }).?; try atom.addRelocation(self, .{ @@ -2645,7 +2654,7 @@ pub fn getDeclVAddr(self: *MachO, decl_index: Module.Decl.Index, reloc_info: Fil .x86_64 => @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_UNSIGNED), else => unreachable, }, - .target = .{ .sym_index = decl.link.macho.sym_index, .file = null }, + .target = .{ .sym_index = sym_index, .file = null }, .offset = @intCast(u32, reloc_info.offset), .addend = reloc_info.addend, .pcrel = false, @@ -3179,7 +3188,7 @@ fn collectRebaseData(self: *MachO, rebase: *Rebase) !void { const slice = self.sections.slice(); for (self.rebases.keys()) |atom, i| { - log.debug(" ATOM(%{d}, '{s}')", .{ atom.sym_index, atom.getName(self) }); + log.debug(" ATOM(%{?d}, '{s}')", .{ atom.getSymbolIndex(), atom.getName(self) }); const sym = atom.getSymbol(self); const segment_index = slice.items(.segment_index)[sym.n_sect - 1]; @@ -3208,7 +3217,7 @@ fn collectBindData(self: *MachO, bind: anytype, raw_bindings: anytype) !void { const slice = self.sections.slice(); for (raw_bindings.keys()) |atom, i| { - log.debug(" ATOM(%{d}, '{s}')", .{ atom.sym_index, atom.getName(self) }); + log.debug(" ATOM(%{?d}, '{s}')", .{ atom.getSymbolIndex(), atom.getName(self) }); const sym = atom.getSymbol(self); const segment_index = slice.items(.segment_index)[sym.n_sect - 1]; @@ -4277,8 +4286,8 @@ pub fn logAtoms(self: *MachO) void { pub fn logAtom(self: *MachO, atom: *const Atom) void { const sym = atom.getSymbol(self); const sym_name = atom.getName(self); - log.debug(" ATOM(%{d}, '{s}') @ {x} (sizeof({x}), alignof({x})) in object({?d}) in sect({d})", .{ - atom.sym_index, + log.debug(" ATOM(%{?d}, '{s}') @ {x} (sizeof({x}), alignof({x})) in object({?d}) in sect({d})", .{ + atom.getSymbolIndex(), sym_name, sym.n_value, atom.size, diff --git a/src/link/MachO/Atom.zig b/src/link/MachO/Atom.zig index 47ef974cb12a4fc020217d068928506211997b03..f15958b3dfe246e0254a8cf13a79ec0db119c522 100644 --- a/src/link/MachO/Atom.zig +++ b/src/link/MachO/Atom.zig @@ -64,6 +64,17 @@ pub const empty = Atom{ .dbg_info_atom = undefined, }; +pub fn ensureInitialized(self: *Atom, macho_file: *MachO) !void { + if (self.getSymbolIndex() != null) return; // Already initialized + self.sym_index = try macho_file.allocateSymbol(); + try macho_file.atom_by_index_table.putNoClobber(macho_file.base.allocator, self.sym_index, self); +} + +pub fn getSymbolIndex(self: Atom) ?u32 { + if (self.sym_index == 0) return null; + return self.sym_index; +} + /// Returns symbol referencing this atom. pub fn getSymbol(self: Atom, macho_file: *MachO) macho.nlist_64 { return self.getSymbolPtr(macho_file).*; @@ -71,20 +82,23 @@ pub fn getSymbol(self: Atom, macho_file: *MachO) macho.nlist_64 { /// Returns pointer-to-symbol referencing this atom. pub fn getSymbolPtr(self: Atom, macho_file: *MachO) *macho.nlist_64 { + const sym_index = self.getSymbolIndex().?; return macho_file.getSymbolPtr(.{ - .sym_index = self.sym_index, + .sym_index = sym_index, .file = self.file, }); } pub fn getSymbolWithLoc(self: Atom) SymbolWithLoc { - return .{ .sym_index = self.sym_index, .file = self.file }; + const sym_index = self.getSymbolIndex().?; + return .{ .sym_index = sym_index, .file = self.file }; } /// Returns the name of this atom. pub fn getName(self: Atom, macho_file: *MachO) []const u8 { + const sym_index = self.getSymbolIndex().?; return macho_file.getSymbolName(.{ - .sym_index = self.sym_index, + .sym_index = sym_index, .file = self.file, }); } @@ -144,7 +158,7 @@ pub fn addRelocations( pub fn addRebase(self: *Atom, macho_file: *MachO, offset: u32) !void { const gpa = macho_file.base.allocator; - log.debug(" (adding rebase at offset 0x{x} in %{d})", .{ offset, self.sym_index }); + log.debug(" (adding rebase at offset 0x{x} in %{?d})", .{ offset, self.getSymbolIndex() }); const gop = try macho_file.rebases.getOrPut(gpa, self); if (!gop.found_existing) { gop.value_ptr.* = .{}; @@ -154,10 +168,10 @@ pub fn addRebase(self: *Atom, macho_file: *MachO, offset: u32) !void { pub fn addBinding(self: *Atom, macho_file: *MachO, binding: Binding) !void { const gpa = macho_file.base.allocator; - log.debug(" (adding binding to symbol {s} at offset 0x{x} in %{d})", .{ + log.debug(" (adding binding to symbol {s} at offset 0x{x} in %{?d})", .{ macho_file.getSymbolName(binding.target), binding.offset, - self.sym_index, + self.getSymbolIndex(), }); const gop = try macho_file.bindings.getOrPut(gpa, self); if (!gop.found_existing) { @@ -168,10 +182,10 @@ pub fn addBinding(self: *Atom, macho_file: *MachO, binding: Binding) !void { pub fn addLazyBinding(self: *Atom, macho_file: *MachO, binding: Binding) !void { const gpa = macho_file.base.allocator; - log.debug(" (adding lazy binding to symbol {s} at offset 0x{x} in %{d})", .{ + log.debug(" (adding lazy binding to symbol {s} at offset 0x{x} in %{?d})", .{ macho_file.getSymbolName(binding.target), binding.offset, - self.sym_index, + self.getSymbolIndex(), }); const gop = try macho_file.lazy_bindings.getOrPut(gpa, self); if (!gop.found_existing) { -- 2.54.0 From 041bc71bc8ff45dc2d4df11d48023e457b8b021e Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Wed, 25 Jan 2023 23:17:13 +0100 Subject: [PATCH 04/84] self-hosted: clean up calling logic for x86_64 and aarch64 across linkers --- src/arch/aarch64/CodeGen.zig | 123 ++++++++--------------- src/arch/x86_64/CodeGen.zig | 187 ++++++++++++----------------------- 2 files changed, 104 insertions(+), 206 deletions(-) diff --git a/src/arch/aarch64/CodeGen.zig b/src/arch/aarch64/CodeGen.zig index b509e36f3a8543efc4e3ea5c0b97128255e829b2..93ac450baeffec8e4fb0ce0a22a5b19ddf3cd2b0 100644 --- a/src/arch/aarch64/CodeGen.zig +++ b/src/arch/aarch64/CodeGen.zig @@ -4302,32 +4302,19 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier // on linking. const mod = self.bin_file.options.module.?; if (self.air.value(callee)) |func_value| { - if (self.bin_file.cast(link.File.Elf)) |elf_file| { - if (func_value.castTag(.function)) |func_payload| { - const func = func_payload.data; + if (func_value.castTag(.function)) |func_payload| { + const func = func_payload.data; + const fn_owner_decl = mod.declPtr(func.owner_decl); + + if (self.bin_file.cast(link.File.Elf)) |elf_file| { const ptr_bits = self.target.cpu.arch.ptrBitWidth(); const ptr_bytes: u64 = @divExact(ptr_bits, 8); - const fn_owner_decl = mod.declPtr(func.owner_decl); const got_addr = blk: { const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?]; break :blk @intCast(u32, got.p_vaddr + fn_owner_decl.link.elf.offset_table_index * ptr_bytes); }; - try self.genSetReg(Type.initTag(.usize), .x30, .{ .memory = got_addr }); - - _ = try self.addInst(.{ - .tag = .blr, - .data = .{ .reg = .x30 }, - }); - } else if (func_value.castTag(.extern_fn)) |_| { - return self.fail("TODO implement calling extern functions", .{}); - } else { - return self.fail("TODO implement calling bitcasted functions", .{}); - } - } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { - if (func_value.castTag(.function)) |func_payload| { - const func = func_payload.data; - const fn_owner_decl = mod.declPtr(func.owner_decl); + } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { try fn_owner_decl.link.macho.ensureInitialized(macho_file); try self.genSetReg(Type.initTag(.u64), .x30, .{ .linker_load = .{ @@ -4335,22 +4322,39 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier .sym_index = fn_owner_decl.link.macho.getSymbolIndex().?, }, }); - // blr x30 - _ = try self.addInst(.{ - .tag = .blr, - .data = .{ .reg = .x30 }, + } else if (self.bin_file.cast(link.File.Coff)) |_| { + try self.genSetReg(Type.initTag(.u64), .x30, .{ + .linker_load = .{ + .type = .got, + .sym_index = fn_owner_decl.link.coff.sym_index, + }, }); - } else if (func_value.castTag(.extern_fn)) |func_payload| { - const extern_fn = func_payload.data; - const decl_name = mod.declPtr(extern_fn.owner_decl).name; - if (extern_fn.lib_name) |lib_name| { - log.debug("TODO enforce that '{s}' is expected in '{s}' library", .{ - decl_name, - lib_name, - }); - } + } else if (self.bin_file.cast(link.File.Plan9)) |p9| { + try p9.seeDecl(func.owner_decl); + const ptr_bits = self.target.cpu.arch.ptrBitWidth(); + const ptr_bytes: u64 = @divExact(ptr_bits, 8); + const got_addr = p9.bases.data; + const got_index = fn_owner_decl.link.plan9.got_index.?; + const fn_got_addr = got_addr + got_index * ptr_bytes; + try self.genSetReg(Type.initTag(.usize), .x30, .{ .memory = fn_got_addr }); + } else unreachable; + + _ = try self.addInst(.{ + .tag = .blr, + .data = .{ .reg = .x30 }, + }); + } else if (func_value.castTag(.extern_fn)) |func_payload| { + const extern_fn = func_payload.data; + const decl_name = mod.declPtr(extern_fn.owner_decl).name; + if (extern_fn.lib_name) |lib_name| { + log.debug("TODO enforce that '{s}' is expected in '{s}' library", .{ + decl_name, + lib_name, + }); + } + + if (self.bin_file.cast(link.File.MachO)) |macho_file| { const sym_index = try macho_file.getGlobalSymbol(mem.sliceTo(decl_name, 0)); - _ = try self.addInst(.{ .tag = .call_extern, .data = .{ @@ -4360,33 +4364,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier }, }, }); - } else { - return self.fail("TODO implement calling bitcasted functions", .{}); - } - } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { - if (func_value.castTag(.function)) |func_payload| { - const func = func_payload.data; - const fn_owner_decl = mod.declPtr(func.owner_decl); - try self.genSetReg(Type.initTag(.u64), .x30, .{ - .linker_load = .{ - .type = .got, - .sym_index = fn_owner_decl.link.coff.sym_index, - }, - }); - // blr x30 - _ = try self.addInst(.{ - .tag = .blr, - .data = .{ .reg = .x30 }, - }); - } else if (func_value.castTag(.extern_fn)) |func_payload| { - const extern_fn = func_payload.data; - const decl_name = mod.declPtr(extern_fn.owner_decl).name; - if (extern_fn.lib_name) |lib_name| { - log.debug("TODO enforce that '{s}' is expected in '{s}' library", .{ - decl_name, - lib_name, - }); - } + } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { const sym_index = try coff_file.getGlobalSymbol(mem.sliceTo(decl_name, 0)); try self.genSetReg(Type.initTag(.u64), .x30, .{ .linker_load = .{ @@ -4394,35 +4372,16 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier .sym_index = sym_index, }, }); - // blr x30 _ = try self.addInst(.{ .tag = .blr, .data = .{ .reg = .x30 }, }); } else { - return self.fail("TODO implement calling bitcasted functions", .{}); - } - } else if (self.bin_file.cast(link.File.Plan9)) |p9| { - if (func_value.castTag(.function)) |func_payload| { - try p9.seeDecl(func_payload.data.owner_decl); - const ptr_bits = self.target.cpu.arch.ptrBitWidth(); - const ptr_bytes: u64 = @divExact(ptr_bits, 8); - const got_addr = p9.bases.data; - const got_index = mod.declPtr(func_payload.data.owner_decl).link.plan9.got_index.?; - const fn_got_addr = got_addr + got_index * ptr_bytes; - - try self.genSetReg(Type.initTag(.usize), .x30, .{ .memory = fn_got_addr }); - - _ = try self.addInst(.{ - .tag = .blr, - .data = .{ .reg = .x30 }, - }); - } else if (func_value.castTag(.extern_fn)) |_| { return self.fail("TODO implement calling extern functions", .{}); - } else { - return self.fail("TODO implement calling bitcasted functions", .{}); } - } else unreachable; + } else { + return self.fail("TODO implement calling bitcasted functions", .{}); + } } else { assert(ty.zigTypeTag() == .Pointer); const mcv = try self.resolveInst(callee); diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 635c5d8d325ba9ef9ce3dc0d8f03f8f4833fd68d..4e8c20efa1e39a53ff260919a8b356ca68a77e0d 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -3992,13 +3992,14 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier // Due to incremental compilation, how function calls are generated depends // on linking. const mod = self.bin_file.options.module.?; - if (self.bin_file.cast(link.File.Elf)) |elf_file| { - if (self.air.value(callee)) |func_value| { - if (func_value.castTag(.function)) |func_payload| { - const func = func_payload.data; + if (self.air.value(callee)) |func_value| { + if (func_value.castTag(.function)) |func_payload| { + const func = func_payload.data; + const fn_owner_decl = mod.declPtr(func.owner_decl); + + if (self.bin_file.cast(link.File.Elf)) |elf_file| { const ptr_bits = self.target.cpu.arch.ptrBitWidth(); const ptr_bytes: u64 = @divExact(ptr_bits, 8); - const fn_owner_decl = mod.declPtr(func.owner_decl); const got_addr = blk: { const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?]; break :blk @intCast(u32, got.p_vaddr + fn_owner_decl.link.elf.offset_table_index * ptr_bytes); @@ -4008,29 +4009,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier .ops = Mir.Inst.Ops.encode(.{ .flags = 0b01 }), .data = .{ .imm = @truncate(u32, got_addr) }, }); - } else if (func_value.castTag(.extern_fn)) |_| { - return self.fail("TODO implement calling extern functions", .{}); - } else { - return self.fail("TODO implement calling bitcasted functions", .{}); - } - } else { - assert(ty.zigTypeTag() == .Pointer); - const mcv = try self.resolveInst(callee); - try self.genSetReg(Type.initTag(.usize), .rax, mcv); - _ = try self.addInst(.{ - .tag = .call, - .ops = Mir.Inst.Ops.encode(.{ - .reg1 = .rax, - .flags = 0b01, - }), - .data = undefined, - }); - } - } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { - if (self.air.value(callee)) |func_value| { - if (func_value.castTag(.function)) |func_payload| { - const func = func_payload.data; - const fn_owner_decl = mod.declPtr(func.owner_decl); + } else if (self.bin_file.cast(link.File.Coff)) |_| { try self.genSetReg(Type.initTag(.usize), .rax, .{ .linker_load = .{ .type = .got, @@ -4045,51 +4024,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier }), .data = undefined, }); - } else if (func_value.castTag(.extern_fn)) |func_payload| { - const extern_fn = func_payload.data; - const decl_name = mod.declPtr(extern_fn.owner_decl).name; - if (extern_fn.lib_name) |lib_name| { - log.debug("TODO enforce that '{s}' is expected in '{s}' library", .{ - decl_name, - lib_name, - }); - } - const sym_index = try coff_file.getGlobalSymbol(mem.sliceTo(decl_name, 0)); - try self.genSetReg(Type.initTag(.usize), .rax, .{ - .linker_load = .{ - .type = .import, - .sym_index = sym_index, - }, - }); - _ = try self.addInst(.{ - .tag = .call, - .ops = Mir.Inst.Ops.encode(.{ - .reg1 = .rax, - .flags = 0b01, - }), - .data = undefined, - }); - } else { - return self.fail("TODO implement calling bitcasted functions", .{}); - } - } else { - assert(ty.zigTypeTag() == .Pointer); - const mcv = try self.resolveInst(callee); - try self.genSetReg(Type.initTag(.usize), .rax, mcv); - _ = try self.addInst(.{ - .tag = .call, - .ops = Mir.Inst.Ops.encode(.{ - .reg1 = .rax, - .flags = 0b01, - }), - .data = undefined, - }); - } - } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { - if (self.air.value(callee)) |func_value| { - if (func_value.castTag(.function)) |func_payload| { - const func = func_payload.data; - const fn_owner_decl = mod.declPtr(func.owner_decl); + } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { try fn_owner_decl.link.macho.ensureInitialized(macho_file); const sym_index = fn_owner_decl.link.macho.getSymbolIndex().?; try self.genSetReg(Type.initTag(.usize), .rax, .{ @@ -4098,7 +4033,6 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier .sym_index = sym_index, }, }); - // callq *%rax _ = try self.addInst(.{ .tag = .call, .ops = Mir.Inst.Ops.encode(.{ @@ -4107,15 +4041,46 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier }), .data = undefined, }); - } else if (func_value.castTag(.extern_fn)) |func_payload| { - const extern_fn = func_payload.data; - const decl_name = mod.declPtr(extern_fn.owner_decl).name; - if (extern_fn.lib_name) |lib_name| { - log.debug("TODO enforce that '{s}' is expected in '{s}' library", .{ - decl_name, - lib_name, - }); - } + } else if (self.bin_file.cast(link.File.Plan9)) |p9| { + try p9.seeDecl(func.owner_decl); + const ptr_bits = self.target.cpu.arch.ptrBitWidth(); + const ptr_bytes: u64 = @divExact(ptr_bits, 8); + const got_addr = p9.bases.data; + const got_index = fn_owner_decl.link.plan9.got_index.?; + const fn_got_addr = got_addr + got_index * ptr_bytes; + _ = try self.addInst(.{ + .tag = .call, + .ops = Mir.Inst.Ops.encode(.{ .flags = 0b01 }), + .data = .{ .imm = @intCast(u32, fn_got_addr) }, + }); + } else unreachable; + } else if (func_value.castTag(.extern_fn)) |func_payload| { + const extern_fn = func_payload.data; + const decl_name = mod.declPtr(extern_fn.owner_decl).name; + if (extern_fn.lib_name) |lib_name| { + log.debug("TODO enforce that '{s}' is expected in '{s}' library", .{ + decl_name, + lib_name, + }); + } + + if (self.bin_file.cast(link.File.Coff)) |coff_file| { + const sym_index = try coff_file.getGlobalSymbol(mem.sliceTo(decl_name, 0)); + try self.genSetReg(Type.initTag(.usize), .rax, .{ + .linker_load = .{ + .type = .import, + .sym_index = sym_index, + }, + }); + _ = try self.addInst(.{ + .tag = .call, + .ops = Mir.Inst.Ops.encode(.{ + .reg1 = .rax, + .flags = 0b01, + }), + .data = undefined, + }); + } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { const sym_index = try macho_file.getGlobalSymbol(mem.sliceTo(decl_name, 0)); _ = try self.addInst(.{ .tag = .call_extern, @@ -4128,50 +4093,24 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier }, }); } else { - return self.fail("TODO implement calling bitcasted functions", .{}); + return self.fail("TODO implement calling extern functions", .{}); } } else { - assert(ty.zigTypeTag() == .Pointer); - const mcv = try self.resolveInst(callee); - try self.genSetReg(Type.initTag(.usize), .rax, mcv); - _ = try self.addInst(.{ - .tag = .call, - .ops = Mir.Inst.Ops.encode(.{ - .reg1 = .rax, - .flags = 0b01, - }), - .data = undefined, - }); + return self.fail("TODO implement calling bitcasted functions", .{}); } - } else if (self.bin_file.cast(link.File.Plan9)) |p9| { - if (self.air.value(callee)) |func_value| { - if (func_value.castTag(.function)) |func_payload| { - try p9.seeDecl(func_payload.data.owner_decl); - const ptr_bits = self.target.cpu.arch.ptrBitWidth(); - const ptr_bytes: u64 = @divExact(ptr_bits, 8); - const got_addr = p9.bases.data; - const got_index = mod.declPtr(func_payload.data.owner_decl).link.plan9.got_index.?; - const fn_got_addr = got_addr + got_index * ptr_bytes; - _ = try self.addInst(.{ - .tag = .call, - .ops = Mir.Inst.Ops.encode(.{ .flags = 0b01 }), - .data = .{ .imm = @intCast(u32, fn_got_addr) }, - }); - } else return self.fail("TODO implement calling extern fn on plan9", .{}); - } else { - assert(ty.zigTypeTag() == .Pointer); - const mcv = try self.resolveInst(callee); - try self.genSetReg(Type.initTag(.usize), .rax, mcv); - _ = try self.addInst(.{ - .tag = .call, - .ops = Mir.Inst.Ops.encode(.{ - .reg1 = .rax, - .flags = 0b01, - }), - .data = undefined, - }); - } - } else unreachable; + } else { + assert(ty.zigTypeTag() == .Pointer); + const mcv = try self.resolveInst(callee); + try self.genSetReg(Type.initTag(.usize), .rax, mcv); + _ = try self.addInst(.{ + .tag = .call, + .ops = Mir.Inst.Ops.encode(.{ + .reg1 = .rax, + .flags = 0b01, + }), + .data = undefined, + }); + } if (info.stack_byte_count > 0) { // Readjust the stack -- 2.54.0 From 2b5d0ca73b6b0ae96f3362aabe92b792ece2ae63 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Wed, 25 Jan 2023 23:34:57 +0100 Subject: [PATCH 05/84] elf: pull out logic for allocating a GOT entry into a helper --- src/link/Elf.zig | 48 ++++++++++++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 18 deletions(-) diff --git a/src/link/Elf.zig b/src/link/Elf.zig index b0acef368a4d2751796860d738687b4a0bc69606..27e4602ed437055365d1ad820c8c85a267e55cc2 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -2289,31 +2289,43 @@ fn allocateLocalSymbol(self: *Elf) !u32 { return index; } -pub fn allocateDeclIndexes(self: *Elf, decl_index: Module.Decl.Index) !void { - if (self.llvm_object) |_| return; - - const mod = self.base.options.module.?; - const decl = mod.declPtr(decl_index); - if (decl.link.elf.local_sym_index != 0) return; - +fn allocateGotOffset(self: *Elf) !u32 { try self.offset_table.ensureUnusedCapacity(self.base.allocator, 1); - try self.decls.putNoClobber(self.base.allocator, decl_index, null); + + const index = blk: { + if (self.offset_table_free_list.popOrNull()) |index| { + log.debug(" (reusing GOT offset at index {d})", .{index}); + break :blk index; + } else { + log.debug(" (allocating GOT offset at index {d})", .{self.offset_table.items.len}); + const index = @intCast(u32, self.offset_table.items.len); + _ = self.offset_table.addOneAssumeCapacity(); + self.offset_table_count_dirty = true; + break :blk index; + } + }; + + self.offset_table.items[index] = 0; + return index; +} + +pub fn allocateDeclIndexes(self: *Elf, decl_index: Module.Decl.Index) !void { + if (self.llvm_object) |_| return; + + const mod = self.base.options.module.?; + const decl = mod.declPtr(decl_index); + const block = &decl.link.elf; + if (block.local_sym_index != 0) return; const decl_name = try decl.getFullyQualifiedName(mod); defer self.base.allocator.free(decl_name); log.debug("allocating symbol indexes for {s}", .{decl_name}); - decl.link.elf.local_sym_index = try self.allocateLocalSymbol(); - try self.atom_by_index_table.putNoClobber(self.base.allocator, decl.link.elf.local_sym_index, &decl.link.elf); - 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; - } - self.offset_table.items[decl.link.elf.offset_table_index] = 0; + block.local_sym_index = try self.allocateLocalSymbol(); + block.offset_table_index = try self.allocateGotOffset(); + try self.atom_by_index_table.putNoClobber(self.base.allocator, block.local_sym_index, block); + try self.decls.putNoClobber(self.base.allocator, decl_index, null); } fn freeUnnamedConsts(self: *Elf, decl_index: Module.Decl.Index) void { -- 2.54.0 From fb8d754a4bf823b66bcf3fa281c469af8be6f923 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Thu, 26 Jan 2023 00:03:42 +0100 Subject: [PATCH 06/84] elf: move TextBlock into its own module and rename to Atom --- src/link/Elf.zig | 59 ++++--------------------------------------- src/link/Elf/Atom.zig | 56 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 54 deletions(-) create mode 100644 src/link/Elf/Atom.zig diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 27e4602ed437055365d1ad820c8c85a267e55cc2..e915fff42388e8d93d1d10e678766b582b116d3a 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -10,6 +10,7 @@ const fs = std.fs; const elf = std.elf; const log = std.log.scoped(.link); +const Atom = @import("Elf/Atom.zig"); const Module = @import("../Module.zig"); const Compilation = @import("../Compilation.zig"); const Dwarf = @import("Dwarf.zig"); @@ -31,6 +32,8 @@ const Air = @import("../Air.zig"); const Liveness = @import("../Liveness.zig"); const LlvmObject = @import("../codegen/llvm.zig").Object; +pub const TextBlock = Atom; + const default_entry_addr = 0x8000000; pub const base_tag: File.Tag = .elf; @@ -188,62 +191,10 @@ const ideal_factor = 3; /// 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 = padToIdeal(minimum_text_block_size); +pub const min_text_capacity = padToIdeal(minimum_text_block_size); pub const PtrWidth = enum { p32, p64 }; -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, - - dbg_info_atom: Dwarf.Atom, - - pub const empty = TextBlock{ - .local_sym_index = 0, - .offset_table_index = undefined, - .prev = null, - .next = null, - .dbg_info_atom = 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 = padToIdeal(self_sym.st_size); - if (cap <= ideal_cap) return false; - const surplus = cap - ideal_cap; - return surplus >= min_text_capacity; - } -}; - pub const Export = struct { sym_index: ?u32 = null, }; @@ -3052,7 +3003,7 @@ fn getLDMOption(target: std.Target) ?[]const u8 { } } -fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) { +pub fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) { return actual_size +| (actual_size / ideal_factor); } diff --git a/src/link/Elf/Atom.zig b/src/link/Elf/Atom.zig new file mode 100644 index 0000000000000000000000000000000000000000..e4061f5bbc9ccc7217592845605a71e4ce80e82e --- /dev/null +++ b/src/link/Elf/Atom.zig @@ -0,0 +1,56 @@ +const Atom = @This(); + +const std = @import("std"); + +const Dwarf = @import("../Dwarf.zig"); +const Elf = @import("../Elf.zig"); + +/// 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: ?*Atom, +next: ?*Atom, + +dbg_info_atom: Dwarf.Atom, + +pub const empty = Atom{ + .local_sym_index = 0, + .offset_table_index = undefined, + .prev = null, + .next = null, + .dbg_info_atom = 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. +pub fn capacity(self: Atom, 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; + } +} + +pub fn freeListEligible(self: Atom, 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 = Elf.padToIdeal(self_sym.st_size); + if (cap <= ideal_cap) return false; + const surplus = cap - ideal_cap; + return surplus >= Elf.min_text_capacity; +} -- 2.54.0 From e1b9800ffa74a637e2b0a6356249c2c37228ec01 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Thu, 26 Jan 2023 13:17:38 +0100 Subject: [PATCH 07/84] elf: migrate to new non-allocateDeclIndexes API --- src/Module.zig | 2 +- src/arch/aarch64/CodeGen.zig | 17 ++---- src/arch/arm/CodeGen.zig | 103 ++++++++++++++++---------------- src/arch/riscv64/CodeGen.zig | 13 ++--- src/arch/sparc64/CodeGen.zig | 17 ++---- src/arch/x86_64/CodeGen.zig | 15 ++--- src/link.zig | 2 +- src/link/Elf.zig | 110 +++++++++++++++++------------------ src/link/Elf/Atom.zig | 52 +++++++++++++++-- src/link/MachO.zig | 7 ++- 10 files changed, 175 insertions(+), 163 deletions(-) diff --git a/src/Module.zig b/src/Module.zig index 2d85399baf72e31bf3b8c86ad639caa9479e7509..4e1f65aff421f277476bc85e24e216b487a1ec3c 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -5324,7 +5324,7 @@ pub fn deleteUnusedDecl(mod: *Module, decl_index: Decl.Index) void { // Until then, we did call `allocateDeclIndexes` on this anonymous Decl and so we // must call `freeDecl` in the linker backend now. switch (mod.comp.bin_file.tag) { - .macho, .c => {}, // this linker backend has already migrated to the new API + .elf, .macho, .c => {}, // this linker backend has already migrated to the new API else => if (decl.has_tv) { if (decl.ty.isFnOrHasRuntimeBits()) { mod.comp.bin_file.freeDecl(decl_index); diff --git a/src/arch/aarch64/CodeGen.zig b/src/arch/aarch64/CodeGen.zig index 93ac450baeffec8e4fb0ce0a22a5b19ddf3cd2b0..8c3f3e816814e03b9b9a1c19be6551b5bd79d90f 100644 --- a/src/arch/aarch64/CodeGen.zig +++ b/src/arch/aarch64/CodeGen.zig @@ -4307,12 +4307,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier const fn_owner_decl = mod.declPtr(func.owner_decl); if (self.bin_file.cast(link.File.Elf)) |elf_file| { - const ptr_bits = self.target.cpu.arch.ptrBitWidth(); - const ptr_bytes: u64 = @divExact(ptr_bits, 8); - const got_addr = blk: { - const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?]; - break :blk @intCast(u32, got.p_vaddr + fn_owner_decl.link.elf.offset_table_index * ptr_bytes); - }; + try fn_owner_decl.link.elf.ensureInitialized(elf_file); + const got_addr = @intCast(u32, fn_owner_decl.link.elf.getOffsetTableAddress(elf_file)); try self.genSetReg(Type.initTag(.usize), .x30, .{ .memory = got_addr }); } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { try fn_owner_decl.link.macho.ensureInitialized(macho_file); @@ -6125,20 +6121,15 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne mod.markDeclAlive(decl); if (self.bin_file.cast(link.File.Elf)) |elf_file| { - 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 }; + try decl.link.elf.ensureInitialized(elf_file); + return MCValue{ .memory = decl.link.elf.getOffsetTableAddress(elf_file) }; } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { - // Because MachO is PIE-always-on, we defer memory address resolution until - // the linker has enough info to perform relocations. try decl.link.macho.ensureInitialized(macho_file); return MCValue{ .linker_load = .{ .type = .got, .sym_index = decl.link.macho.getSymbolIndex().?, } }; } else if (self.bin_file.cast(link.File.Coff)) |_| { - // Because COFF is PIE-always-on, we defer memory address resolution until - // the linker has enough info to perform relocations. assert(decl.link.coff.sym_index != 0); return MCValue{ .linker_load = .{ .type = .got, diff --git a/src/arch/arm/CodeGen.zig b/src/arch/arm/CodeGen.zig index 6a7986a7a8a41e39e5abba49566b628f7db40921..49f979624d0a78ed7489763f219ceb9da3f12881 100644 --- a/src/arch/arm/CodeGen.zig +++ b/src/arch/arm/CodeGen.zig @@ -4253,59 +4253,57 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier // Due to incremental compilation, how function calls are generated depends // on linking. - switch (self.bin_file.tag) { - .elf => { - if (self.air.value(callee)) |func_value| { - if (func_value.castTag(.function)) |func_payload| { - const func = func_payload.data; - const ptr_bits = self.target.cpu.arch.ptrBitWidth(); - const ptr_bytes: u64 = @divExact(ptr_bits, 8); - const mod = self.bin_file.options.module.?; - const fn_owner_decl = mod.declPtr(func.owner_decl); - const got_addr = if (self.bin_file.cast(link.File.Elf)) |elf_file| blk: { - const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?]; - break :blk @intCast(u32, got.p_vaddr + fn_owner_decl.link.elf.offset_table_index * ptr_bytes); - } else unreachable; - try self.genSetReg(Type.initTag(.usize), .lr, .{ .memory = got_addr }); - } else if (func_value.castTag(.extern_fn)) |_| { - return self.fail("TODO implement calling extern functions", .{}); - } else { - return self.fail("TODO implement calling bitcasted functions", .{}); - } + if (self.air.value(callee)) |func_value| { + if (func_value.castTag(.function)) |func_payload| { + const func = func_payload.data; + const mod = self.bin_file.options.module.?; + const fn_owner_decl = mod.declPtr(func.owner_decl); + + if (self.bin_file.cast(link.File.Elf)) |elf_file| { + try fn_owner_decl.link.elf.ensureInitialized(elf_file); + const got_addr = @intCast(u32, fn_owner_decl.link.elf.getOffsetTableAddress(elf_file)); + try self.genSetReg(Type.initTag(.usize), .lr, .{ .memory = got_addr }); + } else if (self.bin_file.cast(link.File.MachO)) |_| { + unreachable; // unsupported architecture for MachO } else { - assert(ty.zigTypeTag() == .Pointer); - const mcv = try self.resolveInst(callee); - - try self.genSetReg(Type.initTag(.usize), .lr, mcv); - } - - // TODO: add Instruction.supportedOn - // function for ARM - if (Target.arm.featureSetHas(self.target.cpu.features, .has_v5t)) { - _ = try self.addInst(.{ - .tag = .blx, - .data = .{ .reg = .lr }, + return self.fail("TODO implement call on {s} for {s}", .{ + @tagName(self.bin_file.tag), + @tagName(self.target.cpu.arch), }); - } else { - return self.fail("TODO fix blx emulation for ARM unreachable, // unsupported architecture for MachO - .coff => return self.fail("TODO implement call in COFF for {}", .{self.target.cpu.arch}), - .plan9 => return self.fail("TODO implement call on plan9 for {}", .{self.target.cpu.arch}), - else => unreachable, + } else if (func_value.castTag(.extern_fn)) |_| { + return self.fail("TODO implement calling extern functions", .{}); + } else { + return self.fail("TODO implement calling bitcasted functions", .{}); + } + } else { + assert(ty.zigTypeTag() == .Pointer); + const mcv = try self.resolveInst(callee); + + try self.genSetReg(Type.initTag(.usize), .lr, mcv); + } + + // TODO: add Instruction.supportedOn + // function for ARM + if (Target.arm.featureSetHas(self.target.cpu.features, .has_v5t)) { + _ = try self.addInst(.{ + .tag = .blx, + .data = .{ .reg = .lr }, + }); + } else { + return self.fail("TODO fix blx emulation for ARM return @fieldParentPtr(Coff, "base", base).allocateDeclIndexes(decl_index), - .elf => return @fieldParentPtr(Elf, "base", base).allocateDeclIndexes(decl_index), + .elf => {}, // no-op .macho => {}, // no-op .wasm => return @fieldParentPtr(Wasm, "base", base).allocateDeclIndexes(decl_index), .plan9 => return @fieldParentPtr(Plan9, "base", base).allocateDeclIndexes(decl_index), diff --git a/src/link/Elf.zig b/src/link/Elf.zig index e915fff42388e8d93d1d10e678766b582b116d3a..9dbc5e846f500009a9a342a580610fa7eb6b471c 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -344,9 +344,10 @@ pub fn getDeclVAddr(self: *Elf, decl_index: Module.Decl.Index, reloc_info: File. const decl = mod.declPtr(decl_index); assert(self.llvm_object == null); - assert(decl.link.elf.local_sym_index != 0); - const target = decl.link.elf.local_sym_index; + try decl.link.elf.ensureInitialized(self); + const target = decl.link.elf.getSymbolIndex().?; + const vaddr = self.local_symbols.items[target].st_value; const atom = self.atom_by_index_table.get(reloc_info.parent_atom_index).?; const gop = try self.relocs.getOrPut(self.base.allocator, atom); @@ -447,7 +448,7 @@ fn makeString(self: *Elf, bytes: []const u8) !u32 { return @intCast(u32, result); } -fn getString(self: Elf, str_off: u32) []const u8 { +pub fn getString(self: Elf, str_off: u32) []const u8 { assert(str_off < self.shstrtab.items.len); return mem.sliceTo(@ptrCast([*:0]const u8, self.shstrtab.items.ptr + str_off), 0); } @@ -2069,7 +2070,7 @@ fn freeTextBlock(self: *Elf, text_block: *TextBlock, phdr_index: u16) void { if (text_block.prev) |prev| { prev.next = text_block.next; - if (!already_have_free_list_node and prev.freeListEligible(self.*)) { + 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. free_list.append(self.base.allocator, prev) catch {}; @@ -2084,6 +2085,15 @@ fn freeTextBlock(self: *Elf, text_block: *TextBlock, phdr_index: u16) void { text_block.next = null; } + // Appending to free lists is allowed to fail because the free lists are heuristics based anyway. + const local_sym_index = text_block.getSymbolIndex().?; + self.local_symbol_free_list.append(self.base.allocator, local_sym_index) catch {}; + self.local_symbols.items[local_sym_index].st_info = 0; + _ = self.atom_by_index_table.remove(local_sym_index); + text_block.local_sym_index = 0; + + self.offset_table_free_list.append(self.base.allocator, text_block.offset_table_index) catch {}; + if (self.dwarf) |*dw| { dw.freeAtom(&text_block.dbg_info_atom); } @@ -2099,7 +2109,7 @@ fn shrinkTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, phdr fn growTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, alignment: u64, phdr_index: u16) !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.*); + 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, phdr_index); } @@ -2128,7 +2138,7 @@ fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, al // 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 capacity = big_block.capacity(self); const ideal_capacity = padToIdeal(capacity); const ideal_capacity_end_vaddr = std.math.add(u64, sym.st_value, ideal_capacity) catch ideal_capacity; const capacity_end_vaddr = sym.st_value + capacity; @@ -2138,7 +2148,7 @@ fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, al // 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.*)) { + if (!big_block.freeListEligible(self)) { _ = free_list.swapRemove(i); } else { i += 1; @@ -2213,7 +2223,7 @@ fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, al return vaddr; } -fn allocateLocalSymbol(self: *Elf) !u32 { +pub fn allocateLocalSymbol(self: *Elf) !u32 { try self.local_symbols.ensureUnusedCapacity(self.base.allocator, 1); const index = blk: { @@ -2240,7 +2250,7 @@ fn allocateLocalSymbol(self: *Elf) !u32 { return index; } -fn allocateGotOffset(self: *Elf) !u32 { +pub fn allocateGotOffset(self: *Elf) !u32 { try self.offset_table.ensureUnusedCapacity(self.base.allocator, 1); const index = blk: { @@ -2260,32 +2270,10 @@ fn allocateGotOffset(self: *Elf) !u32 { return index; } -pub fn allocateDeclIndexes(self: *Elf, decl_index: Module.Decl.Index) !void { - if (self.llvm_object) |_| return; - - const mod = self.base.options.module.?; - const decl = mod.declPtr(decl_index); - const block = &decl.link.elf; - if (block.local_sym_index != 0) return; - - const decl_name = try decl.getFullyQualifiedName(mod); - defer self.base.allocator.free(decl_name); - - log.debug("allocating symbol indexes for {s}", .{decl_name}); - - block.local_sym_index = try self.allocateLocalSymbol(); - block.offset_table_index = try self.allocateGotOffset(); - try self.atom_by_index_table.putNoClobber(self.base.allocator, block.local_sym_index, block); - try self.decls.putNoClobber(self.base.allocator, decl_index, null); -} - fn freeUnnamedConsts(self: *Elf, decl_index: Module.Decl.Index) void { const unnamed_consts = self.unnamed_const_atoms.getPtr(decl_index) orelse return; for (unnamed_consts.items) |atom| { self.freeTextBlock(atom, self.phdr_load_ro_index.?); - self.local_symbol_free_list.append(self.base.allocator, atom.local_sym_index) catch {}; - self.local_symbols.items[atom.local_sym_index].st_info = 0; - _ = self.atom_by_index_table.remove(atom.local_sym_index); } unnamed_consts.clearAndFree(self.base.allocator); } @@ -2298,20 +2286,13 @@ pub fn freeDecl(self: *Elf, decl_index: Module.Decl.Index) void { const mod = self.base.options.module.?; const decl = mod.declPtr(decl_index); - const kv = self.decls.fetchRemove(decl_index); - if (kv.?.value) |index| { - self.freeTextBlock(&decl.link.elf, index); - self.freeUnnamedConsts(decl_index); - } + log.debug("freeDecl {*}", .{decl}); - // Appending to free lists is allowed to fail because the free lists are heuristics based anyway. - 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.local_symbols.items[decl.link.elf.local_sym_index].st_info = 0; - _ = self.atom_by_index_table.remove(decl.link.elf.local_sym_index); - decl.link.elf.local_sym_index = 0; - - self.offset_table_free_list.append(self.base.allocator, decl.link.elf.offset_table_index) catch {}; + if (self.decls.fetchRemove(decl_index)) |kv| { + if (kv.value) |index| { + self.freeTextBlock(&decl.link.elf, index); + self.freeUnnamedConsts(decl_index); + } } if (self.dwarf) |*dw| { @@ -2363,7 +2344,7 @@ fn updateDeclCode(self: *Elf, decl_index: Module.Decl.Index, code: []const u8, s 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 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) { @@ -2424,12 +2405,19 @@ pub fn updateFunc(self: *Elf, module: *Module, func: *Module.Fn, air: Air, liven const tracy = trace(@src()); defer tracy.end(); - var code_buffer = std.ArrayList(u8).init(self.base.allocator); - defer code_buffer.deinit(); - const decl_index = func.owner_decl; const decl = module.declPtr(decl_index); - self.freeUnnamedConsts(decl_index); + const atom = &decl.link.elf; + try atom.ensureInitialized(self); + const gop = try self.decls.getOrPut(self.base.allocator, decl_index); + if (gop.found_existing) { + self.freeUnnamedConsts(decl_index); + } else { + gop.value_ptr.* = null; + } + + var code_buffer = std.ArrayList(u8).init(self.base.allocator); + defer code_buffer.deinit(); var decl_state: ?Dwarf.DeclState = if (self.dwarf) |*dw| try dw.initDeclState(module, decl_index) else null; defer if (decl_state) |*ds| ds.deinit(); @@ -2490,6 +2478,13 @@ pub fn updateDecl(self: *Elf, module: *Module, decl_index: Module.Decl.Index) !v assert(!self.unnamed_const_atoms.contains(decl_index)); + const atom = &decl.link.elf; + try atom.ensureInitialized(self); + const gop = try self.decls.getOrPut(self.base.allocator, decl_index); + if (!gop.found_existing) { + gop.value_ptr.* = null; + } + var code_buffer = std.ArrayList(u8).init(self.base.allocator); defer code_buffer.deinit(); @@ -2633,16 +2628,19 @@ pub fn updateDeclExports( const tracy = trace(@src()); defer tracy.end(); + const decl = module.declPtr(decl_index); + const atom = &decl.link.elf; + + if (atom.getSymbolIndex() == null) return; + + const decl_sym = atom.getSymbol(self); try self.global_symbols.ensureUnusedCapacity(self.base.allocator, exports.len); - const decl = module.declPtr(decl_index); - if (decl.link.elf.local_sym_index == 0) return; - const decl_sym = self.local_symbols.items[decl.link.elf.local_sym_index]; - const decl_ptr = self.decls.getPtr(decl_index).?; - if (decl_ptr.* == null) { - decl_ptr.* = try self.getDeclPhdrIndex(decl); + const gop = try self.decls.getOrPut(self.base.allocator, decl_index); + if (!gop.found_existing) { + gop.value_ptr.* = try self.getDeclPhdrIndex(decl); } - const phdr_index = decl_ptr.*.?; + const phdr_index = gop.value_ptr.*.?; const shdr_index = self.phdr_shdr_table.get(phdr_index).?; for (exports) |exp| { diff --git a/src/link/Elf/Atom.zig b/src/link/Elf/Atom.zig index e4061f5bbc9ccc7217592845605a71e4ce80e82e..caeb3bfbc58d3caf207f32e317e063aa6a4fd589 100644 --- a/src/link/Elf/Atom.zig +++ b/src/link/Elf/Atom.zig @@ -1,6 +1,8 @@ const Atom = @This(); const std = @import("std"); +const assert = std.debug.assert; +const elf = std.elf; const Dwarf = @import("../Dwarf.zig"); const Elf = @import("../Elf.zig"); @@ -12,8 +14,10 @@ const Elf = @import("../Elf.zig"); /// 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: ?*Atom, @@ -29,13 +33,49 @@ pub const empty = Atom{ .dbg_info_atom = undefined, }; +pub fn ensureInitialized(self: *Atom, elf_file: *Elf) !void { + if (self.getSymbolIndex() != null) return; // Already initialized + self.local_sym_index = try elf_file.allocateLocalSymbol(); + self.offset_table_index = try elf_file.allocateGotOffset(); + try elf_file.atom_by_index_table.putNoClobber(elf_file.base.allocator, self.local_sym_index, self); +} + +pub fn getSymbolIndex(self: Atom) ?u32 { + if (self.local_sym_index == 0) return null; + return self.local_sym_index; +} + +pub fn getSymbol(self: Atom, elf_file: *Elf) elf.Elf64_Sym { + const sym_index = self.getSymbolIndex().?; + return elf_file.local_symbols.items[sym_index]; +} + +pub fn getSymbolPtr(self: Atom, elf_file: *Elf) *elf.Elf64_Sym { + const sym_index = self.getSymbolIndex().?; + return &elf_file.local_symbols.items[sym_index]; +} + +pub fn getName(self: Atom, elf_file: *Elf) []const u8 { + const sym = self.getSymbol(); + return elf_file.getString(sym.st_name); +} + +pub fn getOffsetTableAddress(self: Atom, elf_file: *Elf) u64 { + assert(self.getSymbolIndex() != null); + const target = elf_file.base.options.target; + const ptr_bits = target.cpu.arch.ptrBitWidth(); + const ptr_bytes: u64 = @divExact(ptr_bits, 8); + const got = elf_file.program_headers.items[elf_file.phdr_got_index.?]; + return got.p_vaddr + self.offset_table_index * ptr_bytes; +} + /// 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. -pub fn capacity(self: Atom, elf_file: Elf) u64 { - const self_sym = elf_file.local_symbols.items[self.local_sym_index]; +pub fn capacity(self: Atom, elf_file: *Elf) u64 { + const self_sym = self.getSymbol(elf_file); if (self.next) |next| { - const next_sym = elf_file.local_symbols.items[next.local_sym_index]; + const next_sym = next.getSymbol(elf_file); return next_sym.st_value - self_sym.st_value; } else { // We are the last block. The capacity is limited only by virtual address space. @@ -43,11 +83,11 @@ pub fn capacity(self: Atom, elf_file: Elf) u64 { } } -pub fn freeListEligible(self: Atom, elf_file: Elf) bool { +pub fn freeListEligible(self: Atom, 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 self_sym = self.getSymbol(elf_file); + const next_sym = next.getSymbol(elf_file); const cap = next_sym.st_value - self_sym.st_value; const ideal_cap = Elf.padToIdeal(self_sym.st_size); if (cap <= ideal_cap) return false; diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 1ec8ecaaf8627847e8da9c4aa791a754610bc87b..8fe5a1c71210bde76adf75ff3856a1b90955cb63 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -2472,14 +2472,15 @@ pub fn updateDeclExports( const decl = module.declPtr(decl_index); const atom = &decl.link.macho; - try atom.ensureInitialized(self); + + if (atom.getSymbolIndex() == null) return; const gop = try self.decls.getOrPut(gpa, decl_index); if (!gop.found_existing) { - gop.value_ptr.* = null; + gop.value_ptr.* = self.getDeclOutputSection(decl); } - const decl_sym = decl.link.macho.getSymbol(self); + const decl_sym = atom.getSymbol(self); for (exports) |exp| { const exp_name = try std.fmt.allocPrint(gpa, "_{s}", .{exp.options.name}); -- 2.54.0 From cc1d7a0e315ba63b0d8c0cd647b4c7e92a571bf2 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Thu, 26 Jan 2023 14:28:44 +0100 Subject: [PATCH 08/84] coff: migrate to new non-allocateDeclIndexes API --- src/Module.zig | 7 +- src/arch/aarch64/CodeGen.zig | 19 ++--- src/arch/x86_64/CodeGen.zig | 14 ++-- src/link.zig | 12 ++- src/link/Coff.zig | 152 ++++++++++++++++++----------------- src/link/Coff/Atom.zig | 23 +++++- src/link/Elf.zig | 49 ++++++----- src/link/MachO.zig | 135 ++++++++++++------------------- 8 files changed, 209 insertions(+), 202 deletions(-) diff --git a/src/Module.zig b/src/Module.zig index 4e1f65aff421f277476bc85e24e216b487a1ec3c..360dd4d1ecada8a7b48d0bda4ecb9c486a00d1d0 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -5324,7 +5324,12 @@ pub fn deleteUnusedDecl(mod: *Module, decl_index: Decl.Index) void { // Until then, we did call `allocateDeclIndexes` on this anonymous Decl and so we // must call `freeDecl` in the linker backend now. switch (mod.comp.bin_file.tag) { - .elf, .macho, .c => {}, // this linker backend has already migrated to the new API + .coff, + .elf, + .macho, + .c, + => {}, // this linker backend has already migrated to the new API + else => if (decl.has_tv) { if (decl.ty.isFnOrHasRuntimeBits()) { mod.comp.bin_file.freeDecl(decl_index); diff --git a/src/arch/aarch64/CodeGen.zig b/src/arch/aarch64/CodeGen.zig index 8c3f3e816814e03b9b9a1c19be6551b5bd79d90f..200bf3b8e079bd604be9a57ec5624b4325eb73b8 100644 --- a/src/arch/aarch64/CodeGen.zig +++ b/src/arch/aarch64/CodeGen.zig @@ -4000,7 +4000,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type const owner_decl = mod.declPtr(self.mod_fn.owner_decl); const atom_index = switch (self.bin_file.tag) { .macho => owner_decl.link.macho.getSymbolIndex().?, - .coff => owner_decl.link.coff.sym_index, + .coff => owner_decl.link.coff.getSymbolIndex().?, else => unreachable, // unsupported target format }; _ = try self.addInst(.{ @@ -4318,11 +4318,12 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier .sym_index = fn_owner_decl.link.macho.getSymbolIndex().?, }, }); - } else if (self.bin_file.cast(link.File.Coff)) |_| { + } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { + try fn_owner_decl.link.coff.ensureInitialized(coff_file); try self.genSetReg(Type.initTag(.u64), .x30, .{ .linker_load = .{ .type = .got, - .sym_index = fn_owner_decl.link.coff.sym_index, + .sym_index = fn_owner_decl.link.coff.getSymbolIndex().?, }, }); } else if (self.bin_file.cast(link.File.Plan9)) |p9| { @@ -5494,7 +5495,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro const owner_decl = mod.declPtr(self.mod_fn.owner_decl); const atom_index = switch (self.bin_file.tag) { .macho => owner_decl.link.macho.getSymbolIndex().?, - .coff => owner_decl.link.coff.sym_index, + .coff => owner_decl.link.coff.getSymbolIndex().?, else => unreachable, // unsupported target format }; _ = try self.addInst(.{ @@ -5608,7 +5609,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void const owner_decl = mod.declPtr(self.mod_fn.owner_decl); const atom_index = switch (self.bin_file.tag) { .macho => owner_decl.link.macho.getSymbolIndex().?, - .coff => owner_decl.link.coff.sym_index, + .coff => owner_decl.link.coff.getSymbolIndex().?, else => unreachable, // unsupported target format }; _ = try self.addInst(.{ @@ -5802,7 +5803,7 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I const owner_decl = mod.declPtr(self.mod_fn.owner_decl); const atom_index = switch (self.bin_file.tag) { .macho => owner_decl.link.macho.getSymbolIndex().?, - .coff => owner_decl.link.coff.sym_index, + .coff => owner_decl.link.coff.getSymbolIndex().?, else => unreachable, // unsupported target format }; _ = try self.addInst(.{ @@ -6129,11 +6130,11 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne .type = .got, .sym_index = decl.link.macho.getSymbolIndex().?, } }; - } else if (self.bin_file.cast(link.File.Coff)) |_| { - assert(decl.link.coff.sym_index != 0); + } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { + try decl.link.coff.ensureInitialized(coff_file); return MCValue{ .linker_load = .{ .type = .got, - .sym_index = decl.link.coff.sym_index, + .sym_index = decl.link.coff.getSymbolIndex().?, } }; } else if (self.bin_file.cast(link.File.Plan9)) |p9| { try p9.seeDecl(decl_index); diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 93f12691477ee3e831fa5426fbe7ac8a4055cc25..df24fe5e7de694b39c138cfd703585b2f42570f8 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -2673,7 +2673,7 @@ fn loadMemPtrIntoRegister(self: *Self, reg: Register, ptr_ty: Type, ptr: MCValue const atom_index = if (self.bin_file.tag == link.File.MachO.base_tag) fn_owner_decl.link.macho.getSymbolIndex().? else - fn_owner_decl.link.coff.sym_index; + fn_owner_decl.link.coff.getSymbolIndex().?; const flags: u2 = switch (load_struct.type) { .got => 0b00, .direct => 0b01, @@ -4005,11 +4005,13 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier .ops = Mir.Inst.Ops.encode(.{ .flags = 0b01 }), .data = .{ .imm = got_addr }, }); - } else if (self.bin_file.cast(link.File.Coff)) |_| { + } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { + try fn_owner_decl.link.coff.ensureInitialized(coff_file); + const sym_index = fn_owner_decl.link.coff.getSymbolIndex().?; try self.genSetReg(Type.initTag(.usize), .rax, .{ .linker_load = .{ .type = .got, - .sym_index = fn_owner_decl.link.coff.sym_index, + .sym_index = sym_index, }, }); _ = try self.addInst(.{ @@ -6725,11 +6727,11 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne .type = .got, .sym_index = decl.link.macho.getSymbolIndex().?, } }; - } else if (self.bin_file.cast(link.File.Coff)) |_| { - assert(decl.link.coff.sym_index != 0); + } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { + try decl.link.coff.ensureInitialized(coff_file); return MCValue{ .linker_load = .{ .type = .got, - .sym_index = decl.link.coff.sym_index, + .sym_index = decl.link.coff.getSymbolIndex().?, } }; } else if (self.bin_file.cast(link.File.Plan9)) |p9| { try p9.seeDecl(decl_index); diff --git a/src/link.zig b/src/link.zig index d64c09d199cc745adcbb15bdc9e29aea9ca4e8f8..9be5b9ca3aa277bafeb4e736d5dca2b8aad62dee 100644 --- a/src/link.zig +++ b/src/link.zig @@ -615,12 +615,16 @@ pub const File = struct { return; } switch (base.tag) { - .coff => return @fieldParentPtr(Coff, "base", base).allocateDeclIndexes(decl_index), - .elf => {}, // no-op - .macho => {}, // no-op .wasm => return @fieldParentPtr(Wasm, "base", base).allocateDeclIndexes(decl_index), .plan9 => return @fieldParentPtr(Plan9, "base", base).allocateDeclIndexes(decl_index), - .c, .spirv, .nvptx => {}, + + .coff, + .elf, + .macho, + .c, + .spirv, + .nvptx, + => {}, } } diff --git a/src/link/Coff.zig b/src/link/Coff.zig index 65aee010fd34bb8746a3615a9433d5f51e636e8e..dee3c7c381ebaa40a1fd121f8326369add74cf2d 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -480,16 +480,6 @@ fn growSectionVM(self: *Coff, sect_id: u32, needed_size: u32) !void { header.virtual_size = increased_size; } -pub fn allocateDeclIndexes(self: *Coff, decl_index: Module.Decl.Index) !void { - if (self.llvm_object) |_| return; - const decl = self.base.options.module.?.declPtr(decl_index); - if (decl.link.coff.sym_index != 0) return; - decl.link.coff.sym_index = try self.allocateSymbol(); - const gpa = self.base.allocator; - try self.atom_by_index_table.putNoClobber(gpa, decl.link.coff.sym_index, &decl.link.coff); - try self.decls.putNoClobber(gpa, decl_index, null); -} - fn allocateAtom(self: *Coff, atom: *Atom, new_atom_size: u32, alignment: u32) !u32 { const tracy = trace(@src()); defer tracy.end(); @@ -615,7 +605,7 @@ fn allocateAtom(self: *Coff, atom: *Atom, new_atom_size: u32, alignment: u32) !u return vaddr; } -fn allocateSymbol(self: *Coff) !u32 { +pub fn allocateSymbol(self: *Coff) !u32 { const gpa = self.base.allocator; try self.locals.ensureUnusedCapacity(gpa, 1); @@ -716,12 +706,11 @@ fn createGotAtom(self: *Coff, target: SymbolWithLoc) !*Atom { const atom = try gpa.create(Atom); errdefer gpa.destroy(atom); atom.* = Atom.empty; - atom.sym_index = try self.allocateSymbol(); + try atom.ensureInitialized(self); atom.size = @sizeOf(u64); atom.alignment = @alignOf(u64); try self.managed_atoms.append(gpa, atom); - try self.atom_by_index_table.putNoClobber(gpa, atom.sym_index, atom); const sym = atom.getSymbolPtr(self); sym.section_number = @intToEnum(coff.SectionNumber, self.got_section_index.? + 1); @@ -754,12 +743,11 @@ fn createImportAtom(self: *Coff) !*Atom { const atom = try gpa.create(Atom); errdefer gpa.destroy(atom); atom.* = Atom.empty; - atom.sym_index = try self.allocateSymbol(); + try atom.ensureInitialized(self); atom.size = @sizeOf(u64); atom.alignment = @alignOf(u64); try self.managed_atoms.append(gpa, atom); - try self.atom_by_index_table.putNoClobber(gpa, atom.sym_index, atom); const sym = atom.getSymbolPtr(self); sym.section_number = @intToEnum(coff.SectionNumber, self.idata_section_index.? + 1); @@ -790,7 +778,11 @@ fn writeAtom(self: *Coff, atom: *Atom, code: []const u8) !void { const sym = atom.getSymbol(self); const section = self.sections.get(@enumToInt(sym.section_number) - 1); const file_offset = section.header.pointer_to_raw_data + sym.value - section.header.virtual_address; - log.debug("writing atom for symbol {s} at file offset 0x{x} to 0x{x}", .{ atom.getName(self), file_offset, file_offset + code.len }); + log.debug("writing atom for symbol {s} at file offset 0x{x} to 0x{x}", .{ + atom.getName(self), + file_offset, + file_offset + code.len, + }); try self.base.file.?.pwriteAll(code, file_offset); try self.resolveRelocs(atom); } @@ -848,6 +840,7 @@ fn freeAtom(self: *Coff, atom: *Atom) void { // Remove any relocs and base relocs associated with this Atom self.freeRelocationsForAtom(atom); + const gpa = self.base.allocator; const sym = atom.getSymbol(self); const sect_id = @enumToInt(sym.section_number) - 1; const free_list = &self.sections.items(.free_list)[sect_id]; @@ -885,7 +878,7 @@ fn freeAtom(self: *Coff, atom: *Atom) void { 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. - free_list.append(self.base.allocator, prev) catch {}; + free_list.append(gpa, prev) catch {}; } } else { atom.prev = null; @@ -896,6 +889,28 @@ fn freeAtom(self: *Coff, atom: *Atom) void { } else { atom.next = null; } + + // Appending to free lists is allowed to fail because the free lists are heuristics based anyway. + const sym_index = atom.getSymbolIndex().?; + self.locals_free_list.append(gpa, sym_index) catch {}; + + // Try freeing GOT atom if this decl had one + const got_target = SymbolWithLoc{ .sym_index = sym_index, .file = null }; + if (self.got_entries_table.get(got_target)) |got_index| { + self.got_entries_free_list.append(gpa, @intCast(u32, got_index)) catch {}; + self.got_entries.items[got_index] = .{ + .target = .{ .sym_index = 0, .file = null }, + .sym_index = 0, + }; + _ = self.got_entries_table.remove(got_target); + + log.debug(" adding GOT index {d} to free list (target local@{d})", .{ got_index, sym_index }); + } + + self.locals.items[sym_index].section_number = .UNDEFINED; + _ = self.atom_by_index_table.remove(sym_index); + log.debug(" adding local symbol index {d} to free list", .{sym_index}); + atom.sym_index = 0; } pub fn updateFunc(self: *Coff, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void { @@ -912,8 +927,15 @@ pub fn updateFunc(self: *Coff, module: *Module, func: *Module.Fn, air: Air, live const decl_index = func.owner_decl; const decl = module.declPtr(decl_index); - self.freeUnnamedConsts(decl_index); - self.freeRelocationsForAtom(&decl.link.coff); + const atom = &decl.link.coff; + try atom.ensureInitialized(self); + const gop = try self.decls.getOrPut(self.base.allocator, decl_index); + if (gop.found_existing) { + self.freeUnnamedConsts(decl_index); + self.freeRelocationsForAtom(&decl.link.coff); + } else { + gop.value_ptr.* = null; + } var code_buffer = std.ArrayList(u8).init(self.base.allocator); defer code_buffer.deinit(); @@ -960,9 +982,9 @@ pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.In const atom = try gpa.create(Atom); errdefer gpa.destroy(atom); atom.* = Atom.empty; + try atom.ensureInitialized(self); + try self.managed_atoms.append(gpa, atom); - atom.sym_index = try self.allocateSymbol(); - const sym = atom.getSymbolPtr(self); const sym_name = blk: { const decl_name = try decl.getFullyQualifiedName(mod); defer gpa.free(decl_name); @@ -971,14 +993,11 @@ pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.In break :blk try std.fmt.allocPrint(gpa, "__unnamed_{s}_{d}", .{ decl_name, index }); }; defer gpa.free(sym_name); - try self.setSymbolName(sym, sym_name); - sym.section_number = @intToEnum(coff.SectionNumber, self.rdata_section_index.? + 1); - - try self.managed_atoms.append(gpa, atom); - try self.atom_by_index_table.putNoClobber(gpa, atom.sym_index, atom); + try self.setSymbolName(atom.getSymbolPtr(self), sym_name); + atom.getSymbolPtr(self).section_number = @intToEnum(coff.SectionNumber, self.rdata_section_index.? + 1); const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), tv, &code_buffer, .none, .{ - .parent_atom_index = atom.sym_index, + .parent_atom_index = atom.getSymbolIndex().?, }); const code = switch (res) { .ok => code_buffer.items, @@ -993,17 +1012,17 @@ pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.In const required_alignment = tv.ty.abiAlignment(self.base.options.target); atom.alignment = required_alignment; atom.size = @intCast(u32, code.len); - sym.value = try self.allocateAtom(atom, atom.size, atom.alignment); + atom.getSymbolPtr(self).value = try self.allocateAtom(atom, atom.size, atom.alignment); errdefer self.freeAtom(atom); try unnamed_consts.append(gpa, atom); - log.debug("allocated atom for {s} at 0x{x}", .{ sym_name, sym.value }); + log.debug("allocated atom for {s} at 0x{x}", .{ sym_name, atom.getSymbol(self).value }); log.debug(" (required alignment 0x{x})", .{required_alignment}); try self.writeAtom(atom, code); - return atom.sym_index; + return atom.getSymbolIndex().?; } pub fn updateDecl(self: *Coff, module: *Module, decl_index: Module.Decl.Index) !void { @@ -1028,7 +1047,14 @@ pub fn updateDecl(self: *Coff, module: *Module, decl_index: Module.Decl.Index) ! } } - self.freeRelocationsForAtom(&decl.link.coff); + const atom = &decl.link.coff; + try atom.ensureInitialized(self); + const gop = try self.decls.getOrPut(self.base.allocator, decl_index); + if (gop.found_existing) { + self.freeRelocationsForAtom(atom); + } else { + gop.value_ptr.* = null; + } var code_buffer = std.ArrayList(u8).init(self.base.allocator); defer code_buffer.deinit(); @@ -1038,7 +1064,7 @@ pub fn updateDecl(self: *Coff, module: *Module, decl_index: Module.Decl.Index) ! .ty = decl.ty, .val = decl_val, }, &code_buffer, .none, .{ - .parent_atom_index = decl.link.coff.sym_index, + .parent_atom_index = decl.link.coff.getSymbolIndex().?, }); const code = switch (res) { .ok => code_buffer.items, @@ -1099,7 +1125,7 @@ fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []const u8, const code_len = @intCast(u32, code.len); const atom = &decl.link.coff; - assert(atom.sym_index != 0); // Caller forgot to allocateDeclIndexes() + if (atom.size != 0) { const sym = atom.getSymbolPtr(self); try self.setSymbolName(sym, decl_name); @@ -1116,7 +1142,7 @@ fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []const u8, if (vaddr != sym.value) { sym.value = vaddr; log.debug(" (updating GOT entry)", .{}); - const got_target = SymbolWithLoc{ .sym_index = atom.sym_index, .file = null }; + const got_target = SymbolWithLoc{ .sym_index = atom.getSymbolIndex().?, .file = null }; const got_atom = self.getGotAtomForSymbol(got_target).?; self.markRelocsDirtyByTarget(got_target); try self.writePtrWidthAtom(got_atom); @@ -1137,10 +1163,10 @@ fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []const u8, atom.size = code_len; sym.value = vaddr; - const got_target = SymbolWithLoc{ .sym_index = atom.sym_index, .file = null }; + const got_target = SymbolWithLoc{ .sym_index = atom.getSymbolIndex().?, .file = null }; const got_index = try self.allocateGotEntry(got_target); const got_atom = try self.createGotAtom(got_target); - self.got_entries.items[got_index].sym_index = got_atom.sym_index; + self.got_entries.items[got_index].sym_index = got_atom.getSymbolIndex().?; try self.writePtrWidthAtom(got_atom); } @@ -1160,11 +1186,6 @@ fn freeUnnamedConsts(self: *Coff, decl_index: Module.Decl.Index) void { const unnamed_consts = self.unnamed_const_atoms.getPtr(decl_index) orelse return; for (unnamed_consts.items) |atom| { self.freeAtom(atom); - self.locals_free_list.append(gpa, atom.sym_index) catch {}; - self.locals.items[atom.sym_index].section_number = .UNDEFINED; - _ = self.atom_by_index_table.remove(atom.sym_index); - log.debug(" adding local symbol index {d} to free list", .{atom.sym_index}); - atom.sym_index = 0; } unnamed_consts.clearAndFree(gpa); } @@ -1179,35 +1200,11 @@ pub fn freeDecl(self: *Coff, decl_index: Module.Decl.Index) void { log.debug("freeDecl {*}", .{decl}); - const kv = self.decls.fetchRemove(decl_index); - if (kv.?.value) |_| { - self.freeAtom(&decl.link.coff); - self.freeUnnamedConsts(decl_index); - } - - // Appending to free lists is allowed to fail because the free lists are heuristics based anyway. - const gpa = self.base.allocator; - const sym_index = decl.link.coff.sym_index; - if (sym_index != 0) { - self.locals_free_list.append(gpa, sym_index) catch {}; - - // Try freeing GOT atom if this decl had one - const got_target = SymbolWithLoc{ .sym_index = sym_index, .file = null }; - if (self.got_entries_table.get(got_target)) |got_index| { - self.got_entries_free_list.append(gpa, @intCast(u32, got_index)) catch {}; - self.got_entries.items[got_index] = .{ - .target = .{ .sym_index = 0, .file = null }, - .sym_index = 0, - }; - _ = self.got_entries_table.remove(got_target); - - log.debug(" adding GOT index {d} to free list (target local@{d})", .{ got_index, sym_index }); + if (self.decls.fetchRemove(decl_index)) |kv| { + if (kv.value) |_| { + self.freeAtom(&decl.link.coff); + self.freeUnnamedConsts(decl_index); } - - self.locals.items[sym_index].section_number = .UNDEFINED; - _ = self.atom_by_index_table.remove(sym_index); - log.debug(" adding local symbol index {d} to free list", .{sym_index}); - decl.link.coff.sym_index = 0; } } @@ -1261,7 +1258,14 @@ pub fn updateDeclExports( const decl = module.declPtr(decl_index); const atom = &decl.link.coff; - if (atom.sym_index == 0) return; + + if (atom.getSymbolIndex() == null) return; + + const gop = try self.decls.getOrPut(gpa, decl_index); + if (!gop.found_existing) { + gop.value_ptr.* = self.getDeclOutputSection(decl); + } + const decl_sym = atom.getSymbol(self); for (exports) |exp| { @@ -1416,7 +1420,7 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod const import_index = try self.allocateImportEntry(global); const import_atom = try self.createImportAtom(); - self.imports.items[import_index].sym_index = import_atom.sym_index; + self.imports.items[import_index].sym_index = import_atom.getSymbolIndex().?; try self.writePtrWidthAtom(import_atom); } @@ -1460,10 +1464,12 @@ pub fn getDeclVAddr( const decl = mod.declPtr(decl_index); assert(self.llvm_object == null); - assert(decl.link.coff.sym_index != 0); + + try decl.link.coff.ensureInitialized(self); + const sym_index = decl.link.coff.getSymbolIndex().?; const atom = self.getAtomForSymbol(.{ .sym_index = reloc_info.parent_atom_index, .file = null }).?; - const target = SymbolWithLoc{ .sym_index = decl.link.coff.sym_index, .file = null }; + const target = SymbolWithLoc{ .sym_index = sym_index, .file = null }; try atom.addRelocation(self, .{ .type = .direct, .target = target, diff --git a/src/link/Coff/Atom.zig b/src/link/Coff/Atom.zig index b1bb292c620408ed46188d8e3ce8a49ad2a322a0..78824eac1dc3d9de6346c66fe2c90991a50be483 100644 --- a/src/link/Coff/Atom.zig +++ b/src/link/Coff/Atom.zig @@ -39,30 +39,45 @@ pub const empty = Atom{ .next = null, }; +pub fn ensureInitialized(self: *Atom, coff_file: *Coff) !void { + if (self.getSymbolIndex() != null) return; // Already initialized + self.sym_index = try coff_file.allocateSymbol(); + try coff_file.atom_by_index_table.putNoClobber(coff_file.base.allocator, self.sym_index, self); +} + +pub fn getSymbolIndex(self: Atom) ?u32 { + if (self.sym_index == 0) return null; + return self.sym_index; +} + /// Returns symbol referencing this atom. pub fn getSymbol(self: Atom, coff_file: *const Coff) *const coff.Symbol { + const sym_index = self.getSymbolIndex().?; return coff_file.getSymbol(.{ - .sym_index = self.sym_index, + .sym_index = sym_index, .file = self.file, }); } /// Returns pointer-to-symbol referencing this atom. pub fn getSymbolPtr(self: Atom, coff_file: *Coff) *coff.Symbol { + const sym_index = self.getSymbolIndex().?; return coff_file.getSymbolPtr(.{ - .sym_index = self.sym_index, + .sym_index = sym_index, .file = self.file, }); } pub fn getSymbolWithLoc(self: Atom) SymbolWithLoc { - return .{ .sym_index = self.sym_index, .file = self.file }; + const sym_index = self.getSymbolIndex().?; + return .{ .sym_index = sym_index, .file = self.file }; } /// Returns the name of this atom. pub fn getName(self: Atom, coff_file: *const Coff) []const u8 { + const sym_index = self.getSymbolIndex().?; return coff_file.getSymbolName(.{ - .sym_index = self.sym_index, + .sym_index = sym_index, .file = self.file, }); } diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 9dbc5e846f500009a9a342a580610fa7eb6b471c..2c55e55f83226ecadd43ef7e0aee606c6f6bf25d 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -893,7 +893,7 @@ fn growAllocSection(self: *Elf, shdr_index: u16, phdr_index: u16, needed_size: u // Must move the entire section. const new_offset = self.findFreeSpace(needed_size, self.page_size); const existing_size = if (self.atoms.get(phdr_index)) |last| blk: { - const sym = self.local_symbols.items[last.local_sym_index]; + const sym = last.getSymbol(self); break :blk (sym.st_value + sym.st_size) - phdr.p_vaddr; } else if (shdr_index == self.got_section_index.?) blk: { break :blk shdr.sh_size; @@ -1031,7 +1031,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node while (it.next()) |entry| { const atom = entry.key_ptr.*; const relocs = entry.value_ptr.*; - const source_sym = self.local_symbols.items[atom.local_sym_index]; + const source_sym = atom.getSymbol(self); const source_shdr = self.sections.items[source_sym.st_shndx]; log.debug("relocating '{s}'", .{self.getString(source_sym.st_name)}); @@ -2034,11 +2034,13 @@ fn writeElfHeader(self: *Elf) !void { } fn freeTextBlock(self: *Elf, text_block: *TextBlock, phdr_index: u16) void { - const local_sym = self.local_symbols.items[text_block.local_sym_index]; + const local_sym = text_block.getSymbol(self); const name_str_index = local_sym.st_name; const name = self.getString(name_str_index); log.debug("freeTextBlock {*} ({s})", .{ text_block, name }); + self.freeRelocationsForTextBlock(text_block); + const free_list = self.atom_free_lists.getPtr(phdr_index).?; var already_have_free_list_node = false; { @@ -2107,7 +2109,7 @@ fn shrinkTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, phdr } fn growTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, alignment: u64, phdr_index: u16) !u64 { - const sym = self.local_symbols.items[text_block.local_sym_index]; + const sym = text_block.getSymbol(self); 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; @@ -2137,7 +2139,7 @@ fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, al const big_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 sym = big_block.getSymbol(self); const capacity = big_block.capacity(self); const ideal_capacity = padToIdeal(capacity); const ideal_capacity_end_vaddr = std.math.add(u64, sym.st_value, ideal_capacity) catch ideal_capacity; @@ -2168,7 +2170,7 @@ fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, al } break :blk new_start_vaddr; } else if (self.atoms.get(phdr_index)) |last| { - const sym = self.local_symbols.items[last.local_sym_index]; + const sym = last.getSymbol(self); const ideal_capacity = padToIdeal(sym.st_size); const ideal_capacity_end_vaddr = sym.st_value + ideal_capacity; const new_start_vaddr = mem.alignForwardGeneric(u64, ideal_capacity_end_vaddr, alignment); @@ -2270,6 +2272,11 @@ pub fn allocateGotOffset(self: *Elf) !u32 { return index; } +fn freeRelocationsForTextBlock(self: *Elf, text_block: *TextBlock) void { + var removed_relocs = self.relocs.fetchRemove(text_block); + if (removed_relocs) |*relocs| relocs.value.deinit(self.base.allocator); +} + fn freeUnnamedConsts(self: *Elf, decl_index: Module.Decl.Index) void { const unnamed_consts = self.unnamed_const_atoms.getPtr(decl_index) orelse return; for (unnamed_consts.items) |atom| { @@ -2341,8 +2348,7 @@ fn updateDeclCode(self: *Elf, decl_index: Module.Decl.Index, code: []const u8, s const phdr_index = decl_ptr.*.?; const shdr_index = self.phdr_shdr_table.get(phdr_index).?; - 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]; + const local_sym = decl.link.elf.getSymbolPtr(self); if (local_sym.st_size != 0) { const capacity = decl.link.elf.capacity(self); const need_realloc = code.len > capacity or @@ -2366,7 +2372,7 @@ fn updateDeclCode(self: *Elf, decl_index: Module.Decl.Index, code: []const u8, s local_sym.st_other = 0; local_sym.st_shndx = shdr_index; // TODO this write could be avoided if no fields of the symbol were changed. - try self.writeSymbol(decl.link.elf.local_sym_index); + try self.writeSymbol(decl.link.elf.getSymbolIndex().?); } else { const name_str_index = try self.makeString(decl_name); const vaddr = try self.allocateTextBlock(&decl.link.elf, code.len, required_alignment, phdr_index); @@ -2383,7 +2389,7 @@ fn updateDeclCode(self: *Elf, decl_index: Module.Decl.Index, code: []const u8, s }; self.offset_table.items[decl.link.elf.offset_table_index] = vaddr; - try self.writeSymbol(decl.link.elf.local_sym_index); + try self.writeSymbol(decl.link.elf.getSymbolIndex().?); try self.writeOffsetTableEntry(decl.link.elf.offset_table_index); } @@ -2412,6 +2418,7 @@ pub fn updateFunc(self: *Elf, module: *Module, func: *Module.Fn, air: Air, liven const gop = try self.decls.getOrPut(self.base.allocator, decl_index); if (gop.found_existing) { self.freeUnnamedConsts(decl_index); + self.freeRelocationsForTextBlock(atom); } else { gop.value_ptr.* = null; } @@ -2481,7 +2488,9 @@ pub fn updateDecl(self: *Elf, module: *Module, decl_index: Module.Decl.Index) !v const atom = &decl.link.elf; try atom.ensureInitialized(self); const gop = try self.decls.getOrPut(self.base.allocator, decl_index); - if (!gop.found_existing) { + if (gop.found_existing) { + self.freeRelocationsForTextBlock(atom); + } else { gop.value_ptr.* = null; } @@ -2500,14 +2509,14 @@ pub fn updateDecl(self: *Elf, module: *Module, decl_index: Module.Decl.Index) !v }, &code_buffer, .{ .dwarf = ds, }, .{ - .parent_atom_index = decl.link.elf.local_sym_index, + .parent_atom_index = decl.link.elf.getSymbolIndex().?, }) else try codegen.generateSymbol(&self.base, decl.srcLoc(), .{ .ty = decl.ty, .val = decl_val, }, &code_buffer, .none, .{ - .parent_atom_index = decl.link.elf.local_sym_index, + .parent_atom_index = decl.link.elf.getSymbolIndex().?, }); const code = switch (res) { @@ -2551,6 +2560,8 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module const atom = try self.base.allocator.create(TextBlock); errdefer self.base.allocator.destroy(atom); atom.* = TextBlock.empty; + // TODO for unnamed consts we don't need GOT offset/entry allocated + try atom.ensureInitialized(self); try self.managed_atoms.append(self.base.allocator, atom); const name_str_index = blk: { @@ -2565,14 +2576,10 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module }; const name = self.getString(name_str_index); - log.debug("allocating symbol indexes for {s}", .{name}); - atom.local_sym_index = try self.allocateLocalSymbol(); - try self.atom_by_index_table.putNoClobber(self.base.allocator, atom.local_sym_index, atom); - const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), typed_value, &code_buffer, .{ .none = {}, }, .{ - .parent_atom_index = atom.local_sym_index, + .parent_atom_index = atom.getSymbolIndex().?, }); const code = switch (res) { .ok => code_buffer.items, @@ -2592,7 +2599,7 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module log.debug("allocated text block for {s} at 0x{x}", .{ name, vaddr }); - const local_sym = &self.local_symbols.items[atom.local_sym_index]; + const local_sym = atom.getSymbolPtr(self); local_sym.* = .{ .st_name = name_str_index, .st_info = (elf.STB_LOCAL << 4) | elf.STT_OBJECT, @@ -2602,14 +2609,14 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module .st_size = code.len, }; - try self.writeSymbol(atom.local_sym_index); + try self.writeSymbol(atom.getSymbolIndex().?); try unnamed_consts.append(self.base.allocator, atom); const section_offset = local_sym.st_value - self.program_headers.items[phdr_index].p_vaddr; const file_offset = self.sections.items[shdr_index].sh_offset + section_offset; try self.base.file.?.pwriteAll(code, file_offset); - return atom.local_sym_index; + return atom.getSymbolIndex().?; } pub fn updateDeclExports( diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 8fe5a1c71210bde76adf75ff3856a1b90955cb63..543cb473d74a2ef1d1160a36d09dd24814665ecc 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -1056,19 +1056,14 @@ pub fn allocateSpecialSymbols(self: *MachO) !void { pub fn createGotAtom(self: *MachO, target: SymbolWithLoc) !*Atom { const gpa = self.base.allocator; - const sym_index = try self.allocateSymbol(); - const atom = blk: { - const atom = try gpa.create(Atom); - atom.* = Atom.empty; - atom.sym_index = sym_index; - atom.size = @sizeOf(u64); - atom.alignment = @alignOf(u64); - break :blk atom; - }; + const atom = try gpa.create(Atom); + atom.* = Atom.empty; + try atom.ensureInitialized(self); + atom.size = @sizeOf(u64); + atom.alignment = @alignOf(u64); errdefer gpa.destroy(atom); try self.managed_atoms.append(gpa, atom); - try self.atom_by_index_table.putNoClobber(gpa, atom.sym_index, atom); const sym = atom.getSymbolPtr(self); sym.n_type = macho.N_SECT; @@ -1109,15 +1104,11 @@ pub fn createDyldPrivateAtom(self: *MachO) !void { const gpa = self.base.allocator; - const sym_index = try self.allocateSymbol(); - const atom = blk: { - const atom = try gpa.create(Atom); - atom.* = Atom.empty; - atom.sym_index = sym_index; - atom.size = @sizeOf(u64); - atom.alignment = @alignOf(u64); - break :blk atom; - }; + const atom = try gpa.create(Atom); + atom.* = Atom.empty; + try atom.ensureInitialized(self); + atom.size = @sizeOf(u64); + atom.alignment = @alignOf(u64); errdefer gpa.destroy(atom); const sym = atom.getSymbolPtr(self); @@ -1126,7 +1117,6 @@ pub fn createDyldPrivateAtom(self: *MachO) !void { self.dyld_private_atom = atom; try self.managed_atoms.append(gpa, atom); - try self.atom_by_index_table.putNoClobber(gpa, sym_index, atom); sym.n_value = try self.allocateAtom(atom, atom.size, @alignOf(u64)); log.debug("allocated dyld_private atom at 0x{x}", .{sym.n_value}); @@ -1144,18 +1134,14 @@ pub fn createStubHelperPreambleAtom(self: *MachO) !void { .aarch64 => 6 * @sizeOf(u32), else => unreachable, }; - const sym_index = try self.allocateSymbol(); - const atom = blk: { - const atom = try gpa.create(Atom); - atom.* = Atom.empty; - atom.sym_index = sym_index; - atom.size = size; - atom.alignment = switch (arch) { - .x86_64 => 1, - .aarch64 => @alignOf(u32), - else => unreachable, - }; - break :blk atom; + const atom = try gpa.create(Atom); + atom.* = Atom.empty; + try atom.ensureInitialized(self); + atom.size = size; + atom.alignment = switch (arch) { + .x86_64 => 1, + .aarch64 => @alignOf(u32), + else => unreachable, }; errdefer gpa.destroy(atom); @@ -1163,7 +1149,7 @@ pub fn createStubHelperPreambleAtom(self: *MachO) !void { sym.n_type = macho.N_SECT; sym.n_sect = self.stub_helper_section_index.? + 1; - const dyld_private_sym_index = self.dyld_private_atom.?.sym_index; + const dyld_private_sym_index = self.dyld_private_atom.?.getSymbolIndex().?; const code = try gpa.alloc(u8, size); defer gpa.free(code); @@ -1258,7 +1244,6 @@ pub fn createStubHelperPreambleAtom(self: *MachO) !void { self.stub_helper_preamble_atom = atom; try self.managed_atoms.append(gpa, atom); - try self.atom_by_index_table.putNoClobber(gpa, sym_index, atom); sym.n_value = try self.allocateAtom(atom, size, atom.alignment); log.debug("allocated stub preamble atom at 0x{x}", .{sym.n_value}); @@ -1273,18 +1258,14 @@ pub fn createStubHelperAtom(self: *MachO) !*Atom { .aarch64 => 3 * @sizeOf(u32), else => unreachable, }; - const sym_index = try self.allocateSymbol(); - const atom = blk: { - const atom = try gpa.create(Atom); - atom.* = Atom.empty; - atom.sym_index = sym_index; - atom.size = size; - atom.alignment = switch (arch) { - .x86_64 => 1, - .aarch64 => @alignOf(u32), - else => unreachable, - }; - break :blk atom; + const atom = try gpa.create(Atom); + atom.* = Atom.empty; + try atom.ensureInitialized(self); + atom.size = size; + atom.alignment = switch (arch) { + .x86_64 => 1, + .aarch64 => @alignOf(u32), + else => unreachable, }; errdefer gpa.destroy(atom); @@ -1306,7 +1287,7 @@ pub fn createStubHelperAtom(self: *MachO) !*Atom { try atom.addRelocation(self, .{ .type = @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_BRANCH), - .target = .{ .sym_index = self.stub_helper_preamble_atom.?.sym_index, .file = null }, + .target = .{ .sym_index = self.stub_helper_preamble_atom.?.getSymbolIndex().?, .file = null }, .offset = 6, .addend = 0, .pcrel = true, @@ -1329,7 +1310,7 @@ pub fn createStubHelperAtom(self: *MachO) !*Atom { try atom.addRelocation(self, .{ .type = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_BRANCH26), - .target = .{ .sym_index = self.stub_helper_preamble_atom.?.sym_index, .file = null }, + .target = .{ .sym_index = self.stub_helper_preamble_atom.?.getSymbolIndex().?, .file = null }, .offset = 4, .addend = 0, .pcrel = true, @@ -1340,7 +1321,6 @@ pub fn createStubHelperAtom(self: *MachO) !*Atom { } try self.managed_atoms.append(gpa, atom); - try self.atom_by_index_table.putNoClobber(gpa, sym_index, atom); sym.n_value = try self.allocateAtom(atom, size, atom.alignment); log.debug("allocated stub helper atom at 0x{x}", .{sym.n_value}); @@ -1351,15 +1331,11 @@ pub fn createStubHelperAtom(self: *MachO) !*Atom { pub fn createLazyPointerAtom(self: *MachO, stub_sym_index: u32, target: SymbolWithLoc) !*Atom { const gpa = self.base.allocator; - const sym_index = try self.allocateSymbol(); - const atom = blk: { - const atom = try gpa.create(Atom); - atom.* = Atom.empty; - atom.sym_index = sym_index; - atom.size = @sizeOf(u64); - atom.alignment = @alignOf(u64); - break :blk atom; - }; + const atom = try gpa.create(Atom); + atom.* = Atom.empty; + try atom.ensureInitialized(self); + atom.size = @sizeOf(u64); + atom.alignment = @alignOf(u64); errdefer gpa.destroy(atom); const sym = atom.getSymbolPtr(self); @@ -1385,7 +1361,6 @@ pub fn createLazyPointerAtom(self: *MachO, stub_sym_index: u32, target: SymbolWi }); try self.managed_atoms.append(gpa, atom); - try self.atom_by_index_table.putNoClobber(gpa, sym_index, atom); sym.n_value = try self.allocateAtom(atom, atom.size, @alignOf(u64)); log.debug("allocated lazy pointer atom at 0x{x} ({s})", .{ sym.n_value, self.getSymbolName(target) }); @@ -1402,19 +1377,15 @@ pub fn createStubAtom(self: *MachO, laptr_sym_index: u32) !*Atom { .aarch64 => 3 * @sizeOf(u32), else => unreachable, // unhandled architecture type }; - const sym_index = try self.allocateSymbol(); - const atom = blk: { - const atom = try gpa.create(Atom); - atom.* = Atom.empty; - atom.sym_index = sym_index; - atom.size = size; - atom.alignment = switch (arch) { - .x86_64 => 1, - .aarch64 => @alignOf(u32), - else => unreachable, // unhandled architecture type + const atom = try gpa.create(Atom); + atom.* = Atom.empty; + try atom.ensureInitialized(self); + atom.size = size; + atom.alignment = switch (arch) { + .x86_64 => 1, + .aarch64 => @alignOf(u32), + else => unreachable, // unhandled architecture type - }; - break :blk atom; }; errdefer gpa.destroy(atom); @@ -1476,7 +1447,6 @@ pub fn createStubAtom(self: *MachO, laptr_sym_index: u32) !*Atom { } try self.managed_atoms.append(gpa, atom); - try self.atom_by_index_table.putNoClobber(gpa, sym_index, atom); sym.n_value = try self.allocateAtom(atom, size, atom.alignment); log.debug("allocated stub atom at 0x{x}", .{sym.n_value}); @@ -1617,9 +1587,9 @@ pub fn resolveSymbolsInDylibs(self: *MachO) !void { const stub_index = try self.allocateStubEntry(global); const stub_helper_atom = try self.createStubHelperAtom(); - const laptr_atom = try self.createLazyPointerAtom(stub_helper_atom.sym_index, global); - const stub_atom = try self.createStubAtom(laptr_atom.sym_index); - self.stubs.items[stub_index].sym_index = stub_atom.sym_index; + const laptr_atom = try self.createLazyPointerAtom(stub_helper_atom.getSymbolIndex().?, global); + const stub_atom = try self.createStubAtom(laptr_atom.getSymbolIndex().?); + self.stubs.items[stub_index].sym_index = stub_atom.getSymbolIndex().?; self.markRelocsDirtyByTarget(global); } @@ -1717,7 +1687,7 @@ pub fn resolveDyldStubBinder(self: *MachO) !void { // Add dyld_stub_binder as the final GOT entry. const got_index = try self.allocateGotEntry(global); const got_atom = try self.createGotAtom(global); - self.got_entries.items[got_index].sym_index = got_atom.sym_index; + self.got_entries.items[got_index].sym_index = got_atom.getSymbolIndex().?; try self.writePtrWidthAtom(got_atom); } @@ -2098,14 +2068,11 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Modu const atom = try gpa.create(Atom); errdefer gpa.destroy(atom); atom.* = Atom.empty; - - atom.sym_index = try self.allocateSymbol(); - + try atom.ensureInitialized(self); try self.managed_atoms.append(gpa, atom); - try self.atom_by_index_table.putNoClobber(gpa, atom.sym_index, atom); const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), typed_value, &code_buffer, .none, .{ - .parent_atom_index = atom.sym_index, + .parent_atom_index = atom.getSymbolIndex().?, }); const code = switch (res) { .ok => code_buffer.items, @@ -2137,7 +2104,7 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Modu try self.writeAtom(atom, code); - return atom.sym_index; + return atom.getSymbolIndex().?; } pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index) !void { @@ -2188,14 +2155,14 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index) }, &code_buffer, .{ .dwarf = ds, }, .{ - .parent_atom_index = decl.link.macho.sym_index, + .parent_atom_index = decl.link.macho.getSymbolIndex().?, }) else try codegen.generateSymbol(&self.base, decl.srcLoc(), .{ .ty = decl.ty, .val = decl_val, }, &code_buffer, .none, .{ - .parent_atom_index = decl.link.macho.sym_index, + .parent_atom_index = decl.link.macho.getSymbolIndex().?, }); const code = switch (res) { -- 2.54.0 From 3c6c4f88bbedef9579f16f0454998c9dcd7663da Mon Sep 17 00:00:00 2001 From: Takeshi Yoneda Date: Thu, 26 Jan 2023 20:13:07 +0900 Subject: [PATCH 09/84] wasm: uses main instead of main2 for test runner Signed-off-by: Takeshi Yoneda --- lib/test_runner.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/test_runner.zig b/lib/test_runner.zig index d1e5683c98dfea3967410c6c8d3b9115b3de9dd1..3f57b42bf57c0c77a16f8337df2ee7dc374297c3 100644 --- a/lib/test_runner.zig +++ b/lib/test_runner.zig @@ -11,7 +11,7 @@ var log_err_count: usize = 0; pub fn main() void { if (builtin.zig_backend != .stage1 and - (builtin.zig_backend != .stage2_llvm or builtin.cpu.arch == .wasm32) and + builtin.zig_backend != .stage2_llvm and builtin.zig_backend != .stage2_c) { return main2() catch @panic("test failure"); -- 2.54.0 From ce20ebb50c216b67b40c80915c9ebd409afa05db Mon Sep 17 00:00:00 2001 From: Takeshi Yoneda Date: Thu, 26 Jan 2023 17:56:41 +0900 Subject: [PATCH 10/84] wasi: remove unnecessary breakpoint() in abort Signed-off-by: Takeshi Yoneda --- lib/std/os.zig | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/std/os.zig b/lib/std/os.zig index b71b17243dc4c152e93376a56d7048b397e6a084..74c7d43dbc6d76585420247aabd115022b8d5f7b 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -550,7 +550,6 @@ pub fn abort() noreturn { exit(0); // TODO choose appropriate exit code } if (builtin.os.tag == .wasi) { - @breakpoint(); exit(1); } if (builtin.os.tag == .cuda) { -- 2.54.0 From 97b1a9bb6bcf1b293c3da5e3a3bfd829016c0e85 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 26 Jan 2023 12:22:39 -0700 Subject: [PATCH 11/84] cmake: no -Werror on the C++ code we copy from llvm --- CMakeLists.txt | 45 +++++++++------------------------------------ 1 file changed, 9 insertions(+), 36 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 662bd09cdba4da675dbce3053bf89d6d47ce594f..8a9de7bdc1f3de7d772f5059792cfff1e4c7bb21 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -654,46 +654,19 @@ include_directories( "${CMAKE_SOURCE_DIR}/src" ) -# These have to go before the -Wno- flags if(MSVC) set(EXE_CXX_FLAGS "/std:c++14") -else(MSVC) - set(EXE_CXX_FLAGS "-std=c++14") -endif(MSVC) - -if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") - if(MSVC) - set(EXE_CXX_FLAGS "${EXE_CXX_FLAGS} /w") - else() - set(EXE_CXX_FLAGS "${EXE_CXX_FLAGS} -Werror -Wall") - # fallthrough support was added in GCC 7.0 - if(NOT CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 7.0) - set(EXE_CXX_FLAGS "${EXE_CXX_FLAGS} -Werror=implicit-fallthrough") - endif() - # GCC 9.2 and older are unable to detect valid variable initialization in some cases - if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS_EQUAL 9.2) - set(EXE_CXX_FLAGS "${EXE_CXX_FLAGS} -Wno-maybe-uninitialized") - endif() - endif() -endif() - -if(MSVC) - set(EXE_CXX_FLAGS "${EXE_CXX_FLAGS}") + set(EXE_LDFLAGS "/STACK:16777216") + if(NOT "${CMAKE_BUILD_TYPE}" STREQUAL "Release" AND NOT "${CMAKE_BUILD_TYPE}" STREQUAL "MinSizeRel") + set(EXE_LDFLAGS "${EXE_LDFLAGS} /debug:fastlink") + endif() else() - set(EXE_CXX_FLAGS "${EXE_CXX_FLAGS} -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -D_GNU_SOURCE -fvisibility-inlines-hidden -fno-exceptions -fno-rtti -Werror=type-limits -Wno-missing-braces -Wno-comment") - if(MINGW) - set(EXE_CXX_FLAGS "${EXE_CXX_FLAGS} -Wno-format") - endif() -endif() - -set(EXE_LDFLAGS " ") -if(MSVC) - set(EXE_LDFLAGS "${EXE_LDFLAGS} /STACK:16777216") - if(NOT "${CMAKE_BUILD_TYPE}" STREQUAL "Release" AND NOT "${CMAKE_BUILD_TYPE}" STREQUAL "MinSizeRel") - set(EXE_LDFLAGS "${EXE_LDFLAGS} /debug:fastlink") - endif() -elseif(MINGW) + set(EXE_CXX_FLAGS "-std=c++14 -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -D_GNU_SOURCE -fvisibility-inlines-hidden -fno-exceptions -fno-rtti -Werror=type-limits -Wno-missing-braces -Wno-comment") + set(EXE_LDFLAGS " ") + if(MINGW) + set(EXE_CXX_FLAGS "${EXE_CXX_FLAGS} -Wno-format") set(EXE_LDFLAGS "${EXE_LDFLAGS} -Wl,--stack,16777216") + endif() endif() if(ZIG_STATIC) -- 2.54.0 From b25efb86e1b1b2a9e8aa269bf83b717d54f7e276 Mon Sep 17 00:00:00 2001 From: Luuk de Gram Date: Fri, 27 Jan 2023 19:24:15 +0100 Subject: [PATCH 12/84] wasm: migrate to new non-allocateDeclIndexes API --- src/Module.zig | 1 + src/arch/wasm/CodeGen.zig | 13 ++++++-- src/link.zig | 2 +- src/link/Wasm.zig | 70 +++++++++++++++++---------------------- src/link/Wasm/Atom.zig | 11 ++++++ 5 files changed, 53 insertions(+), 44 deletions(-) diff --git a/src/Module.zig b/src/Module.zig index 360dd4d1ecada8a7b48d0bda4ecb9c486a00d1d0..713680c5fa677fcb4abd2295018871e597e7abe6 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -5328,6 +5328,7 @@ pub fn deleteUnusedDecl(mod: *Module, decl_index: Decl.Index) void { .elf, .macho, .c, + .wasm, => {}, // this linker backend has already migrated to the new API else => if (decl.has_tv) { diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index a7d90a8bf9f24b1997fac978853404a2f3869066..342d6b70cc55ef3a8273729323010135a555a066 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -2120,22 +2120,28 @@ fn airCall(func: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModif const module = func.bin_file.base.options.module.?; if (func_val.castTag(.function)) |function| { - break :blk module.declPtr(function.data.owner_decl); + const decl = module.declPtr(function.data.owner_decl); + try decl.link.wasm.ensureInitialized(func.bin_file); + break :blk decl; } else if (func_val.castTag(.extern_fn)) |extern_fn| { const ext_decl = module.declPtr(extern_fn.data.owner_decl); const ext_info = ext_decl.ty.fnInfo(); var func_type = try genFunctype(func.gpa, ext_info.cc, ext_info.param_types, ext_info.return_type, func.target); defer func_type.deinit(func.gpa); + const atom = &ext_decl.link.wasm; + try atom.ensureInitialized(func.bin_file); ext_decl.fn_link.wasm.type_index = try func.bin_file.putOrGetFuncType(func_type); try func.bin_file.addOrUpdateImport( mem.sliceTo(ext_decl.name, 0), - ext_decl.link.wasm.sym_index, + atom.getSymbolIndex().?, ext_decl.getExternFn().?.lib_name, ext_decl.fn_link.wasm.type_index, ); break :blk ext_decl; } else if (func_val.castTag(.decl_ref)) |decl_ref| { - break :blk module.declPtr(decl_ref.data); + const decl = module.declPtr(decl_ref.data); + try decl.link.wasm.ensureInitialized(func.bin_file); + break :blk decl; } return func.fail("Expected a function, but instead found type '{}'", .{func_val.tag()}); }; @@ -2752,6 +2758,7 @@ fn lowerDeclRefValue(func: *CodeGen, tv: TypedValue, decl_index: Module.Decl.Ind } module.markDeclAlive(decl); + try decl.link.wasm.ensureInitialized(func.bin_file); const target_sym_index = decl.link.wasm.sym_index; if (decl.ty.zigTypeTag() == .Fn) { diff --git a/src/link.zig b/src/link.zig index 9be5b9ca3aa277bafeb4e736d5dca2b8aad62dee..f9081499a8c00ac5f76e8ec134e141baa849c5b2 100644 --- a/src/link.zig +++ b/src/link.zig @@ -615,7 +615,6 @@ pub const File = struct { return; } switch (base.tag) { - .wasm => return @fieldParentPtr(Wasm, "base", base).allocateDeclIndexes(decl_index), .plan9 => return @fieldParentPtr(Plan9, "base", base).allocateDeclIndexes(decl_index), .coff, @@ -624,6 +623,7 @@ pub const File = struct { .c, .spirv, .nvptx, + .wasm, => {}, } } diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index 7129722d16bd9e03c8653e1307da211473469470..31dfb87659a113e2c202a42b32efc5ead1016652 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -986,31 +986,23 @@ pub fn deinit(wasm: *Wasm) void { } } -pub fn allocateDeclIndexes(wasm: *Wasm, decl_index: Module.Decl.Index) !void { - if (wasm.llvm_object) |_| return; - const decl = wasm.base.options.module.?.declPtr(decl_index); - if (decl.link.wasm.sym_index != 0) return; - +/// Allocates a new symbol and returns its index. +/// Will re-use slots when a symbol was freed at an earlier stage. +pub fn allocateSymbol(wasm: *Wasm) !u32 { try wasm.symbols.ensureUnusedCapacity(wasm.base.allocator, 1); - try wasm.decls.putNoClobber(wasm.base.allocator, decl_index, {}); - - const atom = &decl.link.wasm; - var symbol: Symbol = .{ .name = undefined, // will be set after updateDecl .flags = @enumToInt(Symbol.Flag.WASM_SYM_BINDING_LOCAL), .tag = undefined, // will be set after updateDecl .index = undefined, // will be set after updateDecl }; - if (wasm.symbols_free_list.popOrNull()) |index| { - atom.sym_index = index; wasm.symbols.items[index] = symbol; - } else { - atom.sym_index = @intCast(u32, wasm.symbols.items.len); - wasm.symbols.appendAssumeCapacity(symbol); + return index; } - try wasm.symbol_atom.putNoClobber(wasm.base.allocator, atom.symbolLoc(), atom); + const index = @intCast(u32, wasm.symbols.items.len); + wasm.symbols.appendAssumeCapacity(symbol); + return index; } pub fn updateFunc(wasm: *Wasm, mod: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void { @@ -1026,9 +1018,12 @@ pub fn updateFunc(wasm: *Wasm, mod: *Module, func: *Module.Fn, air: Air, livenes const decl_index = func.owner_decl; const decl = mod.declPtr(decl_index); - assert(decl.link.wasm.sym_index != 0); // Must call allocateDeclIndexes() - - decl.link.wasm.clear(); + const atom = &decl.link.wasm; + try atom.ensureInitialized(wasm); + const gop = try wasm.decls.getOrPut(wasm.base.allocator, decl_index); + if (gop.found_existing) { + atom.clear(); + } else gop.value_ptr.* = {}; var decl_state: ?Dwarf.DeclState = if (wasm.dwarf) |*dwarf| try dwarf.initDeclState(mod, decl_index) else null; defer if (decl_state) |*ds| ds.deinit(); @@ -1083,16 +1078,19 @@ pub fn updateDecl(wasm: *Wasm, mod: *Module, decl_index: Module.Decl.Index) !voi defer tracy.end(); const decl = mod.declPtr(decl_index); - assert(decl.link.wasm.sym_index != 0); // Must call allocateDeclIndexes() - - decl.link.wasm.clear(); - if (decl.val.castTag(.function)) |_| { return; } else if (decl.val.castTag(.extern_fn)) |_| { return; } + const atom = &decl.link.wasm; + try atom.ensureInitialized(wasm); + const gop = try wasm.decls.getOrPut(wasm.base.allocator, decl_index); + if (gop.found_existing) { + atom.clear(); + } else gop.value_ptr.* = {}; + if (decl.isExtern()) { const variable = decl.getVariable().?; const name = mem.sliceTo(decl.name, 0); @@ -1148,8 +1146,8 @@ fn finishUpdateDecl(wasm: *Wasm, decl: *Module.Decl, code: []const u8) !void { try atom.code.appendSlice(wasm.base.allocator, code); try wasm.resolved_symbols.put(wasm.base.allocator, atom.symbolLoc(), {}); + atom.size = @intCast(u32, code.len); if (code.len == 0) return; - atom.size = @intCast(u32, code.len); atom.alignment = decl.ty.abiAlignment(wasm.base.options.target); } @@ -1211,28 +1209,19 @@ pub fn lowerUnnamedConst(wasm: *Wasm, tv: TypedValue, decl_index: Module.Decl.In defer wasm.base.allocator.free(fqdn); const name = try std.fmt.allocPrintZ(wasm.base.allocator, "__unnamed_{s}_{d}", .{ fqdn, local_index }); defer wasm.base.allocator.free(name); - var symbol: Symbol = .{ - .name = try wasm.string_table.put(wasm.base.allocator, name), - .flags = 0, - .tag = .data, - .index = undefined, - }; - symbol.setFlag(.WASM_SYM_BINDING_LOCAL); const atom = try decl.link.wasm.locals.addOne(wasm.base.allocator); atom.* = Atom.empty; + try atom.ensureInitialized(wasm); atom.alignment = tv.ty.abiAlignment(wasm.base.options.target); - try wasm.symbols.ensureUnusedCapacity(wasm.base.allocator, 1); + wasm.symbols.items[atom.sym_index] = .{ + .name = try wasm.string_table.put(wasm.base.allocator, name), + .flags = @enumToInt(Symbol.Flag.WASM_SYM_BINDING_LOCAL), + .tag = .data, + .index = undefined, + }; - if (wasm.symbols_free_list.popOrNull()) |index| { - atom.sym_index = index; - wasm.symbols.items[index] = symbol; - } else { - atom.sym_index = @intCast(u32, wasm.symbols.items.len); - wasm.symbols.appendAssumeCapacity(symbol); - } try wasm.resolved_symbols.putNoClobber(wasm.base.allocator, atom.symbolLoc(), {}); - try wasm.symbol_atom.putNoClobber(wasm.base.allocator, atom.symbolLoc(), atom); var value_bytes = std.ArrayList(u8).init(wasm.base.allocator); defer value_bytes.deinit(); @@ -1304,8 +1293,8 @@ pub fn getDeclVAddr( ) !u64 { const mod = wasm.base.options.module.?; const decl = mod.declPtr(decl_index); + try decl.link.wasm.ensureInitialized(wasm); const target_symbol_index = decl.link.wasm.sym_index; - assert(target_symbol_index != 0); assert(reloc_info.parent_atom_index != 0); const atom = wasm.symbol_atom.get(.{ .file = null, .index = reloc_info.parent_atom_index }).?; const is_wasm32 = wasm.base.options.target.cpu.arch == .wasm32; @@ -1363,6 +1352,7 @@ pub fn updateDeclExports( } const decl = mod.declPtr(decl_index); + if (decl.link.wasm.getSymbolIndex() == null) return; // unititialized for (exports) |exp| { if (exp.options.section) |section| { diff --git a/src/link/Wasm/Atom.zig b/src/link/Wasm/Atom.zig index de9cefebdc1bdc49d4c630ddcbe880eb823b758e..20f847e475359b3ac069664b4358e04080fca2f2 100644 --- a/src/link/Wasm/Atom.zig +++ b/src/link/Wasm/Atom.zig @@ -95,6 +95,17 @@ pub fn symbolLoc(atom: Atom) Wasm.SymbolLoc { return .{ .file = atom.file, .index = atom.sym_index }; } +pub fn ensureInitialized(atom: *Atom, wasm_bin: *Wasm) !void { + if (atom.getSymbolIndex() != null) return; // already initialized + atom.sym_index = try wasm_bin.allocateSymbol(); + try wasm_bin.symbol_atom.putNoClobber(wasm_bin.base.allocator, atom.symbolLoc(), atom); +} + +pub fn getSymbolIndex(atom: Atom) ?u32 { + if (atom.sym_index == 0) return null; + return atom.sym_index; +} + /// Returns the virtual address of the `Atom`. This is the address starting /// from the first entry within a section. pub fn getVA(atom: Atom, wasm: *const Wasm, symbol: *const Symbol) u32 { -- 2.54.0 From a8987291390d80ad9e2bb45ba225313a108eed0b Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Fri, 27 Jan 2023 19:51:06 +0100 Subject: [PATCH 13/84] self-hosted: remove allocateDeclIndexes from the public link.File API --- src/Module.zig | 26 -------------------------- src/Sema.zig | 1 - src/link.zig | 35 +++-------------------------------- src/link/Plan9.zig | 9 ++------- 4 files changed, 5 insertions(+), 66 deletions(-) diff --git a/src/Module.zig b/src/Module.zig index 713680c5fa677fcb4abd2295018871e597e7abe6..dcdbeec3221e5558c1585e49bf9e25725245e924 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -4585,7 +4585,6 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { // We don't fully codegen the decl until later, but we do need to reserve a global // offset table index for it. This allows us to codegen decls out of dependency // order, increasing how many computations can be done in parallel. - try mod.comp.bin_file.allocateDeclIndexes(decl_index); try mod.comp.work_queue.writeItem(.{ .codegen_func = func }); if (type_changed and mod.emit_h != null) { try mod.comp.work_queue.writeItem(.{ .emit_h_decl = decl_index }); @@ -4697,7 +4696,6 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { // codegen backend wants full access to the Decl Type. try sema.resolveTypeFully(decl.ty); - try mod.comp.bin_file.allocateDeclIndexes(decl_index); try mod.comp.work_queue.writeItem(.{ .codegen_decl = decl_index }); if (type_changed and mod.emit_h != null) { @@ -5315,29 +5313,6 @@ pub fn deleteUnusedDecl(mod: *Module, decl_index: Decl.Index) void { const decl = mod.declPtr(decl_index); log.debug("deleteUnusedDecl {d} ({s})", .{ decl_index, decl.name }); - // TODO: remove `allocateDeclIndexes` and make the API that the linker backends - // are required to notice the first time `updateDecl` happens and keep track - // of it themselves. However they can rely on getting a `freeDecl` call if any - // `updateDecl` or `updateFunc` calls happen. This will allow us to avoid any call - // into the linker backend here, since the linker backend will never have been told - // about the Decl in the first place. - // Until then, we did call `allocateDeclIndexes` on this anonymous Decl and so we - // must call `freeDecl` in the linker backend now. - switch (mod.comp.bin_file.tag) { - .coff, - .elf, - .macho, - .c, - .wasm, - => {}, // this linker backend has already migrated to the new API - - else => if (decl.has_tv) { - if (decl.ty.isFnOrHasRuntimeBits()) { - mod.comp.bin_file.freeDecl(decl_index); - } - }, - } - assert(!mod.declIsRoot(decl_index)); assert(decl.src_namespace.anon_decls.swapRemove(decl_index)); @@ -5822,7 +5797,6 @@ pub fn initNewAnonDecl( // the Decl will be garbage collected by the `codegen_decl` task instead of sent // to the linker. if (typed_value.ty.isFnOrHasRuntimeBits()) { - try mod.comp.bin_file.allocateDeclIndexes(new_decl_index); try mod.comp.anon_work_queue.writeItem(.{ .codegen_decl = new_decl_index }); } } diff --git a/src/Sema.zig b/src/Sema.zig index 2e57de2406453ff3a925f5add50fa259f69004b0..9c553a009236fb83279a65872a877465452601be 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -7510,7 +7510,6 @@ fn resolveGenericInstantiationType( // Queue up a `codegen_func` work item for the new Fn. The `comptime_args` field // will be populated, ensuring it will have `analyzeBody` called with the ZIR // parameters mapped appropriately. - try mod.comp.bin_file.allocateDeclIndexes(new_decl_index); try mod.comp.work_queue.writeItem(.{ .codegen_func = new_func }); return new_func; } diff --git a/src/link.zig b/src/link.zig index f9081499a8c00ac5f76e8ec134e141baa849c5b2..668c5b72e30a9d2c091c64f3c2cb4eb3ec141638 100644 --- a/src/link.zig +++ b/src/link.zig @@ -533,8 +533,7 @@ pub const File = struct { } } - /// May be called before or after updateDeclExports but must be called - /// after allocateDeclIndexes for any given Decl. + /// May be called before or after updateDeclExports for any given Decl. pub fn updateDecl(base: *File, module: *Module, decl_index: Module.Decl.Index) UpdateDeclError!void { const decl = module.declPtr(decl_index); log.debug("updateDecl {*} ({s}), type={}", .{ decl, decl.name, decl.ty.fmtDebug() }); @@ -557,8 +556,7 @@ pub const File = struct { } } - /// May be called before or after updateDeclExports but must be called - /// after allocateDeclIndexes for any given Decl. + /// May be called before or after updateDeclExports for any given Decl. pub fn updateFunc(base: *File, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) UpdateDeclError!void { const owner_decl = module.declPtr(func.owner_decl); log.debug("updateFunc {*} ({s}), type={}", .{ @@ -602,32 +600,6 @@ pub const File = struct { } } - /// Must be called before any call to updateDecl or updateDeclExports for - /// any given Decl. - /// TODO we're transitioning to deleting this function and instead having - /// each linker backend notice the first time updateDecl or updateFunc is called, or - /// a callee referenced from AIR. - pub fn allocateDeclIndexes(base: *File, decl_index: Module.Decl.Index) error{OutOfMemory}!void { - const decl = base.options.module.?.declPtr(decl_index); - log.debug("allocateDeclIndexes {*} ({s})", .{ decl, decl.name }); - if (build_options.only_c) { - assert(base.tag == .c); - return; - } - switch (base.tag) { - .plan9 => return @fieldParentPtr(Plan9, "base", base).allocateDeclIndexes(decl_index), - - .coff, - .elf, - .macho, - .c, - .spirv, - .nvptx, - .wasm, - => {}, - } - } - pub fn releaseLock(self: *File) void { if (self.lock) |*lock| { lock.release(); @@ -878,8 +850,7 @@ pub const File = struct { AnalysisFail, }; - /// May be called before or after updateDecl, but must be called after - /// allocateDeclIndexes for any given Decl. + /// May be called before or after updateDecl for any given Decl. pub fn updateDeclExports( base: *File, module: *Module, diff --git a/src/link/Plan9.zig b/src/link/Plan9.zig index e412c78f7fdfa0a0c1624bf0c3cfbe276460dbe3..a8b8caafab0f98ac72bf3009451b3c7e7e1b29d2 100644 --- a/src/link/Plan9.zig +++ b/src/link/Plan9.zig @@ -424,7 +424,7 @@ fn updateFinish(self: *Plan9, decl: *Module.Decl) !void { // write the internal linker metadata decl.link.plan9.type = sym_t; // write the symbol - // we already have the got index because that got allocated in allocateDeclIndexes + // we already have the got index const sym: aout.Sym = .{ .value = undefined, // the value of stuff gets filled in in flushModule .type = decl.link.plan9.type, @@ -737,7 +737,7 @@ fn addDeclExports( pub fn freeDecl(self: *Plan9, decl_index: Module.Decl.Index) void { // TODO audit the lifetimes of decls table entries. It's possible to get - // allocateDeclIndexes and then freeDecl without any updateDecl in between. + // freeDecl without any updateDecl in between. // However that is planned to change, see the TODO comment in Module.zig // in the deleteUnusedDecl function. const mod = self.base.options.module.?; @@ -959,11 +959,6 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void { } } -/// this will be removed, moved to updateFinish -pub fn allocateDeclIndexes(self: *Plan9, decl_index: Module.Decl.Index) !void { - _ = self; - _ = decl_index; -} /// Must be called only after a successful call to `updateDecl`. pub fn updateDeclLineNumber(self: *Plan9, mod: *Module, decl: *const Module.Decl) !void { _ = self; -- 2.54.0 From f68d3c63df0486c7039732ef442c87fcd7c6fc57 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 27 Jan 2023 14:53:17 -0700 Subject: [PATCH 14/84] CI: give x86_64-linux-release a little more time When the CPU cores are pegged, the thermal throttling kicks in and makes jobs take significantly longer. --- .github/workflows/ci.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 8f0bcb7b964131f8b0337096f11c9b1a2dd6223c..6bb0ce4a1b5b9d12d883e9614819be22ef4bc8c8 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -18,6 +18,7 @@ jobs: - name: Build and Test run: sh ci/x86_64-linux-debug.sh x86_64-linux-release: + timeout-minutes: 420 runs-on: [self-hosted, Linux, x86_64] steps: - name: Checkout -- 2.54.0 From 4c116841840bfa7f0068bef23984dd832da8a54d Mon Sep 17 00:00:00 2001 From: Jon-Eric Cook Date: Sat, 28 Jan 2023 08:26:36 -0800 Subject: [PATCH 15/84] std.json: check output and source lengths in `std.json` --- lib/std/json.zig | 3 ++- lib/std/json/test.zig | 6 ++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/std/json.zig b/lib/std/json.zig index f16d70da80428cd77aa62784b2605d183148666c..92afeead900b28dcfb6215e7f498ca2648a1a175 100644 --- a/lib/std/json.zig +++ b/lib/std/json.zig @@ -1384,7 +1384,7 @@ fn ParseInternalErrorImpl(comptime T: type, comptime inferred_types: []const typ return errors; }, .Array => |arrayInfo| { - return error{ UnexpectedEndOfJson, UnexpectedToken } || TokenStream.Error || + return error{ UnexpectedEndOfJson, UnexpectedToken, LengthMismatch } || TokenStream.Error || UnescapeValidStringError || ParseInternalErrorImpl(arrayInfo.child, inferred_types ++ [_]type{T}); }, @@ -1625,6 +1625,7 @@ fn parseInternal( if (arrayInfo.child != u8) return error.UnexpectedToken; var r: T = undefined; const source_slice = stringToken.slice(tokens.slice, tokens.i - 1); + if (r.len != stringToken.decodedLength()) return error.LengthMismatch; switch (stringToken.escapes) { .None => mem.copy(u8, &r, source_slice), .Some => try unescapeValidString(&r, source_slice), diff --git a/lib/std/json/test.zig b/lib/std/json/test.zig index 2a590fdf152b9f81af61d522bdf66ae1bc24ef7e..0bf07975871668e37199ebf069a9adabda7d82d7 100644 --- a/lib/std/json/test.zig +++ b/lib/std/json/test.zig @@ -2238,6 +2238,12 @@ test "parse into struct with no fields" { try testing.expectEqual(T{}, try parse(T, &ts, ParseOptions{})); } +test "parse into struct where destination and source lengths mismatch" { + const T = struct { a: [2]u8 }; + var ts = TokenStream.init("{\"a\": \"bbb\"}"); + try testing.expectError(error.LengthMismatch, parse(T, &ts, ParseOptions{})); +} + test "parse into struct with misc fields" { @setEvalBranchQuota(10000); const options = ParseOptions{ .allocator = testing.allocator }; -- 2.54.0 From 2b27bc2c65195a82e96995669314a86c76203a3e Mon Sep 17 00:00:00 2001 From: zigster64 Date: Tue, 22 Nov 2022 13:54:33 +1000 Subject: [PATCH 16/84] On BrokenPipe error during os.sendfile - return error rather than unreachable --- lib/std/os.zig | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/std/os.zig b/lib/std/os.zig index 74c7d43dbc6d76585420247aabd115022b8d5f7b..32463aa30ebef36e381fdb0088f42669c7d90809 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -6028,7 +6028,7 @@ pub fn sendfile( .BADF => unreachable, // Always a race condition. .FAULT => unreachable, // Segmentation fault. .OVERFLOW => unreachable, // We avoid passing too large of a `count`. - .NOTCONN => unreachable, // `out_fd` is an unconnected socket. + .NOTCONN => return error.BrokenPipe, // `out_fd` is an unconnected socket .INVAL, .NOSYS => { // EINVAL could be any of the following situations: @@ -6096,7 +6096,7 @@ pub fn sendfile( .BADF => unreachable, // Always a race condition. .FAULT => unreachable, // Segmentation fault. - .NOTCONN => unreachable, // `out_fd` is an unconnected socket. + .NOTCONN => return error.BrokenPipe, // `out_fd` is an unconnected socket .INVAL, .OPNOTSUPP, .NOTSOCK, .NOSYS => { // EINVAL could be any of the following situations: @@ -6178,7 +6178,7 @@ pub fn sendfile( .BADF => unreachable, // Always a race condition. .FAULT => unreachable, // Segmentation fault. .INVAL => unreachable, - .NOTCONN => unreachable, // `out_fd` is an unconnected socket. + .NOTCONN => return error.BrokenPipe, // `out_fd` is an unconnected socket .OPNOTSUPP, .NOTSOCK, .NOSYS => break :sf, @@ -6472,7 +6472,7 @@ pub fn recvfrom( .BADF => unreachable, // always a race condition .FAULT => unreachable, .INVAL => unreachable, - .NOTCONN => unreachable, + .NOTCONN => return error.SocketNotConnected, .NOTSOCK => unreachable, .INTR => continue, .AGAIN => return error.WouldBlock, -- 2.54.0 From 599b3ef9e947f044799d11aecf0dfe659f9a7728 Mon Sep 17 00:00:00 2001 From: Michael Dusan Date: Fri, 27 Jan 2023 13:27:41 -0500 Subject: [PATCH 17/84] netbsd: use versioned __msync13 from libc The system linker shows warning when `msync` is linked instead of `__msync13`: "warning: reference to compatibility msync(); include for correct reference" closes #14422 --- lib/std/c.zig | 3 ++- lib/std/c/netbsd.zig | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/std/c.zig b/lib/std/c.zig index de3ebe15a8930ddde269531bbd5e717bb4ea65f3..57d5beae56b325547b5605af2528c025da88d51a 100644 --- a/lib/std/c.zig +++ b/lib/std/c.zig @@ -90,6 +90,8 @@ pub usingnamespace switch (builtin.os.tag) { pub extern "c" fn stat(noalias path: [*:0]const u8, noalias buf: *c.Stat) c_int; pub extern "c" fn alarm(seconds: c_uint) c_uint; + + pub extern "c" fn msync(addr: *align(page_size) const anyopaque, len: usize, flags: c_int) c_int; }, }; @@ -145,7 +147,6 @@ pub extern "c" fn write(fd: c.fd_t, buf: [*]const u8, nbyte: usize) isize; pub extern "c" fn pwrite(fd: c.fd_t, buf: [*]const u8, nbyte: usize, offset: c.off_t) isize; pub extern "c" fn mmap(addr: ?*align(page_size) anyopaque, len: usize, prot: c_uint, flags: c_uint, fd: c.fd_t, offset: c.off_t) *anyopaque; pub extern "c" fn munmap(addr: *align(page_size) const anyopaque, len: usize) c_int; -pub extern "c" fn msync(addr: *align(page_size) const anyopaque, len: usize, flags: c_int) c_int; pub extern "c" fn mprotect(addr: *align(page_size) anyopaque, len: usize, prot: c_uint) c_int; pub extern "c" fn link(oldpath: [*:0]const u8, newpath: [*:0]const u8, flags: c_int) c_int; pub extern "c" fn linkat(oldfd: c.fd_t, oldpath: [*:0]const u8, newfd: c.fd_t, newpath: [*:0]const u8, flags: c_int) c_int; diff --git a/lib/std/c/netbsd.zig b/lib/std/c/netbsd.zig index bcd0291bb2f31e4d503c7d71e4b893dc536a54c4..579e25d416e043f84de491f86e27093d6be53bed 100644 --- a/lib/std/c/netbsd.zig +++ b/lib/std/c/netbsd.zig @@ -59,6 +59,9 @@ pub const sched_yield = __libc_thr_yield; pub extern "c" fn posix_memalign(memptr: *?*anyopaque, alignment: usize, size: usize) c_int; +pub extern "c" fn __msync13(addr: *align(std.mem.page_size) const anyopaque, len: usize, flags: c_int) c_int; +pub const msync = __msync13; + pub const pthread_mutex_t = extern struct { magic: u32 = 0x33330003, errorcheck: padded_pthread_spin_t = 0, -- 2.54.0 From 76fcb95bdf5509f6b02ca8c68af2b8f630a6cfe0 Mon Sep 17 00:00:00 2001 From: Krzysztof Wolicki Der Teufel Date: Sun, 29 Jan 2023 14:42:18 +0100 Subject: [PATCH 18/84] autodoc: Implemented struct_init_empty for walkInstruction, fixed variable type with has_init but no type before = --- src/Autodoc.zig | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/src/Autodoc.zig b/src/Autodoc.zig index 8afc9c859b5a7aa8c2b2d0eaa94f884db411c3b8..e51d4a3ca933f0ba22dfe6a5938738ca6b33557c 100644 --- a/src/Autodoc.zig +++ b/src/Autodoc.zig @@ -2200,17 +2200,10 @@ fn walkInstruction( false, ); - _ = operand; - - // WIP - - printWithContext( - file, - inst_index, - "TODO: implement `{s}` for walkInstruction\n\n", - .{@tagName(tags[inst_index])}, - ); - return self.cteTodo(@tagName(tags[inst_index])); + return DocData.WalkResult{ + .typeRef = operand.expr, + .expr = .{ .@"struct" = &.{} }, + }; }, .struct_init_anon => { const pl_node = data[inst_index].pl_node; @@ -2537,6 +2530,7 @@ fn walkInstruction( const var_init_ref = @intToEnum(Ref, file.zir.extra[extra_index]); const var_init = try self.walkRef(file, parent_scope, parent_src, var_init_ref, need_type); value.expr = var_init.expr; + value.typeRef = var_init.typeRef; } return value; -- 2.54.0 From 090186a0c26447d99417dad9f1ba8bde49579191 Mon Sep 17 00:00:00 2001 From: joachimschmidt557 Date: Mon, 23 Jan 2023 21:08:43 +0100 Subject: [PATCH 19/84] stage2 AArch64: move copy-register-arg-to-stack code to fn prologue This enhances the debugging experience as upon encountering a breakpoint in a function, all arguments passed as registers have already been moved to the stack, ready to be inspected by the debugger. --- src/arch/aarch64/CodeGen.zig | 57 +++++++++++++++++------------------- 1 file changed, 27 insertions(+), 30 deletions(-) diff --git a/src/arch/aarch64/CodeGen.zig b/src/arch/aarch64/CodeGen.zig index 200bf3b8e079bd604be9a57ec5624b4325eb73b8..0efd34937a0281c7818bf1a146fd3184f5c5c3fe 100644 --- a/src/arch/aarch64/CodeGen.zig +++ b/src/arch/aarch64/CodeGen.zig @@ -181,6 +181,7 @@ const DbgInfoReloc = struct { else => unreachable, } } + fn genArgDbgInfo(reloc: DbgInfoReloc, function: Self) error{OutOfMemory}!void { switch (function.debug_output) { .dwarf => |dw| { @@ -527,6 +528,28 @@ fn gen(self: *Self) !void { self.ret_mcv = MCValue{ .stack_offset = stack_offset }; } + for (self.args) |*arg, arg_index| { + // Copy register arguments to the stack + switch (arg.*) { + .register => |reg| { + // The first AIR instructions of the main body are guaranteed + // to be the functions arguments + const inst = self.air.getMainBody()[arg_index]; + assert(self.air.instructions.items(.tag)[inst] == .arg); + + const ty = self.air.typeOfIndex(inst); + + const abi_size = @intCast(u32, ty.abiSize(self.target.*)); + const abi_align = ty.abiAlignment(self.target.*); + const stack_offset = try self.allocMem(abi_size, abi_align, inst); + try self.genSetStack(ty, stack_offset, MCValue{ .register = reg }); + + arg.* = MCValue{ .stack_offset = stack_offset }; + }, + else => {}, + } + } + _ = try self.addInst(.{ .tag = .dbg_prologue_end, .data = .{ .nop = {} }, @@ -4163,45 +4186,19 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { self.arg_index += 1; const ty = self.air.typeOfIndex(inst); - const result = self.args[arg_index]; + const tag = self.air.instructions.items(.tag)[inst]; const src_index = self.air.instructions.items(.data)[inst].arg.src_index; const name = self.mod_fn.getParamName(self.bin_file.options.module.?, src_index); - const mcv = switch (result) { - // Copy registers to the stack - .register => |reg| blk: { - const mod = self.bin_file.options.module.?; - const abi_size = math.cast(u32, ty.abiSize(self.target.*)) orelse { - return self.fail("type '{}' too big to fit into stack frame", .{ty.fmt(mod)}); - }; - const abi_align = ty.abiAlignment(self.target.*); - const stack_offset = try self.allocMem(abi_size, abi_align, inst); - try self.genSetStack(ty, stack_offset, MCValue{ .register = reg }); - - break :blk MCValue{ .stack_offset = stack_offset }; - }, - else => result, - }; - - const tag = self.air.instructions.items(.tag)[inst]; try self.dbg_info_relocs.append(self.gpa, .{ .tag = tag, .ty = ty, .name = name, - .mcv = result, + .mcv = self.args[arg_index], }); - if (self.liveness.isUnused(inst)) - return self.finishAirBookkeeping(); - - switch (mcv) { - .register => |reg| { - self.register_manager.getRegAssumeFree(reg, inst); - }, - else => {}, - } - - return self.finishAir(inst, mcv, .{ .none, .none, .none }); + const result: MCValue = if (self.liveness.isUnused(inst)) .dead else self.args[arg_index]; + return self.finishAir(inst, result, .{ .none, .none, .none }); } fn airBreakpoint(self: *Self) !void { -- 2.54.0 From 317d57115dc11100022f55c1bdf432b68924b4d8 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 29 Jan 2023 12:48:38 -0700 Subject: [PATCH 20/84] std.debug: disable sporadically failing test see tracking issue #13963 --- lib/std/debug.zig | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/std/debug.zig b/lib/std/debug.zig index d8c327829a9c62cf102fbfc863880ce23fc512cb..3708c4fe81bc32cad9ff0a3ac147cc111ab2efc9 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -2060,6 +2060,11 @@ pub fn dumpStackPointerAddr(prefix: []const u8) void { test "manage resources correctly" { if (builtin.os.tag == .wasi) return error.SkipZigTest; + if (builtin.os.tag == .windows and builtin.cpu.arch == .x86_64) { + // https://github.com/ziglang/zig/issues/13963 + return error.SkipZigTest; + } + const writer = std.io.null_writer; var di = try openSelfDebugInfo(testing.allocator); defer di.deinit(); -- 2.54.0 From fcb05ee2e70ab76c21211ecc2581d5d4ae5917b1 Mon Sep 17 00:00:00 2001 From: kcbanner Date: Sat, 28 Jan 2023 02:06:14 -0500 Subject: [PATCH 21/84] cbe: don't emit unused undefined array literals --- src/codegen/c.zig | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/codegen/c.zig b/src/codegen/c.zig index 68c20ea49c04ef772fec67fc98f43dab2b5ace1d..70c62a1faa9a223918e5ce4174b0f81f214d51cf 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -3726,16 +3726,15 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue { const ptr_val = try f.resolveInst(bin_op.lhs); const src_ty = f.air.typeOf(bin_op.rhs); - const src_val = try f.resolveInst(bin_op.rhs); - - try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); // TODO Sema should emit a different instruction when the store should // possibly do the safety 0xaa bytes for undefined. const src_val_is_undefined = if (f.air.value(bin_op.rhs)) |v| v.isUndefDeep() else false; - if (src_val_is_undefined) + if (src_val_is_undefined) { + try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); return try storeUndefined(f, ptr_info.pointee_type, ptr_val); + } const target = f.object.dg.module.getTarget(); const is_aligned = ptr_info.@"align" == 0 or @@ -3744,6 +3743,9 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue { const need_memcpy = !is_aligned or is_array; const writer = f.object.writer(); + const src_val = try f.resolveInst(bin_op.rhs); + try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); + if (need_memcpy) { // For this memcpy to safely work we need the rhs to have the same // underlying type as the lhs (i.e. they must both be arrays of the same underlying type). @@ -4344,8 +4346,9 @@ fn airDbgInline(f: *Function, inst: Air.Inst.Index) !CValue { fn airDbgVar(f: *Function, inst: Air.Inst.Index) !CValue { const pl_op = f.air.instructions.items(.data)[inst].pl_op; const name = f.air.nullTerminatedString(pl_op.payload); - const operand = try f.resolveInst(pl_op.operand); - _ = operand; + const operand_is_undef = if (f.air.value(pl_op.operand)) |v| v.isUndefDeep() else false; + if (!operand_is_undef) _ = try f.resolveInst(pl_op.operand); + try reap(f, inst, &.{pl_op.operand}); const writer = f.object.writer(); try writer.print("/* var:{s} */\n", .{name}); -- 2.54.0 From 9177e0da4f8e3480f5a7fade6c42f2ec81f5ffd5 Mon Sep 17 00:00:00 2001 From: Yusuf Bham Date: Fri, 27 Jan 2023 21:40:23 -0500 Subject: [PATCH 22/84] std.os.uefi: fix shift in pool allocator --- lib/std/os/uefi/pool_allocator.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/std/os/uefi/pool_allocator.zig b/lib/std/os/uefi/pool_allocator.zig index 69e2f1a37adb7d1d7c5b7816603936ae44d6b67e..8e2d9fe3fc450feeacc08b307da0856044a7907d 100644 --- a/lib/std/os/uefi/pool_allocator.zig +++ b/lib/std/os/uefi/pool_allocator.zig @@ -22,7 +22,7 @@ const UefiPoolAllocator = struct { assert(len > 0); - const ptr_align = 1 << log2_ptr_align; + const ptr_align = @as(usize, 1) << @as(Allocator.Log2Align, log2_ptr_align); const metadata_len = mem.alignForward(@sizeOf(usize), ptr_align); -- 2.54.0 From a9b68308b9eeb494524e2b7ab0d63cfa6b623cd0 Mon Sep 17 00:00:00 2001 From: kcbanner Date: Thu, 26 Jan 2023 00:45:40 -0500 Subject: [PATCH 23/84] cbe: fixes for tls, support for not linking libc, and enabling tests - cbe: Implement linksection support, to support TLS when not linking libc - cbe: Support under-aligned variables / struct fields - cbe: Support packed structs (in the C definition of packed) - windows: Fix regression with x86 _tls_array - compiler_rt: Add 128-bit atomics to compiler_rt - tests: Re-enable threadlocal tests on cbe+windows, and llvm+x86 - tests: Re-enable f80 tests that now pass - ci: change windows ci to run the CBE behaviour tests with -lc, to match how the compiler is bootstrapped - update zig1.wasm --- ci/x86_64-windows-debug.ps1 | 5 +- ci/x86_64-windows-release.ps1 | 5 +- lib/compiler_rt/atomics.zig | 104 ++++++++++++++++++++++++++++++++++ lib/std/start_windows_tls.zig | 8 ++- lib/zig.h | 24 ++++++++ src/codegen/c.zig | 54 +++++++++++++----- stage1/zig1.wasm | Bin 2367320 -> 2369157 bytes test/behavior/math.zig | 3 - test/behavior/muladd.zig | 2 - test/behavior/threadlocal.zig | 18 ++++-- 10 files changed, 190 insertions(+), 33 deletions(-) diff --git a/ci/x86_64-windows-debug.ps1 b/ci/x86_64-windows-debug.ps1 index 52d95f295935a72398d465cdd1ea0cefd3825c21..65b9fbd92adb783bb20593f06ac8f60b201f2487 100644 --- a/ci/x86_64-windows-debug.ps1 +++ b/ci/x86_64-windows-debug.ps1 @@ -76,7 +76,8 @@ Write-Output "Build x86_64-windows-msvc behavior tests using the C backend..." -ofmt=c ` -femit-bin="test-x86_64-windows-msvc.c" ` --test-no-exec ` - -target x86_64-windows-msvc + -target x86_64-windows-msvc ` + -lc CheckLastExitCode & "stage3-debug\bin\zig.exe" build-obj ` @@ -99,7 +100,7 @@ Enter-VsDevShell -VsInstallPath "C:\Program Files\Microsoft Visual Studio\2022\E CheckLastExitCode Write-Output "Build and run behavior tests with msvc..." -& cl.exe -I..\lib test-x86_64-windows-msvc.c compiler_rt-x86_64-windows-msvc.c /W3 /Z7 -link -nologo -debug -subsystem:console -entry:wWinMainCRTStartup kernel32.lib ntdll.lib vcruntime.lib libucrt.lib +& cl.exe -I..\lib test-x86_64-windows-msvc.c compiler_rt-x86_64-windows-msvc.c /W3 /Z7 -link -nologo -debug -subsystem:console kernel32.lib ntdll.lib libcmt.lib CheckLastExitCode & .\test-x86_64-windows-msvc.exe diff --git a/ci/x86_64-windows-release.ps1 b/ci/x86_64-windows-release.ps1 index 6ab689ad7c42d70b9739cd2bee512e31b5f850e1..e3375ccb72ba2dd9e4209a923e484694c4267701 100644 --- a/ci/x86_64-windows-release.ps1 +++ b/ci/x86_64-windows-release.ps1 @@ -76,7 +76,8 @@ Write-Output "Build x86_64-windows-msvc behavior tests using the C backend..." -ofmt=c ` -femit-bin="test-x86_64-windows-msvc.c" ` --test-no-exec ` - -target x86_64-windows-msvc + -target x86_64-windows-msvc ` + -lc CheckLastExitCode & "stage3-release\bin\zig.exe" build-obj ` @@ -99,7 +100,7 @@ Enter-VsDevShell -VsInstallPath "C:\Program Files\Microsoft Visual Studio\2022\E CheckLastExitCode Write-Output "Build and run behavior tests with msvc..." -& cl.exe -I..\lib test-x86_64-windows-msvc.c compiler_rt-x86_64-windows-msvc.c /W3 /Z7 -link -nologo -debug -subsystem:console -entry:wWinMainCRTStartup kernel32.lib ntdll.lib vcruntime.lib libucrt.lib +& cl.exe -I..\lib test-x86_64-windows-msvc.c compiler_rt-x86_64-windows-msvc.c /W3 /Z7 -link -nologo -debug -subsystem:console kernel32.lib ntdll.lib libcmt.lib CheckLastExitCode & .\test-x86_64-windows-msvc.exe diff --git a/lib/compiler_rt/atomics.zig b/lib/compiler_rt/atomics.zig index 73bf3fa03ba008c60f5620e3cac8dd4d467a6d8a..4db6176dc0963b86dcb5910dc6d7bb1926e7b14d 100644 --- a/lib/compiler_rt/atomics.zig +++ b/lib/compiler_rt/atomics.zig @@ -192,6 +192,10 @@ fn __atomic_load_8(src: *u64, model: i32) callconv(.C) u64 { return atomic_load_N(u64, src, model); } +fn __atomic_load_16(src: *u128, model: i32) callconv(.C) u128 { + return atomic_load_N(u128, src, model); +} + inline fn atomic_store_N(comptime T: type, dst: *T, value: T, model: i32) void { _ = model; if (@sizeOf(T) > largest_atomic_size) { @@ -219,6 +223,10 @@ fn __atomic_store_8(dst: *u64, value: u64, model: i32) callconv(.C) void { return atomic_store_N(u64, dst, value, model); } +fn __atomic_store_16(dst: *u128, value: u128, model: i32) callconv(.C) void { + return atomic_store_N(u128, dst, value, model); +} + fn wideUpdate(comptime T: type, ptr: *T, val: T, update: anytype) T { const WideAtomic = std.meta.Int(.unsigned, smallest_atomic_fetch_exch_size * 8); @@ -282,6 +290,10 @@ fn __atomic_exchange_8(ptr: *u64, val: u64, model: i32) callconv(.C) u64 { return atomic_exchange_N(u64, ptr, val, model); } +fn __atomic_exchange_16(ptr: *u128, val: u128, model: i32) callconv(.C) u128 { + return atomic_exchange_N(u128, ptr, val, model); +} + inline fn atomic_compare_exchange_N( comptime T: type, ptr: *T, @@ -327,6 +339,10 @@ fn __atomic_compare_exchange_8(ptr: *u64, expected: *u64, desired: u64, success: return atomic_compare_exchange_N(u64, ptr, expected, desired, success, failure); } +fn __atomic_compare_exchange_16(ptr: *u128, expected: *u128, desired: u128, success: i32, failure: i32) callconv(.C) i32 { + return atomic_compare_exchange_N(u128, ptr, expected, desired, success, failure); +} + inline fn fetch_op_N(comptime T: type, comptime op: std.builtin.AtomicRmwOp, ptr: *T, val: T, model: i32) T { _ = model; const Updater = struct { @@ -338,6 +354,8 @@ inline fn fetch_op_N(comptime T: type, comptime op: std.builtin.AtomicRmwOp, ptr .Nand => ~(old & new), .Or => old | new, .Xor => old ^ new, + .Max => @max(old, new), + .Min => @min(old, new), else => @compileError("unsupported atomic op"), }; } @@ -374,6 +392,10 @@ fn __atomic_fetch_add_8(ptr: *u64, val: u64, model: i32) callconv(.C) u64 { return fetch_op_N(u64, .Add, ptr, val, model); } +fn __atomic_fetch_add_16(ptr: *u128, val: u128, model: i32) callconv(.C) u128 { + return fetch_op_N(u128, .Add, ptr, val, model); +} + fn __atomic_fetch_sub_1(ptr: *u8, val: u8, model: i32) callconv(.C) u8 { return fetch_op_N(u8, .Sub, ptr, val, model); } @@ -390,6 +412,10 @@ fn __atomic_fetch_sub_8(ptr: *u64, val: u64, model: i32) callconv(.C) u64 { return fetch_op_N(u64, .Sub, ptr, val, model); } +fn __atomic_fetch_sub_16(ptr: *u128, val: u128, model: i32) callconv(.C) u128 { + return fetch_op_N(u128, .Sub, ptr, val, model); +} + fn __atomic_fetch_and_1(ptr: *u8, val: u8, model: i32) callconv(.C) u8 { return fetch_op_N(u8, .And, ptr, val, model); } @@ -406,6 +432,10 @@ fn __atomic_fetch_and_8(ptr: *u64, val: u64, model: i32) callconv(.C) u64 { return fetch_op_N(u64, .And, ptr, val, model); } +fn __atomic_fetch_and_16(ptr: *u128, val: u128, model: i32) callconv(.C) u128 { + return fetch_op_N(u128, .And, ptr, val, model); +} + fn __atomic_fetch_or_1(ptr: *u8, val: u8, model: i32) callconv(.C) u8 { return fetch_op_N(u8, .Or, ptr, val, model); } @@ -422,6 +452,10 @@ fn __atomic_fetch_or_8(ptr: *u64, val: u64, model: i32) callconv(.C) u64 { return fetch_op_N(u64, .Or, ptr, val, model); } +fn __atomic_fetch_or_16(ptr: *u128, val: u128, model: i32) callconv(.C) u128 { + return fetch_op_N(u128, .Or, ptr, val, model); +} + fn __atomic_fetch_xor_1(ptr: *u8, val: u8, model: i32) callconv(.C) u8 { return fetch_op_N(u8, .Xor, ptr, val, model); } @@ -438,6 +472,10 @@ fn __atomic_fetch_xor_8(ptr: *u64, val: u64, model: i32) callconv(.C) u64 { return fetch_op_N(u64, .Xor, ptr, val, model); } +fn __atomic_fetch_xor_16(ptr: *u128, val: u128, model: i32) callconv(.C) u128 { + return fetch_op_N(u128, .Xor, ptr, val, model); +} + fn __atomic_fetch_nand_1(ptr: *u8, val: u8, model: i32) callconv(.C) u8 { return fetch_op_N(u8, .Nand, ptr, val, model); } @@ -454,6 +492,50 @@ fn __atomic_fetch_nand_8(ptr: *u64, val: u64, model: i32) callconv(.C) u64 { return fetch_op_N(u64, .Nand, ptr, val, model); } +fn __atomic_fetch_nand_16(ptr: *u128, val: u128, model: i32) callconv(.C) u128 { + return fetch_op_N(u128, .Nand, ptr, val, model); +} + +fn __atomic_fetch_umax_1(ptr: *u8, val: u8, model: i32) callconv(.C) u8 { + return fetch_op_N(u8, .Max, ptr, val, model); +} + +fn __atomic_fetch_umax_2(ptr: *u16, val: u16, model: i32) callconv(.C) u16 { + return fetch_op_N(u16, .Max, ptr, val, model); +} + +fn __atomic_fetch_umax_4(ptr: *u32, val: u32, model: i32) callconv(.C) u32 { + return fetch_op_N(u32, .Max, ptr, val, model); +} + +fn __atomic_fetch_umax_8(ptr: *u64, val: u64, model: i32) callconv(.C) u64 { + return fetch_op_N(u64, .Max, ptr, val, model); +} + +fn __atomic_fetch_umax_16(ptr: *u128, val: u128, model: i32) callconv(.C) u128 { + return fetch_op_N(u128, .Max, ptr, val, model); +} + +fn __atomic_fetch_umin_1(ptr: *u8, val: u8, model: i32) callconv(.C) u8 { + return fetch_op_N(u8, .Min, ptr, val, model); +} + +fn __atomic_fetch_umin_2(ptr: *u16, val: u16, model: i32) callconv(.C) u16 { + return fetch_op_N(u16, .Min, ptr, val, model); +} + +fn __atomic_fetch_umin_4(ptr: *u32, val: u32, model: i32) callconv(.C) u32 { + return fetch_op_N(u32, .Min, ptr, val, model); +} + +fn __atomic_fetch_umin_8(ptr: *u64, val: u64, model: i32) callconv(.C) u64 { + return fetch_op_N(u64, .Min, ptr, val, model); +} + +fn __atomic_fetch_umin_16(ptr: *u128, val: u128, model: i32) callconv(.C) u128 { + return fetch_op_N(u128, .Min, ptr, val, model); +} + comptime { if (supports_atomic_ops and builtin.object_format != .c) { @export(__atomic_load, .{ .name = "__atomic_load", .linkage = linkage, .visibility = visibility }); @@ -465,50 +547,72 @@ comptime { @export(__atomic_fetch_add_2, .{ .name = "__atomic_fetch_add_2", .linkage = linkage, .visibility = visibility }); @export(__atomic_fetch_add_4, .{ .name = "__atomic_fetch_add_4", .linkage = linkage, .visibility = visibility }); @export(__atomic_fetch_add_8, .{ .name = "__atomic_fetch_add_8", .linkage = linkage, .visibility = visibility }); + @export(__atomic_fetch_add_16, .{ .name = "__atomic_fetch_add_16", .linkage = linkage, .visibility = visibility }); @export(__atomic_fetch_sub_1, .{ .name = "__atomic_fetch_sub_1", .linkage = linkage, .visibility = visibility }); @export(__atomic_fetch_sub_2, .{ .name = "__atomic_fetch_sub_2", .linkage = linkage, .visibility = visibility }); @export(__atomic_fetch_sub_4, .{ .name = "__atomic_fetch_sub_4", .linkage = linkage, .visibility = visibility }); @export(__atomic_fetch_sub_8, .{ .name = "__atomic_fetch_sub_8", .linkage = linkage, .visibility = visibility }); + @export(__atomic_fetch_sub_16, .{ .name = "__atomic_fetch_sub_16", .linkage = linkage, .visibility = visibility }); @export(__atomic_fetch_and_1, .{ .name = "__atomic_fetch_and_1", .linkage = linkage, .visibility = visibility }); @export(__atomic_fetch_and_2, .{ .name = "__atomic_fetch_and_2", .linkage = linkage, .visibility = visibility }); @export(__atomic_fetch_and_4, .{ .name = "__atomic_fetch_and_4", .linkage = linkage, .visibility = visibility }); @export(__atomic_fetch_and_8, .{ .name = "__atomic_fetch_and_8", .linkage = linkage, .visibility = visibility }); + @export(__atomic_fetch_and_16, .{ .name = "__atomic_fetch_and_16", .linkage = linkage, .visibility = visibility }); @export(__atomic_fetch_or_1, .{ .name = "__atomic_fetch_or_1", .linkage = linkage, .visibility = visibility }); @export(__atomic_fetch_or_2, .{ .name = "__atomic_fetch_or_2", .linkage = linkage, .visibility = visibility }); @export(__atomic_fetch_or_4, .{ .name = "__atomic_fetch_or_4", .linkage = linkage, .visibility = visibility }); @export(__atomic_fetch_or_8, .{ .name = "__atomic_fetch_or_8", .linkage = linkage, .visibility = visibility }); + @export(__atomic_fetch_or_16, .{ .name = "__atomic_fetch_or_16", .linkage = linkage, .visibility = visibility }); @export(__atomic_fetch_xor_1, .{ .name = "__atomic_fetch_xor_1", .linkage = linkage, .visibility = visibility }); @export(__atomic_fetch_xor_2, .{ .name = "__atomic_fetch_xor_2", .linkage = linkage, .visibility = visibility }); @export(__atomic_fetch_xor_4, .{ .name = "__atomic_fetch_xor_4", .linkage = linkage, .visibility = visibility }); @export(__atomic_fetch_xor_8, .{ .name = "__atomic_fetch_xor_8", .linkage = linkage, .visibility = visibility }); + @export(__atomic_fetch_xor_16, .{ .name = "__atomic_fetch_xor_16", .linkage = linkage, .visibility = visibility }); @export(__atomic_fetch_nand_1, .{ .name = "__atomic_fetch_nand_1", .linkage = linkage, .visibility = visibility }); @export(__atomic_fetch_nand_2, .{ .name = "__atomic_fetch_nand_2", .linkage = linkage, .visibility = visibility }); @export(__atomic_fetch_nand_4, .{ .name = "__atomic_fetch_nand_4", .linkage = linkage, .visibility = visibility }); @export(__atomic_fetch_nand_8, .{ .name = "__atomic_fetch_nand_8", .linkage = linkage, .visibility = visibility }); + @export(__atomic_fetch_nand_16, .{ .name = "__atomic_fetch_nand_16", .linkage = linkage, .visibility = visibility }); + + @export(__atomic_fetch_umax_1, .{ .name = "__atomic_fetch_umax_1", .linkage = linkage, .visibility = visibility }); + @export(__atomic_fetch_umax_2, .{ .name = "__atomic_fetch_umax_2", .linkage = linkage, .visibility = visibility }); + @export(__atomic_fetch_umax_4, .{ .name = "__atomic_fetch_umax_4", .linkage = linkage, .visibility = visibility }); + @export(__atomic_fetch_umax_8, .{ .name = "__atomic_fetch_umax_8", .linkage = linkage, .visibility = visibility }); + @export(__atomic_fetch_umax_16, .{ .name = "__atomic_fetch_umax_16", .linkage = linkage, .visibility = visibility }); + + @export(__atomic_fetch_umin_1, .{ .name = "__atomic_fetch_umin_1", .linkage = linkage, .visibility = visibility }); + @export(__atomic_fetch_umin_2, .{ .name = "__atomic_fetch_umin_2", .linkage = linkage, .visibility = visibility }); + @export(__atomic_fetch_umin_4, .{ .name = "__atomic_fetch_umin_4", .linkage = linkage, .visibility = visibility }); + @export(__atomic_fetch_umin_8, .{ .name = "__atomic_fetch_umin_8", .linkage = linkage, .visibility = visibility }); + @export(__atomic_fetch_umin_16, .{ .name = "__atomic_fetch_umin_16", .linkage = linkage, .visibility = visibility }); @export(__atomic_load_1, .{ .name = "__atomic_load_1", .linkage = linkage, .visibility = visibility }); @export(__atomic_load_2, .{ .name = "__atomic_load_2", .linkage = linkage, .visibility = visibility }); @export(__atomic_load_4, .{ .name = "__atomic_load_4", .linkage = linkage, .visibility = visibility }); @export(__atomic_load_8, .{ .name = "__atomic_load_8", .linkage = linkage, .visibility = visibility }); + @export(__atomic_load_16, .{ .name = "__atomic_load_16", .linkage = linkage, .visibility = visibility }); @export(__atomic_store_1, .{ .name = "__atomic_store_1", .linkage = linkage, .visibility = visibility }); @export(__atomic_store_2, .{ .name = "__atomic_store_2", .linkage = linkage, .visibility = visibility }); @export(__atomic_store_4, .{ .name = "__atomic_store_4", .linkage = linkage, .visibility = visibility }); @export(__atomic_store_8, .{ .name = "__atomic_store_8", .linkage = linkage, .visibility = visibility }); + @export(__atomic_store_16, .{ .name = "__atomic_store_16", .linkage = linkage, .visibility = visibility }); @export(__atomic_exchange_1, .{ .name = "__atomic_exchange_1", .linkage = linkage, .visibility = visibility }); @export(__atomic_exchange_2, .{ .name = "__atomic_exchange_2", .linkage = linkage, .visibility = visibility }); @export(__atomic_exchange_4, .{ .name = "__atomic_exchange_4", .linkage = linkage, .visibility = visibility }); @export(__atomic_exchange_8, .{ .name = "__atomic_exchange_8", .linkage = linkage, .visibility = visibility }); + @export(__atomic_exchange_16, .{ .name = "__atomic_exchange_16", .linkage = linkage, .visibility = visibility }); @export(__atomic_compare_exchange_1, .{ .name = "__atomic_compare_exchange_1", .linkage = linkage, .visibility = visibility }); @export(__atomic_compare_exchange_2, .{ .name = "__atomic_compare_exchange_2", .linkage = linkage, .visibility = visibility }); @export(__atomic_compare_exchange_4, .{ .name = "__atomic_compare_exchange_4", .linkage = linkage, .visibility = visibility }); @export(__atomic_compare_exchange_8, .{ .name = "__atomic_compare_exchange_8", .linkage = linkage, .visibility = visibility }); + @export(__atomic_compare_exchange_16, .{ .name = "__atomic_compare_exchange_16", .linkage = linkage, .visibility = visibility }); } } diff --git a/lib/std/start_windows_tls.zig b/lib/std/start_windows_tls.zig index 0a81f13d46b7f527df79c615b9b7362d42584e13..6a3aad7a99ea8b6f253d245cc384148833a3a447 100644 --- a/lib/std/start_windows_tls.zig +++ b/lib/std/start_windows_tls.zig @@ -7,12 +7,14 @@ export var _tls_end: u8 linksection(".tls$ZZZ") = 0; export var __xl_a: std.os.windows.PIMAGE_TLS_CALLBACK linksection(".CRT$XLA") = null; export var __xl_z: std.os.windows.PIMAGE_TLS_CALLBACK linksection(".CRT$XLZ") = null; -const tls_array: u32 = 0x2c; comptime { - if (builtin.target.cpu.arch == .x86) { + if (builtin.target.cpu.arch == .x86 and builtin.zig_backend != .stage2_c) { // The __tls_array is the offset of the ThreadLocalStoragePointer field // in the TEB block whose base address held in the %fs segment. - @export(tls_array, .{ .name = "_tls_array" }); + asm ( + \\ .global __tls_array + \\ __tls_array = 0x2C + ); } } diff --git a/lib/zig.h b/lib/zig.h index fb9698325e75a5772736a427f0cf2b1c5cf187f8..0756d9f73126e638bf481b8717e9e5e5a04ff9ab 100644 --- a/lib/zig.h +++ b/lib/zig.h @@ -93,6 +93,14 @@ typedef char bool; #define zig_align zig_align_unavailable #endif +#if zig_has_attribute(aligned) +#define zig_under_align(alignment) __attribute__((aligned(alignment))) +#elif _MSC_VER +#define zig_under_align(alignment) zig_align(alignment) +#else +#define zig_align zig_align_unavailable +#endif + #if zig_has_attribute(aligned) #define zig_align_fn(alignment) __attribute__((aligned(alignment))) #elif _MSC_VER @@ -101,6 +109,22 @@ typedef char bool; #define zig_align_fn zig_align_fn_unavailable #endif +#if zig_has_attribute(packed) +#define zig_packed(definition) __attribute__((packed)) definition +#elif _MSC_VER +#define zig_packed(definition) __pragma(pack(1)) definition __pragma(pack()) +#else +#define zig_packed(definition) zig_packed_unavailable +#endif + +#if zig_has_attribute(section) +#define zig_linksection(name, def, ...) def __attribute__((section(name))) +#elif _MSC_VER +#define zig_linksection(name, def, ...) __pragma(section(name, __VA_ARGS__)) __declspec(allocate(name)) def +#else +#define zig_linksection(name, def, ...) zig_linksection_unavailable +#endif + #if zig_has_builtin(unreachable) || defined(zig_gnuc) #define zig_unreachable() __builtin_unreachable() #else diff --git a/src/codegen/c.zig b/src/codegen/c.zig index 70c62a1faa9a223918e5ce4174b0f81f214d51cf..eb0ae1b1f6b12133a7c9023845f5e422563ac7d9 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -1663,6 +1663,22 @@ pub const DeclGen = struct { defer buffer.deinit(); try buffer.appendSlice("struct "); + + var needs_pack_attr = false; + { + var it = t.structFields().iterator(); + while (it.next()) |field| { + const field_ty = field.value_ptr.ty; + if (!field_ty.hasRuntimeBits()) continue; + const alignment = field.value_ptr.abi_align; + if (alignment != 0 and alignment < field_ty.abiAlignment(dg.module.getTarget())) { + needs_pack_attr = true; + try buffer.appendSlice("zig_packed("); + break; + } + } + } + try buffer.appendSlice(name); try buffer.appendSlice(" {\n"); { @@ -1672,7 +1688,7 @@ pub const DeclGen = struct { const field_ty = field.value_ptr.ty; if (!field_ty.hasRuntimeBits()) continue; - const alignment = field.value_ptr.abi_align; + const alignment = field.value_ptr.alignment(dg.module.getTarget(), t.containerLayout()); const field_name = CValue{ .identifier = field.key_ptr.* }; try buffer.append(' '); try dg.renderTypeAndName(buffer.writer(), field_ty, field_name, .Mut, alignment, .Complete); @@ -1682,7 +1698,7 @@ pub const DeclGen = struct { } if (empty) try buffer.appendSlice(" char empty_struct;\n"); } - try buffer.appendSlice("};\n"); + if (needs_pack_attr) try buffer.appendSlice("});\n") else try buffer.appendSlice("};\n"); const rendered = try buffer.toOwnedSlice(); errdefer dg.typedefs.allocator.free(rendered); @@ -2367,8 +2383,13 @@ pub const DeclGen = struct { depth += 1; } - if (alignment != 0 and alignment > ty.abiAlignment(target)) { - try w.print("zig_align({}) ", .{alignment}); + if (alignment != 0) { + const abi_alignment = ty.abiAlignment(target); + if (alignment < abi_alignment) { + try w.print("zig_under_align({}) ", .{alignment}); + } else if (alignment > abi_alignment) { + try w.print("zig_align({}) ", .{alignment}); + } } try dg.renderType(w, render_ty, kind); @@ -2860,27 +2881,30 @@ pub fn genDecl(o: *Object) !void { const w = o.writer(); if (!is_global) try w.writeAll("static "); if (variable.is_threadlocal) try w.writeAll("zig_threadlocal "); + if (o.dg.decl.@"linksection") |section| try w.print("zig_linksection(\"{s}\", ", .{section}); try o.dg.renderTypeAndName(w, o.dg.decl.ty, decl_c_value, .Mut, o.dg.decl.@"align", .Complete); + if (o.dg.decl.@"linksection" != null) try w.writeAll(", read, write)"); try w.writeAll(" = "); try o.dg.renderValue(w, tv.ty, variable.init, .StaticInitializer); try w.writeByte(';'); try o.indent_writer.insertNewline(); } else { + const is_global = o.dg.module.decl_exports.contains(o.dg.decl_index); + const fwd_decl_writer = o.dg.fwd_decl.writer(); const decl_c_value: CValue = .{ .decl = o.dg.decl_index }; - const fwd_decl_writer = o.dg.fwd_decl.writer(); - try fwd_decl_writer.writeAll("static "); - try o.dg.renderTypeAndName(fwd_decl_writer, tv.ty, decl_c_value, .Mut, o.dg.decl.@"align", .Complete); + try fwd_decl_writer.writeAll(if (is_global) "zig_extern " else "static "); + try o.dg.renderTypeAndName(fwd_decl_writer, tv.ty, decl_c_value, .Const, o.dg.decl.@"align", .Complete); try fwd_decl_writer.writeAll(";\n"); - const writer = o.writer(); - try writer.writeAll("static "); - // TODO ask the Decl if it is const - // https://github.com/ziglang/zig/issues/7582 - try o.dg.renderTypeAndName(writer, tv.ty, decl_c_value, .Mut, o.dg.decl.@"align", .Complete); - try writer.writeAll(" = "); - try o.dg.renderValue(writer, tv.ty, tv.val, .StaticInitializer); - try writer.writeAll(";\n"); + const w = o.writer(); + if (!is_global) try w.writeAll("static "); + if (o.dg.decl.@"linksection") |section| try w.print("zig_linksection(\"{s}\", ", .{section}); + try o.dg.renderTypeAndName(w, tv.ty, decl_c_value, .Const, o.dg.decl.@"align", .Complete); + if (o.dg.decl.@"linksection" != null) try w.writeAll(", read)"); + try w.writeAll(" = "); + try o.dg.renderValue(w, tv.ty, tv.val, .StaticInitializer); + try w.writeAll(";\n"); } } diff --git a/stage1/zig1.wasm b/stage1/zig1.wasm index 44052980162eb19a17493b624e4d1e52a2c98be6..e64e05fa1300ae7254391cbb74786b55abd1e48b 100644 GIT binary patch delta 661855 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

EbtQ;X}L#lr~HP|E{@;A`#EEXyC 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

-HQ!XO6%e^Gv4Y}n2O^mY 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%0DwHk0}B&3+W3zqv&?C5 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⋙-=kBoLgNU9 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⁡jF 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%0Ahdu|KFK=w*~O^{ht5#e2 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

oghSFdpWU|)loe+Y^Tk9lhIbPT!3Pbfh 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%0Db85fq7cnbj!z^SP_Oc`B_XS8Dhl>GqsWa0uEUP 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�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 diff --git a/test/behavior/math.zig b/test/behavior/math.zig index 2257a116b736a2b7dfd089cce96f1dfa90832967..c5e36da383ce63a932978577cb6cdebc16d02304 100644 --- a/test/behavior/math.zig +++ b/test/behavior/math.zig @@ -1332,7 +1332,6 @@ test "float remainder division using @rem" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/12602 comptime try frem(f16); comptime try frem(f32); @@ -1375,7 +1374,6 @@ test "float modulo division using @mod" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/12602 comptime try fmod(f16); comptime try fmod(f32); @@ -1438,7 +1436,6 @@ test "@round f80" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/12602 try testRound(f80, 12.0); comptime try testRound(f80, 12.0); diff --git a/test/behavior/muladd.zig b/test/behavior/muladd.zig index da00355b353883f29903e71a21b1e417a86c1a56..a2d9e6d16d1d74b5ef41011e26a151286bc91e24 100644 --- a/test/behavior/muladd.zig +++ b/test/behavior/muladd.zig @@ -50,7 +50,6 @@ test "@mulAdd f80" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/12602 comptime try testMulAdd80(); try testMulAdd80(); @@ -178,7 +177,6 @@ test "vector f80" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/12602 comptime try vector80(); try vector80(); diff --git a/test/behavior/threadlocal.zig b/test/behavior/threadlocal.zig index 1844c5b92d06d93b113b8d9441b3efd6b0a8dc2f..ebeb1177c242862581ec1b5ea2e516aaf3f68a9b 100644 --- a/test/behavior/threadlocal.zig +++ b/test/behavior/threadlocal.zig @@ -7,8 +7,10 @@ test "thread local variable" { if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch != .x86_64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_llvm) switch (builtin.cpu.arch) { + .x86_64, .x86 => {}, + else => return error.SkipZigTest, + }; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO const S = struct { @@ -23,8 +25,10 @@ test "pointer to thread local array" { if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch != .x86_64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_llvm) switch (builtin.cpu.arch) { + .x86_64, .x86 => {}, + else => return error.SkipZigTest, + }; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO const s = "Hello world"; @@ -39,8 +43,10 @@ test "reference a global threadlocal variable" { if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch != .x86_64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_llvm) switch (builtin.cpu.arch) { + .x86_64, .x86 => {}, + else => return error.SkipZigTest, + }; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO _ = nrfx_uart_rx(&g_uart0); -- 2.54.0 From 7c2ba950a758b86893bfbe73521b29895f7ac4f0 Mon Sep 17 00:00:00 2001 From: kcbanner Date: Fri, 27 Jan 2023 18:01:49 -0500 Subject: [PATCH 24/84] build: .c ofmt does not produce a pdb --- lib/std/build/LibExeObjStep.zig | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/std/build/LibExeObjStep.zig b/lib/std/build/LibExeObjStep.zig index 213c5c655924b2f0b8202f7646b190fe9a92c0e3..cb37b248857e8d5846a43c770482c2dd96d18048 100644 --- a/lib/std/build/LibExeObjStep.zig +++ b/lib/std/build/LibExeObjStep.zig @@ -617,6 +617,7 @@ pub fn isStaticLibrary(self: *LibExeObjStep) bool { pub fn producesPdbFile(self: *LibExeObjStep) bool { if (!self.target.isWindows() and !self.target.isUefi()) return false; + if (self.target.getObjectFormat() == .c) return false; if (self.strip == true) return false; return self.isDynamicLibrary() or self.kind == .exe or self.kind == .test_exe; } -- 2.54.0 From 23b7d28896609e3f01765730599119baf53a56c9 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Sun, 22 Jan 2023 16:40:00 +0100 Subject: [PATCH 25/84] std: restrict mem.span() and mem.len() to sentinel terminated pointers These functions are currently footgunny when working with pointers to arrays and slices. They just return the stated length of the array/slice without iterating and looking for the first sentinel, even if the array/slice is a sentinel terminated type. From looking at the quite small list of places in the standard library/compiler that this change breaks existing code, the new code looks to be more readable in all cases. The usage of std.mem.span/len was totally unneeded in most of the cases affected by this breaking change. We could remove these functions entirely in favor of other existing functions in std.mem such as std.mem.sliceTo(), but that would be a somewhat nasty breaking change as std.mem.span() is very widely used for converting sentinel terminated pointers to slices. It is however not at all widely used for anything else. Therefore I think it is better to break these few non-standard and potentially incorrect usages of these functions now and at some later time, if deemed worthwhile, finally remove these functions. If we wait for at least a full release cycle so that everyone adapts to this change first, updating for the removal could be a simple find and replace without needing to worry about the semantics. --- lib/std/Thread.zig | 2 +- lib/std/bounded_array.zig | 6 +- lib/std/cstr.zig | 1 - lib/std/fs.zig | 2 +- lib/std/io/fixed_buffer_stream.zig | 25 +++++-- lib/std/mem.zig | 102 +++++++---------------------- src/link/MachO/load_commands.zig | 2 +- src/main.zig | 8 +-- test/behavior/basic.zig | 2 +- 9 files changed, 56 insertions(+), 94 deletions(-) diff --git a/lib/std/Thread.zig b/lib/std/Thread.zig index d27474584f038325195477de96b4a15116260753..8004f94d7f6540162f98146a5df43cbb4fd1cbdb 100644 --- a/lib/std/Thread.zig +++ b/lib/std/Thread.zig @@ -166,7 +166,7 @@ pub const GetNameError = error{ pub fn getName(self: Thread, buffer_ptr: *[max_name_len:0]u8) GetNameError!?[]const u8 { buffer_ptr[max_name_len] = 0; - var buffer = std.mem.span(buffer_ptr); + var buffer: [:0]u8 = buffer_ptr; switch (target.os.tag) { .linux => if (use_pthreads and is_gnu) { diff --git a/lib/std/bounded_array.zig b/lib/std/bounded_array.zig index 3d74e5e47fe589ec39b0495a2a0dc2f9e9a11d7c..7f1957d6dc05f9d79c7fde96f9caf98bcb063e35 100644 --- a/lib/std/bounded_array.zig +++ b/lib/std/bounded_array.zig @@ -29,7 +29,11 @@ pub fn BoundedArray(comptime T: type, comptime buffer_capacity: usize) type { } /// View the internal array as a slice whose size was previously set. - pub fn slice(self: anytype) mem.Span(@TypeOf(&self.buffer)) { + pub fn slice(self: anytype) switch (@TypeOf(&self.buffer)) { + *[buffer_capacity]T => []T, + *const [buffer_capacity]T => []const T, + else => unreachable, + } { return self.buffer[0..self.len]; } diff --git a/lib/std/cstr.zig b/lib/std/cstr.zig index 068fc419ac577e69c91cbe01f89d2a30415f51ae..52524c50842280600851cbcf26bdca1b976b3419 100644 --- a/lib/std/cstr.zig +++ b/lib/std/cstr.zig @@ -28,7 +28,6 @@ test "cstr fns" { fn testCStrFnsImpl() !void { try testing.expect(cmp("aoeu", "aoez") == -1); - try testing.expect(mem.len("123456789") == 9); } /// Returns a mutable, null-terminated slice with the same length as `slice`. diff --git a/lib/std/fs.zig b/lib/std/fs.zig index 1b000641086fc0b891f7bcd7d4de12938014f5d9..244f3a38ce1a83a64aebd7591de27104d76b563b 100644 --- a/lib/std/fs.zig +++ b/lib/std/fs.zig @@ -834,7 +834,7 @@ pub const IterableDir = struct { self.end_index = self.index; // Force fd_readdir in the next loop. continue :start_over; } - const name = mem.span(self.buf[name_index .. name_index + entry.d_namlen]); + const name = self.buf[name_index .. name_index + entry.d_namlen]; const next_index = name_index + entry.d_namlen; self.index = next_index; diff --git a/lib/std/io/fixed_buffer_stream.zig b/lib/std/io/fixed_buffer_stream.zig index f486356491fa98c4d4c16245d14ecaec114d0e20..2fcb260c72ad605489336f8a6d793702fa56be06 100644 --- a/lib/std/io/fixed_buffer_stream.zig +++ b/lib/std/io/fixed_buffer_stream.zig @@ -113,14 +113,27 @@ pub fn FixedBufferStream(comptime Buffer: type) type { }; } -pub fn fixedBufferStream(buffer: anytype) FixedBufferStream(NonSentinelSpan(@TypeOf(buffer))) { - return .{ .buffer = mem.span(buffer), .pos = 0 }; +pub fn fixedBufferStream(buffer: anytype) FixedBufferStream(Slice(@TypeOf(buffer))) { + return .{ .buffer = buffer, .pos = 0 }; } -fn NonSentinelSpan(comptime T: type) type { - var ptr_info = @typeInfo(mem.Span(T)).Pointer; - ptr_info.sentinel = null; - return @Type(.{ .Pointer = ptr_info }); +fn Slice(comptime T: type) type { + switch (@typeInfo(T)) { + .Pointer => |ptr_info| { + var new_ptr_info = ptr_info; + switch (ptr_info.size) { + .Slice => {}, + .One => switch (@typeInfo(ptr_info.child)) { + .Array => |info| new_ptr_info.child = info.child, + else => @compileError("invalid type given to fixedBufferStream"), + }, + else => @compileError("invalid type given to fixedBufferStream"), + } + new_ptr_info.size = .Slice; + return @Type(.{ .Pointer = new_ptr_info }); + }, + else => @compileError("invalid type given to fixedBufferStream"), + } } test "FixedBufferStream output" { diff --git a/lib/std/mem.zig b/lib/std/mem.zig index 8691c5bbad94f7931ffb14a32f48b3fd2f1a196b..371ef8fd8dc302c05b250d351fd2d2d54c0e4f2d 100644 --- a/lib/std/mem.zig +++ b/lib/std/mem.zig @@ -636,12 +636,9 @@ test "indexOfDiff" { try testing.expectEqual(indexOfDiff(u8, "xne", "one"), 0); } -/// Takes a pointer to an array, a sentinel-terminated pointer, or a slice, and -/// returns a slice. If there is a sentinel on the input type, there will be a -/// sentinel on the output type. The constness of the output type matches -/// the constness of the input type. `[*c]` pointers are assumed to be 0-terminated, -/// and assumed to not allow null. -pub fn Span(comptime T: type) type { +/// Takes a sentinel-terminated pointer and returns a slice preserving pointer attributes. +/// `[*c]` pointers are assumed to be 0-terminated and assumed to not be allowzero. +fn Span(comptime T: type) type { switch (@typeInfo(T)) { .Optional => |optional_info| { return ?Span(optional_info.child); @@ -649,39 +646,22 @@ pub fn Span(comptime T: type) type { .Pointer => |ptr_info| { var new_ptr_info = ptr_info; switch (ptr_info.size) { - .One => switch (@typeInfo(ptr_info.child)) { - .Array => |info| { - new_ptr_info.child = info.child; - new_ptr_info.sentinel = info.sentinel; - }, - else => @compileError("invalid type given to std.mem.Span"), - }, .C => { new_ptr_info.sentinel = &@as(ptr_info.child, 0); new_ptr_info.is_allowzero = false; }, - .Many, .Slice => {}, + .Many => if (ptr_info.sentinel == null) @compileError("invalid type given to std.mem.span: " ++ @typeName(T)), + .One, .Slice => @compileError("invalid type given to std.mem.span: " ++ @typeName(T)), } new_ptr_info.size = .Slice; return @Type(.{ .Pointer = new_ptr_info }); }, - else => @compileError("invalid type given to std.mem.Span"), + else => {}, } + @compileError("invalid type given to std.mem.span: " ++ @typeName(T)); } test "Span" { - try testing.expect(Span(*[5]u16) == []u16); - try testing.expect(Span(?*[5]u16) == ?[]u16); - try testing.expect(Span(*const [5]u16) == []const u16); - try testing.expect(Span(?*const [5]u16) == ?[]const u16); - try testing.expect(Span([]u16) == []u16); - try testing.expect(Span(?[]u16) == ?[]u16); - try testing.expect(Span([]const u8) == []const u8); - try testing.expect(Span(?[]const u8) == ?[]const u8); - try testing.expect(Span([:1]u16) == [:1]u16); - try testing.expect(Span(?[:1]u16) == ?[:1]u16); - try testing.expect(Span([:1]const u8) == [:1]const u8); - try testing.expect(Span(?[:1]const u8) == ?[:1]const u8); try testing.expect(Span([*:1]u16) == [:1]u16); try testing.expect(Span(?[*:1]u16) == ?[:1]u16); try testing.expect(Span([*:1]const u8) == [:1]const u8); @@ -692,13 +672,10 @@ test "Span" { try testing.expect(Span(?[*c]const u8) == ?[:0]const u8); } -/// Takes a pointer to an array, a sentinel-terminated pointer, or a slice, and -/// returns a slice. If there is a sentinel on the input type, there will be a -/// sentinel on the output type. The constness of the output type matches -/// the constness of the input type. -/// -/// When there is both a sentinel and an array length or slice length, the -/// length value is used instead of the sentinel. +/// Takes a sentinel-terminated pointer and returns a slice, iterating over the +/// memory to find the sentinel and determine the length. +/// Ponter attributes such as const are preserved. +/// `[*c]` pointers are assumed to be non-null and 0-terminated. pub fn span(ptr: anytype) Span(@TypeOf(ptr)) { if (@typeInfo(@TypeOf(ptr)) == .Optional) { if (ptr) |non_null| { @@ -722,7 +699,6 @@ test "span" { var array: [5]u16 = [_]u16{ 1, 2, 3, 4, 5 }; const ptr = @as([*:3]u16, array[0..2 :3]); try testing.expect(eql(u16, span(ptr), &[_]u16{ 1, 2 })); - try testing.expect(eql(u16, span(&array), &[_]u16{ 1, 2, 3, 4, 5 })); try testing.expectEqual(@as(?[:0]u16, null), span(@as(?[*:0]u16, null))); } @@ -919,22 +895,15 @@ test "lenSliceTo" { } } -/// Takes a pointer to an array, an array, a vector, a sentinel-terminated pointer, -/// a slice or a tuple, and returns the length. -/// In the case of a sentinel-terminated array, it uses the array length. -/// For C pointers it assumes it is a pointer-to-many with a 0 sentinel. +/// Takes a sentinel-terminated pointer and iterates over the memory to find the +/// sentinel and determine the length. +/// `[*c]` pointers are assumed to be non-null and 0-terminated. pub fn len(value: anytype) usize { - return switch (@typeInfo(@TypeOf(value))) { - .Array => |info| info.len, - .Vector => |info| info.len, + switch (@typeInfo(@TypeOf(value))) { .Pointer => |info| switch (info.size) { - .One => switch (@typeInfo(info.child)) { - .Array => value.len, - else => @compileError("invalid type given to std.mem.len"), - }, .Many => { const sentinel_ptr = info.sentinel orelse - @compileError("length of pointer with no sentinel"); + @compileError("invalid type given to std.mem.len: " ++ @typeName(@TypeOf(value))); const sentinel = @ptrCast(*align(1) const info.child, sentinel_ptr).*; return indexOfSentinel(info.child, sentinel, value); }, @@ -942,41 +911,18 @@ pub fn len(value: anytype) usize { assert(value != null); return indexOfSentinel(info.child, 0, value); }, - .Slice => value.len, + else => @compileError("invalid type given to std.mem.len: " ++ @typeName(@TypeOf(value))), }, - .Struct => |info| if (info.is_tuple) { - return info.fields.len; - } else @compileError("invalid type given to std.mem.len"), - else => @compileError("invalid type given to std.mem.len"), - }; + else => @compileError("invalid type given to std.mem.len: " ++ @typeName(@TypeOf(value))), + } } test "len" { - try testing.expect(len("aoeu") == 4); - - { - var array: [5]u16 = [_]u16{ 1, 2, 3, 4, 5 }; - try testing.expect(len(&array) == 5); - try testing.expect(len(array[0..3]) == 3); - array[2] = 0; - const ptr = @as([*:0]u16, array[0..2 :0]); - try testing.expect(len(ptr) == 2); - } - { - var array: [5:0]u16 = [_:0]u16{ 1, 2, 3, 4, 5 }; - try testing.expect(len(&array) == 5); - array[2] = 0; - try testing.expect(len(&array) == 5); - } - { - const vector: meta.Vector(2, u32) = [2]u32{ 1, 2 }; - try testing.expect(len(vector) == 2); - } - { - const tuple = .{ 1, 2 }; - try testing.expect(len(tuple) == 2); - try testing.expect(tuple[0] == 1); - } + var array: [5]u16 = [_]u16{ 1, 2, 0, 4, 5 }; + const ptr = @as([*:4]u16, array[0..3 :4]); + try testing.expect(len(ptr) == 3); + const c_ptr = @as([*c]u16, ptr); + try testing.expect(len(c_ptr) == 2); } pub fn indexOfSentinel(comptime Elem: type, comptime sentinel: Elem, ptr: [*:sentinel]const Elem) usize { diff --git a/src/link/MachO/load_commands.zig b/src/link/MachO/load_commands.zig index 0e3760526cd69cddd190f0df0017606cdda41248..a452551a0ae90bb6b6d98da8bdfb24567c8818db 100644 --- a/src/link/MachO/load_commands.zig +++ b/src/link/MachO/load_commands.zig @@ -12,7 +12,7 @@ pub const default_dyld_path: [*:0]const u8 = "/usr/lib/dyld"; fn calcInstallNameLen(cmd_size: u64, name: []const u8, assume_max_path_len: bool) u64 { const darwin_path_max = 1024; - const name_len = if (assume_max_path_len) darwin_path_max else std.mem.len(name) + 1; + const name_len = if (assume_max_path_len) darwin_path_max else name.len + 1; return mem.alignForwardGeneric(u64, cmd_size + name_len, @alignOf(u64)); } diff --git a/src/main.zig b/src/main.zig index fdc761ac9204432b02b58e92c6a6d4c6d653b099..72e7e094e63fe7c2fda7f10d644d01517039c88a 100644 --- a/src/main.zig +++ b/src/main.zig @@ -893,7 +893,7 @@ fn buildOutputType( i: usize = 0, fn next(it: *@This()) ?[]const u8 { if (it.i >= it.args.len) { - if (it.resp_file) |*resp| return if (resp.next()) |sentinel| std.mem.span(sentinel) else null; + if (it.resp_file) |*resp| return resp.next(); return null; } defer it.i += 1; @@ -901,7 +901,7 @@ fn buildOutputType( } fn nextOrFatal(it: *@This()) []const u8 { if (it.i >= it.args.len) { - if (it.resp_file) |*resp| if (resp.next()) |sentinel| return std.mem.span(sentinel); + if (it.resp_file) |*resp| if (resp.next()) |ret| return ret; fatal("expected parameter after {s}", .{it.args[it.i - 1]}); } defer it.i += 1; @@ -4973,7 +4973,7 @@ pub const ClangArgIterator = struct { // rather than an argument to a parameter. // We adjust the len below when necessary. self.other_args = (self.argv.ptr + self.next_index)[0..1]; - var arg = mem.span(self.argv[self.next_index]); + var arg = self.argv[self.next_index]; self.incrementArgIndex(); if (mem.startsWith(u8, arg, "@")) { @@ -5017,7 +5017,7 @@ pub const ClangArgIterator = struct { self.has_next = true; self.other_args = (self.argv.ptr + self.next_index)[0..1]; // We adjust len below when necessary. - arg = mem.span(self.argv[self.next_index]); + arg = self.argv[self.next_index]; self.incrementArgIndex(); } diff --git a/test/behavior/basic.zig b/test/behavior/basic.zig index ebca81be96fe0f652bfe999879bb120bed54f8bc..8a97b3cbcd3e788ec6fc171bcfbb31753e3111d5 100644 --- a/test/behavior/basic.zig +++ b/test/behavior/basic.zig @@ -703,7 +703,7 @@ test "string concatenation" { comptime try expect(@TypeOf(a) == *const [12:0]u8); comptime try expect(@TypeOf(b) == *const [12:0]u8); - const len = mem.len(b); + const len = b.len; const len_with_null = len + 1; { var i: u32 = 0; -- 2.54.0 From 92dfc07489c3f8514792434e2857b419ebf1f208 Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Sun, 22 Jan 2023 13:29:05 +0200 Subject: [PATCH 26/84] TypedValue: fix crash when string-like aggregate has undefined element Closes #6334 --- src/TypedValue.zig | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/TypedValue.zig b/src/TypedValue.zig index 6e096ee90a6babad3a2f83ec48f560b49889260f..cb28274f10e9abc4cb7616bc11305d1980b7eced 100644 --- a/src/TypedValue.zig +++ b/src/TypedValue.zig @@ -176,7 +176,9 @@ pub fn print( var i: u32 = 0; while (i < max_len) : (i += 1) { - buf[i] = std.math.cast(u8, val.fieldValue(ty, i).toUnsignedInt(target)) orelse break :str; + const elem = val.fieldValue(ty, i); + if (elem.isUndef()) break :str; + buf[i] = std.math.cast(u8, elem.toUnsignedInt(target)) orelse break :str; } const truncated = if (len > max_string_len) " (truncated)" else ""; @@ -390,6 +392,7 @@ pub fn print( while (i < max_len) : (i += 1) { var elem_buf: Value.ElemValueBuffer = undefined; const elem_val = payload.ptr.elemValueBuffer(mod, i, &elem_buf); + if (elem_val.isUndef()) break :str; buf[i] = std.math.cast(u8, elem_val.toUnsignedInt(target)) orelse break :str; } -- 2.54.0 From d8c3c11c6c5288118b3529c6a99810a4c4add9e9 Mon Sep 17 00:00:00 2001 From: Jiacai Liu Date: Mon, 30 Jan 2023 06:00:14 +0800 Subject: [PATCH 27/84] std: add expectEqualDeep (#13995) --- lib/std/testing.zig | 246 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 246 insertions(+) diff --git a/lib/std/testing.zig b/lib/std/testing.zig index 53877967c95e1e39bbdc1a95cd2f214d63944c28..895a9a097392de005a5e37d8b07a720bd4762335 100644 --- a/lib/std/testing.zig +++ b/lib/std/testing.zig @@ -670,6 +670,252 @@ pub fn expectStringEndsWith(actual: []const u8, expected_ends_with: []const u8) return error.TestExpectedEndsWith; } +/// This function is intended to be used only in tests. When the two values are not +/// deeply equal, prints diagnostics to stderr to show exactly how they are not equal, +/// then returns a test failure error. +/// `actual` is casted to the type of `expected`. +/// +/// Deeply equal is defined as follows: +/// Primitive types are deeply equal if they are equal using `==` operator. +/// Struct values are deeply equal if their corresponding fields are deeply equal. +/// Container types(like Array/Slice/Vector) deeply equal when their corresponding elements are deeply equal. +/// Pointer values are deeply equal if values they point to are deeply equal. +/// +/// Note: Self-referential structs are not supported (e.g. things like std.SinglyLinkedList) +pub fn expectEqualDeep(expected: anytype, actual: @TypeOf(expected)) !void { + switch (@typeInfo(@TypeOf(actual))) { + .NoReturn, + .Opaque, + .Frame, + .AnyFrame, + => @compileError("value of type " ++ @typeName(@TypeOf(actual)) ++ " encountered"), + + .Undefined, + .Null, + .Void, + => return, + + .Type => { + if (actual != expected) { + std.debug.print("expected type {s}, found type {s}\n", .{ @typeName(expected), @typeName(actual) }); + return error.TestExpectedEqual; + } + }, + + .Bool, + .Int, + .Float, + .ComptimeFloat, + .ComptimeInt, + .EnumLiteral, + .Enum, + .Fn, + .ErrorSet, + => { + if (actual != expected) { + std.debug.print("expected {}, found {}\n", .{ expected, actual }); + return error.TestExpectedEqual; + } + }, + + .Pointer => |pointer| { + switch (pointer.size) { + // We have no idea what is behind those pointers, so the best we can do is `==` check. + .C, .Many => { + if (actual != expected) { + std.debug.print("expected {*}, found {*}\n", .{ expected, actual }); + return error.TestExpectedEqual; + } + }, + .One => { + // Length of those pointers are runtime value, so the best we can do is `==` check. + switch (@typeInfo(pointer.child)) { + .Fn, .Opaque => { + if (actual != expected) { + std.debug.print("expected {*}, found {*}\n", .{ expected, actual }); + return error.TestExpectedEqual; + } + }, + else => try expectEqualDeep(expected.*, actual.*), + } + }, + .Slice => { + if (expected.len != actual.len) { + std.debug.print("Slice len not the same, expected {d}, found {d}\n", .{ expected.len, actual.len }); + return error.TestExpectedEqual; + } + var i: usize = 0; + while (i < expected.len) : (i += 1) { + expectEqualDeep(expected[i], actual[i]) catch |e| { + std.debug.print("index {d} incorrect. expected {any}, found {any}\n", .{ + i, expected[i], actual[i], + }); + return e; + }; + } + }, + } + }, + + .Array => |_| { + if (expected.len != actual.len) { + std.debug.print("Array len not the same, expected {d}, found {d}\n", .{ expected.len, actual.len }); + return error.TestExpectedEqual; + } + var i: usize = 0; + while (i < expected.len) : (i += 1) { + expectEqualDeep(expected[i], actual[i]) catch |e| { + std.debug.print("index {d} incorrect. expected {any}, found {any}\n", .{ + i, expected[i], actual[i], + }); + return e; + }; + } + }, + + .Vector => |info| { + if (info.len != @typeInfo(@TypeOf(actual)).Vector.len) { + std.debug.print("Vector len not the same, expected {d}, found {d}\n", .{ info.len, @typeInfo(@TypeOf(actual)).Vector.len }); + return error.TestExpectedEqual; + } + var i: usize = 0; + while (i < info.len) : (i += 1) { + expectEqualDeep(expected[i], actual[i]) catch |e| { + std.debug.print("index {d} incorrect. expected {any}, found {any}\n", .{ + i, expected[i], actual[i], + }); + return e; + }; + } + }, + + .Struct => |structType| { + inline for (structType.fields) |field| { + expectEqualDeep(@field(expected, field.name), @field(actual, field.name)) catch |e| { + std.debug.print("Field {s} incorrect. expected {any}, found {any}\n", .{ field.name, @field(expected, field.name), @field(actual, field.name) }); + return e; + }; + } + }, + + .Union => |union_info| { + if (union_info.tag_type == null) { + @compileError("Unable to compare untagged union values"); + } + + const Tag = std.meta.Tag(@TypeOf(expected)); + + const expectedTag = @as(Tag, expected); + const actualTag = @as(Tag, actual); + + try expectEqual(expectedTag, actualTag); + + // we only reach this loop if the tags are equal + switch (expected) { + inline else => |val, tag| { + try expectEqualDeep(val, @field(actual, @tagName(tag))); + }, + } + }, + + .Optional => { + if (expected) |expected_payload| { + if (actual) |actual_payload| { + try expectEqualDeep(expected_payload, actual_payload); + } else { + std.debug.print("expected {any}, found null\n", .{expected_payload}); + return error.TestExpectedEqual; + } + } else { + if (actual) |actual_payload| { + std.debug.print("expected null, found {any}\n", .{actual_payload}); + return error.TestExpectedEqual; + } + } + }, + + .ErrorUnion => { + if (expected) |expected_payload| { + if (actual) |actual_payload| { + try expectEqualDeep(expected_payload, actual_payload); + } else |actual_err| { + std.debug.print("expected {any}, found {any}\n", .{ expected_payload, actual_err }); + return error.TestExpectedEqual; + } + } else |expected_err| { + if (actual) |actual_payload| { + std.debug.print("expected {any}, found {any}\n", .{ expected_err, actual_payload }); + return error.TestExpectedEqual; + } else |actual_err| { + try expectEqualDeep(expected_err, actual_err); + } + } + }, + } +} + +test "expectEqualDeep primitive type" { + try expectEqualDeep(1, 1); + try expectEqualDeep(true, true); + try expectEqualDeep(1.5, 1.5); + try expectEqualDeep(u8, u8); + try expectEqualDeep(error.Bad, error.Bad); + + // optional + { + const foo: ?u32 = 1; + const bar: ?u32 = 1; + try expectEqualDeep(foo, bar); + try expectEqualDeep(?u32, ?u32); + } + // function type + { + const fnType = struct { + fn foo() void { + unreachable; + } + }.foo; + try expectEqualDeep(fnType, fnType); + } +} + +test "expectEqualDeep pointer" { + const a = 1; + const b = 1; + try expectEqualDeep(&a, &b); +} + +test "expectEqualDeep composite type" { + try expectEqualDeep("abc", "abc"); + const s1: []const u8 = "abc"; + const s2 = "abcd"; + const s3: []const u8 = s2[0..3]; + try expectEqualDeep(s1, s3); + + const TestStruct = struct { s: []const u8 }; + try expectEqualDeep(TestStruct{ .s = "abc" }, TestStruct{ .s = "abc" }); + try expectEqualDeep([_][]const u8{ "a", "b", "c" }, [_][]const u8{ "a", "b", "c" }); + + // vector + try expectEqualDeep(@splat(4, @as(u32, 4)), @splat(4, @as(u32, 4))); + + // nested array + { + const a = [2][2]f32{ + [_]f32{ 1.0, 0.0 }, + [_]f32{ 0.0, 1.0 }, + }; + + const b = [2][2]f32{ + [_]f32{ 1.0, 0.0 }, + [_]f32{ 0.0, 1.0 }, + }; + + try expectEqualDeep(a, b); + try expectEqualDeep(&a, &b); + } +} + fn printIndicatorLine(source: []const u8, indicator_index: usize) void { const line_begin_index = if (std.mem.lastIndexOfScalar(u8, source[0..indicator_index], '\n')) |line_begin| line_begin + 1 -- 2.54.0 From 885d6968958e1cad4862ed1b6f1ea0b2d84c3845 Mon Sep 17 00:00:00 2001 From: Techatrix <19954306+Techatrix@users.noreply.github.com> Date: Sun, 29 Jan 2023 17:37:48 +0100 Subject: [PATCH 28/84] zig fmt: fix file ending in a multi line comment --- lib/std/zig/parser_test.zig | 9 +++++++++ lib/std/zig/render.zig | 3 +-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/std/zig/parser_test.zig b/lib/std/zig/parser_test.zig index 42eb1abdde885442361507bbf25e7616d7d09ff3..49b0715695502a6cf50314504a03fa7f9b2c593a 100644 --- a/lib/std/zig/parser_test.zig +++ b/lib/std/zig/parser_test.zig @@ -186,6 +186,15 @@ test "zig fmt: file ends in comment" { ); } +test "zig fmt: file ends in multi line comment" { + try testTransform( + \\ \\foobar + , + \\\\foobar + \\ + ); +} + test "zig fmt: file ends in comment after var decl" { try testTransform( \\const x = 42; diff --git a/lib/std/zig/render.zig b/lib/std/zig/render.zig index bfee5b0599ccfc64edcbe745a93f82261532cd08..1145007ff36b92a92dc5e624468574378624d5b7 100644 --- a/lib/std/zig/render.zig +++ b/lib/std/zig/render.zig @@ -2759,8 +2759,7 @@ fn tokenSliceForRender(tree: Ast, token_index: Ast.TokenIndex) []const u8 { var ret = tree.tokenSlice(token_index); switch (tree.tokens.items(.tag)[token_index]) { .multiline_string_literal_line => { - assert(ret[ret.len - 1] == '\n'); - ret.len -= 1; + if (ret[ret.len - 1] == '\n') ret.len -= 1; }, .container_doc_comment, .doc_comment => { ret = mem.trimRight(u8, ret, &std.ascii.whitespace); -- 2.54.0 From 720d82721fa6013b2e7e7ff2866db9404bfd2901 Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Sun, 22 Jan 2023 17:26:32 +0200 Subject: [PATCH 29/84] Sema: ensure args to inline comptime args are comptime-known Closes #14413 --- src/Sema.zig | 5 +++++ ...ine_call_runtime_value_to_comptime_param.zig | 17 +++++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 test/cases/compile_errors/inline_call_runtime_value_to_comptime_param.zig diff --git a/src/Sema.zig b/src/Sema.zig index 9c553a009236fb83279a65872a877465452601be..3b744a4f7891e3eb172cd4d73a4899be76bf1e46 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -6879,6 +6879,8 @@ fn analyzeInlineCallArg( if (err == error.AnalysisFail and param_block.comptime_reason != null) try param_block.comptime_reason.?.explain(sema, sema.err); return err; }; + } else if (!is_comptime_call and zir_tags[inst] == .param_comptime) { + _ = try sema.resolveConstMaybeUndefVal(arg_block, arg_src, uncasted_arg, "parameter is comptime"); } const casted_arg = sema.coerceExtra(arg_block, param_ty, uncasted_arg, arg_src, .{ .param_src = .{ .func_inst = func_inst, @@ -6952,6 +6954,9 @@ fn analyzeInlineCallArg( .val = arg_val, }; } else { + if (zir_tags[inst] == .param_anytype_comptime) { + _ = try sema.resolveConstMaybeUndefVal(arg_block, arg_src, uncasted_arg, "parameter is comptime"); + } sema.inst_map.putAssumeCapacityNoClobber(inst, uncasted_arg); } diff --git a/test/cases/compile_errors/inline_call_runtime_value_to_comptime_param.zig b/test/cases/compile_errors/inline_call_runtime_value_to_comptime_param.zig new file mode 100644 index 0000000000000000000000000000000000000000..cddd91384b2e928cb0af5c4a34dec88917feaa04 --- /dev/null +++ b/test/cases/compile_errors/inline_call_runtime_value_to_comptime_param.zig @@ -0,0 +1,17 @@ +inline fn needComptime(comptime a: u64) void { + if (a != 0) @compileError("foo"); +} +fn acceptRuntime(value: u64) void { + needComptime(value); +} +pub export fn entry() void { + var value: u64 = 0; + acceptRuntime(value); +} + +// error +// backend=stage2 +// target=native +// +// :5:18: error: unable to resolve comptime value +// :5:18: note: parameter is comptime -- 2.54.0 From dd300d47b22c740ab75ace54057a3831606f7952 Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Mon, 23 Jan 2023 20:23:12 +0200 Subject: [PATCH 30/84] add test for already implemented proposal Closes #1564 --- test/behavior/sizeof_and_typeof.zig | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/behavior/sizeof_and_typeof.zig b/test/behavior/sizeof_and_typeof.zig index ef4487d9b966040535da6fa333381d66c94ed89e..cfe948ac02d5695e9abe01548b922c189fb8b628 100644 --- a/test/behavior/sizeof_and_typeof.zig +++ b/test/behavior/sizeof_and_typeof.zig @@ -292,3 +292,12 @@ test "@sizeOf optional of previously unresolved union" { const Node = union { a: usize }; try expect(@sizeOf(?Node) == @sizeOf(Node) + @alignOf(Node)); } + +test "@offsetOf zero-bit field" { + const S = packed struct { + a: u32, + b: u0, + c: u32, + }; + try expect(@offsetOf(S, "b") == @offsetOf(S, "c")); +} -- 2.54.0 From b129350cb5de2251d50b142a50d8d74ccd92ae73 Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Fri, 27 Jan 2023 15:54:11 +0200 Subject: [PATCH 31/84] AstGen: fix crash on invalid decltest Closes #14476 --- src/AstGen.zig | 29 ++++++++++++++++++- .../cases/compile_errors/invalid_decltest.zig | 13 +++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 test/cases/compile_errors/invalid_decltest.zig diff --git a/src/AstGen.zig b/src/AstGen.zig index 15b3611a1e67615fed558cbdf6bb40f9858a95ac..df111906e670594145c870ca827f573dfca4341d 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -4278,7 +4278,34 @@ fn testDecl( var num_namespaces_out: u32 = 0; var capturing_namespace: ?*Scope.Namespace = null; while (true) switch (s.tag) { - .local_val, .local_ptr => unreachable, // a test cannot be in a local scope + .local_val => { + const local_val = s.cast(Scope.LocalVal).?; + if (local_val.name == name_str_index) { + local_val.used = test_name_token; + return astgen.failTokNotes(test_name_token, "cannot test a {s}", .{ + @tagName(local_val.id_cat), + }, &[_]u32{ + try astgen.errNoteTok(local_val.token_src, "{s} declared here", .{ + @tagName(local_val.id_cat), + }), + }); + } + s = local_val.parent; + }, + .local_ptr => { + const local_ptr = s.cast(Scope.LocalPtr).?; + if (local_ptr.name == name_str_index) { + local_ptr.used = test_name_token; + return astgen.failTokNotes(test_name_token, "cannot test a {s}", .{ + @tagName(local_ptr.id_cat), + }, &[_]u32{ + try astgen.errNoteTok(local_ptr.token_src, "{s} declared here", .{ + @tagName(local_ptr.id_cat), + }), + }); + } + s = local_ptr.parent; + }, .gen_zir => s = s.cast(GenZir).?.parent, .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent, .namespace, .enum_namespace => { diff --git a/test/cases/compile_errors/invalid_decltest.zig b/test/cases/compile_errors/invalid_decltest.zig new file mode 100644 index 0000000000000000000000000000000000000000..cde984f36603482d460307fb8178863477e629c0 --- /dev/null +++ b/test/cases/compile_errors/invalid_decltest.zig @@ -0,0 +1,13 @@ +export fn foo() void { + const a = 1; + struct { + test a {} + }; +} + +// error +// backend=stage2 +// target=native +// +// :4:14: error: cannot test a local constant +// :2:11: note: local constant declared here -- 2.54.0 From a9785fe8eef564011b4266e8a1b9aa15b7e37189 Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Fri, 27 Jan 2023 16:03:51 +0200 Subject: [PATCH 32/84] Sema: add helpful notes to invalid `@ptrCast` operations Closes #14474 --- doc/langref.html.in | 9 +++++++++ src/Sema.zig | 11 ++++++++++- .../increase_pointer_alignment_in_ptrCast.zig | 1 + 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/doc/langref.html.in b/doc/langref.html.in index fd4aa8ae7615d4bd77861885c3bf711ad7f57459..e1521795ca1f4197b2a7240cad5203e058fa40b3 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -8799,6 +8799,15 @@ pub const PrefetchOptions = struct { {#link|Optional Pointers#} are allowed. Casting an optional pointer which is {#link|null#} to a non-optional pointer invokes safety-checked {#link|Undefined Behavior#}.

+

+ {#syntax#}@ptrCast{#endsyntax#} cannot be used for: +

+
    +
  • Removing {#syntax#}const{#endsyntax#} or {#syntax#}volatile{#endsyntax#} qualifier. TODO add a {#syntax#}@qualCast{#endsyntax#} builtin.
  • +
  • Changing pointer address space, use {#link|@addrSpaceCast#}
  • +
  • Increasing pointer alignment, use {#link|@alignCast#}
  • +
  • Casting a non-slice pointer to a slice, use slicing syntax {#syntax#}ptr[start..end]{#endsyntax#}
  • +
{#header_close#} {#header_open|@ptrToInt#} diff --git a/src/Sema.zig b/src/Sema.zig index 3b744a4f7891e3eb172cd4d73a4899be76bf1e46..712a684bf8628b1f5120ce7004e74452d4810d98 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -19535,7 +19535,14 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air return sema.fail(block, src, "cast discards volatile qualifier", .{}); } if (operand_info.@"addrspace" != dest_info.@"addrspace") { - return sema.fail(block, src, "cast changes pointer address space", .{}); + const msg = msg: { + const msg = try sema.errMsg(block, src, "cast changes pointer address space", .{}); + errdefer msg.destroy(sema.gpa); + + try sema.errNote(block, src, msg, "consider using '@addrSpaceCast'", .{}); + break :msg msg; + }; + return sema.failWithOwnedErrorMsg(msg); } const dest_is_slice = dest_ty.isSlice(); @@ -19590,6 +19597,8 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air try sema.errNote(block, dest_ty_src, msg, "'{}' has alignment '{d}'", .{ dest_ty.fmt(sema.mod), dest_align, }); + + try sema.errNote(block, src, msg, "consider using '@alignCast'", .{}); break :msg msg; }; return sema.failWithOwnedErrorMsg(msg); diff --git a/test/cases/compile_errors/increase_pointer_alignment_in_ptrCast.zig b/test/cases/compile_errors/increase_pointer_alignment_in_ptrCast.zig index 9cc5ed3a4226942eb1982425f7bb6e22022cd130..242454e859c7ebc33d3b21dc9c3a288be12c8929 100644 --- a/test/cases/compile_errors/increase_pointer_alignment_in_ptrCast.zig +++ b/test/cases/compile_errors/increase_pointer_alignment_in_ptrCast.zig @@ -11,3 +11,4 @@ export fn entry() u32 { // :3:17: error: cast increases pointer alignment // :3:32: note: '*u8' has alignment '1' // :3:26: note: '*u32' has alignment '4' +// :3:17: note: consider using '@alignCast' -- 2.54.0 From fe4ea31f7e9e1c8caea6a1df107b91e8ea1a7b8a Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Fri, 27 Jan 2023 16:04:58 +0200 Subject: [PATCH 33/84] Sema: replace backticks with single quotes Most error messages already use single quotes for everything so this makes the remaining ones consistent. --- src/Sema.zig | 10 +++++----- ...ionals_with_a_function_that_returns_an_optional.zig | 2 +- test/cases/compile_errors/discarding_error_value.zig | 2 +- .../helpful_return_type_error_message.zig | 4 ++-- .../compile_errors/ignored_deferred_function_call.zig | 2 +- .../ignored_expression_in_while_continuation.zig | 6 +++--- ...on_of_optional_anyopaque_to_anyopaque_must_fail.zig | 2 +- ...properly_when_assigning_a_value_within_a_struct.zig | 2 +- ...ation_incompatibility_mismatching_handle_is_ptr.zig | 2 +- ...tibility_mismatching_handle_is_ptr_generic_call.zig | 2 +- 10 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/Sema.zig b/src/Sema.zig index 712a684bf8628b1f5120ce7004e74452d4810d98..b4731d9509f6be0efcfdd5940943005a37e20caf 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -3294,7 +3294,7 @@ fn ensureResultUsed( const msg = msg: { const msg = try sema.errMsg(block, src, "error is ignored", .{}); errdefer msg.destroy(sema.gpa); - try sema.errNote(block, src, msg, "consider using `try`, `catch`, or `if`", .{}); + try sema.errNote(block, src, msg, "consider using 'try', 'catch', or 'if'", .{}); break :msg msg; }; return sema.failWithOwnedErrorMsg(msg); @@ -3325,7 +3325,7 @@ fn zirEnsureResultNonError(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com const msg = msg: { const msg = try sema.errMsg(block, src, "error is discarded", .{}); errdefer msg.destroy(sema.gpa); - try sema.errNote(block, src, msg, "consider using `try`, `catch`, or `if`", .{}); + try sema.errNote(block, src, msg, "consider using 'try', 'catch', or 'if'", .{}); break :msg msg; }; return sema.failWithOwnedErrorMsg(msg); @@ -8477,7 +8477,7 @@ fn handleExternLibName( return sema.fail( block, src_loc, - "dependency on dynamic library '{s}' requires enabling Position Independent Code. Fixed by `-l{s}` or `-fPIC`.", + "dependency on dynamic library '{s}' requires enabling Position Independent Code. Fixed by '-l{s}' or '-fPIC'.", .{ lib_name, lib_name }, ); } @@ -25150,7 +25150,7 @@ fn coerceExtra( (try sema.coerceInMemoryAllowed(block, inst_ty.errorUnionPayload(), dest_ty, false, target, dest_ty_src, inst_src)) == .ok) { try sema.errNote(block, inst_src, msg, "cannot convert error union to payload type", .{}); - try sema.errNote(block, inst_src, msg, "consider using `try`, `catch`, or `if`", .{}); + try sema.errNote(block, inst_src, msg, "consider using 'try', 'catch', or 'if'", .{}); } // ?T to T @@ -25159,7 +25159,7 @@ fn coerceExtra( (try sema.coerceInMemoryAllowed(block, inst_ty.optionalChild(&buf), dest_ty, false, target, dest_ty_src, inst_src)) == .ok) { try sema.errNote(block, inst_src, msg, "cannot convert optional to payload type", .{}); - try sema.errNote(block, inst_src, msg, "consider using `.?`, `orelse`, or `if`", .{}); + try sema.errNote(block, inst_src, msg, "consider using '.?', 'orelse', or 'if'", .{}); } try in_memory_result.report(sema, block, inst_src, msg); diff --git a/test/cases/compile_errors/assigning_to_struct_or_union_fields_that_are_not_optionals_with_a_function_that_returns_an_optional.zig b/test/cases/compile_errors/assigning_to_struct_or_union_fields_that_are_not_optionals_with_a_function_that_returns_an_optional.zig index 762eb284f2dffa682f5af382ec6cc14a9eeb88b4..530e5ffb746fe2ab96a9aaa234773878d704648b 100644 --- a/test/cases/compile_errors/assigning_to_struct_or_union_fields_that_are_not_optionals_with_a_function_that_returns_an_optional.zig +++ b/test/cases/compile_errors/assigning_to_struct_or_union_fields_that_are_not_optionals_with_a_function_that_returns_an_optional.zig @@ -20,4 +20,4 @@ export fn entry() void { // // :11:27: error: expected type 'u8', found '?u8' // :11:27: note: cannot convert optional to payload type -// :11:27: note: consider using `.?`, `orelse`, or `if` +// :11:27: note: consider using '.?', 'orelse', or 'if' diff --git a/test/cases/compile_errors/discarding_error_value.zig b/test/cases/compile_errors/discarding_error_value.zig index 6dfe0be2313f1990ed166ce4d64ccdc7e535b014..c24d517d3e3b39133b0e1ec9af2a79239a24df89 100644 --- a/test/cases/compile_errors/discarding_error_value.zig +++ b/test/cases/compile_errors/discarding_error_value.zig @@ -10,4 +10,4 @@ fn foo() !void { // target=native // // :2:12: error: error is discarded -// :2:12: note: consider using `try`, `catch`, or `if` +// :2:12: note: consider using 'try', 'catch', or 'if' diff --git a/test/cases/compile_errors/helpful_return_type_error_message.zig b/test/cases/compile_errors/helpful_return_type_error_message.zig index b8e48036de78a8e026b5ce97b59e3ac926ae1dc6..871e9485372c950d496691a858ee3c687e5a2ef1 100644 --- a/test/cases/compile_errors/helpful_return_type_error_message.zig +++ b/test/cases/compile_errors/helpful_return_type_error_message.zig @@ -26,7 +26,7 @@ export fn quux() u32 { // :11:15: error: expected type 'u32', found '@typeInfo(@typeInfo(@TypeOf(tmp.bar)).Fn.return_type.?).ErrorUnion.error_set!u32' // :10:17: note: function cannot return an error // :11:15: note: cannot convert error union to payload type -// :11:15: note: consider using `try`, `catch`, or `if` +// :11:15: note: consider using 'try', 'catch', or 'if' // :15:14: error: expected type 'u32', found '@typeInfo(@typeInfo(@TypeOf(tmp.bar)).Fn.return_type.?).ErrorUnion.error_set!u32' // :15:14: note: cannot convert error union to payload type -// :15:14: note: consider using `try`, `catch`, or `if` +// :15:14: note: consider using 'try', 'catch', or 'if' diff --git a/test/cases/compile_errors/ignored_deferred_function_call.zig b/test/cases/compile_errors/ignored_deferred_function_call.zig index 05c4373705227b974529365be866124941b3737b..b318baa16cb563b01926c78a4261fe56ac63b9de 100644 --- a/test/cases/compile_errors/ignored_deferred_function_call.zig +++ b/test/cases/compile_errors/ignored_deferred_function_call.zig @@ -8,4 +8,4 @@ fn bar() anyerror!i32 { return 0; } // target=native // // :2:14: error: error is ignored -// :2:14: note: consider using `try`, `catch`, or `if` +// :2:14: note: consider using 'try', 'catch', or 'if' diff --git a/test/cases/compile_errors/ignored_expression_in_while_continuation.zig b/test/cases/compile_errors/ignored_expression_in_while_continuation.zig index d7de0aac57809257a98d78e741801c3648b8d1b8..d108903c82189767de44dc831f4bae600feb3419 100644 --- a/test/cases/compile_errors/ignored_expression_in_while_continuation.zig +++ b/test/cases/compile_errors/ignored_expression_in_while_continuation.zig @@ -18,8 +18,8 @@ fn bad() anyerror!void { // target=native // // :2:24: error: error is ignored -// :2:24: note: consider using `try`, `catch`, or `if` +// :2:24: note: consider using 'try', 'catch', or 'if' // :6:25: error: error is ignored -// :6:25: note: consider using `try`, `catch`, or `if` +// :6:25: note: consider using 'try', 'catch', or 'if' // :10:25: error: error is ignored -// :10:25: note: consider using `try`, `catch`, or `if` +// :10:25: note: consider using 'try', 'catch', or 'if' diff --git a/test/cases/compile_errors/issue_5618_coercion_of_optional_anyopaque_to_anyopaque_must_fail.zig b/test/cases/compile_errors/issue_5618_coercion_of_optional_anyopaque_to_anyopaque_must_fail.zig index f4716bc24d0012b8af21e112e2318c09681e0cda..95bba054b3afbc8b337d43e5ae630be740e6f07f 100644 --- a/test/cases/compile_errors/issue_5618_coercion_of_optional_anyopaque_to_anyopaque_must_fail.zig +++ b/test/cases/compile_errors/issue_5618_coercion_of_optional_anyopaque_to_anyopaque_must_fail.zig @@ -10,5 +10,5 @@ export fn foo() void { // // :4:9: error: expected type '*anyopaque', found '?*anyopaque' // :4:9: note: cannot convert optional to payload type -// :4:9: note: consider using `.?`, `orelse`, or `if` +// :4:9: note: consider using '.?', 'orelse', or 'if' // :4:9: note: '?*anyopaque' could have null values which are illegal in type '*anyopaque' diff --git a/test/cases/compile_errors/regression_test_2980_base_type_u32_is_not_type_checked_properly_when_assigning_a_value_within_a_struct.zig b/test/cases/compile_errors/regression_test_2980_base_type_u32_is_not_type_checked_properly_when_assigning_a_value_within_a_struct.zig index 09c496211a3dc8d104362c59144ffae986a4833a..1b951528bbb260bd14eaa5f2f9a5dd5dd519b1e1 100644 --- a/test/cases/compile_errors/regression_test_2980_base_type_u32_is_not_type_checked_properly_when_assigning_a_value_within_a_struct.zig +++ b/test/cases/compile_errors/regression_test_2980_base_type_u32_is_not_type_checked_properly_when_assigning_a_value_within_a_struct.zig @@ -20,4 +20,4 @@ export fn entry() void { // // :12:25: error: expected type 'u32', found '@typeInfo(@typeInfo(@TypeOf(tmp.get_uval)).Fn.return_type.?).ErrorUnion.error_set!u32' // :12:25: note: cannot convert error union to payload type -// :12:25: note: consider using `try`, `catch`, or `if` +// :12:25: note: consider using 'try', 'catch', or 'if' diff --git a/test/cases/compile_errors/result_location_incompatibility_mismatching_handle_is_ptr.zig b/test/cases/compile_errors/result_location_incompatibility_mismatching_handle_is_ptr.zig index cc1d2c976adb4622b3d8f9ef7ca81e68aff2e2f5..26c1a8d9cf348a385a172893c289a95d57cec84c 100644 --- a/test/cases/compile_errors/result_location_incompatibility_mismatching_handle_is_ptr.zig +++ b/test/cases/compile_errors/result_location_incompatibility_mismatching_handle_is_ptr.zig @@ -17,4 +17,4 @@ pub const Container = struct { // // :3:36: error: expected type 'i32', found '?i32' // :3:36: note: cannot convert optional to payload type -// :3:36: note: consider using `.?`, `orelse`, or `if` +// :3:36: note: consider using '.?', 'orelse', or 'if' diff --git a/test/cases/compile_errors/result_location_incompatibility_mismatching_handle_is_ptr_generic_call.zig b/test/cases/compile_errors/result_location_incompatibility_mismatching_handle_is_ptr_generic_call.zig index 897675d44814490681dfa4ea2f6a3d3f08032146..471f9cca04d8f1b999ff6dcc1704831a9be187db 100644 --- a/test/cases/compile_errors/result_location_incompatibility_mismatching_handle_is_ptr_generic_call.zig +++ b/test/cases/compile_errors/result_location_incompatibility_mismatching_handle_is_ptr_generic_call.zig @@ -17,4 +17,4 @@ pub const Container = struct { // // :3:36: error: expected type 'i32', found '?i32' // :3:36: note: cannot convert optional to payload type -// :3:36: note: consider using `.?`, `orelse`, or `if` +// :3:36: note: consider using '.?', 'orelse', or 'if' -- 2.54.0 From f16c10a86b7183e99e54a70344f4681211cd52bb Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Fri, 27 Jan 2023 20:25:48 +0200 Subject: [PATCH 34/84] implement `@qualCast` --- doc/langref.html.in | 15 +++-- lib/std/child_process.zig | 4 +- lib/std/fs.zig | 2 +- lib/std/os.zig | 2 +- lib/std/os/windows.zig | 14 ++--- lib/std/zig/c_translation.zig | 2 +- src/AstGen.zig | 2 + src/BuiltinFn.zig | 8 +++ src/Sema.zig | 62 ++++++++++++++++++- src/Zir.zig | 6 ++ src/print_zir.zig | 1 + .../cases/compile_errors/invalid_qualcast.zig | 12 ++++ .../ptrCast_discards_const_qualifier.zig | 1 + 13 files changed, 113 insertions(+), 18 deletions(-) create mode 100644 test/cases/compile_errors/invalid_qualcast.zig diff --git a/doc/langref.html.in b/doc/langref.html.in index e1521795ca1f4197b2a7240cad5203e058fa40b3..8c7781ee42654a2860404376cb288d0f2df900c3 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -8803,10 +8803,10 @@ pub const PrefetchOptions = struct { {#syntax#}@ptrCast{#endsyntax#} cannot be used for:

    -
  • Removing {#syntax#}const{#endsyntax#} or {#syntax#}volatile{#endsyntax#} qualifier. TODO add a {#syntax#}@qualCast{#endsyntax#} builtin.
  • -
  • Changing pointer address space, use {#link|@addrSpaceCast#}
  • -
  • Increasing pointer alignment, use {#link|@alignCast#}
  • -
  • Casting a non-slice pointer to a slice, use slicing syntax {#syntax#}ptr[start..end]{#endsyntax#}
  • +
  • Removing {#syntax#}const{#endsyntax#} or {#syntax#}volatile{#endsyntax#} qualifier, use {#link|@qualCast#}.
  • +
  • Changing pointer address space, use {#link|@addrSpaceCast#}.
  • +
  • Increasing pointer alignment, use {#link|@alignCast#}.
  • +
  • Casting a non-slice pointer to a slice, use slicing syntax {#syntax#}ptr[start..end]{#endsyntax#}.
{#header_close#} @@ -8820,6 +8820,13 @@ pub const PrefetchOptions = struct { {#header_close#} + {#header_open|@qualCast#} +
{#syntax#}@qualCast(comptime DestType: type, value: anytype) DestType{#endsyntax#}
+

+ Remove {#syntax#}const{#endsyntax#} or {#syntax#}volatile{#endsyntax#} qualifier from a pointer. +

+ {#header_close#} + {#header_open|@rem#}
{#syntax#}@rem(numerator: T, denominator: T) T{#endsyntax#}

diff --git a/lib/std/child_process.zig b/lib/std/child_process.zig index 4a816c83180e857362ad6f892c95962451dc8a34..21d7b4fe3e1cd7598b6086e76340ce9b20d2f95b 100644 --- a/lib/std/child_process.zig +++ b/lib/std/child_process.zig @@ -1164,7 +1164,7 @@ fn windowsCreateProcessPathExt( var app_name_unicode_string = windows.UNICODE_STRING{ .Length = app_name_len_bytes, .MaximumLength = app_name_len_bytes, - .Buffer = @intToPtr([*]u16, @ptrToInt(app_name_wildcard.ptr)), + .Buffer = @qualCast([*:0]u16, app_name_wildcard.ptr), }; const rc = windows.ntdll.NtQueryDirectoryFile( dir.fd, @@ -1261,7 +1261,7 @@ fn windowsCreateProcessPathExt( var app_name_unicode_string = windows.UNICODE_STRING{ .Length = app_name_len_bytes, .MaximumLength = app_name_len_bytes, - .Buffer = @intToPtr([*]u16, @ptrToInt(app_name_appended.ptr)), + .Buffer = @qualCast([*:0]u16, app_name_appended.ptr), }; // Re-use the directory handle but this time we call with the appended app name diff --git a/lib/std/fs.zig b/lib/std/fs.zig index 244f3a38ce1a83a64aebd7591de27104d76b563b..2300ad044a25edf129d72c12f0eb248aa7ddd735 100644 --- a/lib/std/fs.zig +++ b/lib/std/fs.zig @@ -1763,7 +1763,7 @@ pub const Dir = struct { var nt_name = w.UNICODE_STRING{ .Length = path_len_bytes, .MaximumLength = path_len_bytes, - .Buffer = @intToPtr([*]u16, @ptrToInt(sub_path_w)), + .Buffer = @qualCast([*:0]u16, sub_path_w), }; var attr = w.OBJECT_ATTRIBUTES{ .Length = @sizeOf(w.OBJECT_ATTRIBUTES), diff --git a/lib/std/os.zig b/lib/std/os.zig index 32463aa30ebef36e381fdb0088f42669c7d90809..3cee30c32da38cd4bea296e2a80390c0458f5e7a 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -4513,7 +4513,7 @@ pub fn faccessatW(dirfd: fd_t, sub_path_w: [*:0]const u16, mode: u32, flags: u32 var nt_name = windows.UNICODE_STRING{ .Length = path_len_bytes, .MaximumLength = path_len_bytes, - .Buffer = @intToPtr([*]u16, @ptrToInt(sub_path_w)), + .Buffer = @qualCast([*:0]u16, sub_path_w), }; var attr = windows.OBJECT_ATTRIBUTES{ .Length = @sizeOf(windows.OBJECT_ATTRIBUTES), diff --git a/lib/std/os/windows.zig b/lib/std/os/windows.zig index e53387b27c1cfab3984a346754710380beef31f9..93e762827b39c3df2b8939ba98a3e58974d3022c 100644 --- a/lib/std/os/windows.zig +++ b/lib/std/os/windows.zig @@ -85,7 +85,7 @@ pub fn OpenFile(sub_path_w: []const u16, options: OpenFileOptions) OpenError!HAN var nt_name = UNICODE_STRING{ .Length = path_len_bytes, .MaximumLength = path_len_bytes, - .Buffer = @intToPtr([*]u16, @ptrToInt(sub_path_w.ptr)), + .Buffer = @qualCast([*]u16, sub_path_w.ptr), }; var attr = OBJECT_ATTRIBUTES{ .Length = @sizeOf(OBJECT_ATTRIBUTES), @@ -634,7 +634,7 @@ pub fn SetCurrentDirectory(path_name: []const u16) SetCurrentDirectoryError!void var nt_name = UNICODE_STRING{ .Length = path_len_bytes, .MaximumLength = path_len_bytes, - .Buffer = @intToPtr([*]u16, @ptrToInt(path_name.ptr)), + .Buffer = @qualCast([*]u16, path_name.ptr), }; const rc = ntdll.RtlSetCurrentDirectory_U(&nt_name); @@ -766,7 +766,7 @@ pub fn ReadLink(dir: ?HANDLE, sub_path_w: []const u16, out_buffer: []u8) ReadLin var nt_name = UNICODE_STRING{ .Length = path_len_bytes, .MaximumLength = path_len_bytes, - .Buffer = @intToPtr([*]u16, @ptrToInt(sub_path_w.ptr)), + .Buffer = @qualCast([*]u16, sub_path_w.ptr), }; var attr = OBJECT_ATTRIBUTES{ .Length = @sizeOf(OBJECT_ATTRIBUTES), @@ -876,7 +876,7 @@ pub fn DeleteFile(sub_path_w: []const u16, options: DeleteFileOptions) DeleteFil .Length = path_len_bytes, .MaximumLength = path_len_bytes, // The Windows API makes this mutable, but it will not mutate here. - .Buffer = @intToPtr([*]u16, @ptrToInt(sub_path_w.ptr)), + .Buffer = @qualCast([*]u16, sub_path_w.ptr), }; if (sub_path_w[0] == '.' and sub_path_w[1] == 0) { @@ -1414,7 +1414,7 @@ pub fn sendmsg( } pub fn sendto(s: ws2_32.SOCKET, buf: [*]const u8, len: usize, flags: u32, to: ?*const ws2_32.sockaddr, to_len: ws2_32.socklen_t) i32 { - var buffer = ws2_32.WSABUF{ .len = @truncate(u31, len), .buf = @intToPtr([*]u8, @ptrToInt(buf)) }; + var buffer = ws2_32.WSABUF{ .len = @truncate(u31, len), .buf = @qualCast([*]u8, buf) }; var bytes_send: DWORD = undefined; if (ws2_32.WSASendTo(s, @ptrCast([*]ws2_32.WSABUF, &buffer), 1, &bytes_send, flags, to, @intCast(i32, to_len), null, null) == ws2_32.SOCKET_ERROR) { return ws2_32.SOCKET_ERROR; @@ -1876,13 +1876,13 @@ pub fn eqlIgnoreCaseWTF16(a: []const u16, b: []const u16) bool { const a_string = UNICODE_STRING{ .Length = a_bytes, .MaximumLength = a_bytes, - .Buffer = @intToPtr([*]u16, @ptrToInt(a.ptr)), + .Buffer = @qualCast([*]u16, a.ptr), }; const b_bytes = @intCast(u16, b.len * 2); const b_string = UNICODE_STRING{ .Length = b_bytes, .MaximumLength = b_bytes, - .Buffer = @intToPtr([*]u16, @ptrToInt(b.ptr)), + .Buffer = @qualCast([*]u16, b.ptr), }; return ntdll.RtlEqualUnicodeString(&a_string, &b_string, TRUE) == TRUE; } diff --git a/lib/std/zig/c_translation.zig b/lib/std/zig/c_translation.zig index a050e592a2fd729423f39219a83e3c99999d4efc..d33c74d777300db6637d188e41578a29d30788d3 100644 --- a/lib/std/zig/c_translation.zig +++ b/lib/std/zig/c_translation.zig @@ -75,7 +75,7 @@ fn castPtr(comptime DestType: type, target: anytype) DestType { const source = ptrInfo(@TypeOf(target)); if (source.is_const and !dest.is_const or source.is_volatile and !dest.is_volatile) - return @intToPtr(DestType, @ptrToInt(target)) + return @qualCast(DestType, target) else if (@typeInfo(dest.child) == .Opaque) // dest.alignment would error out return @ptrCast(DestType, target) diff --git a/src/AstGen.zig b/src/AstGen.zig index df111906e670594145c870ca827f573dfca4341d..a5667ce9e8664e0f892429c22ee62a09b45fda40 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -2530,6 +2530,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As .bit_size_of, .typeof_log2_int_type, .ptr_to_int, + .qual_cast, .align_of, .bool_to_int, .embed_file, @@ -8037,6 +8038,7 @@ fn builtinCall( .float_cast => return typeCast(gz, scope, ri, node, params[0], params[1], .float_cast), .int_cast => return typeCast(gz, scope, ri, node, params[0], params[1], .int_cast), .ptr_cast => return typeCast(gz, scope, ri, node, params[0], params[1], .ptr_cast), + .qual_cast => return typeCast(gz, scope, ri, node, params[0], params[1], .qual_cast), .truncate => return typeCast(gz, scope, ri, node, params[0], params[1], .truncate), // zig fmt: on diff --git a/src/BuiltinFn.zig b/src/BuiltinFn.zig index b71d96c3dd39049eed19028a5113fc14e979d17d..80eb7391858b35808e3d1c644eecd95f631af2c9 100644 --- a/src/BuiltinFn.zig +++ b/src/BuiltinFn.zig @@ -75,6 +75,7 @@ pub const Tag = enum { prefetch, ptr_cast, ptr_to_int, + qual_cast, rem, return_address, select, @@ -674,6 +675,13 @@ pub const list = list: { .param_count = 1, }, }, + .{ + "@qualCast", + .{ + .tag = .qual_cast, + .param_count = 2, + }, + }, .{ "@rem", .{ diff --git a/src/Sema.zig b/src/Sema.zig index b4731d9509f6be0efcfdd5940943005a37e20caf..d306c68e08570d6495a909eabd5169e985668c23 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -1015,6 +1015,7 @@ fn analyzeBodyInner( .float_cast => try sema.zirFloatCast(block, inst), .int_cast => try sema.zirIntCast(block, inst), .ptr_cast => try sema.zirPtrCast(block, inst), + .qual_cast => try sema.zirQualCast(block, inst), .truncate => try sema.zirTruncate(block, inst), .align_cast => try sema.zirAlignCast(block, inst), .has_decl => try sema.zirHasDecl(block, inst), @@ -19529,10 +19530,24 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air const operand_info = operand_ty.ptrInfo().data; const dest_info = dest_ty.ptrInfo().data; if (!operand_info.mutable and dest_info.mutable) { - return sema.fail(block, src, "cast discards const qualifier", .{}); + const msg = msg: { + const msg = try sema.errMsg(block, src, "cast discards const qualifier", .{}); + errdefer msg.destroy(sema.gpa); + + try sema.errNote(block, src, msg, "consider using '@qualCast'", .{}); + break :msg msg; + }; + return sema.failWithOwnedErrorMsg(msg); } if (operand_info.@"volatile" and !dest_info.@"volatile") { - return sema.fail(block, src, "cast discards volatile qualifier", .{}); + const msg = msg: { + const msg = try sema.errMsg(block, src, "cast discards volatile qualifier", .{}); + errdefer msg.destroy(sema.gpa); + + try sema.errNote(block, src, msg, "consider using '@qualCast'", .{}); + break :msg msg; + }; + return sema.failWithOwnedErrorMsg(msg); } if (operand_info.@"addrspace" != dest_info.@"addrspace") { const msg = msg: { @@ -19634,6 +19649,49 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air return block.addBitCast(aligned_dest_ty, ptr); } +fn zirQualCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { + const inst_data = sema.code.instructions.items(.data)[inst].pl_node; + const src = inst_data.src(); + const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; + const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; + const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; + const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs); + const operand = try sema.resolveInst(extra.rhs); + const operand_ty = sema.typeOf(operand); + + try sema.checkPtrType(block, dest_ty_src, dest_ty); + try sema.checkPtrOperand(block, operand_src, operand_ty); + + var operand_payload = operand_ty.ptrInfo(); + var dest_info = dest_ty.ptrInfo(); + + operand_payload.data.mutable = dest_info.data.mutable; + operand_payload.data.@"volatile" = dest_info.data.@"volatile"; + + const altered_operand_ty = Type.initPayload(&operand_payload.base); + if (!altered_operand_ty.eql(dest_ty, sema.mod)) { + const msg = msg: { + const msg = try sema.errMsg(block, src, "'@qualCast' can only modify 'const' and 'volatile' qualifiers", .{}); + errdefer msg.destroy(sema.gpa); + + dest_info.data.mutable = !operand_ty.isConstPtr(); + dest_info.data.@"volatile" = operand_ty.isVolatilePtr(); + const altered_dest_ty = Type.initPayload(&dest_info.base); + try sema.errNote(block, src, msg, "expected type '{}'", .{altered_dest_ty.fmt(sema.mod)}); + try sema.errNote(block, src, msg, "got type '{}'", .{operand_ty.fmt(sema.mod)}); + break :msg msg; + }; + return sema.failWithOwnedErrorMsg(msg); + } + + if (try sema.resolveMaybeUndefVal(operand)) |operand_val| { + return sema.addConstant(dest_ty, operand_val); + } + + try sema.requireRuntimeBlock(block, src, null); + return block.addBitCast(dest_ty, operand); +} + fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { const inst_data = sema.code.instructions.items(.data)[inst].pl_node; const src = inst_data.src(); diff --git a/src/Zir.zig b/src/Zir.zig index 94e6a9a11a66d41d84a2d1cd918f03e91cea0172..b93422177ea3efc6cb6bf798c13ffb64ff579b83 100644 --- a/src/Zir.zig +++ b/src/Zir.zig @@ -857,6 +857,9 @@ pub const Inst = struct { /// Implements the `@ptrCast` builtin. /// Uses `pl_node` with payload `Bin`. `lhs` is dest type, `rhs` is operand. ptr_cast, + /// Implements the `@qualCast` builtin. + /// Uses `pl_node` with payload `Bin`. `lhs` is dest type, `rhs` is operand. + qual_cast, /// Implements the `@truncate` builtin. /// Uses `pl_node` with payload `Bin`. `lhs` is dest type, `rhs` is operand. truncate, @@ -1195,6 +1198,7 @@ pub const Inst = struct { .float_cast, .int_cast, .ptr_cast, + .qual_cast, .truncate, .align_cast, .has_field, @@ -1484,6 +1488,7 @@ pub const Inst = struct { .float_cast, .int_cast, .ptr_cast, + .qual_cast, .truncate, .align_cast, .has_field, @@ -1755,6 +1760,7 @@ pub const Inst = struct { .float_cast = .pl_node, .int_cast = .pl_node, .ptr_cast = .pl_node, + .qual_cast = .pl_node, .truncate = .pl_node, .align_cast = .pl_node, .typeof_builtin = .pl_node, diff --git a/src/print_zir.zig b/src/print_zir.zig index 6e8923bed97dae217157a32c5ebc8cb986f56853..e5fc8815edec153f684eb7f162f161c57a53edac 100644 --- a/src/print_zir.zig +++ b/src/print_zir.zig @@ -332,6 +332,7 @@ const Writer = struct { .float_cast, .int_cast, .ptr_cast, + .qual_cast, .truncate, .align_cast, .div_exact, diff --git a/test/cases/compile_errors/invalid_qualcast.zig b/test/cases/compile_errors/invalid_qualcast.zig new file mode 100644 index 0000000000000000000000000000000000000000..20b223b727df6e3a5e1463b7e14b62716a9d0881 --- /dev/null +++ b/test/cases/compile_errors/invalid_qualcast.zig @@ -0,0 +1,12 @@ +pub export fn entry() void { + var a: [*:0]const volatile u16 = undefined; + _ = @qualCast([*]u16, a); +} + +// error +// backend=stage2 +// target=native +// +// :3:9: error: '@qualCast' can only modify 'const' and 'volatile' qualifiers +// :3:9: note: expected type '[*]const volatile u16' +// :3:9: note: got type '[*:0]const volatile u16' diff --git a/test/cases/compile_errors/ptrCast_discards_const_qualifier.zig b/test/cases/compile_errors/ptrCast_discards_const_qualifier.zig index a2fea4ff11925c62b354e09ed458d8f14ac7123a..eedef01234ac34206829b618f668326bf34185f5 100644 --- a/test/cases/compile_errors/ptrCast_discards_const_qualifier.zig +++ b/test/cases/compile_errors/ptrCast_discards_const_qualifier.zig @@ -9,3 +9,4 @@ export fn entry() void { // target=native // // :3:15: error: cast discards const qualifier +// :3:15: note: consider using '@qualCast' -- 2.54.0 From f3bb1957fa7f317873584cfc0ea8e3fd59283ec2 Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Sun, 29 Jan 2023 23:39:03 +0200 Subject: [PATCH 35/84] update zig1.wasm to include `@qualCast` --- stage1/zig1.wasm | Bin 2369157 -> 2373912 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/stage1/zig1.wasm b/stage1/zig1.wasm index e64e05fa1300ae7254391cbb74786b55abd1e48b..ef7d7891c9aef6a9f65ea39fed25ecb815a38f9d 100644 GIT binary patch delta 437132 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

?dcdO zYFl9gPPPI-uyZy98qlUEaVKhU0bi{HJl}g7T)$>&-8 zDbj-!u;NoB9Gl-eABGg9UGrfT4e59JBv|vg{@^^{KTX=OQ~7X^uh7ikszqKHIm)u_j+pWzDdYCx5$vA%YQ$!EyNDB#=~O@MHg#2`H9EVl!u z0czP2b~sXD!kv?n$0pEF1Q+M3+uPGjX~=hVVG z@buJpyu?h%#hZ>W0mwxq%=aE?Ts`{?-zfx%_;ny>Ir9t~a*ur7qQWAn0yBU&m7|KS zgUne@&4WlKh8d$_ijZT0ye^MDy+?YHyK0B~&~4BHBOa2UYSf5^e4G_NrXa&fQf%?o zYc#r=E;Azmc4cgyp87hvz>Fg2WUx7UdMdn_6AWNS9I2QaUxDQI1t{GDEKVipJXrRwwKe|*sR)g**wBi_xGtv%*@?-H_CAy2kmK~hXMI#mQ zjjejslZHFd>@_SffL^7!%a~Z3uAy;-EVDL^1y~I?QH8*DA66JhufYvlRSlwtiG667 zK-`zbhCq3%Sid?{L1{PY(Ay~GL|ytl>=4t!>rsOEPW9;>#5WA3t?2wh^|Mg=w*U-m zSY!Gz5Y)`Z^nC$(w)(Isl_knz)Ml+|3!O3jJeVq%@JF3Qj;|I0wu-LA7DWigi|`~U;TpcRw`pM4fC~pz9~qD4Q2k8 z6MWVQ=%q59j{|H|XKG|IohkYw6#yB0c%J&K3#~)Q6Xx5E{tU_7ZnVff|ERftVPrY? zDEqNH)F^X}n%kYa<1J=(z6V{5>4ctigc%NGfA^%nq3H3wD4a^htbk~|$?y{^?Mc1Z z{N8jJjai{S>`l)*(p@vuqXXy=3N>TFpU^&ZXF2=v6WSCAEcFxm1I{g8gXlh-WZ3z^ z^aD)m4nYyS)G0$~IK?0PhtXhx7MG~EN6-Oo_@n)|)JH^p2K_)+V*2t2ItP}LGsn~4 z$q7~Zk^bmJPP2)V=qMu|h_t4OuF#3#Bqs;cQg(k5jrQVe5h5qffrT1{<%kokW+L2t}tv;LyZ>8x37&tKHb)zY?5jF}a_z$NeWV6`IYVI1l=BI!|Q zx-EunoJm{L9Wm_oO!_e?W$(|TzCIA0hNlDY(A6cv6lfx$g43UA__iXMeLstS0^5Q^ zvmg^xu+wbn&wOW7z2BY~(AoMX3BovXdNw#MypfAs^}Y62VQ`dj=fVD(O+&p7SD^`- zb#~9DVf0vx`Ve@ids&8E4=c@Jb>nDPTOSs{Q&{^j@8i*N6c=&oKXG)3h(_+O&_fip z_D-O9L6db$p!NU1B+N*lb2&ewINdUDMr*P0415s)^BJ9oN0N0C=_Tw)ViFzT3d^>^ ztEoSBwF#@CA0eZZPUA3Lm`Dys+JjWEzjx3GQlXCC zNhiW5*3=8Ts1qUos@HeJCURvsr!$@$cL|iu_MQ5M|6cw zd32a-I+zL8C^-bCsS@^m9_@{!oq2Q>jR&`R9OAa*GK)S%O|H;a9q~(dE+#j_Wwr@W zWR-gQ6kS7TY$5xrfcp5A!=}{m%0q92{VoRaz}<;5N4{1!7tl_Q

{aOha7?FqE#t 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%0Av^=yf0M;Zh#p|cff)%lLC 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%0A}zI)bo##2a;zTe!cUYoza|b&?YyEpF(9wX~X_ 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 delta 436299 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%0Ag}3&w3?5_hsyFt4P`IQCFGM_~5M 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

X7f65DtJmc0xMk-5wijKFwzYb)^ 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%0D>PNkkce*?B*z_}VfTPVJ_D~!Pqte>u?*q>;e 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𝔱OeUuDiHKR=4VA$1(G|O|pu`6MBq;Qqk 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 Date: Mon, 30 Jan 2023 18:22:50 +0100 Subject: [PATCH 36/84] link: make MachO atoms fully owned by the linker --- src/Module.zig | 12 +- src/Sema.zig | 2 +- src/arch/aarch64/CodeGen.zig | 38 +- src/arch/aarch64/Emit.zig | 10 +- src/arch/riscv64/CodeGen.zig | 4 +- src/arch/x86_64/CodeGen.zig | 31 +- src/arch/x86_64/Emit.zig | 8 +- src/link.zig | 4 +- src/link/Dwarf.zig | 2 +- src/link/MachO.zig | 719 ++++++++++++++++++---------------- src/link/MachO/Atom.zig | 81 ++-- src/link/MachO/Relocation.zig | 16 +- 12 files changed, 495 insertions(+), 432 deletions(-) diff --git a/src/Module.zig b/src/Module.zig index dcdbeec3221e5558c1585e49bf9e25725245e924..83015054922ca49241c558d22c47436b84e6defc 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -4098,7 +4098,7 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void { // The exports this Decl performs will be re-discovered, so we remove them here // prior to re-analysis. - mod.deleteDeclExports(decl_index); + try mod.deleteDeclExports(decl_index); // Similarly, `@setAlignStack` invocations will be re-discovered. if (decl.getFunction()) |func| { @@ -5265,7 +5265,7 @@ pub fn clearDecl( assert(emit_h.decl_table.swapRemove(decl_index)); } _ = mod.compile_log_decls.swapRemove(decl_index); - mod.deleteDeclExports(decl_index); + try mod.deleteDeclExports(decl_index); if (decl.has_tv) { if (decl.ty.isFnOrHasRuntimeBits()) { @@ -5276,7 +5276,7 @@ pub fn clearDecl( decl.link = switch (mod.comp.bin_file.tag) { .coff => .{ .coff = link.File.Coff.Atom.empty }, .elf => .{ .elf = link.File.Elf.TextBlock.empty }, - .macho => .{ .macho = link.File.MachO.Atom.empty }, + .macho => .{ .macho = {} }, .plan9 => .{ .plan9 = link.File.Plan9.DeclBlock.empty }, .c => .{ .c = {} }, .wasm => .{ .wasm = link.File.Wasm.DeclBlock.empty }, @@ -5358,7 +5358,7 @@ pub fn abortAnonDecl(mod: *Module, decl_index: Decl.Index) void { /// Delete all the Export objects that are caused by this Decl. Re-analysis of /// this Decl will cause them to be re-created (or not). -fn deleteDeclExports(mod: *Module, decl_index: Decl.Index) void { +fn deleteDeclExports(mod: *Module, decl_index: Decl.Index) Allocator.Error!void { var export_owners = (mod.export_owners.fetchSwapRemove(decl_index) orelse return).value; for (export_owners.items) |exp| { @@ -5384,7 +5384,7 @@ fn deleteDeclExports(mod: *Module, decl_index: Decl.Index) void { elf.deleteExport(exp.link.elf); } if (mod.comp.bin_file.cast(link.File.MachO)) |macho| { - macho.deleteExport(exp.link.macho); + try macho.deleteDeclExport(decl_index, exp.options.name); } if (mod.comp.bin_file.cast(link.File.Wasm)) |wasm| { wasm.deleteExport(exp.link.wasm); @@ -5696,7 +5696,7 @@ pub fn allocateNewDecl( .link = switch (mod.comp.bin_file.tag) { .coff => .{ .coff = link.File.Coff.Atom.empty }, .elf => .{ .elf = link.File.Elf.TextBlock.empty }, - .macho => .{ .macho = link.File.MachO.Atom.empty }, + .macho => .{ .macho = {} }, .plan9 => .{ .plan9 = link.File.Plan9.DeclBlock.empty }, .c => .{ .c = {} }, .wasm => .{ .wasm = link.File.Wasm.DeclBlock.empty }, diff --git a/src/Sema.zig b/src/Sema.zig index 9c553a009236fb83279a65872a877465452601be..9083cc92abee98b1461d0f25319c6effb7a7fc4b 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -5567,7 +5567,7 @@ pub fn analyzeExport( .link = switch (mod.comp.bin_file.tag) { .coff => .{ .coff = .{} }, .elf => .{ .elf = .{} }, - .macho => .{ .macho = .{} }, + .macho => .{ .macho = {} }, .plan9 => .{ .plan9 = null }, .c => .{ .c = {} }, .wasm => .{ .wasm = .{} }, diff --git a/src/arch/aarch64/CodeGen.zig b/src/arch/aarch64/CodeGen.zig index 0efd34937a0281c7818bf1a146fd3184f5c5c3fe..edbe7905a213ffe715b2e66f40135d947fc15ed7 100644 --- a/src/arch/aarch64/CodeGen.zig +++ b/src/arch/aarch64/CodeGen.zig @@ -4022,7 +4022,11 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type const mod = self.bin_file.options.module.?; const owner_decl = mod.declPtr(self.mod_fn.owner_decl); const atom_index = switch (self.bin_file.tag) { - .macho => owner_decl.link.macho.getSymbolIndex().?, + .macho => blk: { + const macho_file = self.bin_file.cast(link.File.MachO).?; + const atom = try macho_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl); + break :blk macho_file.getAtom(atom).getSymbolIndex().?; + }, .coff => owner_decl.link.coff.getSymbolIndex().?, else => unreachable, // unsupported target format }; @@ -4308,11 +4312,12 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier const got_addr = @intCast(u32, fn_owner_decl.link.elf.getOffsetTableAddress(elf_file)); try self.genSetReg(Type.initTag(.usize), .x30, .{ .memory = got_addr }); } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { - try fn_owner_decl.link.macho.ensureInitialized(macho_file); + const atom = try macho_file.getOrCreateAtomForDecl(func.owner_decl); + const sym_index = macho_file.getAtom(atom).getSymbolIndex().?; try self.genSetReg(Type.initTag(.u64), .x30, .{ .linker_load = .{ .type = .got, - .sym_index = fn_owner_decl.link.macho.getSymbolIndex().?, + .sym_index = sym_index, }, }); } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { @@ -4349,11 +4354,13 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier if (self.bin_file.cast(link.File.MachO)) |macho_file| { const sym_index = try macho_file.getGlobalSymbol(mem.sliceTo(decl_name, 0)); + const atom = try macho_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl); + const atom_index = macho_file.getAtom(atom).getSymbolIndex().?; _ = try self.addInst(.{ .tag = .call_extern, .data = .{ .relocation = .{ - .atom_index = mod.declPtr(self.mod_fn.owner_decl).link.macho.getSymbolIndex().?, + .atom_index = atom_index, .sym_index = sym_index, }, }, @@ -5491,7 +5498,11 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro const mod = self.bin_file.options.module.?; const owner_decl = mod.declPtr(self.mod_fn.owner_decl); const atom_index = switch (self.bin_file.tag) { - .macho => owner_decl.link.macho.getSymbolIndex().?, + .macho => blk: { + const macho_file = self.bin_file.cast(link.File.MachO).?; + const atom = try macho_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl); + break :blk macho_file.getAtom(atom).getSymbolIndex().?; + }, .coff => owner_decl.link.coff.getSymbolIndex().?, else => unreachable, // unsupported target format }; @@ -5605,7 +5616,11 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void const mod = self.bin_file.options.module.?; const owner_decl = mod.declPtr(self.mod_fn.owner_decl); const atom_index = switch (self.bin_file.tag) { - .macho => owner_decl.link.macho.getSymbolIndex().?, + .macho => blk: { + const macho_file = self.bin_file.cast(link.File.MachO).?; + const atom = try macho_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl); + break :blk macho_file.getAtom(atom).getSymbolIndex().?; + }, .coff => owner_decl.link.coff.getSymbolIndex().?, else => unreachable, // unsupported target format }; @@ -5799,7 +5814,11 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I const mod = self.bin_file.options.module.?; const owner_decl = mod.declPtr(self.mod_fn.owner_decl); const atom_index = switch (self.bin_file.tag) { - .macho => owner_decl.link.macho.getSymbolIndex().?, + .macho => blk: { + const macho_file = self.bin_file.cast(link.File.MachO).?; + const atom = try macho_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl); + break :blk macho_file.getAtom(atom).getSymbolIndex().?; + }, .coff => owner_decl.link.coff.getSymbolIndex().?, else => unreachable, // unsupported target format }; @@ -6122,10 +6141,11 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne try decl.link.elf.ensureInitialized(elf_file); return MCValue{ .memory = decl.link.elf.getOffsetTableAddress(elf_file) }; } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { - try decl.link.macho.ensureInitialized(macho_file); + const atom = try macho_file.getOrCreateAtomForDecl(decl_index); + const sym_index = macho_file.getAtom(atom).getSymbolIndex().?; return MCValue{ .linker_load = .{ .type = .got, - .sym_index = decl.link.macho.getSymbolIndex().?, + .sym_index = sym_index, } }; } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { try decl.link.coff.ensureInitialized(coff_file); diff --git a/src/arch/aarch64/Emit.zig b/src/arch/aarch64/Emit.zig index 3812597789adce41408985b09decd69062100b6e..f348fb70e37677b56a10a26f77bd48ca28754017 100644 --- a/src/arch/aarch64/Emit.zig +++ b/src/arch/aarch64/Emit.zig @@ -670,9 +670,9 @@ fn mirCallExtern(emit: *Emit, inst: Mir.Inst.Index) !void { if (emit.bin_file.cast(link.File.MachO)) |macho_file| { // Add relocation to the decl. - const atom = macho_file.getAtomForSymbol(.{ .sym_index = relocation.atom_index, .file = null }).?; + const atom_index = macho_file.getAtomIndexForSymbol(.{ .sym_index = relocation.atom_index, .file = null }).?; const target = macho_file.getGlobalByIndex(relocation.sym_index); - try atom.addRelocation(macho_file, .{ + try link.File.MachO.Atom.addRelocation(macho_file, atom_index, .{ .type = @enumToInt(std.macho.reloc_type_arm64.ARM64_RELOC_BRANCH26), .target = target, .offset = offset, @@ -883,10 +883,10 @@ fn mirLoadMemoryPie(emit: *Emit, inst: Mir.Inst.Index) !void { } if (emit.bin_file.cast(link.File.MachO)) |macho_file| { - const atom = macho_file.getAtomForSymbol(.{ .sym_index = data.atom_index, .file = null }).?; + const atom_index = macho_file.getAtomIndexForSymbol(.{ .sym_index = data.atom_index, .file = null }).?; // TODO this causes segfault in stage1 // try atom.addRelocations(macho_file, 2, .{ - try atom.addRelocation(macho_file, .{ + try link.File.MachO.Atom.addRelocation(macho_file, atom_index, .{ .target = .{ .sym_index = data.sym_index, .file = null }, .offset = offset, .addend = 0, @@ -902,7 +902,7 @@ fn mirLoadMemoryPie(emit: *Emit, inst: Mir.Inst.Index) !void { else => unreachable, }, }); - try atom.addRelocation(macho_file, .{ + try link.File.MachO.Atom.addRelocation(macho_file, atom_index, .{ .target = .{ .sym_index = data.sym_index, .file = null }, .offset = offset + 4, .addend = 0, diff --git a/src/arch/riscv64/CodeGen.zig b/src/arch/riscv64/CodeGen.zig index d50a614206c59495008c8acd448c418728f40063..07a8dcd8582a935fcce13c899ec6120d8f74631b 100644 --- a/src/arch/riscv64/CodeGen.zig +++ b/src/arch/riscv64/CodeGen.zig @@ -2556,9 +2556,7 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne try decl.link.elf.ensureInitialized(elf_file); return MCValue{ .memory = decl.link.elf.getOffsetTableAddress(elf_file) }; } else if (self.bin_file.cast(link.File.MachO)) |_| { - // TODO I'm hacking my way through here by repurposing .memory for storing - // index to the GOT target symbol index. - return MCValue{ .memory = decl.link.macho.sym_index }; + unreachable; } else if (self.bin_file.cast(link.File.Coff)) |_| { return self.fail("TODO codegen COFF const Decl pointer", .{}); } else if (self.bin_file.cast(link.File.Plan9)) |p9| { diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index df24fe5e7de694b39c138cfd703585b2f42570f8..fc244e3130afa595af98853ef09d2210dd5a087d 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -2670,10 +2670,12 @@ fn loadMemPtrIntoRegister(self: *Self, reg: Register, ptr_ty: Type, ptr: MCValue const abi_size = @intCast(u32, ptr_ty.abiSize(self.target.*)); const mod = self.bin_file.options.module.?; const fn_owner_decl = mod.declPtr(self.mod_fn.owner_decl); - const atom_index = if (self.bin_file.tag == link.File.MachO.base_tag) - fn_owner_decl.link.macho.getSymbolIndex().? - else - fn_owner_decl.link.coff.getSymbolIndex().?; + const atom_index = if (self.bin_file.cast(link.File.MachO)) |macho_file| blk: { + const atom = try macho_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl); + break :blk macho_file.getAtom(atom).getSymbolIndex().?; + } else if (self.bin_file.cast(link.File.Coff)) |_| blk: { + break :blk fn_owner_decl.link.coff.getSymbolIndex().?; + } else unreachable; const flags: u2 = switch (load_struct.type) { .got => 0b00, .direct => 0b01, @@ -4023,8 +4025,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier .data = undefined, }); } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { - try fn_owner_decl.link.macho.ensureInitialized(macho_file); - const sym_index = fn_owner_decl.link.macho.getSymbolIndex().?; + const atom_index = try macho_file.getOrCreateAtomForDecl(func.owner_decl); + const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?; try self.genSetReg(Type.initTag(.usize), .rax, .{ .linker_load = .{ .type = .got, @@ -4080,15 +4082,15 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier }); } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { const sym_index = try macho_file.getGlobalSymbol(mem.sliceTo(decl_name, 0)); + const atom = try macho_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl); + const atom_index = macho_file.getAtom(atom).getSymbolIndex().?; _ = try self.addInst(.{ .tag = .call_extern, .ops = undefined, - .data = .{ - .relocation = .{ - .atom_index = mod.declPtr(self.mod_fn.owner_decl).link.macho.getSymbolIndex().?, - .sym_index = sym_index, - }, - }, + .data = .{ .relocation = .{ + .atom_index = atom_index, + .sym_index = sym_index, + } }, }); } else { return self.fail("TODO implement calling extern functions", .{}); @@ -6722,10 +6724,11 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne try decl.link.elf.ensureInitialized(elf_file); return MCValue{ .memory = decl.link.elf.getOffsetTableAddress(elf_file) }; } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { - try decl.link.macho.ensureInitialized(macho_file); + const atom_index = try macho_file.getOrCreateAtomForDecl(decl_index); + const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?; return MCValue{ .linker_load = .{ .type = .got, - .sym_index = decl.link.macho.getSymbolIndex().?, + .sym_index = sym_index, } }; } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { try decl.link.coff.ensureInitialized(coff_file); diff --git a/src/arch/x86_64/Emit.zig b/src/arch/x86_64/Emit.zig index af3ed5e0534786e4ce4e6345279cbdfbb0bb95ae..980dbfd41e51eb6f132939d6e02daca9d167002b 100644 --- a/src/arch/x86_64/Emit.zig +++ b/src/arch/x86_64/Emit.zig @@ -1001,8 +1001,8 @@ fn mirLeaPic(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { 0b01 => @enumToInt(std.macho.reloc_type_x86_64.X86_64_RELOC_SIGNED), else => unreachable, }; - const atom = macho_file.getAtomForSymbol(.{ .sym_index = relocation.atom_index, .file = null }).?; - try atom.addRelocation(macho_file, .{ + const atom_index = macho_file.getAtomIndexForSymbol(.{ .sym_index = relocation.atom_index, .file = null }).?; + try link.File.MachO.Atom.addRelocation(macho_file, atom_index, .{ .type = reloc_type, .target = .{ .sym_index = relocation.sym_index, .file = null }, .offset = @intCast(u32, end_offset - 4), @@ -1140,9 +1140,9 @@ fn mirCallExtern(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { if (emit.bin_file.cast(link.File.MachO)) |macho_file| { // Add relocation to the decl. - const atom = macho_file.getAtomForSymbol(.{ .sym_index = relocation.atom_index, .file = null }).?; + const atom_index = macho_file.getAtomIndexForSymbol(.{ .sym_index = relocation.atom_index, .file = null }).?; const target = macho_file.getGlobalByIndex(relocation.sym_index); - try atom.addRelocation(macho_file, .{ + try link.File.MachO.Atom.addRelocation(macho_file, atom_index, .{ .type = @enumToInt(std.macho.reloc_type_x86_64.X86_64_RELOC_BRANCH), .target = target, .offset = offset, diff --git a/src/link.zig b/src/link.zig index 668c5b72e30a9d2c091c64f3c2cb4eb3ec141638..2a96efe89da6b5f69020846bd683e9e184d81743 100644 --- a/src/link.zig +++ b/src/link.zig @@ -264,7 +264,7 @@ pub const File = struct { pub const LinkBlock = union { elf: Elf.TextBlock, coff: Coff.Atom, - macho: MachO.Atom, + macho: void, plan9: Plan9.DeclBlock, c: void, wasm: Wasm.DeclBlock, @@ -286,7 +286,7 @@ pub const File = struct { pub const Export = union { elf: Elf.Export, coff: Coff.Export, - macho: MachO.Export, + macho: void, plan9: Plan9.Export, c: void, wasm: Wasm.Export, diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig index 1b65bbb04b89b98dd8bb4cc2ff47c71454cc844a..2595cd8ba56acc7796a8c62161ea5dedacd54c41 100644 --- a/src/link/Dwarf.zig +++ b/src/link/Dwarf.zig @@ -2639,7 +2639,7 @@ fn getDbgInfoAtom(tag: File.Tag, mod: *Module, decl_index: Module.Decl.Index) *A const decl = mod.declPtr(decl_index); return switch (tag) { .elf => &decl.link.elf.dbg_info_atom, - .macho => &decl.link.macho.dbg_info_atom, + .macho => unreachable, .wasm => &decl.link.wasm.dbg_info_atom, else => unreachable, }; diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 543cb473d74a2ef1d1160a36d09dd24814665ecc..29aed25b3108b52080eed45f72d3d5e9b3f29872 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -66,7 +66,7 @@ const Section = struct { // TODO is null here necessary, or can we do away with tracking via section // size in incremental context? - last_atom: ?*Atom = null, + last_atom_index: ?Atom.Index = null, /// A list of atoms that have surplus capacity. This list can have false /// positives, as functions grow and shrink over time, only sometimes being added @@ -83,7 +83,7 @@ const Section = struct { /// overcapacity can be negative. A simple way to have negative overcapacity is to /// allocate a fresh atom, which will have ideal capacity, and then grow it /// by 1 byte. It will then have -1 overcapacity. - free_list: std.ArrayListUnmanaged(*Atom) = .{}, + free_list: std.ArrayListUnmanaged(Atom.Index) = .{}, }; base: File, @@ -140,8 +140,8 @@ locals_free_list: std.ArrayListUnmanaged(u32) = .{}, globals_free_list: std.ArrayListUnmanaged(u32) = .{}, dyld_stub_binder_index: ?u32 = null, -dyld_private_atom: ?*Atom = null, -stub_helper_preamble_atom: ?*Atom = null, +dyld_private_atom_index: ?Atom.Index = null, +stub_helper_preamble_atom_index: ?Atom.Index = null, strtab: StringTable(.strtab) = .{}, @@ -164,10 +164,10 @@ segment_table_dirty: bool = false, cold_start: bool = true, /// List of atoms that are either synthetic or map directly to the Zig source program. -managed_atoms: std.ArrayListUnmanaged(*Atom) = .{}, +atoms: std.ArrayListUnmanaged(Atom) = .{}, /// Table of atoms indexed by the symbol index. -atom_by_index_table: std.AutoHashMapUnmanaged(u32, *Atom) = .{}, +atom_by_index_table: std.AutoHashMapUnmanaged(u32, Atom.Index) = .{}, /// Table of unnamed constants associated with a parent `Decl`. /// We store them here so that we can free the constants whenever the `Decl` @@ -210,11 +210,36 @@ bindings: BindingTable = .{}, /// this will be a table indexed by index into the list of Atoms. lazy_bindings: BindingTable = .{}, -/// Table of Decls that are currently alive. -/// We store them here so that we can properly dispose of any allocated -/// memory within the atom in the incremental linker. -/// TODO consolidate this. -decls: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, ?u8) = .{}, +/// Table of tracked Decls. +decls: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, DeclMetadata) = .{}, + +const DeclMetadata = struct { + atom: Atom.Index, + section: u8, + /// A list of all exports aliases of this Decl. + /// TODO do we actually need this at all? + exports: std.ArrayListUnmanaged(u32) = .{}, + + fn getExport(m: DeclMetadata, macho_file: *const MachO, name: []const u8) ?u32 { + for (m.exports.items) |exp| { + if (mem.eql(u8, name, macho_file.getSymbolName(.{ + .sym_index = exp, + .file = null, + }))) return exp; + } + return null; + } + + fn getExportPtr(m: *DeclMetadata, macho_file: *MachO, name: []const u8) ?*u32 { + for (m.exports.items) |*exp| { + if (mem.eql(u8, name, macho_file.getSymbolName(.{ + .sym_index = exp.*, + .file = null, + }))) return exp; + } + return null; + } +}; const Entry = struct { target: SymbolWithLoc, @@ -229,8 +254,8 @@ const Entry = struct { return macho_file.getSymbolPtr(.{ .sym_index = entry.sym_index, .file = null }); } - pub fn getAtom(entry: Entry, macho_file: *MachO) ?*Atom { - return macho_file.getAtomForSymbol(.{ .sym_index = entry.sym_index, .file = null }); + pub fn getAtomIndex(entry: Entry, macho_file: *MachO) ?Atom.Index { + return macho_file.getAtomIndexForSymbol(.{ .sym_index = entry.sym_index, .file = null }); } pub fn getName(entry: Entry, macho_file: *MachO) []const u8 { @@ -238,10 +263,10 @@ const Entry = struct { } }; -const BindingTable = std.AutoArrayHashMapUnmanaged(*Atom, std.ArrayListUnmanaged(Atom.Binding)); -const UnnamedConstTable = std.AutoArrayHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(*Atom)); -const RebaseTable = std.AutoArrayHashMapUnmanaged(*Atom, std.ArrayListUnmanaged(u32)); -const RelocationTable = std.AutoArrayHashMapUnmanaged(*Atom, std.ArrayListUnmanaged(Relocation)); +const BindingTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Atom.Binding)); +const UnnamedConstTable = std.AutoArrayHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Atom.Index)); +const RebaseTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(u32)); +const RelocationTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Relocation)); const PendingUpdate = union(enum) { resolve_undef: u32, @@ -286,10 +311,6 @@ pub const default_pagezero_vmsize: u64 = 0x100000000; /// potential future extensions. pub const default_headerpad_size: u32 = 0x1000; -pub const Export = struct { - sym_index: ?u32 = null, -}; - pub fn openPath(allocator: Allocator, options: link.Options) !*MachO { assert(options.target.ofmt == .macho); @@ -451,9 +472,9 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented; - if (self.d_sym) |*d_sym| { - try d_sym.dwarf.flushModule(module); - } + // if (self.d_sym) |*d_sym| { + // try d_sym.dwarf.flushModule(module); + // } var libs = std.StringArrayHashMap(link.SystemLib).init(arena); try resolveLibSystem( @@ -547,8 +568,8 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No try self.allocateSpecialSymbols(); - for (self.relocs.keys()) |atom| { - try atom.resolveRelocations(self); + for (self.relocs.keys()) |atom_index| { + try Atom.resolveRelocations(self, atom_index); } if (build_options.enable_logging) { @@ -643,10 +664,10 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No try self.writeCodeSignature(comp, csig); // code signing always comes last } - if (self.d_sym) |*d_sym| { - // Flush debug symbols bundle. - try d_sym.flushModule(self); - } + // if (self.d_sym) |*d_sym| { + // // Flush debug symbols bundle. + // try d_sym.flushModule(self); + // } // if (build_options.enable_link_snapshots) { // if (self.base.options.enable_link_snapshots) @@ -999,18 +1020,19 @@ pub fn parseDependentLibs(self: *MachO, syslibroot: ?[]const u8, dependent_libs: } } -pub fn writeAtom(self: *MachO, atom: *Atom, code: []const u8) !void { +pub fn writeAtom(self: *MachO, atom_index: Atom.Index, code: []const u8) !void { + const atom = self.getAtom(atom_index); const sym = atom.getSymbol(self); const section = self.sections.get(sym.n_sect - 1); const file_offset = section.header.offset + sym.n_value - section.header.addr; log.debug("writing atom for symbol {s} at file offset 0x{x}", .{ atom.getName(self), file_offset }); try self.base.file.?.pwriteAll(code, file_offset); - try atom.resolveRelocations(self); + try Atom.resolveRelocations(self, atom_index); } -fn writePtrWidthAtom(self: *MachO, atom: *Atom) !void { +fn writePtrWidthAtom(self: *MachO, atom_index: Atom.Index) !void { var buffer: [@sizeOf(u64)]u8 = [_]u8{0} ** @sizeOf(u64); - try self.writeAtom(atom, &buffer); + try self.writeAtom(atom_index, &buffer); } fn markRelocsDirtyByTarget(self: *MachO, target: SymbolWithLoc) void { @@ -1026,7 +1048,8 @@ fn markRelocsDirtyByTarget(self: *MachO, target: SymbolWithLoc) void { fn markRelocsDirtyByAddress(self: *MachO, addr: u64) void { for (self.relocs.values()) |*relocs| { for (relocs.items) |*reloc| { - const target_atom = reloc.getTargetAtom(self) orelse continue; + const target_atom_index = reloc.getTargetAtomIndex(self) orelse continue; + const target_atom = self.getAtom(target_atom_index); const target_sym = target_atom.getSymbol(self); if (target_sym.n_value < addr) continue; reloc.dirty = true; @@ -1053,26 +1076,39 @@ pub fn allocateSpecialSymbols(self: *MachO) !void { } } -pub fn createGotAtom(self: *MachO, target: SymbolWithLoc) !*Atom { +pub fn createAtom(self: *MachO) !Atom.Index { const gpa = self.base.allocator; + const atom_index = @intCast(Atom.Index, self.atoms.items.len); + const atom = try self.atoms.addOne(gpa); + const sym_index = try self.allocateSymbol(); + try self.atom_by_index_table.putNoClobber(gpa, sym_index, atom_index); + atom.* = .{ + .sym_index = sym_index, + .file = null, + .size = 0, + .alignment = 0, + .prev_index = null, + .next_index = null, + .dbg_info_atom = undefined, + }; + log.debug("creating ATOM(%{d}) at index {d}", .{ sym_index, atom_index }); + return atom_index; +} - const atom = try gpa.create(Atom); - atom.* = Atom.empty; - try atom.ensureInitialized(self); +pub fn createGotAtom(self: *MachO, target: SymbolWithLoc) !Atom.Index { + const atom_index = try self.createAtom(); + const atom = self.getAtomPtr(atom_index); atom.size = @sizeOf(u64); atom.alignment = @alignOf(u64); - errdefer gpa.destroy(atom); - - try self.managed_atoms.append(gpa, atom); const sym = atom.getSymbolPtr(self); sym.n_type = macho.N_SECT; sym.n_sect = self.got_section_index.? + 1; - sym.n_value = try self.allocateAtom(atom, atom.size, @alignOf(u64)); + sym.n_value = try self.allocateAtom(atom_index, atom.size, @alignOf(u64)); log.debug("allocated GOT atom at 0x{x}", .{sym.n_value}); - try atom.addRelocation(self, .{ + try Atom.addRelocation(self, atom_index, .{ .type = switch (self.base.options.target.cpu.arch) { .aarch64 => @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_UNSIGNED), .x86_64 => @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_UNSIGNED), @@ -1087,45 +1123,39 @@ pub fn createGotAtom(self: *MachO, target: SymbolWithLoc) !*Atom { const target_sym = self.getSymbol(target); if (target_sym.undf()) { - try atom.addBinding(self, .{ + try Atom.addBinding(self, atom_index, .{ .target = self.getGlobal(self.getSymbolName(target)).?, .offset = 0, }); } else { - try atom.addRebase(self, 0); + try Atom.addRebase(self, atom_index, 0); } - return atom; + return atom_index; } pub fn createDyldPrivateAtom(self: *MachO) !void { if (self.dyld_stub_binder_index == null) return; - if (self.dyld_private_atom != null) return; + if (self.dyld_private_atom_index != null) return; - const gpa = self.base.allocator; - - const atom = try gpa.create(Atom); - atom.* = Atom.empty; - try atom.ensureInitialized(self); + const atom_index = try self.createAtom(); + const atom = self.getAtomPtr(atom_index); atom.size = @sizeOf(u64); atom.alignment = @alignOf(u64); - errdefer gpa.destroy(atom); const sym = atom.getSymbolPtr(self); sym.n_type = macho.N_SECT; sym.n_sect = self.data_section_index.? + 1; - self.dyld_private_atom = atom; + self.dyld_private_atom_index = atom_index; - try self.managed_atoms.append(gpa, atom); - - sym.n_value = try self.allocateAtom(atom, atom.size, @alignOf(u64)); + sym.n_value = try self.allocateAtom(atom_index, atom.size, @alignOf(u64)); log.debug("allocated dyld_private atom at 0x{x}", .{sym.n_value}); - try self.writePtrWidthAtom(atom); + try self.writePtrWidthAtom(atom_index); } pub fn createStubHelperPreambleAtom(self: *MachO) !void { if (self.dyld_stub_binder_index == null) return; - if (self.stub_helper_preamble_atom != null) return; + if (self.stub_helper_preamble_atom_index != null) return; const gpa = self.base.allocator; const arch = self.base.options.target.cpu.arch; @@ -1134,22 +1164,23 @@ pub fn createStubHelperPreambleAtom(self: *MachO) !void { .aarch64 => 6 * @sizeOf(u32), else => unreachable, }; - const atom = try gpa.create(Atom); - atom.* = Atom.empty; - try atom.ensureInitialized(self); + const atom_index = try self.createAtom(); + const atom = self.getAtomPtr(atom_index); atom.size = size; atom.alignment = switch (arch) { .x86_64 => 1, .aarch64 => @alignOf(u32), else => unreachable, }; - errdefer gpa.destroy(atom); const sym = atom.getSymbolPtr(self); sym.n_type = macho.N_SECT; sym.n_sect = self.stub_helper_section_index.? + 1; - const dyld_private_sym_index = self.dyld_private_atom.?.getSymbolIndex().?; + const dyld_private_sym_index = if (self.dyld_private_atom_index) |dyld_index| + self.getAtom(dyld_index).getSymbolIndex().? + else + unreachable; const code = try gpa.alloc(u8, size); defer gpa.free(code); @@ -1168,7 +1199,7 @@ pub fn createStubHelperPreambleAtom(self: *MachO) !void { code[9] = 0xff; code[10] = 0x25; - try atom.addRelocations(self, 2, .{ .{ + try Atom.addRelocations(self, atom_index, 2, .{ .{ .type = @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_SIGNED), .target = .{ .sym_index = dyld_private_sym_index, .file = null }, .offset = 3, @@ -1208,7 +1239,7 @@ pub fn createStubHelperPreambleAtom(self: *MachO) !void { // br x16 mem.writeIntLittle(u32, code[20..][0..4], aarch64.Instruction.br(.x16).toU32()); - try atom.addRelocations(self, 4, .{ .{ + try Atom.addRelocations(self, atom_index, 4, .{ .{ .type = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_PAGE21), .target = .{ .sym_index = dyld_private_sym_index, .file = null }, .offset = 0, @@ -1241,16 +1272,14 @@ pub fn createStubHelperPreambleAtom(self: *MachO) !void { else => unreachable, } - self.stub_helper_preamble_atom = atom; + self.stub_helper_preamble_atom_index = atom_index; - try self.managed_atoms.append(gpa, atom); - - sym.n_value = try self.allocateAtom(atom, size, atom.alignment); + sym.n_value = try self.allocateAtom(atom_index, size, atom.alignment); log.debug("allocated stub preamble atom at 0x{x}", .{sym.n_value}); - try self.writeAtom(atom, code); + try self.writeAtom(atom_index, code); } -pub fn createStubHelperAtom(self: *MachO) !*Atom { +pub fn createStubHelperAtom(self: *MachO) !Atom.Index { const gpa = self.base.allocator; const arch = self.base.options.target.cpu.arch; const size: u4 = switch (arch) { @@ -1258,16 +1287,14 @@ pub fn createStubHelperAtom(self: *MachO) !*Atom { .aarch64 => 3 * @sizeOf(u32), else => unreachable, }; - const atom = try gpa.create(Atom); - atom.* = Atom.empty; - try atom.ensureInitialized(self); + const atom_index = try self.createAtom(); + const atom = self.getAtomPtr(atom_index); atom.size = size; atom.alignment = switch (arch) { .x86_64 => 1, .aarch64 => @alignOf(u32), else => unreachable, }; - errdefer gpa.destroy(atom); const sym = atom.getSymbolPtr(self); sym.n_type = macho.N_SECT; @@ -1277,6 +1304,11 @@ pub fn createStubHelperAtom(self: *MachO) !*Atom { defer gpa.free(code); mem.set(u8, code, 0); + const stub_helper_preamble_atom_sym_index = if (self.stub_helper_preamble_atom_index) |stub_index| + self.getAtom(stub_index).getSymbolIndex().? + else + unreachable; + switch (arch) { .x86_64 => { // pushq @@ -1285,9 +1317,9 @@ pub fn createStubHelperAtom(self: *MachO) !*Atom { // jmpq code[5] = 0xe9; - try atom.addRelocation(self, .{ + try Atom.addRelocation(self, atom_index, .{ .type = @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_BRANCH), - .target = .{ .sym_index = self.stub_helper_preamble_atom.?.getSymbolIndex().?, .file = null }, + .target = .{ .sym_index = stub_helper_preamble_atom_sym_index, .file = null }, .offset = 6, .addend = 0, .pcrel = true, @@ -1308,9 +1340,9 @@ pub fn createStubHelperAtom(self: *MachO) !*Atom { mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.b(0).toU32()); // Next 4 bytes 8..12 are just a placeholder populated in `populateLazyBindOffsetsInStubHelper`. - try atom.addRelocation(self, .{ + try Atom.addRelocation(self, atom_index, .{ .type = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_BRANCH26), - .target = .{ .sym_index = self.stub_helper_preamble_atom.?.getSymbolIndex().?, .file = null }, + .target = .{ .sym_index = stub_helper_preamble_atom_sym_index, .file = null }, .offset = 4, .addend = 0, .pcrel = true, @@ -1320,29 +1352,24 @@ pub fn createStubHelperAtom(self: *MachO) !*Atom { else => unreachable, } - try self.managed_atoms.append(gpa, atom); - - sym.n_value = try self.allocateAtom(atom, size, atom.alignment); + sym.n_value = try self.allocateAtom(atom_index, size, atom.alignment); log.debug("allocated stub helper atom at 0x{x}", .{sym.n_value}); - try self.writeAtom(atom, code); + try self.writeAtom(atom_index, code); - return atom; + return atom_index; } -pub fn createLazyPointerAtom(self: *MachO, stub_sym_index: u32, target: SymbolWithLoc) !*Atom { - const gpa = self.base.allocator; - const atom = try gpa.create(Atom); - atom.* = Atom.empty; - try atom.ensureInitialized(self); +pub fn createLazyPointerAtom(self: *MachO, stub_sym_index: u32, target: SymbolWithLoc) !Atom.Index { + const atom_index = try self.createAtom(); + const atom = self.getAtomPtr(atom_index); atom.size = @sizeOf(u64); atom.alignment = @alignOf(u64); - errdefer gpa.destroy(atom); const sym = atom.getSymbolPtr(self); sym.n_type = macho.N_SECT; sym.n_sect = self.la_symbol_ptr_section_index.? + 1; - try atom.addRelocation(self, .{ + try Atom.addRelocation(self, atom_index, .{ .type = switch (self.base.options.target.cpu.arch) { .aarch64 => @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_UNSIGNED), .x86_64 => @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_UNSIGNED), @@ -1354,22 +1381,20 @@ pub fn createLazyPointerAtom(self: *MachO, stub_sym_index: u32, target: SymbolWi .pcrel = false, .length = 3, }); - try atom.addRebase(self, 0); - try atom.addLazyBinding(self, .{ + try Atom.addRebase(self, atom_index, 0); + try Atom.addLazyBinding(self, atom_index, .{ .target = self.getGlobal(self.getSymbolName(target)).?, .offset = 0, }); - try self.managed_atoms.append(gpa, atom); - - sym.n_value = try self.allocateAtom(atom, atom.size, @alignOf(u64)); + sym.n_value = try self.allocateAtom(atom_index, atom.size, @alignOf(u64)); log.debug("allocated lazy pointer atom at 0x{x} ({s})", .{ sym.n_value, self.getSymbolName(target) }); - try self.writePtrWidthAtom(atom); + try self.writePtrWidthAtom(atom_index); - return atom; + return atom_index; } -pub fn createStubAtom(self: *MachO, laptr_sym_index: u32) !*Atom { +pub fn createStubAtom(self: *MachO, laptr_sym_index: u32) !Atom.Index { const gpa = self.base.allocator; const arch = self.base.options.target.cpu.arch; const size: u4 = switch (arch) { @@ -1377,9 +1402,8 @@ pub fn createStubAtom(self: *MachO, laptr_sym_index: u32) !*Atom { .aarch64 => 3 * @sizeOf(u32), else => unreachable, // unhandled architecture type }; - const atom = try gpa.create(Atom); - atom.* = Atom.empty; - try atom.ensureInitialized(self); + const atom_index = try self.createAtom(); + const atom = self.getAtomPtr(atom_index); atom.size = size; atom.alignment = switch (arch) { .x86_64 => 1, @@ -1387,7 +1411,6 @@ pub fn createStubAtom(self: *MachO, laptr_sym_index: u32) !*Atom { else => unreachable, // unhandled architecture type }; - errdefer gpa.destroy(atom); const sym = atom.getSymbolPtr(self); sym.n_type = macho.N_SECT; @@ -1403,7 +1426,7 @@ pub fn createStubAtom(self: *MachO, laptr_sym_index: u32) !*Atom { code[0] = 0xff; code[1] = 0x25; - try atom.addRelocation(self, .{ + try Atom.addRelocation(self, atom_index, .{ .type = @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_BRANCH), .target = .{ .sym_index = laptr_sym_index, .file = null }, .offset = 2, @@ -1424,7 +1447,7 @@ pub fn createStubAtom(self: *MachO, laptr_sym_index: u32) !*Atom { // br x16 mem.writeIntLittle(u32, code[8..12], aarch64.Instruction.br(.x16).toU32()); - try atom.addRelocations(self, 2, .{ + try Atom.addRelocations(self, atom_index, 2, .{ .{ .type = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_PAGE21), .target = .{ .sym_index = laptr_sym_index, .file = null }, @@ -1446,13 +1469,11 @@ pub fn createStubAtom(self: *MachO, laptr_sym_index: u32) !*Atom { else => unreachable, } - try self.managed_atoms.append(gpa, atom); - - sym.n_value = try self.allocateAtom(atom, size, atom.alignment); + sym.n_value = try self.allocateAtom(atom_index, size, atom.alignment); log.debug("allocated stub atom at 0x{x}", .{sym.n_value}); - try self.writeAtom(atom, code); + try self.writeAtom(atom_index, code); - return atom; + return atom_index; } pub fn createMhExecuteHeaderSymbol(self: *MachO) !void { @@ -1586,9 +1607,12 @@ pub fn resolveSymbolsInDylibs(self: *MachO) !void { if (self.stubs_table.contains(global)) break :blk; const stub_index = try self.allocateStubEntry(global); - const stub_helper_atom = try self.createStubHelperAtom(); - const laptr_atom = try self.createLazyPointerAtom(stub_helper_atom.getSymbolIndex().?, global); - const stub_atom = try self.createStubAtom(laptr_atom.getSymbolIndex().?); + const stub_helper_atom_index = try self.createStubHelperAtom(); + const stub_helper_atom = self.getAtom(stub_helper_atom_index); + const laptr_atom_index = try self.createLazyPointerAtom(stub_helper_atom.getSymbolIndex().?, global); + const laptr_atom = self.getAtom(laptr_atom_index); + const stub_atom_index = try self.createStubAtom(laptr_atom.getSymbolIndex().?); + const stub_atom = self.getAtom(stub_atom_index); self.stubs.items[stub_index].sym_index = stub_atom.getSymbolIndex().?; self.markRelocsDirtyByTarget(global); } @@ -1686,10 +1710,11 @@ pub fn resolveDyldStubBinder(self: *MachO) !void { // Add dyld_stub_binder as the final GOT entry. const got_index = try self.allocateGotEntry(global); - const got_atom = try self.createGotAtom(global); + const got_atom_index = try self.createGotAtom(global); + const got_atom = self.getAtom(got_atom_index); self.got_entries.items[got_index].sym_index = got_atom.getSymbolIndex().?; - try self.writePtrWidthAtom(got_atom); + try self.writePtrWidthAtom(got_atom_index); } pub fn deinit(self: *MachO) void { @@ -1699,9 +1724,9 @@ pub fn deinit(self: *MachO) void { if (self.llvm_object) |llvm_object| llvm_object.destroy(gpa); } - if (self.d_sym) |*d_sym| { - d_sym.deinit(); - } + // if (self.d_sym) |*d_sym| { + // d_sym.deinit(); + // } self.got_entries.deinit(gpa); self.got_entries_free_list.deinit(gpa); @@ -1739,12 +1764,12 @@ pub fn deinit(self: *MachO) void { } self.sections.deinit(gpa); - for (self.managed_atoms.items) |atom| { - gpa.destroy(atom); - } - self.managed_atoms.deinit(gpa); + self.atoms.deinit(gpa); if (self.base.options.module) |_| { + for (self.decls.values()) |*m| { + m.exports.deinit(gpa); + } self.decls.deinit(gpa); } else { assert(self.decls.count() == 0); @@ -1778,14 +1803,15 @@ pub fn deinit(self: *MachO) void { self.lazy_bindings.deinit(gpa); } -fn freeAtom(self: *MachO, atom: *Atom) void { - log.debug("freeAtom {*}", .{atom}); +fn freeAtom(self: *MachO, atom_index: Atom.Index) void { + log.debug("freeAtom {d}", .{atom_index}); const gpa = self.base.allocator; // Remove any relocs and base relocs associated with this Atom - self.freeRelocationsForAtom(atom); + Atom.freeRelocations(self, atom_index); + const atom = self.getAtom(atom_index); const sect_id = atom.getSymbol(self).n_sect - 1; const free_list = &self.sections.items(.free_list)[sect_id]; var already_have_free_list_node = false; @@ -1793,45 +1819,46 @@ fn freeAtom(self: *MachO, atom: *Atom) void { var i: usize = 0; // TODO turn free_list into a hash map while (i < free_list.items.len) { - if (free_list.items[i] == atom) { + if (free_list.items[i] == atom_index) { _ = free_list.swapRemove(i); continue; } - if (free_list.items[i] == atom.prev) { + if (free_list.items[i] == atom.prev_index) { already_have_free_list_node = true; } i += 1; } } - const maybe_last_atom = &self.sections.items(.last_atom)[sect_id]; - if (maybe_last_atom.*) |last_atom| { - if (last_atom == atom) { - if (atom.prev) |prev| { + const maybe_last_atom_index = &self.sections.items(.last_atom_index)[sect_id]; + if (maybe_last_atom_index.*) |last_atom_index| { + if (last_atom_index == atom_index) { + if (atom.prev_index) |prev_index| { // TODO shrink the section size here - maybe_last_atom.* = prev; + maybe_last_atom_index.* = prev_index; } else { - maybe_last_atom.* = null; + maybe_last_atom_index.* = null; } } } - if (atom.prev) |prev| { - prev.next = atom.next; + if (atom.prev_index) |prev_index| { + const prev = self.getAtomPtr(prev_index); + prev.next_index = atom.next_index; - if (!already_have_free_list_node and prev.freeListEligible(self)) { + 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. - free_list.append(gpa, prev) catch {}; + free_list.append(gpa, prev_index) catch {}; } } else { - atom.prev = null; + self.getAtomPtr(atom_index).prev_index = null; } - if (atom.next) |next| { - next.prev = atom.prev; + if (atom.next_index) |next_index| { + self.getAtomPtr(next_index).prev_index = atom.prev_index; } else { - atom.next = null; + self.getAtomPtr(atom_index).next_index = null; } // Appending to free lists is allowed to fail because the free lists are heuristics based anyway. @@ -1849,9 +1876,9 @@ fn freeAtom(self: *MachO, atom: *Atom) void { }; _ = self.got_entries_table.remove(got_target); - if (self.d_sym) |*d_sym| { - d_sym.swapRemoveRelocs(sym_index); - } + // if (self.d_sym) |*d_sym| { + // d_sym.swapRemoveRelocs(sym_index); + // } log.debug(" adding GOT index {d} to free list (target local@{d})", .{ got_index, sym_index }); } @@ -1859,27 +1886,28 @@ fn freeAtom(self: *MachO, atom: *Atom) void { self.locals.items[sym_index].n_type = 0; _ = self.atom_by_index_table.remove(sym_index); log.debug(" adding local symbol index {d} to free list", .{sym_index}); - atom.sym_index = 0; + self.getAtomPtr(atom_index).sym_index = 0; - if (self.d_sym) |*d_sym| { - d_sym.dwarf.freeAtom(&atom.dbg_info_atom); - } + // if (self.d_sym) |*d_sym| { + // d_sym.dwarf.freeAtom(&atom.dbg_info_atom); + // } } -fn shrinkAtom(self: *MachO, atom: *Atom, new_block_size: u64) void { +fn shrinkAtom(self: *MachO, atom_index: Atom.Index, new_block_size: u64) void { _ = self; - _ = atom; + _ = atom_index; _ = new_block_size; // 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 growAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64) !u64 { +fn growAtom(self: *MachO, atom_index: Atom.Index, new_atom_size: u64, alignment: u64) !u64 { + const atom = self.getAtom(atom_index); const sym = atom.getSymbol(self); const align_ok = mem.alignBackwardGeneric(u64, sym.n_value, alignment) == sym.n_value; const need_realloc = !align_ok or new_atom_size > atom.capacity(self); if (!need_realloc) return sym.n_value; - return self.allocateAtom(atom, new_atom_size, alignment); + return self.allocateAtom(atom_index, new_atom_size, alignment); } pub fn allocateSymbol(self: *MachO) !u32 { @@ -1986,31 +2014,29 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv const decl_index = func.owner_decl; const decl = module.declPtr(decl_index); - const atom = &decl.link.macho; - try atom.ensureInitialized(self); - const gop = try self.decls.getOrPut(self.base.allocator, decl_index); - if (gop.found_existing) { - self.freeUnnamedConsts(decl_index); - self.freeRelocationsForAtom(atom); - } else { - gop.value_ptr.* = null; - } + + const atom_index = try self.getOrCreateAtomForDecl(decl_index); + self.freeUnnamedConsts(decl_index); + Atom.freeRelocations(self, atom_index); + + const atom = self.getAtom(atom_index); + _ = atom; var code_buffer = std.ArrayList(u8).init(self.base.allocator); defer code_buffer.deinit(); - var decl_state = if (self.d_sym) |*d_sym| - try d_sym.dwarf.initDeclState(module, decl_index) - else - null; - defer if (decl_state) |*ds| ds.deinit(); + // var decl_state = if (self.d_sym) |*d_sym| + // try d_sym.dwarf.initDeclState(module, decl_index) + // else + // null; + // defer if (decl_state) |*ds| ds.deinit(); - const res = if (decl_state) |*ds| - try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .{ - .dwarf = ds, - }) - else - try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .none); + // const res = if (decl_state) |*ds| + // try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .{ + // .dwarf = ds, + // }) + // else + const res = try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .none); const code = switch (res) { .ok => code_buffer.items, @@ -2022,16 +2048,11 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv }; const addr = try self.updateDeclCode(decl_index, code); + _ = addr; - if (decl_state) |*ds| { - try self.d_sym.?.dwarf.commitDeclState( - module, - decl_index, - addr, - decl.link.macho.size, - ds, - ); - } + // if (decl_state) |*ds| { + // try self.d_sym.?.dwarf.commitDeclState(module, decl_index, addr, atom.size, ds); + // } // Since we updated the vaddr and the size, each corresponding export symbol also // needs to be updated. @@ -2065,11 +2086,8 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Modu log.debug("allocating symbol indexes for {?s}", .{name}); - const atom = try gpa.create(Atom); - errdefer gpa.destroy(atom); - atom.* = Atom.empty; - try atom.ensureInitialized(self); - try self.managed_atoms.append(gpa, atom); + const atom_index = try self.createAtom(); + const atom = self.getAtomPtr(atom_index); const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), typed_value, &code_buffer, .none, .{ .parent_atom_index = atom.getSymbolIndex().?, @@ -2088,21 +2106,21 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Modu atom.size = code.len; atom.alignment = required_alignment; // TODO: work out logic for disambiguating functions from function pointers - // const sect_id = self.getDeclOutputSection(decl); + // const sect_id = self.getDeclOutputSection(decl_index); const sect_id = self.data_const_section_index.?; const symbol = atom.getSymbolPtr(self); symbol.n_strx = name_str_index; symbol.n_type = macho.N_SECT; symbol.n_sect = sect_id + 1; - symbol.n_value = try self.allocateAtom(atom, code.len, required_alignment); - errdefer self.freeAtom(atom); + symbol.n_value = try self.allocateAtom(atom_index, code.len, required_alignment); + errdefer self.freeAtom(atom_index); - try unnamed_consts.append(gpa, atom); + try unnamed_consts.append(gpa, atom_index); log.debug("allocated atom for {?s} at 0x{x}", .{ name, symbol.n_value }); log.debug(" (required alignment 0x{x})", .{required_alignment}); - try self.writeAtom(atom, code); + try self.writeAtom(atom_index, code); return atom.getSymbolIndex().?; } @@ -2129,41 +2147,36 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index) } } - const atom = &decl.link.macho; - try atom.ensureInitialized(self); - const gop = try self.decls.getOrPut(self.base.allocator, decl_index); - if (gop.found_existing) { - self.freeRelocationsForAtom(atom); - } else { - gop.value_ptr.* = null; - } + const atom_index = try self.getOrCreateAtomForDecl(decl_index); + Atom.freeRelocations(self, atom_index); + const atom = self.getAtom(atom_index); var code_buffer = std.ArrayList(u8).init(self.base.allocator); defer code_buffer.deinit(); - var decl_state: ?Dwarf.DeclState = if (self.d_sym) |*d_sym| - try d_sym.dwarf.initDeclState(module, decl_index) - else - null; - defer if (decl_state) |*ds| ds.deinit(); + // var decl_state: ?Dwarf.DeclState = if (self.d_sym) |*d_sym| + // try d_sym.dwarf.initDeclState(module, decl_index) + // else + // null; + // defer if (decl_state) |*ds| ds.deinit(); const decl_val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val; - const res = if (decl_state) |*ds| - try codegen.generateSymbol(&self.base, decl.srcLoc(), .{ - .ty = decl.ty, - .val = decl_val, - }, &code_buffer, .{ - .dwarf = ds, - }, .{ - .parent_atom_index = decl.link.macho.getSymbolIndex().?, - }) - else - try codegen.generateSymbol(&self.base, decl.srcLoc(), .{ - .ty = decl.ty, - .val = decl_val, - }, &code_buffer, .none, .{ - .parent_atom_index = decl.link.macho.getSymbolIndex().?, - }); + // const res = if (decl_state) |*ds| + // try codegen.generateSymbol(&self.base, decl.srcLoc(), .{ + // .ty = decl.ty, + // .val = decl_val, + // }, &code_buffer, .{ + // .dwarf = ds, + // }, .{ + // .parent_atom_index = atom.getSymbolIndex().?, + // }) + // else + const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), .{ + .ty = decl.ty, + .val = decl_val, + }, &code_buffer, .none, .{ + .parent_atom_index = atom.getSymbolIndex().?, + }); const code = switch (res) { .ok => code_buffer.items, @@ -2174,23 +2187,31 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index) }, }; const addr = try self.updateDeclCode(decl_index, code); + _ = addr; - if (decl_state) |*ds| { - try self.d_sym.?.dwarf.commitDeclState( - module, - decl_index, - addr, - decl.link.macho.size, - ds, - ); - } + // if (decl_state) |*ds| { + // try self.d_sym.?.dwarf.commitDeclState(module, decl_index, addr, atom.size, ds); + // } // Since we updated the vaddr and the size, each corresponding export symbol also // needs to be updated. try self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index)); } -fn getDeclOutputSection(self: *MachO, decl: *Module.Decl) u8 { +pub fn getOrCreateAtomForDecl(self: *MachO, decl_index: Module.Decl.Index) !Atom.Index { + const gop = try self.decls.getOrPut(self.base.allocator, decl_index); + if (!gop.found_existing) { + gop.value_ptr.* = .{ + .atom = try self.createAtom(), + .section = self.getDeclOutputSection(decl_index), + .exports = .{}, + }; + } + return gop.value_ptr.atom; +} + +fn getDeclOutputSection(self: *MachO, decl_index: Module.Decl.Index) u8 { + const decl = self.base.options.module.?.declPtr(decl_index); const ty = decl.ty; const val = decl.val; const zig_ty = ty.zigTypeTag(); @@ -2341,13 +2362,11 @@ fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []const u8) const sym_name = try decl.getFullyQualifiedName(mod); defer self.base.allocator.free(sym_name); - const atom = &decl.link.macho; - const sym_index = atom.getSymbolIndex().?; // Atom was not initialized - const decl_ptr = self.decls.getPtr(decl_index).?; - if (decl_ptr.* == null) { - decl_ptr.* = self.getDeclOutputSection(decl); - } - const sect_id = decl_ptr.*.?; + const decl_metadata = self.decls.get(decl_index).?; + const atom_index = decl_metadata.atom; + const atom = self.getAtom(atom_index); + const sym_index = atom.getSymbolIndex().?; + const sect_id = decl_metadata.section; const code_len = code.len; if (atom.size != 0) { @@ -2357,11 +2376,11 @@ fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []const u8) sym.n_sect = sect_id + 1; sym.n_desc = 0; - const capacity = decl.link.macho.capacity(self); + const capacity = atom.capacity(self); const need_realloc = code_len > capacity or !mem.isAlignedGeneric(u64, sym.n_value, required_alignment); if (need_realloc) { - const vaddr = try self.growAtom(atom, code_len, required_alignment); + const vaddr = try self.growAtom(atom_index, code_len, required_alignment); log.debug("growing {s} and moving from 0x{x} to 0x{x}", .{ sym_name, sym.n_value, vaddr }); log.debug(" (required alignment 0x{x})", .{required_alignment}); @@ -2369,19 +2388,19 @@ fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []const u8) sym.n_value = vaddr; log.debug(" (updating GOT entry)", .{}); const got_target = SymbolWithLoc{ .sym_index = sym_index, .file = null }; - const got_atom = self.getGotAtomForSymbol(got_target).?; + const got_atom_index = self.getGotAtomIndexForSymbol(got_target).?; self.markRelocsDirtyByTarget(got_target); - try self.writePtrWidthAtom(got_atom); + try self.writePtrWidthAtom(got_atom_index); } } else if (code_len < atom.size) { - self.shrinkAtom(atom, code_len); - } else if (atom.next == null) { + self.shrinkAtom(atom_index, code_len); + } else if (atom.next_index == null) { const header = &self.sections.items(.header)[sect_id]; const segment = self.getSegment(sect_id); const needed_size = (sym.n_value + code_len) - segment.vmaddr; header.size = needed_size; } - atom.size = code_len; + self.getAtomPtr(atom_index).size = code_len; } else { const name_str_index = try self.strtab.insert(gpa, sym_name); const sym = atom.getSymbolPtr(self); @@ -2390,33 +2409,36 @@ fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []const u8) sym.n_sect = sect_id + 1; sym.n_desc = 0; - const vaddr = try self.allocateAtom(atom, code_len, required_alignment); - errdefer self.freeAtom(atom); + const vaddr = try self.allocateAtom(atom_index, code_len, required_alignment); + errdefer self.freeAtom(atom_index); log.debug("allocated atom for {s} at 0x{x}", .{ sym_name, vaddr }); log.debug(" (required alignment 0x{x})", .{required_alignment}); - atom.size = code_len; + self.getAtomPtr(atom_index).size = code_len; sym.n_value = vaddr; const got_target = SymbolWithLoc{ .sym_index = sym_index, .file = null }; const got_index = try self.allocateGotEntry(got_target); - const got_atom = try self.createGotAtom(got_target); + const got_atom_index = try self.createGotAtom(got_target); + const got_atom = self.getAtom(got_atom_index); self.got_entries.items[got_index].sym_index = got_atom.getSymbolIndex().?; - try self.writePtrWidthAtom(got_atom); + try self.writePtrWidthAtom(got_atom_index); } self.markRelocsDirtyByTarget(atom.getSymbolWithLoc()); - try self.writeAtom(atom, code); + try self.writeAtom(atom_index, code); return atom.getSymbol(self).n_value; } pub fn updateDeclLineNumber(self: *MachO, module: *Module, decl: *const Module.Decl) !void { + _ = decl; + _ = self; _ = module; - if (self.d_sym) |*d_sym| { - try d_sym.dwarf.updateDeclLineNumber(decl); - } + // if (self.d_sym) |*d_sym| { + // try d_sym.dwarf.updateDeclLineNumber(decl); + // } } pub fn updateDeclExports( @@ -2432,22 +2454,17 @@ pub fn updateDeclExports( if (self.llvm_object) |llvm_object| return llvm_object.updateDeclExports(module, decl_index, exports); } + const tracy = trace(@src()); defer tracy.end(); const gpa = self.base.allocator; const decl = module.declPtr(decl_index); - const atom = &decl.link.macho; - - if (atom.getSymbolIndex() == null) return; - - const gop = try self.decls.getOrPut(gpa, decl_index); - if (!gop.found_existing) { - gop.value_ptr.* = self.getDeclOutputSection(decl); - } - + const atom_index = try self.getOrCreateAtomForDecl(decl_index); + const atom = self.getAtom(atom_index); const decl_sym = atom.getSymbol(self); + const decl_metadata = self.decls.getPtr(decl_index).?; for (exports) |exp| { const exp_name = try std.fmt.allocPrint(gpa, "_{s}", .{exp.options.name}); @@ -2485,9 +2502,9 @@ pub fn updateDeclExports( continue; } - const sym_index = exp.link.macho.sym_index orelse blk: { + const sym_index = decl_metadata.getExport(self, exp_name) orelse blk: { const sym_index = try self.allocateSymbol(); - exp.link.macho.sym_index = sym_index; + try decl_metadata.exports.append(gpa, sym_index); break :blk sym_index; }; const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = null }; @@ -2535,16 +2552,18 @@ pub fn updateDeclExports( } } -pub fn deleteExport(self: *MachO, exp: Export) void { +pub fn deleteDeclExport(self: *MachO, decl_index: Module.Decl.Index, name: []const u8) Allocator.Error!void { if (self.llvm_object) |_| return; - const sym_index = exp.sym_index orelse return; + const metadata = self.decls.getPtr(decl_index) orelse return; const gpa = self.base.allocator; + const exp_name = try std.fmt.allocPrint(gpa, "_{s}", .{name}); + defer gpa.free(exp_name); + const sym_index = metadata.getExportPtr(self, exp_name) orelse return; - const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = null }; + const sym_loc = SymbolWithLoc{ .sym_index = sym_index.*, .file = null }; const sym = self.getSymbolPtr(sym_loc); - const sym_name = self.getSymbolName(sym_loc); - log.debug("deleting export '{s}'", .{sym_name}); + log.debug("deleting export '{s}'", .{exp_name}); assert(sym.sect() and sym.ext()); sym.* = .{ .n_strx = 0, @@ -2553,9 +2572,9 @@ pub fn deleteExport(self: *MachO, exp: Export) void { .n_desc = 0, .n_value = 0, }; - self.locals_free_list.append(gpa, sym_index) catch {}; + self.locals_free_list.append(gpa, sym_index.*) catch {}; - if (self.resolver.fetchRemove(sym_name)) |entry| { + if (self.resolver.fetchRemove(exp_name)) |entry| { defer gpa.free(entry.key); self.globals_free_list.append(gpa, entry.value) catch {}; self.globals.items[entry.value] = .{ @@ -2563,17 +2582,8 @@ pub fn deleteExport(self: *MachO, exp: Export) void { .file = null, }; } -} -fn freeRelocationsForAtom(self: *MachO, atom: *Atom) void { - var removed_relocs = self.relocs.fetchOrderedRemove(atom); - if (removed_relocs) |*relocs| relocs.value.deinit(self.base.allocator); - var removed_rebases = self.rebases.fetchOrderedRemove(atom); - if (removed_rebases) |*rebases| rebases.value.deinit(self.base.allocator); - var removed_bindings = self.bindings.fetchOrderedRemove(atom); - if (removed_bindings) |*bindings| bindings.value.deinit(self.base.allocator); - var removed_lazy_bindings = self.lazy_bindings.fetchOrderedRemove(atom); - if (removed_lazy_bindings) |*lazy_bindings| lazy_bindings.value.deinit(self.base.allocator); + sym_index.* = 0; } fn freeUnnamedConsts(self: *MachO, decl_index: Module.Decl.Index) void { @@ -2595,28 +2605,22 @@ pub fn freeDecl(self: *MachO, decl_index: Module.Decl.Index) void { log.debug("freeDecl {*}", .{decl}); if (self.decls.fetchSwapRemove(decl_index)) |kv| { - if (kv.value) |_| { - self.freeAtom(&decl.link.macho); - self.freeUnnamedConsts(decl_index); - } + self.freeAtom(kv.value.atom); + self.freeUnnamedConsts(decl_index); } - if (self.d_sym) |*d_sym| { - d_sym.dwarf.freeDecl(decl); - } + // if (self.d_sym) |*d_sym| { + // d_sym.dwarf.freeDecl(decl); + // } } pub fn getDeclVAddr(self: *MachO, decl_index: Module.Decl.Index, reloc_info: File.RelocInfo) !u64 { - const mod = self.base.options.module.?; - const decl = mod.declPtr(decl_index); - assert(self.llvm_object == null); - try decl.link.macho.ensureInitialized(self); - const sym_index = decl.link.macho.getSymbolIndex().?; - - const atom = self.getAtomForSymbol(.{ .sym_index = reloc_info.parent_atom_index, .file = null }).?; - try atom.addRelocation(self, .{ + const this_atom_index = try self.getOrCreateAtomForDecl(decl_index); + const sym_index = self.getAtom(this_atom_index).getSymbolIndex().?; + const atom_index = self.getAtomIndexForSymbol(.{ .sym_index = reloc_info.parent_atom_index, .file = null }).?; + try Atom.addRelocation(self, atom_index, .{ .type = switch (self.base.options.target.cpu.arch) { .aarch64 => @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_UNSIGNED), .x86_64 => @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_UNSIGNED), @@ -2628,7 +2632,7 @@ pub fn getDeclVAddr(self: *MachO, decl_index: Module.Decl.Index, reloc_info: Fil .pcrel = false, .length = 3, }); - try atom.addRebase(self, @intCast(u32, reloc_info.offset)); + try Atom.addRebase(self, atom_index, @intCast(u32, reloc_info.offset)); return 0; } @@ -2860,34 +2864,36 @@ fn moveSectionInVirtualMemory(self: *MachO, sect_id: u8, needed_size: u64) !void // TODO: enforce order by increasing VM addresses in self.sections container. for (self.sections.items(.header)[sect_id + 1 ..]) |*next_header, next_sect_id| { const index = @intCast(u8, sect_id + 1 + next_sect_id); - const maybe_last_atom = &self.sections.items(.last_atom)[index]; const next_segment = self.getSegmentPtr(index); next_header.addr += diff; next_segment.vmaddr += diff; - if (maybe_last_atom.*) |last_atom| { - var atom = last_atom; + const maybe_last_atom_index = &self.sections.items(.last_atom_index)[index]; + if (maybe_last_atom_index.*) |last_atom_index| { + var atom_index = last_atom_index; while (true) { + const atom = self.getAtom(atom_index); const sym = atom.getSymbolPtr(self); sym.n_value += diff; - if (atom.prev) |prev| { - atom = prev; + if (atom.prev_index) |prev_index| { + atom_index = prev_index; } else break; } } } } -fn allocateAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64) !u64 { +fn allocateAtom(self: *MachO, atom_index: Atom.Index, new_atom_size: u64, alignment: u64) !u64 { const tracy = trace(@src()); defer tracy.end(); + const atom = self.getAtom(atom_index); const sect_id = atom.getSymbol(self).n_sect - 1; const segment = self.getSegmentPtr(sect_id); const header = &self.sections.items(.header)[sect_id]; const free_list = &self.sections.items(.free_list)[sect_id]; - const maybe_last_atom = &self.sections.items(.last_atom)[sect_id]; + const maybe_last_atom_index = &self.sections.items(.last_atom_index)[sect_id]; const requires_padding = blk: { if (!header.isCode()) break :blk false; if (header.isSymbolStubs()) break :blk false; @@ -2901,7 +2907,7 @@ fn allocateAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64) ! // 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 atom_placement: ?*Atom = null; + var atom_placement: ?Atom.Index = null; var free_list_removal: ?usize = null; // First we look for an appropriately sized free list node. @@ -2909,7 +2915,8 @@ fn allocateAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64) ! var vaddr = blk: { var i: usize = 0; while (i < free_list.items.len) { - const big_atom = free_list.items[i]; + const big_atom_index = free_list.items[i]; + const big_atom = self.getAtom(big_atom_index); // We now have a pointer to a live atom that has too much capacity. // Is it enough that we could fit this new atom? const sym = big_atom.getSymbol(self); @@ -2937,30 +2944,35 @@ fn allocateAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64) ! const keep_free_list_node = remaining_capacity >= min_text_capacity; // Set up the metadata to be updated, after errors are no longer possible. - atom_placement = big_atom; + atom_placement = big_atom_index; if (!keep_free_list_node) { free_list_removal = i; } break :blk new_start_vaddr; - } else if (maybe_last_atom.*) |last| { + } else if (maybe_last_atom_index.*) |last_index| { + const last = self.getAtom(last_index); const last_symbol = last.getSymbol(self); const ideal_capacity = if (requires_padding) padToIdeal(last.size) else last.size; const ideal_capacity_end_vaddr = last_symbol.n_value + ideal_capacity; const new_start_vaddr = mem.alignForwardGeneric(u64, ideal_capacity_end_vaddr, alignment); - atom_placement = last; + atom_placement = last_index; break :blk new_start_vaddr; } else { break :blk mem.alignForwardGeneric(u64, segment.vmaddr, alignment); } }; - const expand_section = atom_placement == null or atom_placement.?.next == null; + const expand_section = if (atom_placement) |placement_index| + self.getAtom(placement_index).next_index == null + else + true; if (expand_section) { const sect_capacity = self.allocatedSize(header.offset); const needed_size = (vaddr + new_atom_size) - segment.vmaddr; if (needed_size > sect_capacity) { const new_offset = self.findFreeSpace(needed_size, self.page_size); - const current_size = if (maybe_last_atom.*) |last_atom| blk: { + const current_size = if (maybe_last_atom_index.*) |last_atom_index| blk: { + const last_atom = self.getAtom(last_atom_index); const sym = last_atom.getSymbol(self); break :blk (sym.n_value + last_atom.size) - segment.vmaddr; } else 0; @@ -2992,7 +3004,7 @@ fn allocateAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64) ! header.size = needed_size; segment.filesize = mem.alignForwardGeneric(u64, needed_size, self.page_size); segment.vmsize = mem.alignForwardGeneric(u64, needed_size, self.page_size); - maybe_last_atom.* = atom; + maybe_last_atom_index.* = atom_index; self.segment_table_dirty = true; } @@ -3002,20 +3014,25 @@ fn allocateAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64) ! header.@"align" = align_pow; } - if (atom.prev) |prev| { - prev.next = atom.next; + if (atom.prev_index) |prev_index| { + const prev = self.getAtomPtr(prev_index); + prev.next_index = atom.next_index; } - if (atom.next) |next| { - next.prev = atom.prev; + if (atom.next_index) |next_index| { + const next = self.getAtomPtr(next_index); + next.prev_index = atom.prev_index; } - if (atom_placement) |big_atom| { - atom.prev = big_atom; - atom.next = big_atom.next; - big_atom.next = atom; + if (atom_placement) |big_atom_index| { + const big_atom = self.getAtomPtr(big_atom_index); + const atom_ptr = self.getAtomPtr(atom_index); + atom_ptr.prev_index = big_atom_index; + atom_ptr.next_index = big_atom.next_index; + big_atom.next_index = atom_index; } else { - atom.prev = null; - atom.next = null; + const atom_ptr = self.getAtomPtr(atom_index); + atom_ptr.prev_index = null; + atom_ptr.next_index = null; } if (free_list_removal) |i| { _ = free_list.swapRemove(i); @@ -3155,7 +3172,8 @@ fn collectRebaseData(self: *MachO, rebase: *Rebase) !void { const gpa = self.base.allocator; const slice = self.sections.slice(); - for (self.rebases.keys()) |atom, i| { + for (self.rebases.keys()) |atom_index, i| { + const atom = self.getAtom(atom_index); log.debug(" ATOM(%{?d}, '{s}')", .{ atom.getSymbolIndex(), atom.getName(self) }); const sym = atom.getSymbol(self); @@ -3184,7 +3202,8 @@ fn collectBindData(self: *MachO, bind: anytype, raw_bindings: anytype) !void { const gpa = self.base.allocator; const slice = self.sections.slice(); - for (raw_bindings.keys()) |atom, i| { + for (raw_bindings.keys()) |atom_index, i| { + const atom = self.getAtom(atom_index); log.debug(" ATOM(%{?d}, '{s}')", .{ atom.getSymbolIndex(), atom.getName(self) }); const sym = atom.getSymbol(self); @@ -3359,7 +3378,7 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, lazy_bind: LazyBind) !void if (lazy_bind.size() == 0) return; const stub_helper_section_index = self.stub_helper_section_index.?; - assert(self.stub_helper_preamble_atom != null); + assert(self.stub_helper_preamble_atom_index != null); const section = self.sections.get(stub_helper_section_index); @@ -3369,10 +3388,11 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, lazy_bind: LazyBind) !void else => unreachable, }; const header = section.header; - var atom = section.last_atom.?; + var atom_index = section.last_atom_index.?; var index: usize = lazy_bind.offsets.items.len; while (index > 0) : (index -= 1) { + const atom = self.getAtom(atom_index); const sym = atom.getSymbol(self); const file_offset = header.offset + sym.n_value - header.addr + stub_offset; const bind_offset = lazy_bind.offsets.items[index - 1]; @@ -3385,7 +3405,7 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, lazy_bind: LazyBind) !void try self.base.file.?.pwriteAll(mem.asBytes(&bind_offset), file_offset); - atom = atom.prev.?; + atom_index = atom.prev_index.?; } } @@ -3828,25 +3848,35 @@ pub fn getOrPutGlobalPtr(self: *MachO, name: []const u8) !GetOrPutGlobalPtrResul return GetOrPutGlobalPtrResult{ .found_existing = false, .value_ptr = ptr }; } +pub fn getAtom(self: *MachO, atom_index: Atom.Index) Atom { + assert(atom_index < self.atoms.items.len); + return self.atoms.items[atom_index]; +} + +pub fn getAtomPtr(self: *MachO, atom_index: Atom.Index) *Atom { + assert(atom_index < self.atoms.items.len); + return &self.atoms.items[atom_index]; +} + /// Returns atom if there is an atom referenced by the symbol described by `sym_with_loc` descriptor. /// Returns null on failure. -pub fn getAtomForSymbol(self: *MachO, sym_with_loc: SymbolWithLoc) ?*Atom { +pub fn getAtomIndexForSymbol(self: *MachO, sym_with_loc: SymbolWithLoc) ?Atom.Index { assert(sym_with_loc.file == null); return self.atom_by_index_table.get(sym_with_loc.sym_index); } /// Returns GOT atom that references `sym_with_loc` if one exists. /// Returns null otherwise. -pub fn getGotAtomForSymbol(self: *MachO, sym_with_loc: SymbolWithLoc) ?*Atom { +pub fn getGotAtomIndexForSymbol(self: *MachO, sym_with_loc: SymbolWithLoc) ?Atom.Index { const got_index = self.got_entries_table.get(sym_with_loc) orelse return null; - return self.got_entries.items[got_index].getAtom(self); + return self.got_entries.items[got_index].getAtomIndex(self); } /// Returns stubs atom that references `sym_with_loc` if one exists. /// Returns null otherwise. -pub fn getStubsAtomForSymbol(self: *MachO, sym_with_loc: SymbolWithLoc) ?*Atom { +pub fn getStubsAtomIndexForSymbol(self: *MachO, sym_with_loc: SymbolWithLoc) ?Atom.Index { const stubs_index = self.stubs_table.get(sym_with_loc) orelse return null; - return self.stubs.items[stubs_index].getAtom(self); + return self.stubs.items[stubs_index].getAtomIndex(self); } /// Returns symbol location corresponding to the set entrypoint. @@ -4232,26 +4262,31 @@ pub fn logAtoms(self: *MachO) void { log.debug("atoms:", .{}); const slice = self.sections.slice(); - for (slice.items(.last_atom)) |last, i| { - var atom = last orelse continue; + for (slice.items(.last_atom_index)) |last_atom_index, i| { + var atom_index = last_atom_index orelse continue; const header = slice.items(.header)[i]; - while (atom.prev) |prev| { - atom = prev; + while (true) { + const atom = self.getAtom(atom_index); + if (atom.prev_index) |prev_index| { + atom_index = prev_index; + } else break; } log.debug("{s},{s}", .{ header.segName(), header.sectName() }); while (true) { - self.logAtom(atom); - if (atom.next) |next| { - atom = next; + self.logAtom(atom_index); + const atom = self.getAtom(atom_index); + if (atom.next_index) |next_index| { + atom_index = next_index; } else break; } } } -pub fn logAtom(self: *MachO, atom: *const Atom) void { +pub fn logAtom(self: *MachO, atom_index: Atom.Index) void { + const atom = self.getAtom(atom_index); const sym = atom.getSymbol(self); const sym_name = atom.getName(self); log.debug(" ATOM(%{?d}, '{s}') @ {x} (sizeof({x}), alignof({x})) in object({?d}) in sect({d})", .{ diff --git a/src/link/MachO/Atom.zig b/src/link/MachO/Atom.zig index f15958b3dfe246e0254a8cf13a79ec0db119c522..da0115d0698376724788ad72a2620735787f62b7 100644 --- a/src/link/MachO/Atom.zig +++ b/src/link/MachO/Atom.zig @@ -39,11 +39,14 @@ size: u64, alignment: u32, /// Points to the previous and next neighbours -next: ?*Atom, -prev: ?*Atom, +/// TODO use the same trick as with symbols: reserve index 0 as null atom +next_index: ?Atom.Index, +prev_index: ?Atom.Index, dbg_info_atom: Dwarf.Atom, +pub const Index = u32; + pub const Binding = struct { target: SymbolWithLoc, offset: u64, @@ -54,22 +57,6 @@ pub const SymbolAtOffset = struct { offset: u64, }; -pub const empty = Atom{ - .sym_index = 0, - .file = null, - .size = 0, - .alignment = 0, - .prev = null, - .next = null, - .dbg_info_atom = undefined, -}; - -pub fn ensureInitialized(self: *Atom, macho_file: *MachO) !void { - if (self.getSymbolIndex() != null) return; // Already initialized - self.sym_index = try macho_file.allocateSymbol(); - try macho_file.atom_by_index_table.putNoClobber(macho_file.base.allocator, self.sym_index, self); -} - pub fn getSymbolIndex(self: Atom) ?u32 { if (self.sym_index == 0) return null; return self.sym_index; @@ -108,7 +95,8 @@ pub fn getName(self: Atom, macho_file: *MachO) []const u8 { /// this calculation. pub fn capacity(self: Atom, macho_file: *MachO) u64 { const self_sym = self.getSymbol(macho_file); - if (self.next) |next| { + if (self.next_index) |next_index| { + const next = macho_file.getAtom(next_index); const next_sym = next.getSymbol(macho_file); return next_sym.n_value - self_sym.n_value; } else { @@ -120,7 +108,8 @@ pub fn capacity(self: Atom, macho_file: *MachO) u64 { pub fn freeListEligible(self: Atom, macho_file: *MachO) bool { // No need to keep a free list node for the last atom. - const next = self.next orelse return false; + const next_index = self.next_index orelse return false; + const next = macho_file.getAtom(next_index); const self_sym = self.getSymbol(macho_file); const next_sym = next.getSymbol(macho_file); const cap = next_sym.n_value - self_sym.n_value; @@ -130,19 +119,19 @@ pub fn freeListEligible(self: Atom, macho_file: *MachO) bool { return surplus >= MachO.min_text_capacity; } -pub fn addRelocation(self: *Atom, macho_file: *MachO, reloc: Relocation) !void { - return self.addRelocations(macho_file, 1, .{reloc}); +pub fn addRelocation(macho_file: *MachO, atom_index: Atom.Index, reloc: Relocation) !void { + return addRelocations(macho_file, atom_index, 1, .{reloc}); } pub fn addRelocations( - self: *Atom, macho_file: *MachO, + atom_index: Atom.Index, comptime count: comptime_int, relocs: [count]Relocation, ) !void { const gpa = macho_file.base.allocator; const target = macho_file.base.options.target; - const gop = try macho_file.relocs.getOrPut(gpa, self); + const gop = try macho_file.relocs.getOrPut(gpa, atom_index); if (!gop.found_existing) { gop.value_ptr.* = .{}; } @@ -156,56 +145,72 @@ pub fn addRelocations( } } -pub fn addRebase(self: *Atom, macho_file: *MachO, offset: u32) !void { +pub fn addRebase(macho_file: *MachO, atom_index: Atom.Index, offset: u32) !void { const gpa = macho_file.base.allocator; - log.debug(" (adding rebase at offset 0x{x} in %{?d})", .{ offset, self.getSymbolIndex() }); - const gop = try macho_file.rebases.getOrPut(gpa, self); + const atom = macho_file.getAtom(atom_index); + log.debug(" (adding rebase at offset 0x{x} in %{?d})", .{ offset, atom.getSymbolIndex() }); + const gop = try macho_file.rebases.getOrPut(gpa, atom_index); if (!gop.found_existing) { gop.value_ptr.* = .{}; } try gop.value_ptr.append(gpa, offset); } -pub fn addBinding(self: *Atom, macho_file: *MachO, binding: Binding) !void { +pub fn addBinding(macho_file: *MachO, atom_index: Atom.Index, binding: Binding) !void { const gpa = macho_file.base.allocator; + const atom = macho_file.getAtom(atom_index); log.debug(" (adding binding to symbol {s} at offset 0x{x} in %{?d})", .{ macho_file.getSymbolName(binding.target), binding.offset, - self.getSymbolIndex(), + atom.getSymbolIndex(), }); - const gop = try macho_file.bindings.getOrPut(gpa, self); + const gop = try macho_file.bindings.getOrPut(gpa, atom_index); if (!gop.found_existing) { gop.value_ptr.* = .{}; } try gop.value_ptr.append(gpa, binding); } -pub fn addLazyBinding(self: *Atom, macho_file: *MachO, binding: Binding) !void { +pub fn addLazyBinding(macho_file: *MachO, atom_index: Atom.Index, binding: Binding) !void { const gpa = macho_file.base.allocator; + const atom = macho_file.getAtom(atom_index); log.debug(" (adding lazy binding to symbol {s} at offset 0x{x} in %{?d})", .{ macho_file.getSymbolName(binding.target), binding.offset, - self.getSymbolIndex(), + atom.getSymbolIndex(), }); - const gop = try macho_file.lazy_bindings.getOrPut(gpa, self); + const gop = try macho_file.lazy_bindings.getOrPut(gpa, atom_index); if (!gop.found_existing) { gop.value_ptr.* = .{}; } try gop.value_ptr.append(gpa, binding); } -pub fn resolveRelocations(self: *Atom, macho_file: *MachO) !void { - const relocs = macho_file.relocs.get(self) orelse return; - const source_sym = self.getSymbol(macho_file); +pub fn resolveRelocations(macho_file: *MachO, atom_index: Atom.Index) !void { + const atom = macho_file.getAtom(atom_index); + const relocs = macho_file.relocs.get(atom_index) orelse return; + const source_sym = atom.getSymbol(macho_file); const source_section = macho_file.sections.get(source_sym.n_sect - 1).header; const file_offset = source_section.offset + source_sym.n_value - source_section.addr; - log.debug("relocating '{s}'", .{self.getName(macho_file)}); + log.debug("relocating '{s}'", .{atom.getName(macho_file)}); for (relocs.items) |*reloc| { if (!reloc.dirty) continue; - try reloc.resolve(self, macho_file, file_offset); + try reloc.resolve(macho_file, atom_index, file_offset); reloc.dirty = false; } } + +pub fn freeRelocations(macho_file: *MachO, atom_index: Atom.Index) void { + const gpa = macho_file.base.allocator; + var removed_relocs = macho_file.relocs.fetchOrderedRemove(atom_index); + if (removed_relocs) |*relocs| relocs.value.deinit(gpa); + var removed_rebases = macho_file.rebases.fetchOrderedRemove(atom_index); + if (removed_rebases) |*rebases| rebases.value.deinit(gpa); + var removed_bindings = macho_file.bindings.fetchOrderedRemove(atom_index); + if (removed_bindings) |*bindings| bindings.value.deinit(gpa); + var removed_lazy_bindings = macho_file.lazy_bindings.fetchOrderedRemove(atom_index); + if (removed_lazy_bindings) |*lazy_bindings| lazy_bindings.value.deinit(gpa); +} diff --git a/src/link/MachO/Relocation.zig b/src/link/MachO/Relocation.zig index ca6bf9d681fd2ed3d211d1f679cbc646bd89e3d2..07e5cf1aa255ede83cfd2571dcc691c12768c65b 100644 --- a/src/link/MachO/Relocation.zig +++ b/src/link/MachO/Relocation.zig @@ -29,33 +29,35 @@ pub fn fmtType(self: Relocation, target: std.Target) []const u8 { } } -pub fn getTargetAtom(self: Relocation, macho_file: *MachO) ?*Atom { +pub fn getTargetAtomIndex(self: Relocation, macho_file: *MachO) ?Atom.Index { switch (macho_file.base.options.target.cpu.arch) { .aarch64 => switch (@intToEnum(macho.reloc_type_arm64, self.type)) { .ARM64_RELOC_GOT_LOAD_PAGE21, .ARM64_RELOC_GOT_LOAD_PAGEOFF12, .ARM64_RELOC_POINTER_TO_GOT, - => return macho_file.getGotAtomForSymbol(self.target), + => return macho_file.getGotAtomIndexForSymbol(self.target), else => {}, }, .x86_64 => switch (@intToEnum(macho.reloc_type_x86_64, self.type)) { .X86_64_RELOC_GOT, .X86_64_RELOC_GOT_LOAD, - => return macho_file.getGotAtomForSymbol(self.target), + => return macho_file.getGotAtomIndexForSymbol(self.target), else => {}, }, else => unreachable, } - if (macho_file.getStubsAtomForSymbol(self.target)) |stubs_atom| return stubs_atom; - return macho_file.getAtomForSymbol(self.target); + if (macho_file.getStubsAtomIndexForSymbol(self.target)) |stubs_atom| return stubs_atom; + return macho_file.getAtomIndexForSymbol(self.target); } -pub fn resolve(self: Relocation, atom: *Atom, macho_file: *MachO, base_offset: u64) !void { +pub fn resolve(self: Relocation, macho_file: *MachO, atom_index: Atom.Index, base_offset: u64) !void { const arch = macho_file.base.options.target.cpu.arch; + const atom = macho_file.getAtom(atom_index); const source_sym = atom.getSymbol(macho_file); const source_addr = source_sym.n_value + self.offset; - const target_atom = self.getTargetAtom(macho_file) orelse return; + const target_atom_index = self.getTargetAtomIndex(macho_file) orelse return; + const target_atom = macho_file.getAtom(target_atom_index); const target_addr = @intCast(i64, target_atom.getSymbol(macho_file).n_value) + self.addend; log.debug(" ({x}: [() => 0x{x} ({s})) ({s})", .{ -- 2.54.0 From 1f64432196e51785fe1dba442a0878c1b10f8b06 Mon Sep 17 00:00:00 2001 From: Techatrix <19954306+Techatrix@users.noreply.github.com> Date: Tue, 31 Jan 2023 00:59:18 +0100 Subject: [PATCH 37/84] wasm: correctly handle optional slices --- src/arch/wasm/CodeGen.zig | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index 342d6b70cc55ef3a8273729323010135a555a066..d0ff27a3e2117387aefb81b2753aaba3aefb3269 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -1706,9 +1706,11 @@ fn isByRef(ty: Type, target: std.Target) bool { return true; }, .Optional => { - if (ty.optionalReprIsPayload()) return false; + if (ty.isPtrLikeOptional()) return false; var buf: Type.Payload.ElemType = undefined; - return ty.optionalChild(&buf).hasRuntimeBitsIgnoreComptime(); + const pl_type = ty.optionalChild(&buf); + if (pl_type.zigTypeTag() == .ErrorSet) return false; + return pl_type.hasRuntimeBitsIgnoreComptime(); }, .Pointer => { // Slices act like struct and will be passed by reference @@ -3869,14 +3871,17 @@ fn airIsNull(func: *CodeGen, inst: Air.Inst.Index, opcode: wasm.Opcode, op_kind: /// NOTE: Leaves the result on the stack fn isNull(func: *CodeGen, operand: WValue, optional_ty: Type, opcode: wasm.Opcode) InnerError!WValue { try func.emitWValue(operand); + var buf: Type.Payload.ElemType = undefined; + const payload_ty = optional_ty.optionalChild(&buf); if (!optional_ty.optionalReprIsPayload()) { - var buf: Type.Payload.ElemType = undefined; - const payload_ty = optional_ty.optionalChild(&buf); // When payload is zero-bits, we can treat operand as a value, rather than // a pointer to the stack value if (payload_ty.hasRuntimeBitsIgnoreComptime()) { try func.addMemArg(.i32_load8_u, .{ .offset = operand.offset(), .alignment = 1 }); } + } else if (payload_ty.isSlice()) { + // move the ptr on top of the stack + _ = try func.load(operand, Type.usize, 0); } // Compare the null value with '0' -- 2.54.0 From d6b430b520103fb6691b2c18ae06c2f2a360e806 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 30 Jan 2023 18:53:14 -0700 Subject: [PATCH 38/84] std.Target: remove workaround This was working around a stage1 compiler bug. --- lib/std/target.zig | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/lib/std/target.zig b/lib/std/target.zig index 4964e75852e3b404851341aa3b957a5f150b57f9..8ae175aac8a338b544ac31cf7699ea0429e0d343 100644 --- a/lib/std/target.zig +++ b/lib/std/target.zig @@ -697,9 +697,6 @@ pub const Target = struct { pub const ShiftInt = std.math.Log2Int(usize); pub const empty = Set{ .ints = [1]usize{0} ** usize_count }; - pub fn empty_workaround() Set { - return Set{ .ints = [1]usize{0} ** usize_count }; - } pub fn isEmpty(set: Set) bool { return for (set.ints) |x| { @@ -782,7 +779,7 @@ pub const Target = struct { return struct { /// Populates only the feature bits specified. pub fn featureSet(features: []const F) Set { - var x = Set.empty_workaround(); // TODO remove empty_workaround + var x = Set.empty; for (features) |feature| { x.addFeature(@enumToInt(feature)); } -- 2.54.0 From 17404f8e6edea28fc70e074fd75101e1ed48b620 Mon Sep 17 00:00:00 2001 From: r00ster91 Date: Sun, 29 Jan 2023 23:25:31 +0100 Subject: [PATCH 39/84] Sema: emit compile error for comptime or inline call of function pointer --- src/Sema.zig | 7 ++++++- .../comptime_call_of_function_pointer.zig | 10 ++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 test/cases/compile_errors/comptime_call_of_function_pointer.zig diff --git a/src/Sema.zig b/src/Sema.zig index 9c553a009236fb83279a65872a877465452601be..7448fd149c1d25307cf4d231dd921978cdbec6b7 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -6446,7 +6446,12 @@ fn analyzeCall( .extern_fn => return sema.fail(block, call_src, "{s} call of extern function", .{ @as([]const u8, if (is_comptime_call) "comptime" else "inline"), }), - else => unreachable, + else => { + assert(callee_ty.isPtrAtRuntime()); + return sema.fail(block, call_src, "{s} call of function pointer", .{ + @as([]const u8, if (is_comptime_call) "comptime" else "inline"), + }); + }, }; if (func_ty_info.is_var_args) { return sema.fail(block, call_src, "{s} call of variadic function", .{ diff --git a/test/cases/compile_errors/comptime_call_of_function_pointer.zig b/test/cases/compile_errors/comptime_call_of_function_pointer.zig new file mode 100644 index 0000000000000000000000000000000000000000..cf01f5ea2ca486528aaaf625440038a711bd73f9 --- /dev/null +++ b/test/cases/compile_errors/comptime_call_of_function_pointer.zig @@ -0,0 +1,10 @@ +export fn entry() void { + const fn_ptr = @intToPtr(*align(1) fn () void, 0xffd2); + comptime fn_ptr(); +} + +// error +// backend=stage2 +// target=native +// +// :3:20: error: comptime call of function pointer -- 2.54.0 From 47ff57ed7ddbf4c4a0f93208fc96851c9033b8b7 Mon Sep 17 00:00:00 2001 From: Techatrix <19954306+Techatrix@users.noreply.github.com> Date: Tue, 31 Jan 2023 17:01:56 +0100 Subject: [PATCH 40/84] wasm: apply request change --- src/arch/wasm/CodeGen.zig | 7 +++++-- test/behavior/cast.zig | 3 --- test/behavior/optional.zig | 2 -- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index d0ff27a3e2117387aefb81b2753aaba3aefb3269..c0d0c11b56240cce5c6cacc0dfd55cbdcce95604 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -3880,8 +3880,11 @@ fn isNull(func: *CodeGen, operand: WValue, optional_ty: Type, opcode: wasm.Opcod try func.addMemArg(.i32_load8_u, .{ .offset = operand.offset(), .alignment = 1 }); } } else if (payload_ty.isSlice()) { - // move the ptr on top of the stack - _ = try func.load(operand, Type.usize, 0); + switch (func.arch()) { + .wasm32 => try func.addMemArg(.i32_load, .{ .offset = operand.offset(), .alignment = 4 }), + .wasm64 => try func.addMemArg(.i64_load, .{ .offset = operand.offset(), .alignment = 8 }), + else => unreachable, + } } // Compare the null value with '0' diff --git a/test/behavior/cast.zig b/test/behavior/cast.zig index 7c0746bfcd64bbfe4bb68b28cbc03fccfa2714ea..dbb4c07f64f469b401ccb050e4b1c9c51b247c6f 100644 --- a/test/behavior/cast.zig +++ b/test/behavior/cast.zig @@ -1179,7 +1179,6 @@ fn peerTypeEmptyArrayAndSlice(a: bool, slice: []const u8) []const u8 { test "implicitly cast from [N]T to ?[]const T" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO try expect(mem.eql(u8, castToOptionalSlice().?, "hi")); @@ -1264,7 +1263,6 @@ test "cast from array reference to fn: runtime fn ptr" { test "*const [N]null u8 to ?[]const u8" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO const S = struct { @@ -1413,7 +1411,6 @@ test "cast i8 fn call peers to i32 result" { test "cast compatible optional types" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO var a: ?[:0]const u8 = null; diff --git a/test/behavior/optional.zig b/test/behavior/optional.zig index 3e91c6807c3191717cf619fec6a8be620370c670..3a5b7b008bbee8e86bf1c3fca7304fd8ecc56448 100644 --- a/test/behavior/optional.zig +++ b/test/behavior/optional.zig @@ -439,7 +439,6 @@ test "Optional slice size is optimized" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO try expect(@sizeOf(?[]u8) == @sizeOf([]u8)); @@ -479,7 +478,6 @@ test "cast slice to const slice nested in error union and optional" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; const S = struct { fn inner() !?[]u8 { -- 2.54.0 From 4404c4d20094bb5021aac4a047cd33b6c24b9a9b Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Tue, 31 Jan 2023 17:54:12 +0100 Subject: [PATCH 41/84] link: make Elf atoms fully owned by the linker --- src/Module.zig | 6 +- src/Sema.zig | 2 +- src/arch/aarch64/CodeGen.zig | 13 +- src/arch/arm/CodeGen.zig | 15 +- src/arch/riscv64/CodeGen.zig | 14 +- src/arch/sparc64/CodeGen.zig | 12 +- src/arch/x86_64/CodeGen.zig | 13 +- src/link.zig | 4 +- src/link/Dwarf.zig | 26 +- src/link/Elf.zig | 1525 ++++++++++++++++++---------------- src/link/Elf/Atom.zig | 61 +- src/link/MachO.zig | 4 +- 12 files changed, 886 insertions(+), 809 deletions(-) diff --git a/src/Module.zig b/src/Module.zig index 83015054922ca49241c558d22c47436b84e6defc..0695a2e98aace36593ce627ccc538bceee08e725 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -5275,7 +5275,7 @@ pub fn clearDecl( // and allow it to be variably sized. decl.link = switch (mod.comp.bin_file.tag) { .coff => .{ .coff = link.File.Coff.Atom.empty }, - .elf => .{ .elf = link.File.Elf.TextBlock.empty }, + .elf => .{ .elf = {} }, .macho => .{ .macho = {} }, .plan9 => .{ .plan9 = link.File.Plan9.DeclBlock.empty }, .c => .{ .c = {} }, @@ -5381,7 +5381,7 @@ fn deleteDeclExports(mod: *Module, decl_index: Decl.Index) Allocator.Error!void } } if (mod.comp.bin_file.cast(link.File.Elf)) |elf| { - elf.deleteExport(exp.link.elf); + elf.deleteDeclExport(decl_index, exp.options.name); } if (mod.comp.bin_file.cast(link.File.MachO)) |macho| { try macho.deleteDeclExport(decl_index, exp.options.name); @@ -5695,7 +5695,7 @@ pub fn allocateNewDecl( .src_scope = src_scope, .link = switch (mod.comp.bin_file.tag) { .coff => .{ .coff = link.File.Coff.Atom.empty }, - .elf => .{ .elf = link.File.Elf.TextBlock.empty }, + .elf => .{ .elf = {} }, .macho => .{ .macho = {} }, .plan9 => .{ .plan9 = link.File.Plan9.DeclBlock.empty }, .c => .{ .c = {} }, diff --git a/src/Sema.zig b/src/Sema.zig index 9083cc92abee98b1461d0f25319c6effb7a7fc4b..28d559f730f01dcd17340f017d386383e81e222c 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -5566,7 +5566,7 @@ pub fn analyzeExport( .src = src, .link = switch (mod.comp.bin_file.tag) { .coff => .{ .coff = .{} }, - .elf => .{ .elf = .{} }, + .elf => .{ .elf = {} }, .macho => .{ .macho = {} }, .plan9 => .{ .plan9 = null }, .c => .{ .c = {} }, diff --git a/src/arch/aarch64/CodeGen.zig b/src/arch/aarch64/CodeGen.zig index edbe7905a213ffe715b2e66f40135d947fc15ed7..67197c35f890b06936bde181daa4a2e2de72bbd3 100644 --- a/src/arch/aarch64/CodeGen.zig +++ b/src/arch/aarch64/CodeGen.zig @@ -4308,8 +4308,9 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier const fn_owner_decl = mod.declPtr(func.owner_decl); if (self.bin_file.cast(link.File.Elf)) |elf_file| { - try fn_owner_decl.link.elf.ensureInitialized(elf_file); - const got_addr = @intCast(u32, fn_owner_decl.link.elf.getOffsetTableAddress(elf_file)); + const atom_index = try elf_file.getOrCreateAtomForDecl(func.owner_decl); + const atom = elf_file.getAtom(atom_index); + const got_addr = @intCast(u32, atom.getOffsetTableAddress(elf_file)); try self.genSetReg(Type.initTag(.usize), .x30, .{ .memory = got_addr }); } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { const atom = try macho_file.getOrCreateAtomForDecl(func.owner_decl); @@ -6138,8 +6139,9 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne mod.markDeclAlive(decl); if (self.bin_file.cast(link.File.Elf)) |elf_file| { - try decl.link.elf.ensureInitialized(elf_file); - return MCValue{ .memory = decl.link.elf.getOffsetTableAddress(elf_file) }; + const atom_index = try elf_file.getOrCreateAtomForDecl(decl_index); + const atom = elf_file.getAtom(atom_index); + return MCValue{ .memory = atom.getOffsetTableAddress(elf_file) }; } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { const atom = try macho_file.getOrCreateAtomForDecl(decl_index); const sym_index = macho_file.getAtom(atom).getSymbolIndex().?; @@ -6168,8 +6170,7 @@ fn lowerUnnamedConst(self: *Self, tv: TypedValue) InnerError!MCValue { return self.fail("lowering unnamed constant failed: {s}", .{@errorName(err)}); }; if (self.bin_file.cast(link.File.Elf)) |elf_file| { - const vaddr = elf_file.local_symbols.items[local_sym_index].st_value; - return MCValue{ .memory = vaddr }; + return MCValue{ .memory = elf_file.getSymbol(local_sym_index).st_value }; } else if (self.bin_file.cast(link.File.MachO)) |_| { return MCValue{ .linker_load = .{ .type = .direct, diff --git a/src/arch/arm/CodeGen.zig b/src/arch/arm/CodeGen.zig index 49f979624d0a78ed7489763f219ceb9da3f12881..c6ee960e510163f433cb6d35bcc66cbae90497e5 100644 --- a/src/arch/arm/CodeGen.zig +++ b/src/arch/arm/CodeGen.zig @@ -4256,12 +4256,11 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier if (self.air.value(callee)) |func_value| { if (func_value.castTag(.function)) |func_payload| { const func = func_payload.data; - const mod = self.bin_file.options.module.?; - const fn_owner_decl = mod.declPtr(func.owner_decl); if (self.bin_file.cast(link.File.Elf)) |elf_file| { - try fn_owner_decl.link.elf.ensureInitialized(elf_file); - const got_addr = @intCast(u32, fn_owner_decl.link.elf.getOffsetTableAddress(elf_file)); + const atom_index = try elf_file.getOrCreateAtomForDecl(func.owner_decl); + const atom = elf_file.getAtom(atom_index); + const got_addr = @intCast(u32, atom.getOffsetTableAddress(elf_file)); try self.genSetReg(Type.initTag(.usize), .lr, .{ .memory = got_addr }); } else if (self.bin_file.cast(link.File.MachO)) |_| { unreachable; // unsupported architecture for MachO @@ -6084,8 +6083,9 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne mod.markDeclAlive(decl); if (self.bin_file.cast(link.File.Elf)) |elf_file| { - try decl.link.elf.ensureInitialized(elf_file); - return MCValue{ .memory = decl.link.elf.getOffsetTableAddress(elf_file) }; + const atom_index = try elf_file.getOrCreateAtomForDecl(decl_index); + const atom = elf_file.getAtom(atom_index); + return MCValue{ .memory = atom.getOffsetTableAddress(elf_file) }; } else if (self.bin_file.cast(link.File.MachO)) |_| { unreachable; // unsupported architecture for MachO } else if (self.bin_file.cast(link.File.Coff)) |_| { @@ -6106,8 +6106,7 @@ fn lowerUnnamedConst(self: *Self, tv: TypedValue) InnerError!MCValue { return self.fail("lowering unnamed constant failed: {s}", .{@errorName(err)}); }; if (self.bin_file.cast(link.File.Elf)) |elf_file| { - const vaddr = elf_file.local_symbols.items[local_sym_index].st_value; - return MCValue{ .memory = vaddr }; + return MCValue{ .memory = elf_file.getSymbol(local_sym_index).st_value }; } else if (self.bin_file.cast(link.File.MachO)) |_| { unreachable; } else if (self.bin_file.cast(link.File.Coff)) |_| { diff --git a/src/arch/riscv64/CodeGen.zig b/src/arch/riscv64/CodeGen.zig index 07a8dcd8582a935fcce13c899ec6120d8f74631b..a0af1b3ccec40a4257898c67f8402cadff040c50 100644 --- a/src/arch/riscv64/CodeGen.zig +++ b/src/arch/riscv64/CodeGen.zig @@ -1721,12 +1721,9 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier if (self.air.value(callee)) |func_value| { if (func_value.castTag(.function)) |func_payload| { const func = func_payload.data; - - const mod = self.bin_file.options.module.?; - const fn_owner_decl = mod.declPtr(func.owner_decl); - try fn_owner_decl.link.elf.ensureInitialized(elf_file); - const got_addr = @intCast(u32, fn_owner_decl.link.elf.getOffsetTableAddress(elf_file)); - + const atom_index = try elf_file.getOrCreateAtomForDecl(func.owner_decl); + const atom = elf_file.getAtom(atom_index); + const got_addr = @intCast(u32, atom.getOffsetTableAddress(elf_file)); try self.genSetReg(Type.initTag(.usize), .ra, .{ .memory = got_addr }); _ = try self.addInst(.{ .tag = .jalr, @@ -2553,8 +2550,9 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne const decl = mod.declPtr(decl_index); mod.markDeclAlive(decl); if (self.bin_file.cast(link.File.Elf)) |elf_file| { - try decl.link.elf.ensureInitialized(elf_file); - return MCValue{ .memory = decl.link.elf.getOffsetTableAddress(elf_file) }; + const atom_index = try elf_file.getOrCreateAtomForDecl(decl_index); + const atom = elf_file.getAtom(atom_index); + return MCValue{ .memory = atom.getOffsetTableAddress(elf_file) }; } else if (self.bin_file.cast(link.File.MachO)) |_| { unreachable; } else if (self.bin_file.cast(link.File.Coff)) |_| { diff --git a/src/arch/sparc64/CodeGen.zig b/src/arch/sparc64/CodeGen.zig index 5e9326d23b3f1c66b5992fbe9697c7d1c5e424b7..e67244167ef25351157c701e35add5749f7388b2 100644 --- a/src/arch/sparc64/CodeGen.zig +++ b/src/arch/sparc64/CodeGen.zig @@ -1216,11 +1216,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier if (self.bin_file.tag == link.File.Elf.base_tag) { if (func_value.castTag(.function)) |func_payload| { const func = func_payload.data; - const mod = self.bin_file.options.module.?; - const fn_owner_decl = mod.declPtr(func.owner_decl); const got_addr = if (self.bin_file.cast(link.File.Elf)) |elf_file| blk: { - try fn_owner_decl.link.elf.ensureInitialized(elf_file); - break :blk @intCast(u32, fn_owner_decl.link.elf.getOffsetTableAddress(elf_file)); + const atom_index = try elf_file.getOrCreateAtomForDecl(func.owner_decl); + const atom = elf_file.getAtom(atom_index); + break :blk @intCast(u32, atom.getOffsetTableAddress(elf_file)); } else unreachable; try self.genSetReg(Type.initTag(.usize), .o7, .{ .memory = got_addr }); @@ -4205,8 +4204,9 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne mod.markDeclAlive(decl); if (self.bin_file.cast(link.File.Elf)) |elf_file| { - try decl.link.elf.ensureInitialized(elf_file); - return MCValue{ .memory = decl.link.elf.getOffsetTableAddress(elf_file) }; + const atom_index = try elf_file.getOrCreateAtomForDecl(decl_index); + const atom = elf_file.getAtom(atom_index); + return MCValue{ .memory = atom.getOffsetTableAddress(elf_file) }; } else { return self.fail("TODO codegen non-ELF const Decl pointer", .{}); } diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index fc244e3130afa595af98853ef09d2210dd5a087d..23d3ca5514c86eebdd2e4c78e14d20ce5ba1e1c6 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -4000,8 +4000,9 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier const fn_owner_decl = mod.declPtr(func.owner_decl); if (self.bin_file.cast(link.File.Elf)) |elf_file| { - try fn_owner_decl.link.elf.ensureInitialized(elf_file); - const got_addr = @intCast(u32, fn_owner_decl.link.elf.getOffsetTableAddress(elf_file)); + const atom_index = try elf_file.getOrCreateAtomForDecl(func.owner_decl); + const atom = elf_file.getAtom(atom_index); + const got_addr = @intCast(u32, atom.getOffsetTableAddress(elf_file)); _ = try self.addInst(.{ .tag = .call, .ops = Mir.Inst.Ops.encode(.{ .flags = 0b01 }), @@ -6721,8 +6722,9 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne module.markDeclAlive(decl); if (self.bin_file.cast(link.File.Elf)) |elf_file| { - try decl.link.elf.ensureInitialized(elf_file); - return MCValue{ .memory = decl.link.elf.getOffsetTableAddress(elf_file) }; + const atom_index = try elf_file.getOrCreateAtomForDecl(decl_index); + const atom = elf_file.getAtom(atom_index); + return MCValue{ .memory = atom.getOffsetTableAddress(elf_file) }; } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { const atom_index = try macho_file.getOrCreateAtomForDecl(decl_index); const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?; @@ -6751,8 +6753,7 @@ fn lowerUnnamedConst(self: *Self, tv: TypedValue) InnerError!MCValue { return self.fail("lowering unnamed constant failed: {s}", .{@errorName(err)}); }; if (self.bin_file.cast(link.File.Elf)) |elf_file| { - const vaddr = elf_file.local_symbols.items[local_sym_index].st_value; - return MCValue{ .memory = vaddr }; + return MCValue{ .memory = elf_file.getSymbol(local_sym_index).st_value }; } else if (self.bin_file.cast(link.File.MachO)) |_| { return MCValue{ .linker_load = .{ .type = .direct, diff --git a/src/link.zig b/src/link.zig index 2a96efe89da6b5f69020846bd683e9e184d81743..09804add531c1e5bc5d3c2f915053b43b01556ff 100644 --- a/src/link.zig +++ b/src/link.zig @@ -262,7 +262,7 @@ pub const File = struct { lock: ?Cache.Lock = null, pub const LinkBlock = union { - elf: Elf.TextBlock, + elf: void, coff: Coff.Atom, macho: void, plan9: Plan9.DeclBlock, @@ -284,7 +284,7 @@ pub const File = struct { }; pub const Export = union { - elf: Elf.Export, + elf: void, coff: Coff.Export, macho: void, plan9: Plan9.Export, diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig index 2595cd8ba56acc7796a8c62161ea5dedacd54c41..8278377095edfc5cd29a17aae7dc533fc4cbfd52 100644 --- a/src/link/Dwarf.zig +++ b/src/link/Dwarf.zig @@ -1099,7 +1099,7 @@ pub fn commitDeclState( switch (self.bin_file.tag) { .elf => { const elf_file = self.bin_file.cast(File.Elf).?; - const debug_line_sect = &elf_file.sections.items[elf_file.debug_line_section_index.?]; + const debug_line_sect = &elf_file.sections.items(.shdr)[elf_file.debug_line_section_index.?]; const file_pos = debug_line_sect.sh_offset + src_fn.off; try pwriteDbgLineNops(elf_file.base.file.?, file_pos, 0, &[0]u8{}, src_fn.len); }, @@ -1152,7 +1152,7 @@ pub fn commitDeclState( const elf_file = self.bin_file.cast(File.Elf).?; const shdr_index = elf_file.debug_line_section_index.?; try elf_file.growNonAllocSection(shdr_index, needed_size, 1, true); - const debug_line_sect = elf_file.sections.items[shdr_index]; + const debug_line_sect = elf_file.sections.items(.shdr)[shdr_index]; const file_pos = debug_line_sect.sh_offset + src_fn.off; try pwriteDbgLineNops( elf_file.base.file.?, @@ -1332,7 +1332,7 @@ fn updateDeclDebugInfoAllocation(self: *Dwarf, atom: *Atom, len: u32) !void { switch (self.bin_file.tag) { .elf => { const elf_file = self.bin_file.cast(File.Elf).?; - const debug_info_sect = &elf_file.sections.items[elf_file.debug_info_section_index.?]; + const debug_info_sect = &elf_file.sections.items(.shdr)[elf_file.debug_info_section_index.?]; const file_pos = debug_info_sect.sh_offset + atom.off; try pwriteDbgInfoNops(elf_file.base.file.?, file_pos, 0, &[0]u8{}, atom.len, false); }, @@ -1399,7 +1399,7 @@ fn writeDeclDebugInfo(self: *Dwarf, atom: *Atom, dbg_info_buf: []const u8) !void const elf_file = self.bin_file.cast(File.Elf).?; const shdr_index = elf_file.debug_info_section_index.?; try elf_file.growNonAllocSection(shdr_index, needed_size, 1, true); - const debug_info_sect = elf_file.sections.items[shdr_index]; + const debug_info_sect = elf_file.sections.items(.shdr)[shdr_index]; const file_pos = debug_info_sect.sh_offset + atom.off; try pwriteDbgInfoNops( elf_file.base.file.?, @@ -1475,7 +1475,7 @@ pub fn updateDeclLineNumber(self: *Dwarf, decl: *const Module.Decl) !void { switch (self.bin_file.tag) { .elf => { const elf_file = self.bin_file.cast(File.Elf).?; - const shdr = elf_file.sections.items[elf_file.debug_line_section_index.?]; + const shdr = elf_file.sections.items(.shdr)[elf_file.debug_line_section_index.?]; const file_pos = shdr.sh_offset + decl.fn_link.elf.off + self.getRelocDbgLineOff(); try elf_file.base.file.?.pwriteAll(&data, file_pos); }, @@ -1690,7 +1690,7 @@ pub fn writeDbgAbbrev(self: *Dwarf) !void { const elf_file = self.bin_file.cast(File.Elf).?; const shdr_index = elf_file.debug_abbrev_section_index.?; try elf_file.growNonAllocSection(shdr_index, needed_size, 1, false); - const debug_abbrev_sect = elf_file.sections.items[shdr_index]; + const debug_abbrev_sect = elf_file.sections.items(.shdr)[shdr_index]; const file_pos = debug_abbrev_sect.sh_offset + abbrev_offset; try elf_file.base.file.?.pwriteAll(&abbrev_buf, file_pos); }, @@ -1805,7 +1805,7 @@ pub fn writeDbgInfoHeader(self: *Dwarf, module: *Module, low_pc: u64, high_pc: u switch (self.bin_file.tag) { .elf => { const elf_file = self.bin_file.cast(File.Elf).?; - const debug_info_sect = elf_file.sections.items[elf_file.debug_info_section_index.?]; + const debug_info_sect = elf_file.sections.items(.shdr)[elf_file.debug_info_section_index.?]; const file_pos = debug_info_sect.sh_offset; try pwriteDbgInfoNops(elf_file.base.file.?, file_pos, 0, di_buf.items, jmp_amt, false); }, @@ -2124,7 +2124,7 @@ pub fn writeDbgAranges(self: *Dwarf, addr: u64, size: u64) !void { const elf_file = self.bin_file.cast(File.Elf).?; const shdr_index = elf_file.debug_aranges_section_index.?; try elf_file.growNonAllocSection(shdr_index, needed_size, 16, false); - const debug_aranges_sect = elf_file.sections.items[shdr_index]; + const debug_aranges_sect = elf_file.sections.items(.shdr)[shdr_index]; const file_pos = debug_aranges_sect.sh_offset; try elf_file.base.file.?.pwriteAll(di_buf.items, file_pos); }, @@ -2285,9 +2285,9 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void { .elf => { const elf_file = self.bin_file.cast(File.Elf).?; const shdr_index = elf_file.debug_line_section_index.?; - const needed_size = elf_file.sections.items[shdr_index].sh_size + delta; + const needed_size = elf_file.sections.items(.shdr)[shdr_index].sh_size + delta; try elf_file.growNonAllocSection(shdr_index, needed_size, 1, true); - const file_pos = elf_file.sections.items[shdr_index].sh_offset + src_fn.off; + const file_pos = elf_file.sections.items(.shdr)[shdr_index].sh_offset + src_fn.off; const amt = try elf_file.base.file.?.preadAll(buffer, file_pos); if (amt != buffer.len) return error.InputOutput; @@ -2346,7 +2346,7 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void { switch (self.bin_file.tag) { .elf => { const elf_file = self.bin_file.cast(File.Elf).?; - const debug_line_sect = elf_file.sections.items[elf_file.debug_line_section_index.?]; + const debug_line_sect = elf_file.sections.items(.shdr)[elf_file.debug_line_section_index.?]; const file_pos = debug_line_sect.sh_offset; try pwriteDbgLineNops(elf_file.base.file.?, file_pos, 0, di_buf.items, jmp_amt); }, @@ -2487,7 +2487,7 @@ pub fn flushModule(self: *Dwarf, module: *Module) !void { switch (self.bin_file.tag) { .elf => { const elf_file = self.bin_file.cast(File.Elf).?; - const debug_info_sect = &elf_file.sections.items[elf_file.debug_info_section_index.?]; + const debug_info_sect = &elf_file.sections.items(.shdr)[elf_file.debug_info_section_index.?]; break :blk debug_info_sect.sh_offset; }, .macho => { @@ -2638,7 +2638,7 @@ fn addDbgInfoErrorSet( fn getDbgInfoAtom(tag: File.Tag, mod: *Module, decl_index: Module.Decl.Index) *Atom { const decl = mod.declPtr(decl_index); return switch (tag) { - .elf => &decl.link.elf.dbg_info_atom, + .elf => unreachable, .macho => unreachable, .wasm => &decl.link.wasm.dbg_info_atom, else => unreachable, diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 2c55e55f83226ecadd43ef7e0aee606c6f6bf25d..0b8128aa3308413498246533904835027be6c125 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -1,43 +1,89 @@ const Elf = @This(); const std = @import("std"); +const build_options = @import("build_options"); const builtin = @import("builtin"); -const math = std.math; -const mem = std.mem; const assert = std.debug.assert; -const Allocator = std.mem.Allocator; -const fs = std.fs; const elf = std.elf; +const fs = std.fs; const log = std.log.scoped(.link); +const math = std.math; +const mem = std.mem; -const Atom = @import("Elf/Atom.zig"); -const Module = @import("../Module.zig"); -const Compilation = @import("../Compilation.zig"); -const Dwarf = @import("Dwarf.zig"); const codegen = @import("../codegen.zig"); -const lldMain = @import("../main.zig").lldMain; -const trace = @import("../tracy.zig").trace; -const Package = @import("../Package.zig"); -const Value = @import("../value.zig").Value; -const Type = @import("../type.zig").Type; -const TypedValue = @import("../TypedValue.zig"); -const link = @import("../link.zig"); -const File = link.File; -const build_options = @import("build_options"); -const target_util = @import("../target.zig"); const glibc = @import("../glibc.zig"); +const link = @import("../link.zig"); +const lldMain = @import("../main.zig").lldMain; const musl = @import("../musl.zig"); -const Cache = @import("../Cache.zig"); +const target_util = @import("../target.zig"); +const trace = @import("../tracy.zig").trace; + const Air = @import("../Air.zig"); +const Allocator = std.mem.Allocator; +pub const Atom = @import("Elf/Atom.zig"); +const Cache = @import("../Cache.zig"); +const Compilation = @import("../Compilation.zig"); +const Dwarf = @import("Dwarf.zig"); +const File = link.File; const Liveness = @import("../Liveness.zig"); const LlvmObject = @import("../codegen/llvm.zig").Object; - -pub const TextBlock = Atom; +const Module = @import("../Module.zig"); +const Package = @import("../Package.zig"); +const StringTable = @import("strtab.zig").StringTable; +const Type = @import("../type.zig").Type; +const TypedValue = @import("../TypedValue.zig"); +const Value = @import("../value.zig").Value; const default_entry_addr = 0x8000000; pub const base_tag: File.Tag = .elf; +const Section = struct { + shdr: elf.Elf64_Shdr, + phdr_index: u16, + + /// Index of the last allocated atom in this section. + last_atom_index: ?Atom.Index = null, + + /// A list of atoms 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. + /// + /// An atom has surplus capacity when its overcapacity value is greater than + /// padToIdeal(minimum_atom_size). 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 + (size / ideal_factor) + /// + /// 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. + free_list: std.ArrayListUnmanaged(Atom.Index) = .{}, +}; + +const DeclMetadata = struct { + atom: Atom.Index, + shdr: u16, + /// A list of all exports aliases of this Decl. + exports: std.ArrayListUnmanaged(u32) = .{}, + + fn getExport(m: DeclMetadata, elf_file: *const Elf, name: []const u8) ?u32 { + for (m.exports.items) |exp| { + if (mem.eql(u8, name, elf_file.getSymbolName(exp))) return exp; + } + return null; + } + + fn getExportPtr(m: *DeclMetadata, elf_file: *Elf, name: []const u8) ?*u32 { + for (m.exports.items) |*exp| { + if (mem.eql(u8, name, elf_file.getSymbolName(exp.*))) return exp; + } + return null; + } +}; + base: File, dwarf: ?Dwarf = null, @@ -48,12 +94,12 @@ llvm_object: ?*LlvmObject = null, /// 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){}, +sections: std.MultiArrayList(Section) = .{}, 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){}, +program_headers: 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, @@ -65,12 +111,10 @@ phdr_load_ro_index: ?u16 = null, /// The index into the program headers of a PT_LOAD program header with Write flag phdr_load_rw_index: ?u16 = null, -phdr_shdr_table: std.AutoHashMapUnmanaged(u16, u16) = .{}, - entry_addr: ?u64 = null, page_size: u32, -shstrtab: std.ArrayListUnmanaged(u8) = std.ArrayListUnmanaged(u8){}, +shstrtab: StringTable(.strtab) = .{}, shstrtab_index: ?u16 = null, symtab_section_index: ?u16 = null, @@ -113,39 +157,14 @@ debug_line_header_dirty: bool = false, error_flags: File.ErrorFlags = File.ErrorFlags{}, -/// Pointer to the last allocated atom -atoms: std.AutoHashMapUnmanaged(u16, *TextBlock) = .{}, - -/// 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 -/// padToIdeal(minimum_text_block_size). 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 + (size / ideal_factor) -/// -/// 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. -atom_free_lists: std.AutoHashMapUnmanaged(u16, std.ArrayListUnmanaged(*TextBlock)) = .{}, - -/// Table of Decls that are currently alive. -/// We store them here so that we can properly dispose of any allocated -/// memory within the atom in the incremental linker. -/// TODO consolidate this. -decls: std.AutoHashMapUnmanaged(Module.Decl.Index, ?u16) = .{}, +/// Table of tracked Decls. +decls: std.AutoHashMapUnmanaged(Module.Decl.Index, DeclMetadata) = .{}, /// List of atoms that are owned directly by the linker. -/// Currently these are only atoms that are the result of linking -/// object files. Atoms which take part in incremental linking are -/// at present owned by Module.Decl. -/// TODO consolidate this. -managed_atoms: std.ArrayListUnmanaged(*TextBlock) = .{}, -atom_by_index_table: std.AutoHashMapUnmanaged(u32, *TextBlock) = .{}, +atoms: std.ArrayListUnmanaged(Atom) = .{}, + +/// Table of atoms indexed by the symbol index. +atom_by_index_table: std.AutoHashMapUnmanaged(u32, Atom.Index) = .{}, /// Table of unnamed constants associated with a parent `Decl`. /// We store them here so that we can free the constants whenever the `Decl` @@ -173,15 +192,8 @@ unnamed_const_atoms: UnnamedConstTable = .{}, /// this will be a table indexed by index into the list of Atoms. relocs: RelocTable = .{}, -const Reloc = struct { - target: u32, - offset: u64, - addend: u32, - prev_vaddr: u64, -}; - -const RelocTable = std.AutoHashMapUnmanaged(*TextBlock, std.ArrayListUnmanaged(Reloc)); -const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(*TextBlock)); +const RelocTable = std.AutoHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Atom.Reloc)); +const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Atom.Index)); /// When allocating, the ideal_capacity is calculated by /// actual_capacity + (actual_capacity / ideal_factor) @@ -190,15 +202,11 @@ const ideal_factor = 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; -pub const min_text_capacity = padToIdeal(minimum_text_block_size); +const minimum_atom_size = 64; +pub const min_text_capacity = padToIdeal(minimum_atom_size); pub const PtrWidth = enum { p32, p64 }; -pub const Export = struct { - sym_index: ?u32 = null, -}; - pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*Elf { assert(options.target.ofmt == .elf); @@ -230,16 +238,19 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option // 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, + .shdr = .{ + .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, + }, + .phdr_index = undefined, }); try self.populateMissingMetadata(); @@ -286,75 +297,67 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Elf { } pub fn deinit(self: *Elf) void { + const gpa = self.base.allocator; + if (build_options.have_llvm) { - if (self.llvm_object) |llvm_object| llvm_object.destroy(self.base.allocator); + if (self.llvm_object) |llvm_object| llvm_object.destroy(gpa); } - self.sections.deinit(self.base.allocator); - self.program_headers.deinit(self.base.allocator); - self.shstrtab.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.offset_table.deinit(self.base.allocator); - self.phdr_shdr_table.deinit(self.base.allocator); - self.decls.deinit(self.base.allocator); + for (self.sections.items(.free_list)) |*free_list| { + free_list.deinit(gpa); + } + self.sections.deinit(gpa); + + self.program_headers.deinit(gpa); + self.shstrtab.deinit(gpa); + self.local_symbols.deinit(gpa); + self.global_symbols.deinit(gpa); + self.global_symbol_free_list.deinit(gpa); + self.local_symbol_free_list.deinit(gpa); + self.offset_table_free_list.deinit(gpa); + self.offset_table.deinit(gpa); - self.atoms.deinit(self.base.allocator); { - var it = self.atom_free_lists.valueIterator(); - while (it.next()) |free_list| { - free_list.deinit(self.base.allocator); + var it = self.decls.iterator(); + while (it.next()) |entry| { + entry.value_ptr.exports.deinit(gpa); } - self.atom_free_lists.deinit(self.base.allocator); + self.decls.deinit(gpa); } - for (self.managed_atoms.items) |atom| { - self.base.allocator.destroy(atom); - } - self.managed_atoms.deinit(self.base.allocator); + self.atoms.deinit(gpa); + self.atom_by_index_table.deinit(gpa); { var it = self.unnamed_const_atoms.valueIterator(); while (it.next()) |atoms| { - atoms.deinit(self.base.allocator); + atoms.deinit(gpa); } - self.unnamed_const_atoms.deinit(self.base.allocator); + self.unnamed_const_atoms.deinit(gpa); } { var it = self.relocs.valueIterator(); while (it.next()) |relocs| { - relocs.deinit(self.base.allocator); + relocs.deinit(gpa); } - self.relocs.deinit(self.base.allocator); + self.relocs.deinit(gpa); } - self.atom_by_index_table.deinit(self.base.allocator); - - if (self.dwarf) |*dw| { - dw.deinit(); - } + // if (self.dwarf) |*dw| { + // dw.deinit(); + // } } pub fn getDeclVAddr(self: *Elf, decl_index: Module.Decl.Index, reloc_info: File.RelocInfo) !u64 { - const mod = self.base.options.module.?; - const decl = mod.declPtr(decl_index); - assert(self.llvm_object == null); - try decl.link.elf.ensureInitialized(self); - const target = decl.link.elf.getSymbolIndex().?; - - const vaddr = self.local_symbols.items[target].st_value; - const atom = self.atom_by_index_table.get(reloc_info.parent_atom_index).?; - const gop = try self.relocs.getOrPut(self.base.allocator, atom); - if (!gop.found_existing) { - gop.value_ptr.* = .{}; - } - try gop.value_ptr.append(self.base.allocator, .{ + const this_atom_index = try self.getOrCreateAtomForDecl(decl_index); + const this_atom = self.getAtom(this_atom_index); + const target = this_atom.getSymbolIndex().?; + const vaddr = this_atom.getSymbol(self).st_value; + const atom_index = self.getAtomIndexForSymbol(reloc_info.parent_atom_index).?; + try Atom.addRelocation(self, atom_index, .{ .target = target, .offset = reloc_info.offset, .addend = reloc_info.addend, @@ -375,7 +378,7 @@ fn detectAllocCollision(self: *Elf, start: u64, size: u64) ?u64 { 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 tight_size = self.sections.slice().len * shdr_size; const increased_size = padToIdeal(tight_size); const test_end = off + increased_size; if (end > off and start < test_end) { @@ -385,7 +388,7 @@ fn detectAllocCollision(self: *Elf, start: u64, size: u64) ?u64 { 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 tight_size = self.sections.slice().len * phdr_size; const increased_size = padToIdeal(tight_size); const test_end = off + increased_size; if (end > off and start < test_end) { @@ -393,7 +396,7 @@ fn detectAllocCollision(self: *Elf, start: u64, size: u64) ?u64 { } } - for (self.sections.items) |section| { + for (self.sections.items(.shdr)) |section| { const increased_size = padToIdeal(section.sh_size); const test_end = section.sh_offset + increased_size; if (end > section.sh_offset and start < test_end) { @@ -420,7 +423,7 @@ pub fn allocatedSize(self: *Elf, start: u64) u64 { if (self.phdr_table_offset) |off| { if (off > start and off < min_pos) min_pos = off; } - for (self.sections.items) |section| { + for (self.sections.items(.shdr)) |section| { if (section.sh_offset <= start) continue; if (section.sh_offset < min_pos) min_pos = section.sh_offset; } @@ -439,31 +442,10 @@ pub fn findFreeSpace(self: *Elf, object_size: u64, min_alignment: u32) u64 { return start; } -/// TODO Improve this to use a table. -fn makeString(self: *Elf, bytes: []const u8) !u32 { - try self.shstrtab.ensureUnusedCapacity(self.base.allocator, bytes.len + 1); - const result = self.shstrtab.items.len; - self.shstrtab.appendSliceAssumeCapacity(bytes); - self.shstrtab.appendAssumeCapacity(0); - return @intCast(u32, result); -} - -pub fn getString(self: Elf, str_off: u32) []const u8 { - assert(str_off < self.shstrtab.items.len); - return mem.sliceTo(@ptrCast([*:0]const u8, self.shstrtab.items.ptr + str_off), 0); -} - -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 { assert(self.llvm_object == null); + const gpa = self.base.allocator; const small_ptr = switch (self.ptr_width) { .p32 => true, .p64 => false, @@ -477,7 +459,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { const off = self.findFreeSpace(file_size, p_align); log.debug("found PT_LOAD RE free space 0x{x} to 0x{x}", .{ off, off + file_size }); const entry_addr: u64 = self.entry_addr orelse if (self.base.options.target.cpu.arch == .spu_2) @as(u64, 0) else default_entry_addr; - try self.program_headers.append(self.base.allocator, .{ + try self.program_headers.append(gpa, .{ .p_type = elf.PT_LOAD, .p_offset = off, .p_filesz = file_size, @@ -487,7 +469,6 @@ pub fn populateMissingMetadata(self: *Elf) !void { .p_align = p_align, .p_flags = elf.PF_X | elf.PF_R, }); - try self.atom_free_lists.putNoClobber(self.base.allocator, self.phdr_load_re_index.?, .{}); self.entry_addr = null; self.phdr_table_dirty = true; } @@ -504,7 +485,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { // we'll need to re-use that function anyway, in case the GOT grows and overlaps something // else in virtual memory. const got_addr: u32 = if (self.base.options.target.cpu.arch.ptrBitWidth() >= 32) 0x4000000 else 0x8000; - try self.program_headers.append(self.base.allocator, .{ + try self.program_headers.append(gpa, .{ .p_type = elf.PT_LOAD, .p_offset = off, .p_filesz = file_size, @@ -527,7 +508,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { log.debug("found PT_LOAD RO free space 0x{x} to 0x{x}", .{ off, off + file_size }); // TODO Same as for GOT const rodata_addr: u32 = if (self.base.options.target.cpu.arch.ptrBitWidth() >= 32) 0xc000000 else 0xa000; - try self.program_headers.append(self.base.allocator, .{ + try self.program_headers.append(gpa, .{ .p_type = elf.PT_LOAD, .p_offset = off, .p_filesz = file_size, @@ -537,7 +518,6 @@ pub fn populateMissingMetadata(self: *Elf) !void { .p_align = p_align, .p_flags = elf.PF_R, }); - try self.atom_free_lists.putNoClobber(self.base.allocator, self.phdr_load_ro_index.?, .{}); self.phdr_table_dirty = true; } @@ -551,7 +531,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { log.debug("found PT_LOAD RW free space 0x{x} to 0x{x}", .{ off, off + file_size }); // TODO Same as for GOT const rwdata_addr: u32 = if (self.base.options.target.cpu.arch.ptrBitWidth() >= 32) 0x10000000 else 0xc000; - try self.program_headers.append(self.base.allocator, .{ + try self.program_headers.append(gpa, .{ .p_type = elf.PT_LOAD, .p_offset = off, .p_filesz = file_size, @@ -561,278 +541,290 @@ pub fn populateMissingMetadata(self: *Elf) !void { .p_align = p_align, .p_flags = elf.PF_R | elf.PF_W, }); - try self.atom_free_lists.putNoClobber(self.base.allocator, self.phdr_load_rw_index.?, .{}); 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}", .{ 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_index = @intCast(u16, self.sections.slice().len); + assert(self.shstrtab.buffer.items.len == 0); + try self.shstrtab.buffer.append(gpa, 0); // need a 0 at position 0 + const off = self.findFreeSpace(self.shstrtab.buffer.items.len, 1); + log.debug("found shstrtab free space 0x{x} to 0x{x}", .{ off, off + self.shstrtab.buffer.items.len }); + try self.sections.append(gpa, .{ + .shdr = .{ + .sh_name = try self.shstrtab.insert(gpa, ".shstrtab"), + .sh_type = elf.SHT_STRTAB, + .sh_flags = 0, + .sh_addr = 0, + .sh_offset = off, + .sh_size = self.shstrtab.buffer.items.len, + .sh_link = 0, + .sh_info = 0, + .sh_addralign = 1, + .sh_entsize = 0, + }, + .phdr_index = undefined, }); 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); + self.text_section_index = @intCast(u16, self.sections.slice().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 = 1, - .sh_entsize = 0, + try self.sections.append(gpa, .{ + .shdr = .{ + .sh_name = try self.shstrtab.insert(gpa, ".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 = 1, + .sh_entsize = 0, + }, + .phdr_index = self.phdr_load_re_index.?, }); - try self.phdr_shdr_table.putNoClobber( - self.base.allocator, - self.phdr_load_re_index.?, - self.text_section_index.?, - ); self.shdr_table_dirty = true; } if (self.got_section_index == null) { - self.got_section_index = @intCast(u16, self.sections.items.len); + self.got_section_index = @intCast(u16, self.sections.slice().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 = @as(u16, ptr_size), - .sh_entsize = 0, + try self.sections.append(gpa, .{ + .shdr = .{ + .sh_name = try self.shstrtab.insert(gpa, ".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 = @as(u16, ptr_size), + .sh_entsize = 0, + }, + .phdr_index = self.phdr_got_index.?, }); - try self.phdr_shdr_table.putNoClobber( - self.base.allocator, - self.phdr_got_index.?, - self.got_section_index.?, - ); self.shdr_table_dirty = true; } if (self.rodata_section_index == null) { - self.rodata_section_index = @intCast(u16, self.sections.items.len); + self.rodata_section_index = @intCast(u16, self.sections.slice().len); const phdr = &self.program_headers.items[self.phdr_load_ro_index.?]; - try self.sections.append(self.base.allocator, .{ - .sh_name = try self.makeString(".rodata"), - .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 = 1, - .sh_entsize = 0, + try self.sections.append(gpa, .{ + .shdr = .{ + .sh_name = try self.shstrtab.insert(gpa, ".rodata"), + .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 = 1, + .sh_entsize = 0, + }, + .phdr_index = self.phdr_load_ro_index.?, }); - try self.phdr_shdr_table.putNoClobber( - self.base.allocator, - self.phdr_load_ro_index.?, - self.rodata_section_index.?, - ); self.shdr_table_dirty = true; } if (self.data_section_index == null) { - self.data_section_index = @intCast(u16, self.sections.items.len); + self.data_section_index = @intCast(u16, self.sections.slice().len); const phdr = &self.program_headers.items[self.phdr_load_rw_index.?]; - try self.sections.append(self.base.allocator, .{ - .sh_name = try self.makeString(".data"), - .sh_type = elf.SHT_PROGBITS, - .sh_flags = elf.SHF_WRITE | 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 = @as(u16, ptr_size), - .sh_entsize = 0, + try self.sections.append(gpa, .{ + .shdr = .{ + .sh_name = try self.shstrtab.insert(gpa, ".data"), + .sh_type = elf.SHT_PROGBITS, + .sh_flags = elf.SHF_WRITE | 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 = @as(u16, ptr_size), + .sh_entsize = 0, + }, + .phdr_index = self.phdr_load_rw_index.?, }); - try self.phdr_shdr_table.putNoClobber( - self.base.allocator, - self.phdr_load_rw_index.?, - self.data_section_index.?, - ); self.shdr_table_dirty = true; } if (self.symtab_section_index == null) { - self.symtab_section_index = @intCast(u16, self.sections.items.len); + self.symtab_section_index = @intCast(u16, self.sections.slice().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}", .{ 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, + try self.sections.append(gpa, .{ + .shdr = .{ + .sh_name = try self.shstrtab.insert(gpa, ".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, + }, + .phdr_index = undefined, }); self.shdr_table_dirty = true; try self.writeSymbol(0); } - if (self.dwarf) |*dw| { - if (self.debug_str_section_index == null) { - self.debug_str_section_index = @intCast(u16, self.sections.items.len); - assert(dw.strtab.items.len == 0); - try dw.strtab.append(self.base.allocator, 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 = 0, - .sh_link = 0, - .sh_info = 0, - .sh_addralign = 1, - .sh_entsize = 1, - }); - self.debug_strtab_dirty = true; - self.shdr_table_dirty = true; - } + // if (self.dwarf) |*dw| { + // if (self.debug_str_section_index == null) { + // self.debug_str_section_index = @intCast(u16, self.sections.slice().len); + // assert(dw.strtab.items.len == 0); + // try dw.strtab.append(gpa, 0); + // try self.sections.append(gpa, .{ + // .shdr = .{ + // .sh_name = try self.shstrtab.insert(gpa, ".debug_str"), + // .sh_type = elf.SHT_PROGBITS, + // .sh_flags = elf.SHF_MERGE | elf.SHF_STRINGS, + // .sh_addr = 0, + // .sh_offset = 0, + // .sh_size = 0, + // .sh_link = 0, + // .sh_info = 0, + // .sh_addralign = 1, + // .sh_entsize = 1, + // }, + // .phdr_index = undefined, + // }); + // 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); + // if (self.debug_info_section_index == null) { + // self.debug_info_section_index = @intCast(u16, self.sections.slice().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}", .{ - 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; - } + // 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}", .{ + // off, + // off + file_size_hint, + // }); + // try self.sections.append(gpa, .{ + // .shdr = .{ + // .sh_name = try self.shstrtab.insert(gpa, ".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, + // }, + // .phdr_index = undefined, + // }); + // 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); + // if (self.debug_abbrev_section_index == null) { + // self.debug_abbrev_section_index = @intCast(u16, self.sections.slice().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}", .{ - 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; - } + // 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}", .{ + // off, + // off + file_size_hint, + // }); + // try self.sections.append(gpa, .{ + // .shdr = .{ + // .sh_name = try self.shstrtab.insert(gpa, ".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, + // }, + // .phdr_index = undefined, + // }); + // 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); + // if (self.debug_aranges_section_index == null) { + // self.debug_aranges_section_index = @intCast(u16, self.sections.slice().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}", .{ - 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; - } + // 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}", .{ + // off, + // off + file_size_hint, + // }); + // try self.sections.append(gpa, .{ + // .shdr = .{ + // .sh_name = try self.shstrtab.insert(gpa, ".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, + // }, + // .phdr_index = undefined, + // }); + // 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); + // if (self.debug_line_section_index == null) { + // self.debug_line_section_index = @intCast(u16, self.sections.slice().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}", .{ - 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 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}", .{ + // off, + // off + file_size_hint, + // }); + // try self.sections.append(gpa, .{ + // .shdr = .{ + // .sh_name = try self.shstrtab.insert(gpa, ".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, + // }, + // .phdr_index = undefined, + // }); + // self.shdr_table_dirty = true; + // self.debug_line_header_dirty = true; + // } + // } const shsize: u64 = switch (self.ptr_width) { .p32 => @sizeOf(elf.Elf32_Shdr), @@ -843,7 +835,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { .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_offset = self.findFreeSpace(self.sections.slice().len * shsize, shalign); self.shdr_table_dirty = true; } @@ -874,7 +866,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { // offset + it's filesize. var max_file_offset: u64 = 0; - for (self.sections.items) |shdr| { + for (self.sections.items(.shdr)) |shdr| { if (shdr.sh_offset + shdr.sh_size > max_file_offset) { max_file_offset = shdr.sh_offset + shdr.sh_size; } @@ -884,15 +876,18 @@ pub fn populateMissingMetadata(self: *Elf) !void { } } -fn growAllocSection(self: *Elf, shdr_index: u16, phdr_index: u16, needed_size: u64) !void { +fn growAllocSection(self: *Elf, shdr_index: u16, needed_size: u64) !void { // TODO Also detect virtual address collisions. - const shdr = &self.sections.items[shdr_index]; + const shdr = &self.sections.items(.shdr)[shdr_index]; + const phdr_index = self.sections.items(.phdr_index)[shdr_index]; const phdr = &self.program_headers.items[phdr_index]; + const maybe_last_atom_index = self.sections.items(.last_atom_index)[shdr_index]; if (needed_size > self.allocatedSize(shdr.sh_offset)) { // Must move the entire section. const new_offset = self.findFreeSpace(needed_size, self.page_size); - const existing_size = if (self.atoms.get(phdr_index)) |last| blk: { + const existing_size = if (maybe_last_atom_index) |last_atom_index| blk: { + const last = self.getAtom(last_atom_index); const sym = last.getSymbol(self); break :blk (sym.st_value + sym.st_size) - phdr.p_vaddr; } else if (shdr_index == self.got_section_index.?) blk: { @@ -900,8 +895,8 @@ fn growAllocSection(self: *Elf, shdr_index: u16, phdr_index: u16, needed_size: u } else 0; shdr.sh_size = 0; - log.debug("new '{s}' file offset 0x{x} to 0x{x}", .{ - self.getString(shdr.sh_name), + log.debug("new '{?s}' file offset 0x{x} to 0x{x}", .{ + self.shstrtab.get(shdr.sh_name), new_offset, new_offset + existing_size, }); @@ -927,7 +922,7 @@ pub fn growNonAllocSection( min_alignment: u32, requires_file_copy: bool, ) !void { - const shdr = &self.sections.items[shdr_index]; + const shdr = &self.sections.items(.shdr)[shdr_index]; if (needed_size > self.allocatedSize(shdr.sh_offset)) { const existing_size = if (self.symtab_section_index.? == shdr_index) blk: { @@ -940,7 +935,7 @@ pub fn growNonAllocSection( shdr.sh_size = 0; // Move all the symbols to a new file location. const new_offset = self.findFreeSpace(needed_size, min_alignment); - log.debug("moving '{s}' from 0x{x} to 0x{x}", .{ self.getString(shdr.sh_name), shdr.sh_offset, new_offset }); + log.debug("moving '{?s}' from 0x{x} to 0x{x}", .{ self.shstrtab.get(shdr.sh_name), shdr.sh_offset, new_offset }); if (requires_file_copy) { const amt = try self.base.file.?.copyRangeAll( @@ -961,25 +956,26 @@ pub fn growNonAllocSection( } pub fn markDirty(self: *Elf, shdr_index: u16, phdr_index: ?u16) void { + _ = shdr_index; self.shdr_table_dirty = true; // TODO look into only writing one section if (phdr_index) |_| { self.phdr_table_dirty = true; // TODO look into making only the one program header dirty } - if (self.dwarf) |_| { - if (self.debug_info_section_index.? == shdr_index) { - self.debug_info_header_dirty = true; - } else if (self.debug_line_section_index.? == shdr_index) { - self.debug_line_header_dirty = true; - } else if (self.debug_abbrev_section_index.? == shdr_index) { - self.debug_abbrev_section_dirty = true; - } else if (self.debug_str_section_index.? == shdr_index) { - self.debug_strtab_dirty = true; - } else if (self.debug_aranges_section_index.? == shdr_index) { - self.debug_aranges_section_dirty = true; - } - } + // if (self.dwarf) |_| { + // if (self.debug_info_section_index.? == shdr_index) { + // self.debug_info_header_dirty = true; + // } else if (self.debug_line_section_index.? == shdr_index) { + // self.debug_line_header_dirty = true; + // } else if (self.debug_abbrev_section_index.? == shdr_index) { + // self.debug_abbrev_section_dirty = true; + // } else if (self.debug_str_section_index.? == shdr_index) { + // self.debug_strtab_dirty = true; + // } else if (self.debug_aranges_section_index.? == shdr_index) { + // self.debug_aranges_section_dirty = true; + // } + // } } pub fn flush(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void { @@ -1011,6 +1007,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node } } + const gpa = self.base.allocator; var sub_prog_node = prog_node.start("ELF Flush", 0); sub_prog_node.activate(); defer sub_prog_node.end(); @@ -1018,23 +1015,25 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node // TODO This linker code currently assumes there is only 1 compilation unit and it // corresponds to the Zig source code. const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented; + _ = module; const target_endian = self.base.options.target.cpu.arch.endian(); const foreign_endian = target_endian != builtin.cpu.arch.endian(); - if (self.dwarf) |*dw| { - try dw.flushModule(module); - } + // if (self.dwarf) |*dw| { + // try dw.flushModule(module); + // } { var it = self.relocs.iterator(); while (it.next()) |entry| { - const atom = entry.key_ptr.*; + const atom_index = entry.key_ptr.*; const relocs = entry.value_ptr.*; + const atom = self.getAtom(atom_index); const source_sym = atom.getSymbol(self); - const source_shdr = self.sections.items[source_sym.st_shndx]; + const source_shdr = self.sections.items(.shdr)[source_sym.st_shndx]; - log.debug("relocating '{s}'", .{self.getString(source_sym.st_name)}); + log.debug("relocating '{?s}'", .{self.shstrtab.get(source_sym.st_name)}); for (relocs.items) |*reloc| { const target_sym = self.local_symbols.items[reloc.target]; @@ -1045,10 +1044,10 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node const section_offset = (source_sym.st_value + reloc.offset) - source_shdr.sh_addr; const file_offset = source_shdr.sh_offset + section_offset; - log.debug(" ({x}: [() => 0x{x}] ({s}))", .{ + log.debug(" ({x}: [() => 0x{x}] ({?s}))", .{ reloc.offset, target_vaddr, - self.getString(target_sym.st_name), + self.shstrtab.get(target_sym.st_name), }); switch (self.ptr_width) { @@ -1069,43 +1068,43 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node self.logSymtab(); } - if (self.dwarf) |*dw| { - if (self.debug_abbrev_section_dirty) { - try dw.writeDbgAbbrev(); - 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.dwarf) |*dw| { + // if (self.debug_abbrev_section_dirty) { + // try dw.writeDbgAbbrev(); + // 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) { - // 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; - try dw.writeDbgInfoHeader(module, low_pc, high_pc); - self.debug_info_header_dirty = false; - } + // if (self.debug_info_header_dirty) { + // // 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; + // try dw.writeDbgInfoHeader(module, low_pc, high_pc); + // self.debug_info_header_dirty = false; + // } - if (self.debug_aranges_section_dirty) { - // 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.?]; - try dw.writeDbgAranges(text_phdr.p_vaddr, text_phdr.p_memsz); - 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_aranges_section_dirty) { + // // 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.?]; + // try dw.writeDbgAranges(text_phdr.p_vaddr, text_phdr.p_memsz); + // 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) { - try dw.writeDbgLineHeader(); - self.debug_line_header_dirty = false; - } - } + // if (self.debug_line_header_dirty) { + // try dw.writeDbgLineHeader(); + // self.debug_line_header_dirty = false; + // } + // } if (self.phdr_table_dirty) { const phsize: u64 = switch (self.ptr_width) { @@ -1126,8 +1125,8 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node 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); + const buf = try gpa.alloc(elf.Elf32_Phdr, self.program_headers.items.len); + defer gpa.free(buf); for (buf) |*phdr, i| { phdr.* = progHeaderTo32(self.program_headers.items[i]); @@ -1138,8 +1137,8 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node 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); + const buf = try gpa.alloc(elf.Elf64_Phdr, self.program_headers.items.len); + defer gpa.free(buf); for (buf) |*phdr, i| { phdr.* = self.program_headers.items[i]; @@ -1155,23 +1154,23 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node { const shdr_index = self.shstrtab_index.?; - if (self.shstrtab_dirty or self.shstrtab.items.len != self.sections.items[shdr_index].sh_size) { - try self.growNonAllocSection(shdr_index, self.shstrtab.items.len, 1, false); - const shstrtab_sect = self.sections.items[shdr_index]; - try self.base.file.?.pwriteAll(self.shstrtab.items, shstrtab_sect.sh_offset); + if (self.shstrtab_dirty or self.shstrtab.buffer.items.len != self.sections.items(.shdr)[shdr_index].sh_size) { + try self.growNonAllocSection(shdr_index, self.shstrtab.buffer.items.len, 1, false); + const shstrtab_sect = self.sections.items(.shdr)[shdr_index]; + try self.base.file.?.pwriteAll(self.shstrtab.buffer.items, shstrtab_sect.sh_offset); self.shstrtab_dirty = false; } } - if (self.dwarf) |dwarf| { - const shdr_index = self.debug_str_section_index.?; - if (self.debug_strtab_dirty or dwarf.strtab.items.len != self.sections.items[shdr_index].sh_size) { - try self.growNonAllocSection(shdr_index, dwarf.strtab.items.len, 1, false); - const debug_strtab_sect = self.sections.items[shdr_index]; - try self.base.file.?.pwriteAll(dwarf.strtab.items, debug_strtab_sect.sh_offset); - self.debug_strtab_dirty = false; - } - } + // if (self.dwarf) |dwarf| { + // const shdr_index = self.debug_str_section_index.?; + // if (self.debug_strtab_dirty or dwarf.strtab.items.len != self.sections.items(.shdr)[shdr_index].sh_size) { + // try self.growNonAllocSection(shdr_index, dwarf.strtab.items.len, 1, false); + // const debug_strtab_sect = self.sections.items(.shdr)[shdr_index]; + // try self.base.file.?.pwriteAll(dwarf.strtab.items, debug_strtab_sect.sh_offset); + // self.debug_strtab_dirty = false; + // } + // } if (self.shdr_table_dirty) { const shsize: u64 = switch (self.ptr_width) { @@ -1183,7 +1182,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node .p64 => @alignOf(elf.Elf64_Shdr), }; const allocated_size = self.allocatedSize(self.shdr_table_offset.?); - const needed_size = self.sections.items.len * shsize; + const needed_size = self.sections.slice().len * shsize; if (needed_size > allocated_size) { self.shdr_table_offset = null; // free the space @@ -1192,12 +1191,13 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node 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); + const slice = self.sections.slice(); + const buf = try gpa.alloc(elf.Elf32_Shdr, slice.len); + defer gpa.free(buf); for (buf) |*shdr, i| { - shdr.* = sectHeaderTo32(self.sections.items[i]); - log.debug("writing section {s}: {}", .{ self.getString(shdr.sh_name), shdr.* }); + shdr.* = sectHeaderTo32(slice.items(.shdr)[i]); + log.debug("writing section {?s}: {}", .{ self.shstrtab.get(shdr.sh_name), shdr.* }); if (foreign_endian) { mem.byteSwapAllFields(elf.Elf32_Shdr, shdr); } @@ -1205,12 +1205,13 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node 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); + const slice = self.sections.slice(); + const buf = try gpa.alloc(elf.Elf64_Shdr, slice.len); + defer gpa.free(buf); for (buf) |*shdr, i| { - shdr.* = self.sections.items[i]; - log.debug("writing section {s}: {}", .{ self.getString(shdr.sh_name), shdr.* }); + shdr.* = slice.items(.shdr)[i]; + log.debug("writing section {?s}: {}", .{ self.shstrtab.get(shdr.sh_name), shdr.* }); if (foreign_endian) { mem.byteSwapAllFields(elf.Elf64_Shdr, shdr); } @@ -2021,7 +2022,7 @@ fn writeElfHeader(self: *Elf) !void { mem.writeInt(u16, hdr_buf[index..][0..2], e_shentsize, endian); index += 2; - const e_shnum = @intCast(u16, self.sections.items.len); + const e_shnum = @intCast(u16, self.sections.slice().len); mem.writeInt(u16, hdr_buf[index..][0..2], e_shnum, endian); index += 2; @@ -2033,124 +2034,150 @@ fn writeElfHeader(self: *Elf) !void { try self.base.file.?.pwriteAll(hdr_buf[0..index], 0); } -fn freeTextBlock(self: *Elf, text_block: *TextBlock, phdr_index: u16) void { - const local_sym = text_block.getSymbol(self); - const name_str_index = local_sym.st_name; - const name = self.getString(name_str_index); - log.debug("freeTextBlock {*} ({s})", .{ text_block, name }); +fn freeAtom(self: *Elf, atom_index: Atom.Index) void { + const atom = self.getAtom(atom_index); + log.debug("freeAtom {d} ({s})", .{ atom_index, atom.getName(self) }); - self.freeRelocationsForTextBlock(text_block); + Atom.freeRelocations(self, atom_index); - const free_list = self.atom_free_lists.getPtr(phdr_index).?; + const gpa = self.base.allocator; + const shndx = atom.getSymbol(self).st_shndx; + const free_list = &self.sections.items(.free_list)[shndx]; var already_have_free_list_node = false; { var i: usize = 0; // TODO turn free_list into a hash map while (i < free_list.items.len) { - if (free_list.items[i] == text_block) { + if (free_list.items[i] == atom_index) { _ = free_list.swapRemove(i); continue; } - if (free_list.items[i] == text_block.prev) { + if (free_list.items[i] == atom.prev_index) { already_have_free_list_node = true; } i += 1; } } - if (self.atoms.getPtr(phdr_index)) |last_block| { - if (last_block.* == text_block) { - if (text_block.prev) |prev| { + const maybe_last_atom_index = &self.sections.items(.last_atom_index)[shndx]; + if (maybe_last_atom_index.*) |last_atom_index| { + if (last_atom_index == atom_index) { + if (atom.prev_index) |prev_index| { // TODO shrink the section size here - last_block.* = prev; + maybe_last_atom_index.* = prev_index; } else { - _ = self.atoms.fetchRemove(phdr_index); + maybe_last_atom_index.* = null; } } } - if (text_block.prev) |prev| { - prev.next = text_block.next; + if (atom.prev_index) |prev_index| { + const prev = self.getAtomPtr(prev_index); + prev.next_index = atom.next_index; - if (!already_have_free_list_node and prev.freeListEligible(self)) { + 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. - free_list.append(self.base.allocator, prev) catch {}; + free_list.append(gpa, prev_index) catch {}; } } else { - text_block.prev = null; + self.getAtomPtr(atom_index).prev_index = null; } - if (text_block.next) |next| { - next.prev = text_block.prev; + if (atom.next_index) |next_index| { + self.getAtomPtr(next_index).prev_index = atom.prev_index; } else { - text_block.next = null; + self.getAtomPtr(atom_index).next_index = null; } // Appending to free lists is allowed to fail because the free lists are heuristics based anyway. - const local_sym_index = text_block.getSymbolIndex().?; - self.local_symbol_free_list.append(self.base.allocator, local_sym_index) catch {}; + const local_sym_index = atom.getSymbolIndex().?; + + self.local_symbol_free_list.append(gpa, local_sym_index) catch {}; self.local_symbols.items[local_sym_index].st_info = 0; + self.local_symbols.items[local_sym_index].st_shndx = 0; _ = self.atom_by_index_table.remove(local_sym_index); - text_block.local_sym_index = 0; + self.getAtomPtr(atom_index).local_sym_index = 0; - self.offset_table_free_list.append(self.base.allocator, text_block.offset_table_index) catch {}; + self.offset_table_free_list.append(self.base.allocator, atom.offset_table_index) catch {}; - if (self.dwarf) |*dw| { - dw.freeAtom(&text_block.dbg_info_atom); - } + // if (self.dwarf) |*dw| { + // dw.freeAtom(&atom.dbg_info_atom); + // } } -fn shrinkTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, phdr_index: u16) void { +fn shrinkAtom(self: *Elf, atom_index: Atom.Index, new_block_size: u64) void { _ = self; - _ = text_block; + _ = atom_index; _ = new_block_size; - _ = phdr_index; } -fn growTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, alignment: u64, phdr_index: u16) !u64 { - const sym = text_block.getSymbol(self); +fn growAtom(self: *Elf, atom_index: Atom.Index, new_block_size: u64, alignment: u64) !u64 { + const atom = self.getAtom(atom_index); + const sym = atom.getSymbol(self); 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); + const need_realloc = !align_ok or new_block_size > atom.capacity(self); if (!need_realloc) return sym.st_value; - return self.allocateTextBlock(text_block, new_block_size, alignment, phdr_index); + return self.allocateAtom(atom_index, new_block_size, alignment); } -fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, alignment: u64, phdr_index: u16) !u64 { - const shdr_index = self.phdr_shdr_table.get(phdr_index).?; +pub fn createAtom(self: *Elf) !Atom.Index { + const gpa = self.base.allocator; + const atom_index = @intCast(Atom.Index, self.atoms.items.len); + const atom = try self.atoms.addOne(gpa); + const local_sym_index = try self.allocateLocalSymbol(); + const offset_table_index = try self.allocateGotOffset(); + try self.atom_by_index_table.putNoClobber(gpa, local_sym_index, atom_index); + atom.* = .{ + .local_sym_index = local_sym_index, + .offset_table_index = offset_table_index, + .prev_index = null, + .next_index = null, + .dbg_info_atom = undefined, + }; + log.debug("creating ATOM(%{d}) at index {d}", .{ local_sym_index, atom_index }); + return atom_index; +} + +fn allocateAtom(self: *Elf, atom_index: Atom.Index, new_block_size: u64, alignment: u64) !u64 { + const atom = self.getAtom(atom_index); + const sym = atom.getSymbol(self); + const phdr_index = self.sections.items(.phdr_index)[sym.st_shndx]; const phdr = &self.program_headers.items[phdr_index]; - const shdr = &self.sections.items[shdr_index]; - const new_block_ideal_capacity = padToIdeal(new_block_size); + const shdr = &self.sections.items(.shdr)[sym.st_shndx]; + const free_list = &self.sections.items(.free_list)[sym.st_shndx]; + const maybe_last_atom_index = &self.sections.items(.last_atom_index)[sym.st_shndx]; + const new_atom_ideal_capacity = padToIdeal(new_block_size); - // We use these to indicate our intention to update metadata, placing the new block, + // We use these to indicate our intention to update metadata, placing the new atom, // 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 atom_placement: ?Atom.Index = null; var free_list_removal: ?usize = null; - var free_list = self.atom_free_lists.get(phdr_index).?; // 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 < free_list.items.len) { - const big_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 = big_block.getSymbol(self); - const capacity = big_block.capacity(self); + const big_atom_index = free_list.items[i]; + const big_atom = self.getAtom(big_atom_index); + // We now have a pointer to a live atom that has too much capacity. + // Is it enough that we could fit this new atom? + const big_atom_sym = big_atom.getSymbol(self); + const capacity = big_atom.capacity(self); const ideal_capacity = padToIdeal(capacity); - const ideal_capacity_end_vaddr = std.math.add(u64, sym.st_value, ideal_capacity) catch ideal_capacity; - const capacity_end_vaddr = sym.st_value + capacity; - const new_start_vaddr_unaligned = capacity_end_vaddr - new_block_ideal_capacity; + const ideal_capacity_end_vaddr = std.math.add(u64, big_atom_sym.st_value, ideal_capacity) catch ideal_capacity; + const capacity_end_vaddr = big_atom_sym.st_value + capacity; + const new_start_vaddr_unaligned = capacity_end_vaddr - new_atom_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)) { + if (!big_atom.freeListEligible(self)) { _ = free_list.swapRemove(i); } else { i += 1; @@ -2164,60 +2191,69 @@ fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, al 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; + atom_placement = big_atom_index; if (!keep_free_list_node) { free_list_removal = i; } break :blk new_start_vaddr; - } else if (self.atoms.get(phdr_index)) |last| { - const sym = last.getSymbol(self); - const ideal_capacity = padToIdeal(sym.st_size); - const ideal_capacity_end_vaddr = sym.st_value + ideal_capacity; + } else if (maybe_last_atom_index.*) |last_index| { + const last = self.getAtom(last_index); + const last_sym = last.getSymbol(self); + const ideal_capacity = padToIdeal(last_sym.st_size); + const ideal_capacity_end_vaddr = last_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; + atom_placement = last_index; 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 expand_section = if (atom_placement) |placement_index| + self.getAtom(placement_index).next_index == null + else + true; + if (expand_section) { const needed_size = (vaddr + new_block_size) - phdr.p_vaddr; - try self.growAllocSection(shdr_index, phdr_index, needed_size); - _ = try self.atoms.put(self.base.allocator, phdr_index, text_block); + try self.growAllocSection(sym.st_shndx, needed_size); + maybe_last_atom_index.* = atom_index; - if (self.dwarf) |_| { - // 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; - } + // if (self.dwarf) |_| { + // // 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; + // } } shdr.sh_addralign = math.max(shdr.sh_addralign, alignment); - // This function can also reallocate a text block. + // This function can also reallocate an atom. // 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 (atom.prev_index) |prev_index| { + const prev = self.getAtomPtr(prev_index); + prev.next_index = atom.next_index; } - if (text_block.next) |next| { - next.prev = text_block.prev; + if (atom.next_index) |next_index| { + const next = self.getAtomPtr(next_index); + next.prev_index = atom.prev_index; } - if (block_placement) |big_block| { - text_block.prev = big_block; - text_block.next = big_block.next; - big_block.next = text_block; + if (atom_placement) |big_atom_index| { + const big_atom = self.getAtomPtr(big_atom_index); + const atom_ptr = self.getAtomPtr(atom_index); + atom_ptr.prev_index = big_atom_index; + atom_ptr.next_index = big_atom.next_index; + big_atom.next_index = atom_index; } else { - text_block.prev = null; - text_block.next = null; + const atom_ptr = self.getAtomPtr(atom_index); + atom_ptr.prev_index = null; + atom_ptr.next_index = null; } if (free_list_removal) |i| { _ = free_list.swapRemove(i); @@ -2272,15 +2308,10 @@ pub fn allocateGotOffset(self: *Elf) !u32 { return index; } -fn freeRelocationsForTextBlock(self: *Elf, text_block: *TextBlock) void { - var removed_relocs = self.relocs.fetchRemove(text_block); - if (removed_relocs) |*relocs| relocs.value.deinit(self.base.allocator); -} - fn freeUnnamedConsts(self: *Elf, decl_index: Module.Decl.Index) void { const unnamed_consts = self.unnamed_const_atoms.getPtr(decl_index) orelse return; for (unnamed_consts.items) |atom| { - self.freeTextBlock(atom, self.phdr_load_ro_index.?); + self.freeAtom(atom); } unnamed_consts.clearAndFree(self.base.allocator); } @@ -2295,43 +2326,57 @@ pub fn freeDecl(self: *Elf, decl_index: Module.Decl.Index) void { log.debug("freeDecl {*}", .{decl}); - if (self.decls.fetchRemove(decl_index)) |kv| { - if (kv.value) |index| { - self.freeTextBlock(&decl.link.elf, index); - self.freeUnnamedConsts(decl_index); - } + if (self.decls.fetchRemove(decl_index)) |const_kv| { + var kv = const_kv; + self.freeAtom(kv.value.atom); + self.freeUnnamedConsts(decl_index); + kv.value.exports.deinit(self.base.allocator); } - if (self.dwarf) |*dw| { - dw.freeDecl(decl); + // if (self.dwarf) |*dw| { + // dw.freeDecl(decl); + // } +} + +pub fn getOrCreateAtomForDecl(self: *Elf, decl_index: Module.Decl.Index) !Atom.Index { + const gop = try self.decls.getOrPut(self.base.allocator, decl_index); + if (!gop.found_existing) { + gop.value_ptr.* = .{ + .atom = try self.createAtom(), + .shdr = self.getDeclShdrIndex(decl_index), + .exports = .{}, + }; } + return gop.value_ptr.atom; } -fn getDeclPhdrIndex(self: *Elf, decl: *Module.Decl) !u16 { +fn getDeclShdrIndex(self: *Elf, decl_index: Module.Decl.Index) u16 { + const decl = self.base.options.module.?.declPtr(decl_index); const ty = decl.ty; const zig_ty = ty.zigTypeTag(); const val = decl.val; - const phdr_index: u16 = blk: { + const shdr_index: u16 = blk: { if (val.isUndefDeep()) { // TODO in release-fast and release-small, we should put undef in .bss - break :blk self.phdr_load_rw_index.?; + break :blk self.data_section_index.?; } switch (zig_ty) { // TODO: what if this is a function pointer? - .Fn => break :blk self.phdr_load_re_index.?, + .Fn => break :blk self.text_section_index.?, else => { if (val.castTag(.variable)) |_| { - break :blk self.phdr_load_rw_index.?; + break :blk self.data_section_index.?; } - break :blk self.phdr_load_ro_index.?; + break :blk self.rodata_section_index.?; }, } }; - return phdr_index; + return shdr_index; } fn updateDeclCode(self: *Elf, decl_index: Module.Decl.Index, code: []const u8, stt_bits: u8) !*elf.Elf64_Sym { + const gpa = self.base.allocator; const mod = self.base.options.module.?; const decl = mod.declPtr(decl_index); @@ -2341,60 +2386,65 @@ fn updateDeclCode(self: *Elf, decl_index: Module.Decl.Index, code: []const u8, s log.debug("updateDeclCode {s}{*}", .{ decl_name, decl }); const required_alignment = decl.getAlignment(self.base.options.target); - const decl_ptr = self.decls.getPtr(decl_index).?; - if (decl_ptr.* == null) { - decl_ptr.* = try self.getDeclPhdrIndex(decl); - } - const phdr_index = decl_ptr.*.?; - const shdr_index = self.phdr_shdr_table.get(phdr_index).?; + const decl_metadata = self.decls.get(decl_index).?; + const atom_index = decl_metadata.atom; + const atom = self.getAtom(atom_index); - const local_sym = decl.link.elf.getSymbolPtr(self); - if (local_sym.st_size != 0) { - const capacity = decl.link.elf.capacity(self); + const shdr_index = decl_metadata.shdr; + if (atom.getSymbol(self).st_size != 0) { + const local_sym = atom.getSymbolPtr(self); + local_sym.st_name = try self.shstrtab.insert(gpa, decl_name); + local_sym.st_info = (elf.STB_LOCAL << 4) | stt_bits; + local_sym.st_other = 0; + local_sym.st_shndx = shdr_index; + + const capacity = atom.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, phdr_index); + const vaddr = try self.growAtom(atom_index, code.len, required_alignment); log.debug("growing {s} from 0x{x} to 0x{x}", .{ 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)", .{}); - self.offset_table.items[decl.link.elf.offset_table_index] = vaddr; - try self.writeOffsetTableEntry(decl.link.elf.offset_table_index); + self.offset_table.items[atom.offset_table_index] = vaddr; + try self.writeOffsetTableEntry(atom.offset_table_index); } } else if (code.len < local_sym.st_size) { - self.shrinkTextBlock(&decl.link.elf, code.len, phdr_index); + self.shrinkAtom(atom_index, code.len); } local_sym.st_size = code.len; - local_sym.st_name = try self.updateString(local_sym.st_name, decl_name); - local_sym.st_info = (elf.STB_LOCAL << 4) | stt_bits; - local_sym.st_other = 0; - local_sym.st_shndx = shdr_index; + // TODO this write could be avoided if no fields of the symbol were changed. - try self.writeSymbol(decl.link.elf.getSymbolIndex().?); + try self.writeSymbol(atom.getSymbolIndex().?); } else { - const name_str_index = try self.makeString(decl_name); - const vaddr = try self.allocateTextBlock(&decl.link.elf, code.len, required_alignment, phdr_index); - errdefer self.freeTextBlock(&decl.link.elf, phdr_index); - log.debug("allocated text block for {s} at 0x{x}", .{ decl_name, vaddr }); - + const local_sym = atom.getSymbolPtr(self); local_sym.* = .{ - .st_name = name_str_index, + .st_name = try self.shstrtab.insert(gpa, decl_name), .st_info = (elf.STB_LOCAL << 4) | stt_bits, .st_other = 0, .st_shndx = shdr_index, - .st_value = vaddr, - .st_size = code.len, + .st_value = 0, + .st_size = 0, }; - self.offset_table.items[decl.link.elf.offset_table_index] = vaddr; + const vaddr = try self.allocateAtom(atom_index, code.len, required_alignment); + errdefer self.freeAtom(atom_index); + log.debug("allocated text block for {s} at 0x{x}", .{ decl_name, vaddr }); - try self.writeSymbol(decl.link.elf.getSymbolIndex().?); - try self.writeOffsetTableEntry(decl.link.elf.offset_table_index); + self.offset_table.items[atom.offset_table_index] = vaddr; + local_sym.st_value = vaddr; + local_sym.st_size = code.len; + + try self.writeSymbol(atom.getSymbolIndex().?); + try self.writeOffsetTableEntry(atom.offset_table_index); } + const local_sym = atom.getSymbolPtr(self); + const phdr_index = self.sections.items(.phdr_index)[shdr_index]; const section_offset = local_sym.st_value - self.program_headers.items[phdr_index].p_vaddr; - const file_offset = self.sections.items[shdr_index].sh_offset + section_offset; + const file_offset = self.sections.items(.shdr)[shdr_index].sh_offset + section_offset; try self.base.file.?.pwriteAll(code, file_offset); return local_sym; @@ -2413,28 +2463,23 @@ pub fn updateFunc(self: *Elf, module: *Module, func: *Module.Fn, air: Air, liven const decl_index = func.owner_decl; const decl = module.declPtr(decl_index); - const atom = &decl.link.elf; - try atom.ensureInitialized(self); - const gop = try self.decls.getOrPut(self.base.allocator, decl_index); - if (gop.found_existing) { - self.freeUnnamedConsts(decl_index); - self.freeRelocationsForTextBlock(atom); - } else { - gop.value_ptr.* = null; - } + + const atom_index = try self.getOrCreateAtomForDecl(decl_index); + self.freeUnnamedConsts(decl_index); + Atom.freeRelocations(self, atom_index); var code_buffer = std.ArrayList(u8).init(self.base.allocator); defer code_buffer.deinit(); - var decl_state: ?Dwarf.DeclState = if (self.dwarf) |*dw| try dw.initDeclState(module, decl_index) else null; - defer if (decl_state) |*ds| ds.deinit(); + // var decl_state: ?Dwarf.DeclState = if (self.dwarf) |*dw| try dw.initDeclState(module, decl_index) else null; + // defer if (decl_state) |*ds| ds.deinit(); - const res = if (decl_state) |*ds| - try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .{ - .dwarf = ds, - }) - else - try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .none); + // const res = if (decl_state) |*ds| + // try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .{ + // .dwarf = ds, + // }) + // else + const res = try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .none); const code = switch (res) { .ok => code_buffer.items, @@ -2445,15 +2490,16 @@ pub fn updateFunc(self: *Elf, module: *Module, func: *Module.Fn, air: Air, liven }, }; const local_sym = try self.updateDeclCode(decl_index, code, elf.STT_FUNC); - if (decl_state) |*ds| { - try self.dwarf.?.commitDeclState( - module, - decl_index, - local_sym.st_value, - local_sym.st_size, - ds, - ); - } + _ = local_sym; + // if (decl_state) |*ds| { + // try self.dwarf.?.commitDeclState( + // module, + // decl_index, + // local_sym.st_value, + // local_sym.st_size, + // ds, + // ); + // } // Since we updated the vaddr and the size, each corresponding export // symbol also needs to be updated. @@ -2483,41 +2529,34 @@ pub fn updateDecl(self: *Elf, module: *Module, decl_index: Module.Decl.Index) !v } } - assert(!self.unnamed_const_atoms.contains(decl_index)); - - const atom = &decl.link.elf; - try atom.ensureInitialized(self); - const gop = try self.decls.getOrPut(self.base.allocator, decl_index); - if (gop.found_existing) { - self.freeRelocationsForTextBlock(atom); - } else { - gop.value_ptr.* = null; - } + const atom_index = try self.getOrCreateAtomForDecl(decl_index); + Atom.freeRelocations(self, atom_index); + const atom = self.getAtom(atom_index); var code_buffer = std.ArrayList(u8).init(self.base.allocator); defer code_buffer.deinit(); - var decl_state: ?Dwarf.DeclState = if (self.dwarf) |*dw| try dw.initDeclState(module, decl_index) else null; - defer if (decl_state) |*ds| ds.deinit(); + // var decl_state: ?Dwarf.DeclState = if (self.dwarf) |*dw| try dw.initDeclState(module, decl_index) else null; + // defer if (decl_state) |*ds| ds.deinit(); // TODO implement .debug_info for global variables const decl_val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val; - const res = if (decl_state) |*ds| - try codegen.generateSymbol(&self.base, decl.srcLoc(), .{ - .ty = decl.ty, - .val = decl_val, - }, &code_buffer, .{ - .dwarf = ds, - }, .{ - .parent_atom_index = decl.link.elf.getSymbolIndex().?, - }) - else - try codegen.generateSymbol(&self.base, decl.srcLoc(), .{ - .ty = decl.ty, - .val = decl_val, - }, &code_buffer, .none, .{ - .parent_atom_index = decl.link.elf.getSymbolIndex().?, - }); + // const res = if (decl_state) |*ds| + // try codegen.generateSymbol(&self.base, decl.srcLoc(), .{ + // .ty = decl.ty, + // .val = decl_val, + // }, &code_buffer, .{ + // .dwarf = ds, + // }, .{ + // .parent_atom_index = atom.getSymbolIndex().?, + // }) + // else + const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), .{ + .ty = decl.ty, + .val = decl_val, + }, &code_buffer, .none, .{ + .parent_atom_index = atom.getSymbolIndex().?, + }); const code = switch (res) { .ok => code_buffer.items, @@ -2529,15 +2568,16 @@ pub fn updateDecl(self: *Elf, module: *Module, decl_index: Module.Decl.Index) !v }; const local_sym = try self.updateDeclCode(decl_index, code, elf.STT_OBJECT); - if (decl_state) |*ds| { - try self.dwarf.?.commitDeclState( - module, - decl_index, - local_sym.st_value, - local_sym.st_size, - ds, - ); - } + _ = local_sym; + // if (decl_state) |*ds| { + // try self.dwarf.?.commitDeclState( + // module, + // decl_index, + // local_sym.st_value, + // local_sym.st_size, + // ds, + // ); + // } // Since we updated the vaddr and the size, each corresponding export // symbol also needs to be updated. @@ -2545,36 +2585,31 @@ pub fn updateDecl(self: *Elf, module: *Module, decl_index: Module.Decl.Index) !v } pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module.Decl.Index) !u32 { - var code_buffer = std.ArrayList(u8).init(self.base.allocator); + const gpa = self.base.allocator; + + var code_buffer = std.ArrayList(u8).init(gpa); defer code_buffer.deinit(); const mod = self.base.options.module.?; - const decl = mod.declPtr(decl_index); - - const gop = try self.unnamed_const_atoms.getOrPut(self.base.allocator, decl_index); + const gop = try self.unnamed_const_atoms.getOrPut(gpa, decl_index); if (!gop.found_existing) { gop.value_ptr.* = .{}; } const unnamed_consts = gop.value_ptr; - const atom = try self.base.allocator.create(TextBlock); - errdefer self.base.allocator.destroy(atom); - atom.* = TextBlock.empty; - // TODO for unnamed consts we don't need GOT offset/entry allocated - try atom.ensureInitialized(self); - try self.managed_atoms.append(self.base.allocator, atom); - + const decl = mod.declPtr(decl_index); const name_str_index = blk: { const decl_name = try decl.getFullyQualifiedName(mod); - defer self.base.allocator.free(decl_name); - + defer gpa.free(decl_name); const index = unnamed_consts.items.len; - const name = try std.fmt.allocPrint(self.base.allocator, "__unnamed_{s}_{d}", .{ decl_name, index }); - defer self.base.allocator.free(name); - - break :blk try self.makeString(name); + const name = try std.fmt.allocPrint(gpa, "__unnamed_{s}_{d}", .{ decl_name, index }); + defer gpa.free(name); + break :blk try self.shstrtab.insert(gpa, name); }; - const name = self.getString(name_str_index); + const name = self.shstrtab.get(name_str_index).?; + + const atom_index = try self.createAtom(); + const atom = self.getAtomPtr(atom_index); const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), typed_value, &code_buffer, .{ .none = {}, @@ -2592,28 +2627,24 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module }; const required_alignment = typed_value.ty.abiAlignment(self.base.options.target); - const phdr_index = self.phdr_load_ro_index.?; - const shdr_index = self.phdr_shdr_table.get(phdr_index).?; - const vaddr = try self.allocateTextBlock(atom, code.len, required_alignment, phdr_index); - errdefer self.freeTextBlock(atom, phdr_index); - - log.debug("allocated text block for {s} at 0x{x}", .{ name, vaddr }); - + const shdr_index = self.rodata_section_index.?; + const phdr_index = self.sections.items(.phdr_index)[shdr_index]; const local_sym = atom.getSymbolPtr(self); - local_sym.* = .{ - .st_name = name_str_index, - .st_info = (elf.STB_LOCAL << 4) | elf.STT_OBJECT, - .st_other = 0, - .st_shndx = shdr_index, - .st_value = vaddr, - .st_size = code.len, - }; + local_sym.st_name = name_str_index; + local_sym.st_info = (elf.STB_LOCAL << 4) | elf.STT_OBJECT; + local_sym.st_other = 0; + local_sym.st_shndx = shdr_index; + local_sym.st_size = code.len; + local_sym.st_value = try self.allocateAtom(atom_index, code.len, required_alignment); + errdefer self.freeAtom(atom_index); + + log.debug("allocated text block for {s} at 0x{x}", .{ name, local_sym.st_value }); try self.writeSymbol(atom.getSymbolIndex().?); - try unnamed_consts.append(self.base.allocator, atom); + try unnamed_consts.append(gpa, atom_index); const section_offset = local_sym.st_value - self.program_headers.items[phdr_index].p_vaddr; - const file_offset = self.sections.items[shdr_index].sh_offset + section_offset; + const file_offset = self.sections.items(.shdr)[shdr_index].sh_offset + section_offset; try self.base.file.?.pwriteAll(code, file_offset); return atom.getSymbolIndex().?; @@ -2635,20 +2666,16 @@ pub fn updateDeclExports( const tracy = trace(@src()); defer tracy.end(); + const gpa = self.base.allocator; + const decl = module.declPtr(decl_index); - const atom = &decl.link.elf; - - if (atom.getSymbolIndex() == null) return; - + const atom_index = try self.getOrCreateAtomForDecl(decl_index); + const atom = self.getAtom(atom_index); const decl_sym = atom.getSymbol(self); - try self.global_symbols.ensureUnusedCapacity(self.base.allocator, exports.len); + const decl_metadata = self.decls.getPtr(decl_index).?; + const shdr_index = decl_metadata.shdr; - const gop = try self.decls.getOrPut(self.base.allocator, decl_index); - if (!gop.found_existing) { - gop.value_ptr.* = try self.getDeclPhdrIndex(decl); - } - const phdr_index = gop.value_ptr.*.?; - const shdr_index = self.phdr_shdr_table.get(phdr_index).?; + try self.global_symbols.ensureUnusedCapacity(gpa, exports.len); for (exports) |exp| { if (exp.options.section) |section_name| { @@ -2681,10 +2708,10 @@ pub fn updateDeclExports( }, }; const stt_bits: u8 = @truncate(u4, decl_sym.st_info); - if (exp.link.elf.sym_index) |i| { + if (decl_metadata.getExport(self, exp.options.name)) |i| { const sym = &self.global_symbols.items[i]; sym.* = .{ - .st_name = try self.updateString(sym.st_name, exp.options.name), + .st_name = try self.shstrtab.insert(gpa, exp.options.name), .st_info = (stb_bits << 4) | stt_bits, .st_other = 0, .st_shndx = shdr_index, @@ -2692,21 +2719,19 @@ pub fn updateDeclExports( .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; }; + try decl_metadata.exports.append(gpa, @intCast(u32, i)); self.global_symbols.items[i] = .{ - .st_name = name, + .st_name = try self.shstrtab.insert(gpa, exp.options.name), .st_info = (stb_bits << 4) | stt_bits, .st_other = 0, .st_shndx = shdr_index, .st_value = decl_sym.st_value, .st_size = decl_sym.st_size, }; - - exp.link.elf.sym_index = @intCast(u32, i); } } } @@ -2722,17 +2747,19 @@ pub fn updateDeclLineNumber(self: *Elf, mod: *Module, decl: *const Module.Decl) log.debug("updateDeclLineNumber {s}{*}", .{ decl_name, decl }); if (self.llvm_object) |_| return; - if (self.dwarf) |*dw| { - try dw.updateDeclLineNumber(decl); - } + // if (self.dwarf) |*dw| { + // try dw.updateDeclLineNumber(decl); + // } } -pub fn deleteExport(self: *Elf, exp: Export) void { +pub fn deleteDeclExport(self: *Elf, decl_index: Module.Decl.Index, name: []const u8) void { if (self.llvm_object) |_| return; - - 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; + const metadata = self.decls.getPtr(decl_index) orelse return; + const sym_index = metadata.getExportPtr(self, name) orelse return; + log.debug("deleting export '{s}'", .{name}); + self.global_symbol_free_list.append(self.base.allocator, sym_index.*) catch {}; + self.global_symbols.items[sym_index.*].st_info = 0; + sym_index.* = 0; } fn writeProgHeader(self: *Elf, index: usize) !void { @@ -2761,7 +2788,7 @@ fn writeSectHeader(self: *Elf, index: usize) !void { switch (self.ptr_width) { .p32 => { var shdr: [1]elf.Elf32_Shdr = undefined; - shdr[0] = sectHeaderTo32(self.sections.items[index]); + shdr[0] = sectHeaderTo32(self.sections.items(.shdr)[index]); if (foreign_endian) { mem.byteSwapAllFields(elf.Elf32_Shdr, &shdr[0]); } @@ -2769,7 +2796,7 @@ fn writeSectHeader(self: *Elf, index: usize) !void { return self.base.file.?.pwriteAll(mem.sliceAsBytes(&shdr), offset); }, .p64 => { - var shdr = [1]elf.Elf64_Shdr{self.sections.items[index]}; + var shdr = [1]elf.Elf64_Shdr{self.sections.items(.shdr)[index]}; if (foreign_endian) { mem.byteSwapAllFields(elf.Elf64_Shdr, &shdr[0]); } @@ -2783,11 +2810,11 @@ fn writeOffsetTableEntry(self: *Elf, index: usize) !void { const entry_size: u16 = self.archPtrWidthBytes(); if (self.offset_table_count_dirty) { const needed_size = self.offset_table.items.len * entry_size; - try self.growAllocSection(self.got_section_index.?, self.phdr_got_index.?, needed_size); + try self.growAllocSection(self.got_section_index.?, needed_size); self.offset_table_count_dirty = false; } const endian = self.base.options.target.cpu.arch.endian(); - const shdr = &self.sections.items[self.got_section_index.?]; + const shdr = &self.sections.items(.shdr)[self.got_section_index.?]; const off = shdr.sh_offset + @as(u64, entry_size) * index; switch (entry_size) { 2 => { @@ -2813,7 +2840,7 @@ fn writeSymbol(self: *Elf, index: usize) !void { const tracy = trace(@src()); defer tracy.end(); - const syms_sect = &self.sections.items[self.symtab_section_index.?]; + const syms_sect = &self.sections.items(.shdr)[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) { @@ -2835,7 +2862,7 @@ fn writeSymbol(self: *Elf, index: usize) !void { .p64 => syms_sect.sh_offset + @sizeOf(elf.Elf64_Sym) * index, }; const local = self.local_symbols.items[index]; - log.debug("writing symbol {d}, '{s}' at 0x{x}", .{ index, self.getString(local.st_name), off }); + log.debug("writing symbol {d}, '{?s}' at 0x{x}", .{ index, self.shstrtab.get(local.st_name), off }); log.debug(" ({})", .{local}); switch (self.ptr_width) { .p32 => { @@ -2865,7 +2892,7 @@ fn writeSymbol(self: *Elf, index: usize) !void { } fn writeAllGlobalSymbols(self: *Elf) !void { - const syms_sect = &self.sections.items[self.symtab_section_index.?]; + const syms_sect = &self.sections.items(.shdr)[self.symtab_section_index.?]; const sym_size: u64 = switch (self.ptr_width) { .p32 => @sizeOf(elf.Elf32_Sym), .p64 => @sizeOf(elf.Elf64_Sym), @@ -3215,10 +3242,52 @@ const CsuObjects = struct { fn logSymtab(self: Elf) void { log.debug("locals:", .{}); for (self.local_symbols.items) |sym, id| { - log.debug(" {d}: {s}: @{x} in {d}", .{ id, self.getString(sym.st_name), sym.st_value, sym.st_shndx }); + log.debug(" {d}: {?s}: @{x} in {d}", .{ id, self.shstrtab.get(sym.st_name), sym.st_value, sym.st_shndx }); } log.debug("globals:", .{}); for (self.global_symbols.items) |sym, id| { - log.debug(" {d}: {s}: @{x} in {d}", .{ id, self.getString(sym.st_name), sym.st_value, sym.st_shndx }); + log.debug(" {d}: {?s}: @{x} in {d}", .{ id, self.shstrtab.get(sym.st_name), sym.st_value, sym.st_shndx }); } } + +pub fn getProgramHeader(self: *const Elf, shdr_index: u16) elf.Elf64_Phdr { + const index = self.sections.items(.phdr_index)[shdr_index]; + return self.program_headers.items[index]; +} + +pub fn getProgramHeaderPtr(self: *Elf, shdr_index: u16) *elf.Elf64_Phdr { + const index = self.sections.items(.phdr_index)[shdr_index]; + return &self.program_headers.items[index]; +} + +/// Returns pointer-to-symbol described at sym_index. +pub fn getSymbolPtr(self: *Elf, sym_index: u32) *elf.Elf64_Sym { + return &self.local_symbols.items[sym_index]; +} + +/// Returns symbol at sym_index. +pub fn getSymbol(self: *const Elf, sym_index: u32) elf.Elf64_Sym { + return self.local_symbols.items[sym_index]; +} + +/// Returns name of the symbol at sym_index. +pub fn getSymbolName(self: *const Elf, sym_index: u32) []const u8 { + const sym = self.local_symbols.items[sym_index]; + return self.shstrtab.get(sym.st_name).?; +} + +pub fn getAtom(self: *const Elf, atom_index: Atom.Index) Atom { + assert(atom_index < self.atoms.items.len); + return self.atoms.items[atom_index]; +} + +pub fn getAtomPtr(self: *Elf, atom_index: Atom.Index) *Atom { + assert(atom_index < self.atoms.items.len); + return &self.atoms.items[atom_index]; +} + +/// Returns atom if there is an atom referenced by the symbol. +/// Returns null on failure. +pub fn getAtomIndexForSymbol(self: *Elf, sym_index: u32) ?Atom.Index { + return self.atom_by_index_table.get(sym_index); +} diff --git a/src/link/Elf/Atom.zig b/src/link/Elf/Atom.zig index caeb3bfbc58d3caf207f32e317e063aa6a4fd589..79b699636fc3f532e14dba6946a1cf742e41c7cf 100644 --- a/src/link/Elf/Atom.zig +++ b/src/link/Elf/Atom.zig @@ -20,44 +20,35 @@ 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: ?*Atom, -next: ?*Atom, +prev_index: ?Atom.Index, +next_index: ?Atom.Index, dbg_info_atom: Dwarf.Atom, -pub const empty = Atom{ - .local_sym_index = 0, - .offset_table_index = undefined, - .prev = null, - .next = null, - .dbg_info_atom = undefined, +pub const Index = u32; + +pub const Reloc = struct { + target: u32, + offset: u64, + addend: u32, + prev_vaddr: u64, }; -pub fn ensureInitialized(self: *Atom, elf_file: *Elf) !void { - if (self.getSymbolIndex() != null) return; // Already initialized - self.local_sym_index = try elf_file.allocateLocalSymbol(); - self.offset_table_index = try elf_file.allocateGotOffset(); - try elf_file.atom_by_index_table.putNoClobber(elf_file.base.allocator, self.local_sym_index, self); -} - pub fn getSymbolIndex(self: Atom) ?u32 { if (self.local_sym_index == 0) return null; return self.local_sym_index; } -pub fn getSymbol(self: Atom, elf_file: *Elf) elf.Elf64_Sym { - const sym_index = self.getSymbolIndex().?; - return elf_file.local_symbols.items[sym_index]; +pub fn getSymbol(self: Atom, elf_file: *const Elf) elf.Elf64_Sym { + return elf_file.getSymbol(self.getSymbolIndex().?); } pub fn getSymbolPtr(self: Atom, elf_file: *Elf) *elf.Elf64_Sym { - const sym_index = self.getSymbolIndex().?; - return &elf_file.local_symbols.items[sym_index]; + return elf_file.getSymbolPtr(self.getSymbolIndex().?); } -pub fn getName(self: Atom, elf_file: *Elf) []const u8 { - const sym = self.getSymbol(); - return elf_file.getString(sym.st_name); +pub fn getName(self: Atom, elf_file: *const Elf) []const u8 { + return elf_file.getSymbolName(self.getSymbolIndex().?); } pub fn getOffsetTableAddress(self: Atom, elf_file: *Elf) u64 { @@ -72,9 +63,10 @@ pub fn getOffsetTableAddress(self: Atom, elf_file: *Elf) u64 { /// 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. -pub fn capacity(self: Atom, elf_file: *Elf) u64 { +pub fn capacity(self: Atom, elf_file: *const Elf) u64 { const self_sym = self.getSymbol(elf_file); - if (self.next) |next| { + if (self.next_index) |next_index| { + const next = elf_file.getAtom(next_index); const next_sym = next.getSymbol(elf_file); return next_sym.st_value - self_sym.st_value; } else { @@ -83,9 +75,10 @@ pub fn capacity(self: Atom, elf_file: *Elf) u64 { } } -pub fn freeListEligible(self: Atom, elf_file: *Elf) bool { +pub fn freeListEligible(self: Atom, elf_file: *const Elf) bool { // No need to keep a free list node for the last block. - const next = self.next orelse return false; + const next_index = self.next_index orelse return false; + const next = elf_file.getAtom(next_index); const self_sym = self.getSymbol(elf_file); const next_sym = next.getSymbol(elf_file); const cap = next_sym.st_value - self_sym.st_value; @@ -94,3 +87,17 @@ pub fn freeListEligible(self: Atom, elf_file: *Elf) bool { const surplus = cap - ideal_cap; return surplus >= Elf.min_text_capacity; } + +pub fn addRelocation(elf_file: *Elf, atom_index: Index, reloc: Reloc) !void { + const gpa = elf_file.base.allocator; + const gop = try elf_file.relocs.getOrPut(gpa, atom_index); + if (!gop.found_existing) { + gop.value_ptr.* = .{}; + } + try gop.value_ptr.append(gpa, reloc); +} + +pub fn freeRelocations(elf_file: *Elf, atom_index: Index) void { + var removed_relocs = elf_file.relocs.fetchRemove(atom_index); + if (removed_relocs) |*relocs| relocs.value.deinit(elf_file.base.allocator); +} diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 29aed25b3108b52080eed45f72d3d5e9b3f29872..11a1119449dd640959b9f4673f6ecf7d4c2bb73e 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -2604,9 +2604,11 @@ pub fn freeDecl(self: *MachO, decl_index: Module.Decl.Index) void { log.debug("freeDecl {*}", .{decl}); - if (self.decls.fetchSwapRemove(decl_index)) |kv| { + if (self.decls.fetchSwapRemove(decl_index)) |const_kv| { + var kv = const_kv; self.freeAtom(kv.value.atom); self.freeUnnamedConsts(decl_index); + kv.value.exports.deinit(self.base.allocator); } // if (self.d_sym) |*d_sym| { -- 2.54.0 From ef8f694d777029caaa48c50c28ff805c058ccccb Mon Sep 17 00:00:00 2001 From: leap123 Date: Wed, 1 Feb 2023 01:08:30 +0700 Subject: [PATCH 42/84] std.os.uefi: fix shift in pool allocator (again) (#14497) --- lib/std/os/uefi/pool_allocator.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/std/os/uefi/pool_allocator.zig b/lib/std/os/uefi/pool_allocator.zig index 8e2d9fe3fc450feeacc08b307da0856044a7907d..8f26aac32c74ab38ea19e6e99fb7a15d1a4bad21 100644 --- a/lib/std/os/uefi/pool_allocator.zig +++ b/lib/std/os/uefi/pool_allocator.zig @@ -22,7 +22,7 @@ const UefiPoolAllocator = struct { assert(len > 0); - const ptr_align = @as(usize, 1) << @as(Allocator.Log2Align, log2_ptr_align); + const ptr_align = @as(usize, 1) << @intCast(Allocator.Log2Align, log2_ptr_align); const metadata_len = mem.alignForward(@sizeOf(usize), ptr_align); -- 2.54.0 From c430e9afa7b050400b9703360a0af4ab824335ce Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Tue, 31 Jan 2023 20:27:17 +0100 Subject: [PATCH 43/84] link: make Coff atoms fully owned by the linker --- src/Module.zig | 6 +- src/Sema.zig | 2 +- src/arch/aarch64/CodeGen.zig | 42 ++-- src/arch/aarch64/Emit.zig | 6 +- src/arch/x86_64/CodeGen.zig | 16 +- src/arch/x86_64/Emit.zig | 8 +- src/link.zig | 4 +- src/link/Coff.zig | 460 +++++++++++++++++++---------------- src/link/Coff/Atom.zig | 46 ++-- src/link/Coff/Relocation.zig | 18 +- src/link/Elf.zig | 10 +- src/link/MachO.zig | 5 + 12 files changed, 349 insertions(+), 274 deletions(-) diff --git a/src/Module.zig b/src/Module.zig index 0695a2e98aace36593ce627ccc538bceee08e725..b39fd2bab241a304819cd056a7ae5c51b1266ddf 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -5274,7 +5274,7 @@ pub fn clearDecl( // TODO instead of a union, put this memory trailing Decl objects, // and allow it to be variably sized. decl.link = switch (mod.comp.bin_file.tag) { - .coff => .{ .coff = link.File.Coff.Atom.empty }, + .coff => .{ .coff = {} }, .elf => .{ .elf = {} }, .macho => .{ .macho = {} }, .plan9 => .{ .plan9 = link.File.Plan9.DeclBlock.empty }, @@ -5390,7 +5390,7 @@ fn deleteDeclExports(mod: *Module, decl_index: Decl.Index) Allocator.Error!void wasm.deleteExport(exp.link.wasm); } if (mod.comp.bin_file.cast(link.File.Coff)) |coff| { - coff.deleteExport(exp.link.coff); + coff.deleteDeclExport(decl_index, exp.options.name); } if (mod.failed_exports.fetchSwapRemove(exp)) |failed_kv| { failed_kv.value.destroy(mod.gpa); @@ -5694,7 +5694,7 @@ pub fn allocateNewDecl( .zir_decl_index = 0, .src_scope = src_scope, .link = switch (mod.comp.bin_file.tag) { - .coff => .{ .coff = link.File.Coff.Atom.empty }, + .coff => .{ .coff = {} }, .elf => .{ .elf = {} }, .macho => .{ .macho = {} }, .plan9 => .{ .plan9 = link.File.Plan9.DeclBlock.empty }, diff --git a/src/Sema.zig b/src/Sema.zig index 28d559f730f01dcd17340f017d386383e81e222c..82321ef54565a72dd319b2862fa793560e9c89c3 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -5565,7 +5565,7 @@ pub fn analyzeExport( }, .src = src, .link = switch (mod.comp.bin_file.tag) { - .coff => .{ .coff = .{} }, + .coff => .{ .coff = {} }, .elf => .{ .elf = {} }, .macho => .{ .macho = {} }, .plan9 => .{ .plan9 = null }, diff --git a/src/arch/aarch64/CodeGen.zig b/src/arch/aarch64/CodeGen.zig index 67197c35f890b06936bde181daa4a2e2de72bbd3..d0fba2fd0e737c6ca453fd743731c2ab30f64fc8 100644 --- a/src/arch/aarch64/CodeGen.zig +++ b/src/arch/aarch64/CodeGen.zig @@ -4019,15 +4019,17 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type .direct => .load_memory_ptr_direct, .import => unreachable, }; - const mod = self.bin_file.options.module.?; - const owner_decl = mod.declPtr(self.mod_fn.owner_decl); const atom_index = switch (self.bin_file.tag) { .macho => blk: { const macho_file = self.bin_file.cast(link.File.MachO).?; const atom = try macho_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl); break :blk macho_file.getAtom(atom).getSymbolIndex().?; }, - .coff => owner_decl.link.coff.getSymbolIndex().?, + .coff => blk: { + const coff_file = self.bin_file.cast(link.File.Coff).?; + const atom = try coff_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl); + break :blk coff_file.getAtom(atom).getSymbolIndex().?; + }, else => unreachable, // unsupported target format }; _ = try self.addInst(.{ @@ -4322,11 +4324,12 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier }, }); } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { - try fn_owner_decl.link.coff.ensureInitialized(coff_file); + const atom = try coff_file.getOrCreateAtomForDecl(func.owner_decl); + const sym_index = coff_file.getAtom(atom).getSymbolIndex().?; try self.genSetReg(Type.initTag(.u64), .x30, .{ .linker_load = .{ .type = .got, - .sym_index = fn_owner_decl.link.coff.getSymbolIndex().?, + .sym_index = sym_index, }, }); } else if (self.bin_file.cast(link.File.Plan9)) |p9| { @@ -5496,15 +5499,17 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro .direct => .load_memory_ptr_direct, .import => unreachable, }; - const mod = self.bin_file.options.module.?; - const owner_decl = mod.declPtr(self.mod_fn.owner_decl); const atom_index = switch (self.bin_file.tag) { .macho => blk: { const macho_file = self.bin_file.cast(link.File.MachO).?; const atom = try macho_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl); break :blk macho_file.getAtom(atom).getSymbolIndex().?; }, - .coff => owner_decl.link.coff.getSymbolIndex().?, + .coff => blk: { + const coff_file = self.bin_file.cast(link.File.Coff).?; + const atom = try coff_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl); + break :blk coff_file.getAtom(atom).getSymbolIndex().?; + }, else => unreachable, // unsupported target format }; _ = try self.addInst(.{ @@ -5614,15 +5619,17 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void .direct => .load_memory_direct, .import => .load_memory_import, }; - const mod = self.bin_file.options.module.?; - const owner_decl = mod.declPtr(self.mod_fn.owner_decl); const atom_index = switch (self.bin_file.tag) { .macho => blk: { const macho_file = self.bin_file.cast(link.File.MachO).?; const atom = try macho_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl); break :blk macho_file.getAtom(atom).getSymbolIndex().?; }, - .coff => owner_decl.link.coff.getSymbolIndex().?, + .coff => blk: { + const coff_file = self.bin_file.cast(link.File.Coff).?; + const atom = try coff_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl); + break :blk coff_file.getAtom(atom).getSymbolIndex().?; + }, else => unreachable, // unsupported target format }; _ = try self.addInst(.{ @@ -5812,15 +5819,17 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I .direct => .load_memory_ptr_direct, .import => unreachable, }; - const mod = self.bin_file.options.module.?; - const owner_decl = mod.declPtr(self.mod_fn.owner_decl); const atom_index = switch (self.bin_file.tag) { .macho => blk: { const macho_file = self.bin_file.cast(link.File.MachO).?; const atom = try macho_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl); break :blk macho_file.getAtom(atom).getSymbolIndex().?; }, - .coff => owner_decl.link.coff.getSymbolIndex().?, + .coff => blk: { + const coff_file = self.bin_file.cast(link.File.Coff).?; + const atom = try coff_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl); + break :blk coff_file.getAtom(atom).getSymbolIndex().?; + }, else => unreachable, // unsupported target format }; _ = try self.addInst(.{ @@ -6150,10 +6159,11 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne .sym_index = sym_index, } }; } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { - try decl.link.coff.ensureInitialized(coff_file); + const atom_index = try coff_file.getOrCreateAtomForDecl(decl_index); + const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?; return MCValue{ .linker_load = .{ .type = .got, - .sym_index = decl.link.coff.getSymbolIndex().?, + .sym_index = sym_index, } }; } else if (self.bin_file.cast(link.File.Plan9)) |p9| { try p9.seeDecl(decl_index); diff --git a/src/arch/aarch64/Emit.zig b/src/arch/aarch64/Emit.zig index f348fb70e37677b56a10a26f77bd48ca28754017..3c2a81d5d1a74d733d5beb4fff28169672c1b32b 100644 --- a/src/arch/aarch64/Emit.zig +++ b/src/arch/aarch64/Emit.zig @@ -919,7 +919,7 @@ fn mirLoadMemoryPie(emit: *Emit, inst: Mir.Inst.Index) !void { }, }); } else if (emit.bin_file.cast(link.File.Coff)) |coff_file| { - const atom = coff_file.getAtomForSymbol(.{ .sym_index = data.atom_index, .file = null }).?; + const atom_index = coff_file.getAtomIndexForSymbol(.{ .sym_index = data.atom_index, .file = null }).?; const target = switch (tag) { .load_memory_got, .load_memory_ptr_got, @@ -929,7 +929,7 @@ fn mirLoadMemoryPie(emit: *Emit, inst: Mir.Inst.Index) !void { .load_memory_import => coff_file.getGlobalByIndex(data.sym_index), else => unreachable, }; - try atom.addRelocation(coff_file, .{ + try link.File.Coff.Atom.addRelocation(coff_file, atom_index, .{ .target = target, .offset = offset, .addend = 0, @@ -946,7 +946,7 @@ fn mirLoadMemoryPie(emit: *Emit, inst: Mir.Inst.Index) !void { else => unreachable, }, }); - try atom.addRelocation(coff_file, .{ + try link.File.Coff.Atom.addRelocation(coff_file, atom_index, .{ .target = target, .offset = offset + 4, .addend = 0, diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 23d3ca5514c86eebdd2e4c78e14d20ce5ba1e1c6..b41973ea9742aa26815ed1e2bbfde2484753cefa 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -2668,13 +2668,12 @@ fn loadMemPtrIntoRegister(self: *Self, reg: Register, ptr_ty: Type, ptr: MCValue switch (ptr) { .linker_load => |load_struct| { const abi_size = @intCast(u32, ptr_ty.abiSize(self.target.*)); - const mod = self.bin_file.options.module.?; - const fn_owner_decl = mod.declPtr(self.mod_fn.owner_decl); const atom_index = if (self.bin_file.cast(link.File.MachO)) |macho_file| blk: { const atom = try macho_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl); break :blk macho_file.getAtom(atom).getSymbolIndex().?; - } else if (self.bin_file.cast(link.File.Coff)) |_| blk: { - break :blk fn_owner_decl.link.coff.getSymbolIndex().?; + } else if (self.bin_file.cast(link.File.Coff)) |coff_file| blk: { + const atom = try coff_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl); + break :blk coff_file.getAtom(atom).getSymbolIndex().?; } else unreachable; const flags: u2 = switch (load_struct.type) { .got => 0b00, @@ -4009,8 +4008,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier .data = .{ .imm = got_addr }, }); } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { - try fn_owner_decl.link.coff.ensureInitialized(coff_file); - const sym_index = fn_owner_decl.link.coff.getSymbolIndex().?; + const atom_index = try coff_file.getOrCreateAtomForDecl(func.owner_decl); + const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?; try self.genSetReg(Type.initTag(.usize), .rax, .{ .linker_load = .{ .type = .got, @@ -6733,10 +6732,11 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne .sym_index = sym_index, } }; } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { - try decl.link.coff.ensureInitialized(coff_file); + const atom_index = try coff_file.getOrCreateAtomForDecl(decl_index); + const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?; return MCValue{ .linker_load = .{ .type = .got, - .sym_index = decl.link.coff.getSymbolIndex().?, + .sym_index = sym_index, } }; } else if (self.bin_file.cast(link.File.Plan9)) |p9| { try p9.seeDecl(decl_index); diff --git a/src/arch/x86_64/Emit.zig b/src/arch/x86_64/Emit.zig index 980dbfd41e51eb6f132939d6e02daca9d167002b..c4f9b4eb4237a0665f7259fb360ea53d120b6df6 100644 --- a/src/arch/x86_64/Emit.zig +++ b/src/arch/x86_64/Emit.zig @@ -1011,8 +1011,8 @@ fn mirLeaPic(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { .length = 2, }); } else if (emit.bin_file.cast(link.File.Coff)) |coff_file| { - const atom = coff_file.getAtomForSymbol(.{ .sym_index = relocation.atom_index, .file = null }).?; - try atom.addRelocation(coff_file, .{ + const atom_index = coff_file.getAtomIndexForSymbol(.{ .sym_index = relocation.atom_index, .file = null }).?; + try link.File.Coff.Atom.addRelocation(coff_file, atom_index, .{ .type = switch (ops.flags) { 0b00 => .got, 0b01 => .direct, @@ -1152,9 +1152,9 @@ fn mirCallExtern(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { }); } else if (emit.bin_file.cast(link.File.Coff)) |coff_file| { // Add relocation to the decl. - const atom = coff_file.getAtomForSymbol(.{ .sym_index = relocation.atom_index, .file = null }).?; + const atom_index = coff_file.getAtomIndexForSymbol(.{ .sym_index = relocation.atom_index, .file = null }).?; const target = coff_file.getGlobalByIndex(relocation.sym_index); - try atom.addRelocation(coff_file, .{ + try link.File.Coff.Atom.addRelocation(coff_file, atom_index, .{ .type = .direct, .target = target, .offset = offset, diff --git a/src/link.zig b/src/link.zig index 09804add531c1e5bc5d3c2f915053b43b01556ff..eb74615492f35ee96ea699287fbe97f24e5445ad 100644 --- a/src/link.zig +++ b/src/link.zig @@ -263,7 +263,7 @@ pub const File = struct { pub const LinkBlock = union { elf: void, - coff: Coff.Atom, + coff: void, macho: void, plan9: Plan9.DeclBlock, c: void, @@ -285,7 +285,7 @@ pub const File = struct { pub const Export = union { elf: void, - coff: Coff.Export, + coff: void, macho: void, plan9: Plan9.Export, c: void, diff --git a/src/link/Coff.zig b/src/link/Coff.zig index dee3c7c381ebaa40a1fd121f8326369add74cf2d..c062276b73e5b3b997395085974bab07e13552cf 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -79,13 +79,13 @@ entry_addr: ?u32 = null, /// We store them here so that we can properly dispose of any allocated /// memory within the atom in the incremental linker. /// TODO consolidate this. -decls: std.AutoHashMapUnmanaged(Module.Decl.Index, ?u16) = .{}, +decls: std.AutoHashMapUnmanaged(Module.Decl.Index, DeclMetadata) = .{}, /// List of atoms that are either synthetic or map directly to the Zig source program. -managed_atoms: std.ArrayListUnmanaged(*Atom) = .{}, +atoms: std.ArrayListUnmanaged(Atom) = .{}, /// Table of atoms indexed by the symbol index. -atom_by_index_table: std.AutoHashMapUnmanaged(u32, *Atom) = .{}, +atom_by_index_table: std.AutoHashMapUnmanaged(u32, Atom.Index) = .{}, /// Table of unnamed constants associated with a parent `Decl`. /// We store them here so that we can free the constants whenever the `Decl` @@ -124,9 +124,9 @@ const Entry = struct { sym_index: u32, }; -const RelocTable = std.AutoHashMapUnmanaged(*Atom, std.ArrayListUnmanaged(Relocation)); -const BaseRelocationTable = std.AutoHashMapUnmanaged(*Atom, std.ArrayListUnmanaged(u32)); -const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(*Atom)); +const RelocTable = std.AutoHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Relocation)); +const BaseRelocationTable = std.AutoHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(u32)); +const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Atom.Index)); const default_file_alignment: u16 = 0x200; const default_size_of_stack_reserve: u32 = 0x1000000; @@ -137,7 +137,7 @@ const default_size_of_heap_commit: u32 = 0x1000; const Section = struct { header: coff.SectionHeader, - last_atom: ?*Atom = null, + last_atom_index: ?Atom.Index = null, /// A list of atoms that have surplus capacity. This list can have false /// positives, as functions grow and shrink over time, only sometimes being added @@ -154,7 +154,34 @@ const Section = struct { /// overcapacity can be negative. A simple way to have negative overcapacity is to /// allocate a fresh atom, which will have ideal capacity, and then grow it /// by 1 byte. It will then have -1 overcapacity. - free_list: std.ArrayListUnmanaged(*Atom) = .{}, + free_list: std.ArrayListUnmanaged(Atom.Index) = .{}, +}; + +const DeclMetadata = struct { + atom: Atom.Index, + section: u16, + /// A list of all exports aliases of this Decl. + exports: std.ArrayListUnmanaged(u32) = .{}, + + fn getExport(m: DeclMetadata, coff_file: *const Coff, name: []const u8) ?u32 { + for (m.exports.items) |exp| { + if (mem.eql(u8, name, coff_file.getSymbolName(.{ + .sym_index = exp, + .file = null, + }))) return exp; + } + return null; + } + + fn getExportPtr(m: *DeclMetadata, coff_file: *Coff, name: []const u8) ?*u32 { + for (m.exports.items) |*exp| { + if (mem.eql(u8, name, coff_file.getSymbolName(.{ + .sym_index = exp.*, + .file = null, + }))) return exp; + } + return null; + } }; pub const PtrWidth = enum { @@ -170,10 +197,6 @@ pub const PtrWidth = enum { }; pub const SrcFn = void; -pub const Export = struct { - sym_index: ?u32 = null, -}; - pub const SymbolWithLoc = struct { // Index into the respective symbol table. sym_index: u32, @@ -271,11 +294,7 @@ pub fn deinit(self: *Coff) void { } self.sections.deinit(gpa); - for (self.managed_atoms.items) |atom| { - gpa.destroy(atom); - } - self.managed_atoms.deinit(gpa); - + self.atoms.deinit(gpa); self.locals.deinit(gpa); self.globals.deinit(gpa); @@ -297,7 +316,15 @@ pub fn deinit(self: *Coff) void { self.imports.deinit(gpa); self.imports_free_list.deinit(gpa); self.imports_table.deinit(gpa); - self.decls.deinit(gpa); + + { + var it = self.decls.iterator(); + while (it.next()) |entry| { + entry.value_ptr.exports.deinit(gpa); + } + self.decls.deinit(gpa); + } + self.atom_by_index_table.deinit(gpa); { @@ -461,17 +488,18 @@ fn growSectionVM(self: *Coff, sect_id: u32, needed_size: u32) !void { // TODO: enforce order by increasing VM addresses in self.sections container. // This is required by the loader anyhow as far as I can tell. for (self.sections.items(.header)[sect_id + 1 ..]) |*next_header, next_sect_id| { - const maybe_last_atom = &self.sections.items(.last_atom)[sect_id + 1 + next_sect_id]; + const maybe_last_atom_index = self.sections.items(.last_atom_index)[sect_id + 1 + next_sect_id]; next_header.virtual_address += diff; - if (maybe_last_atom.*) |last_atom| { - var atom = last_atom; + if (maybe_last_atom_index) |last_atom_index| { + var atom_index = last_atom_index; while (true) { + const atom = self.getAtom(atom_index); const sym = atom.getSymbolPtr(self); sym.value += diff; - if (atom.prev) |prev| { - atom = prev; + if (atom.prev_index) |prev_index| { + atom_index = prev_index; } else break; } } @@ -480,14 +508,15 @@ fn growSectionVM(self: *Coff, sect_id: u32, needed_size: u32) !void { header.virtual_size = increased_size; } -fn allocateAtom(self: *Coff, atom: *Atom, new_atom_size: u32, alignment: u32) !u32 { +fn allocateAtom(self: *Coff, atom_index: Atom.Index, new_atom_size: u32, alignment: u32) !u32 { const tracy = trace(@src()); defer tracy.end(); + const atom = self.getAtom(atom_index); const sect_id = @enumToInt(atom.getSymbol(self).section_number) - 1; const header = &self.sections.items(.header)[sect_id]; const free_list = &self.sections.items(.free_list)[sect_id]; - const maybe_last_atom = &self.sections.items(.last_atom)[sect_id]; + const maybe_last_atom_index = &self.sections.items(.last_atom_index)[sect_id]; const new_atom_ideal_capacity = if (header.isCode()) padToIdeal(new_atom_size) else new_atom_size; // We use these to indicate our intention to update metadata, placing the new atom, @@ -495,7 +524,7 @@ fn allocateAtom(self: *Coff, atom: *Atom, new_atom_size: u32, alignment: u32) !u // 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 atom_placement: ?*Atom = null; + var atom_placement: ?Atom.Index = null; var free_list_removal: ?usize = null; // First we look for an appropriately sized free list node. @@ -503,7 +532,8 @@ fn allocateAtom(self: *Coff, atom: *Atom, new_atom_size: u32, alignment: u32) !u var vaddr = blk: { var i: usize = 0; while (i < free_list.items.len) { - const big_atom = free_list.items[i]; + const big_atom_index = free_list.items[i]; + const big_atom = self.getAtom(big_atom_index); // We now have a pointer to a live atom that has too much capacity. // Is it enough that we could fit this new atom? const sym = big_atom.getSymbol(self); @@ -531,34 +561,43 @@ fn allocateAtom(self: *Coff, atom: *Atom, new_atom_size: u32, alignment: u32) !u const keep_free_list_node = remaining_capacity >= min_text_capacity; // Set up the metadata to be updated, after errors are no longer possible. - atom_placement = big_atom; + atom_placement = big_atom_index; if (!keep_free_list_node) { free_list_removal = i; } break :blk new_start_vaddr; - } else if (maybe_last_atom.*) |last| { + } else if (maybe_last_atom_index.*) |last_index| { + const last = self.getAtom(last_index); const last_symbol = last.getSymbol(self); const ideal_capacity = if (header.isCode()) padToIdeal(last.size) else last.size; const ideal_capacity_end_vaddr = last_symbol.value + ideal_capacity; const new_start_vaddr = mem.alignForwardGeneric(u32, ideal_capacity_end_vaddr, alignment); - atom_placement = last; + atom_placement = last_index; break :blk new_start_vaddr; } else { break :blk mem.alignForwardGeneric(u32, header.virtual_address, alignment); } }; - const expand_section = atom_placement == null or atom_placement.?.next == null; + const expand_section = if (atom_placement) |placement_index| + self.getAtom(placement_index).next_index == null + else + true; if (expand_section) { const sect_capacity = self.allocatedSize(header.pointer_to_raw_data); const needed_size: u32 = (vaddr + new_atom_size) - header.virtual_address; if (needed_size > sect_capacity) { const new_offset = self.findFreeSpace(needed_size, default_file_alignment); - const current_size = if (maybe_last_atom.*) |last_atom| blk: { + const current_size = if (maybe_last_atom_index.*) |last_atom_index| blk: { + const last_atom = self.getAtom(last_atom_index); const sym = last_atom.getSymbol(self); break :blk (sym.value + last_atom.size) - header.virtual_address; } else 0; - log.debug("moving {s} from 0x{x} to 0x{x}", .{ self.getSectionName(header), header.pointer_to_raw_data, new_offset }); + log.debug("moving {s} from 0x{x} to 0x{x}", .{ + self.getSectionName(header), + header.pointer_to_raw_data, + new_offset, + }); const amt = try self.base.file.?.copyRangeAll( header.pointer_to_raw_data, self.base.file.?, @@ -577,26 +616,34 @@ fn allocateAtom(self: *Coff, atom: *Atom, new_atom_size: u32, alignment: u32) !u header.virtual_size = @max(header.virtual_size, needed_size); header.size_of_raw_data = needed_size; - maybe_last_atom.* = atom; + maybe_last_atom_index.* = atom_index; } - atom.size = new_atom_size; - atom.alignment = alignment; + { + const atom_ptr = self.getAtomPtr(atom_index); + atom_ptr.size = new_atom_size; + atom_ptr.alignment = alignment; + } - if (atom.prev) |prev| { - prev.next = atom.next; + if (atom.prev_index) |prev_index| { + const prev = self.getAtomPtr(prev_index); + prev.next_index = atom.next_index; } - if (atom.next) |next| { - next.prev = atom.prev; + if (atom.next_index) |next_index| { + const next = self.getAtomPtr(next_index); + next.prev_index = atom.prev_index; } - if (atom_placement) |big_atom| { - atom.prev = big_atom; - atom.next = big_atom.next; - big_atom.next = atom; + if (atom_placement) |big_atom_index| { + const big_atom = self.getAtomPtr(big_atom_index); + const atom_ptr = self.getAtomPtr(atom_index); + atom_ptr.prev_index = big_atom_index; + atom_ptr.next_index = big_atom.next_index; + big_atom.next_index = atom_index; } else { - atom.prev = null; - atom.next = null; + const atom_ptr = self.getAtomPtr(atom_index); + atom_ptr.prev_index = null; + atom_ptr.next_index = null; } if (free_list_removal) |i| { _ = free_list.swapRemove(i); @@ -701,24 +748,37 @@ pub fn allocateImportEntry(self: *Coff, target: SymbolWithLoc) !u32 { return index; } -fn createGotAtom(self: *Coff, target: SymbolWithLoc) !*Atom { +pub fn createAtom(self: *Coff) !Atom.Index { const gpa = self.base.allocator; - const atom = try gpa.create(Atom); - errdefer gpa.destroy(atom); - atom.* = Atom.empty; - try atom.ensureInitialized(self); + const atom_index = @intCast(Atom.Index, self.atoms.items.len); + const atom = try self.atoms.addOne(gpa); + const sym_index = try self.allocateSymbol(); + try self.atom_by_index_table.putNoClobber(gpa, sym_index, atom_index); + atom.* = .{ + .sym_index = sym_index, + .file = null, + .size = 0, + .alignment = 0, + .prev_index = null, + .next_index = null, + }; + log.debug("creating ATOM(%{d}) at index {d}", .{ sym_index, atom_index }); + return atom_index; +} + +fn createGotAtom(self: *Coff, target: SymbolWithLoc) !Atom.Index { + const atom_index = try self.createAtom(); + const atom = self.getAtomPtr(atom_index); atom.size = @sizeOf(u64); atom.alignment = @alignOf(u64); - try self.managed_atoms.append(gpa, atom); - const sym = atom.getSymbolPtr(self); sym.section_number = @intToEnum(coff.SectionNumber, self.got_section_index.? + 1); - sym.value = try self.allocateAtom(atom, atom.size, atom.alignment); + sym.value = try self.allocateAtom(atom_index, atom.size, atom.alignment); log.debug("allocated GOT atom at 0x{x}", .{sym.value}); - try atom.addRelocation(self, .{ + try Atom.addRelocation(self, atom_index, .{ .type = .direct, .target = target, .offset = 0, @@ -732,49 +792,46 @@ fn createGotAtom(self: *Coff, target: SymbolWithLoc) !*Atom { .UNDEFINED => @panic("TODO generate a binding for undefined GOT target"), .ABSOLUTE => {}, .DEBUG => unreachable, // not possible - else => try atom.addBaseRelocation(self, 0), + else => try Atom.addBaseRelocation(self, atom_index, 0), } - return atom; + return atom_index; } -fn createImportAtom(self: *Coff) !*Atom { - const gpa = self.base.allocator; - const atom = try gpa.create(Atom); - errdefer gpa.destroy(atom); - atom.* = Atom.empty; - try atom.ensureInitialized(self); +fn createImportAtom(self: *Coff) !Atom.Index { + const atom_index = try self.createAtom(); + const atom = self.getAtomPtr(atom_index); atom.size = @sizeOf(u64); atom.alignment = @alignOf(u64); - try self.managed_atoms.append(gpa, atom); - const sym = atom.getSymbolPtr(self); sym.section_number = @intToEnum(coff.SectionNumber, self.idata_section_index.? + 1); - sym.value = try self.allocateAtom(atom, atom.size, atom.alignment); + sym.value = try self.allocateAtom(atom_index, atom.size, atom.alignment); log.debug("allocated import atom at 0x{x}", .{sym.value}); - return atom; + return atom_index; } -fn growAtom(self: *Coff, atom: *Atom, new_atom_size: u32, alignment: u32) !u32 { +fn growAtom(self: *Coff, atom_index: Atom.Index, new_atom_size: u32, alignment: u32) !u32 { + const atom = self.getAtom(atom_index); const sym = atom.getSymbol(self); const align_ok = mem.alignBackwardGeneric(u32, sym.value, alignment) == sym.value; const need_realloc = !align_ok or new_atom_size > atom.capacity(self); if (!need_realloc) return sym.value; - return self.allocateAtom(atom, new_atom_size, alignment); + return self.allocateAtom(atom_index, new_atom_size, alignment); } -fn shrinkAtom(self: *Coff, atom: *Atom, new_block_size: u32) void { +fn shrinkAtom(self: *Coff, atom_index: Atom.Index, new_block_size: u32) void { _ = self; - _ = atom; + _ = atom_index; _ = new_block_size; // 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 writeAtom(self: *Coff, atom: *Atom, code: []const u8) !void { +fn writeAtom(self: *Coff, atom_index: Atom.Index, code: []const u8) !void { + const atom = self.getAtom(atom_index); const sym = atom.getSymbol(self); const section = self.sections.get(@enumToInt(sym.section_number) - 1); const file_offset = section.header.pointer_to_raw_data + sym.value - section.header.virtual_address; @@ -784,18 +841,18 @@ fn writeAtom(self: *Coff, atom: *Atom, code: []const u8) !void { file_offset + code.len, }); try self.base.file.?.pwriteAll(code, file_offset); - try self.resolveRelocs(atom); + try self.resolveRelocs(atom_index); } -fn writePtrWidthAtom(self: *Coff, atom: *Atom) !void { +fn writePtrWidthAtom(self: *Coff, atom_index: Atom.Index) !void { switch (self.ptr_width) { .p32 => { var buffer: [@sizeOf(u32)]u8 = [_]u8{0} ** @sizeOf(u32); - try self.writeAtom(atom, &buffer); + try self.writeAtom(atom_index, &buffer); }, .p64 => { var buffer: [@sizeOf(u64)]u8 = [_]u8{0} ** @sizeOf(u64); - try self.writeAtom(atom, &buffer); + try self.writeAtom(atom_index, &buffer); }, } } @@ -815,7 +872,8 @@ fn markRelocsDirtyByAddress(self: *Coff, addr: u32) void { var it = self.relocs.valueIterator(); while (it.next()) |relocs| { for (relocs.items) |*reloc| { - const target_atom = reloc.getTargetAtom(self) orelse continue; + const target_atom_index = reloc.getTargetAtomIndex(self) orelse continue; + const target_atom = self.getAtom(target_atom_index); const target_sym = target_atom.getSymbol(self); if (target_sym.value < addr) continue; reloc.dirty = true; @@ -823,24 +881,26 @@ fn markRelocsDirtyByAddress(self: *Coff, addr: u32) void { } } -fn resolveRelocs(self: *Coff, atom: *Atom) !void { - const relocs = self.relocs.get(atom) orelse return; +fn resolveRelocs(self: *Coff, atom_index: Atom.Index) !void { + const relocs = self.relocs.get(atom_index) orelse return; - log.debug("relocating '{s}'", .{atom.getName(self)}); + log.debug("relocating '{s}'", .{self.getAtom(atom_index).getName(self)}); for (relocs.items) |*reloc| { if (!reloc.dirty) continue; - try reloc.resolve(atom, self); + try reloc.resolve(atom_index, self); } } -fn freeAtom(self: *Coff, atom: *Atom) void { - log.debug("freeAtom {*}", .{atom}); +fn freeAtom(self: *Coff, atom_index: Atom.Index) void { + log.debug("freeAtom {d}", .{atom_index}); + + const gpa = self.base.allocator; // Remove any relocs and base relocs associated with this Atom - self.freeRelocationsForAtom(atom); + Atom.freeRelocations(self, atom_index); - const gpa = self.base.allocator; + const atom = self.getAtom(atom_index); const sym = atom.getSymbol(self); const sect_id = @enumToInt(sym.section_number) - 1; const free_list = &self.sections.items(.free_list)[sect_id]; @@ -849,45 +909,46 @@ fn freeAtom(self: *Coff, atom: *Atom) void { var i: usize = 0; // TODO turn free_list into a hash map while (i < free_list.items.len) { - if (free_list.items[i] == atom) { + if (free_list.items[i] == atom_index) { _ = free_list.swapRemove(i); continue; } - if (free_list.items[i] == atom.prev) { + if (free_list.items[i] == atom.prev_index) { already_have_free_list_node = true; } i += 1; } } - const maybe_last_atom = &self.sections.items(.last_atom)[sect_id]; - if (maybe_last_atom.*) |last_atom| { - if (last_atom == atom) { - if (atom.prev) |prev| { + const maybe_last_atom_index = &self.sections.items(.last_atom_index)[sect_id]; + if (maybe_last_atom_index.*) |last_atom_index| { + if (last_atom_index == atom_index) { + if (atom.prev_index) |prev_index| { // TODO shrink the section size here - maybe_last_atom.* = prev; + maybe_last_atom_index.* = prev_index; } else { - maybe_last_atom.* = null; + maybe_last_atom_index.* = null; } } } - if (atom.prev) |prev| { - prev.next = atom.next; + if (atom.prev_index) |prev_index| { + const prev = self.getAtomPtr(prev_index); + prev.next_index = atom.next_index; - if (!already_have_free_list_node and prev.freeListEligible(self)) { + 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. - free_list.append(gpa, prev) catch {}; + free_list.append(gpa, prev_index) catch {}; } } else { - atom.prev = null; + self.getAtomPtr(atom_index).prev_index = null; } - if (atom.next) |next| { - next.prev = atom.prev; + if (atom.next_index) |next_index| { + self.getAtomPtr(next_index).prev_index = atom.prev_index; } else { - atom.next = null; + self.getAtomPtr(atom_index).next_index = null; } // Appending to free lists is allowed to fail because the free lists are heuristics based anyway. @@ -910,7 +971,7 @@ fn freeAtom(self: *Coff, atom: *Atom) void { self.locals.items[sym_index].section_number = .UNDEFINED; _ = self.atom_by_index_table.remove(sym_index); log.debug(" adding local symbol index {d} to free list", .{sym_index}); - atom.sym_index = 0; + self.getAtomPtr(atom_index).sym_index = 0; } pub fn updateFunc(self: *Coff, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void { @@ -927,15 +988,10 @@ pub fn updateFunc(self: *Coff, module: *Module, func: *Module.Fn, air: Air, live const decl_index = func.owner_decl; const decl = module.declPtr(decl_index); - const atom = &decl.link.coff; - try atom.ensureInitialized(self); - const gop = try self.decls.getOrPut(self.base.allocator, decl_index); - if (gop.found_existing) { - self.freeUnnamedConsts(decl_index); - self.freeRelocationsForAtom(&decl.link.coff); - } else { - gop.value_ptr.* = null; - } + + const atom_index = try self.getOrCreateAtomForDecl(decl_index); + self.freeUnnamedConsts(decl_index); + Atom.freeRelocations(self, atom_index); var code_buffer = std.ArrayList(u8).init(self.base.allocator); defer code_buffer.deinit(); @@ -979,11 +1035,8 @@ pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.In } const unnamed_consts = gop.value_ptr; - const atom = try gpa.create(Atom); - errdefer gpa.destroy(atom); - atom.* = Atom.empty; - try atom.ensureInitialized(self); - try self.managed_atoms.append(gpa, atom); + const atom_index = try self.createAtom(); + const atom = self.getAtomPtr(atom_index); const sym_name = blk: { const decl_name = try decl.getFullyQualifiedName(mod); @@ -1012,15 +1065,15 @@ pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.In const required_alignment = tv.ty.abiAlignment(self.base.options.target); atom.alignment = required_alignment; atom.size = @intCast(u32, code.len); - atom.getSymbolPtr(self).value = try self.allocateAtom(atom, atom.size, atom.alignment); - errdefer self.freeAtom(atom); + atom.getSymbolPtr(self).value = try self.allocateAtom(atom_index, atom.size, atom.alignment); + errdefer self.freeAtom(atom_index); - try unnamed_consts.append(gpa, atom); + try unnamed_consts.append(gpa, atom_index); log.debug("allocated atom for {s} at 0x{x}", .{ sym_name, atom.getSymbol(self).value }); log.debug(" (required alignment 0x{x})", .{required_alignment}); - try self.writeAtom(atom, code); + try self.writeAtom(atom_index, code); return atom.getSymbolIndex().?; } @@ -1047,14 +1100,9 @@ pub fn updateDecl(self: *Coff, module: *Module, decl_index: Module.Decl.Index) ! } } - const atom = &decl.link.coff; - try atom.ensureInitialized(self); - const gop = try self.decls.getOrPut(self.base.allocator, decl_index); - if (gop.found_existing) { - self.freeRelocationsForAtom(atom); - } else { - gop.value_ptr.* = null; - } + const atom_index = try self.getOrCreateAtomForDecl(decl_index); + Atom.freeRelocations(self, atom_index); + const atom = self.getAtom(atom_index); var code_buffer = std.ArrayList(u8).init(self.base.allocator); defer code_buffer.deinit(); @@ -1064,7 +1112,7 @@ pub fn updateDecl(self: *Coff, module: *Module, decl_index: Module.Decl.Index) ! .ty = decl.ty, .val = decl_val, }, &code_buffer, .none, .{ - .parent_atom_index = decl.link.coff.getSymbolIndex().?, + .parent_atom_index = atom.getSymbolIndex().?, }); const code = switch (res) { .ok => code_buffer.items, @@ -1082,7 +1130,20 @@ pub fn updateDecl(self: *Coff, module: *Module, decl_index: Module.Decl.Index) ! return self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index)); } -fn getDeclOutputSection(self: *Coff, decl: *Module.Decl) u16 { +pub fn getOrCreateAtomForDecl(self: *Coff, decl_index: Module.Decl.Index) !Atom.Index { + const gop = try self.decls.getOrPut(self.base.allocator, decl_index); + if (!gop.found_existing) { + gop.value_ptr.* = .{ + .atom = try self.createAtom(), + .section = self.getDeclOutputSection(decl_index), + .exports = .{}, + }; + } + return gop.value_ptr.atom; +} + +fn getDeclOutputSection(self: *Coff, decl_index: Module.Decl.Index) u16 { + const decl = self.base.options.module.?.declPtr(decl_index); const ty = decl.ty; const zig_ty = ty.zigTypeTag(); const val = decl.val; @@ -1117,14 +1178,11 @@ fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []const u8, log.debug("updateDeclCode {s}{*}", .{ decl_name, decl }); const required_alignment = decl.getAlignment(self.base.options.target); - const decl_ptr = self.decls.getPtr(decl_index).?; - if (decl_ptr.* == null) { - decl_ptr.* = self.getDeclOutputSection(decl); - } - const sect_index = decl_ptr.*.?; - + const decl_metadata = self.decls.get(decl_index).?; + const atom_index = decl_metadata.atom; + const atom = self.getAtom(atom_index); + const sect_index = decl_metadata.section; const code_len = @intCast(u32, code.len); - const atom = &decl.link.coff; if (atom.size != 0) { const sym = atom.getSymbolPtr(self); @@ -1135,7 +1193,7 @@ fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []const u8, const capacity = atom.capacity(self); const need_realloc = code.len > capacity or !mem.isAlignedGeneric(u64, sym.value, required_alignment); if (need_realloc) { - const vaddr = try self.growAtom(atom, code_len, required_alignment); + const vaddr = try self.growAtom(atom_index, code_len, required_alignment); log.debug("growing {s} from 0x{x} to 0x{x}", .{ decl_name, sym.value, vaddr }); log.debug(" (required alignment 0x{x}", .{required_alignment}); @@ -1143,49 +1201,43 @@ fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []const u8, sym.value = vaddr; log.debug(" (updating GOT entry)", .{}); const got_target = SymbolWithLoc{ .sym_index = atom.getSymbolIndex().?, .file = null }; - const got_atom = self.getGotAtomForSymbol(got_target).?; + const got_atom_index = self.getGotAtomIndexForSymbol(got_target).?; self.markRelocsDirtyByTarget(got_target); - try self.writePtrWidthAtom(got_atom); + try self.writePtrWidthAtom(got_atom_index); } } else if (code_len < atom.size) { - self.shrinkAtom(atom, code_len); + self.shrinkAtom(atom_index, code_len); } - atom.size = code_len; + self.getAtomPtr(atom_index).size = code_len; } else { const sym = atom.getSymbolPtr(self); try self.setSymbolName(sym, decl_name); sym.section_number = @intToEnum(coff.SectionNumber, sect_index + 1); sym.type = .{ .complex_type = complex_type, .base_type = .NULL }; - const vaddr = try self.allocateAtom(atom, code_len, required_alignment); - errdefer self.freeAtom(atom); + const vaddr = try self.allocateAtom(atom_index, code_len, required_alignment); + errdefer self.freeAtom(atom_index); log.debug("allocated atom for {s} at 0x{x}", .{ decl_name, vaddr }); - atom.size = code_len; + self.getAtomPtr(atom_index).size = code_len; sym.value = vaddr; const got_target = SymbolWithLoc{ .sym_index = atom.getSymbolIndex().?, .file = null }; const got_index = try self.allocateGotEntry(got_target); - const got_atom = try self.createGotAtom(got_target); + const got_atom_index = try self.createGotAtom(got_target); + const got_atom = self.getAtom(got_atom_index); self.got_entries.items[got_index].sym_index = got_atom.getSymbolIndex().?; - try self.writePtrWidthAtom(got_atom); + try self.writePtrWidthAtom(got_atom_index); } self.markRelocsDirtyByTarget(atom.getSymbolWithLoc()); - try self.writeAtom(atom, code); -} - -fn freeRelocationsForAtom(self: *Coff, atom: *Atom) void { - var removed_relocs = self.relocs.fetchRemove(atom); - if (removed_relocs) |*relocs| relocs.value.deinit(self.base.allocator); - var removed_base_relocs = self.base_relocs.fetchRemove(atom); - if (removed_base_relocs) |*base_relocs| base_relocs.value.deinit(self.base.allocator); + try self.writeAtom(atom_index, code); } fn freeUnnamedConsts(self: *Coff, decl_index: Module.Decl.Index) void { const gpa = self.base.allocator; const unnamed_consts = self.unnamed_const_atoms.getPtr(decl_index) orelse return; - for (unnamed_consts.items) |atom| { - self.freeAtom(atom); + for (unnamed_consts.items) |atom_index| { + self.freeAtom(atom_index); } unnamed_consts.clearAndFree(gpa); } @@ -1200,11 +1252,11 @@ pub fn freeDecl(self: *Coff, decl_index: Module.Decl.Index) void { log.debug("freeDecl {*}", .{decl}); - if (self.decls.fetchRemove(decl_index)) |kv| { - if (kv.value) |_| { - self.freeAtom(&decl.link.coff); - self.freeUnnamedConsts(decl_index); - } + if (self.decls.fetchRemove(decl_index)) |const_kv| { + var kv = const_kv; + self.freeAtom(kv.value.atom); + self.freeUnnamedConsts(decl_index); + kv.value.exports.deinit(self.base.allocator); } } @@ -1257,16 +1309,10 @@ pub fn updateDeclExports( const gpa = self.base.allocator; const decl = module.declPtr(decl_index); - const atom = &decl.link.coff; - - if (atom.getSymbolIndex() == null) return; - - const gop = try self.decls.getOrPut(gpa, decl_index); - if (!gop.found_existing) { - gop.value_ptr.* = self.getDeclOutputSection(decl); - } - + const atom_index = try self.getOrCreateAtomForDecl(decl_index); + const atom = self.getAtom(atom_index); const decl_sym = atom.getSymbol(self); + const decl_metadata = self.decls.getPtr(decl_index).?; for (exports) |exp| { log.debug("adding new export '{s}'", .{exp.options.name}); @@ -1301,9 +1347,9 @@ pub fn updateDeclExports( continue; } - const sym_index = exp.link.coff.sym_index orelse blk: { + const sym_index = decl_metadata.getExport(self, exp.options.name) orelse blk: { const sym_index = try self.allocateSymbol(); - exp.link.coff.sym_index = sym_index; + try decl_metadata.exports.append(gpa, sym_index); break :blk sym_index; }; const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = null }; @@ -1326,16 +1372,15 @@ pub fn updateDeclExports( } } -pub fn deleteExport(self: *Coff, exp: Export) void { +pub fn deleteDeclExport(self: *Coff, decl_index: Module.Decl.Index, name: []const u8) void { if (self.llvm_object) |_| return; - const sym_index = exp.sym_index orelse return; + const metadata = self.decls.getPtr(decl_index) orelse return; + const sym_index = metadata.getExportPtr(self, name) orelse return; const gpa = self.base.allocator; - - const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = null }; + const sym_loc = SymbolWithLoc{ .sym_index = sym_index.*, .file = null }; const sym = self.getSymbolPtr(sym_loc); - const sym_name = self.getSymbolName(sym_loc); - log.debug("deleting export '{s}'", .{sym_name}); + log.debug("deleting export '{s}'", .{name}); assert(sym.storage_class == .EXTERNAL and sym.section_number != .UNDEFINED); sym.* = .{ .name = [_]u8{0} ** 8, @@ -1345,9 +1390,9 @@ pub fn deleteExport(self: *Coff, exp: Export) void { .storage_class = .NULL, .number_of_aux_symbols = 0, }; - self.locals_free_list.append(gpa, sym_index) catch {}; + self.locals_free_list.append(gpa, sym_index.*) catch {}; - if (self.resolver.fetchRemove(sym_name)) |entry| { + if (self.resolver.fetchRemove(name)) |entry| { defer gpa.free(entry.key); self.globals_free_list.append(gpa, entry.value) catch {}; self.globals.items[entry.value] = .{ @@ -1355,6 +1400,8 @@ pub fn deleteExport(self: *Coff, exp: Export) void { .file = null, }; } + + sym_index.* = 0; } fn resolveGlobalSymbol(self: *Coff, current: SymbolWithLoc) !void { @@ -1419,9 +1466,10 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod if (self.imports_table.contains(global)) continue; const import_index = try self.allocateImportEntry(global); - const import_atom = try self.createImportAtom(); + const import_atom_index = try self.createImportAtom(); + const import_atom = self.getAtom(import_atom_index); self.imports.items[import_index].sym_index = import_atom.getSymbolIndex().?; - try self.writePtrWidthAtom(import_atom); + try self.writePtrWidthAtom(import_atom_index); } if (build_options.enable_logging) { @@ -1455,22 +1503,14 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod } } -pub fn getDeclVAddr( - self: *Coff, - decl_index: Module.Decl.Index, - reloc_info: link.File.RelocInfo, -) !u64 { - const mod = self.base.options.module.?; - const decl = mod.declPtr(decl_index); - +pub fn getDeclVAddr(self: *Coff, decl_index: Module.Decl.Index, reloc_info: link.File.RelocInfo) !u64 { assert(self.llvm_object == null); - try decl.link.coff.ensureInitialized(self); - const sym_index = decl.link.coff.getSymbolIndex().?; - - const atom = self.getAtomForSymbol(.{ .sym_index = reloc_info.parent_atom_index, .file = null }).?; + const this_atom_index = try self.getOrCreateAtomForDecl(decl_index); + const sym_index = self.getAtom(this_atom_index).getSymbolIndex().?; + const atom_index = self.getAtomIndexForSymbol(.{ .sym_index = reloc_info.parent_atom_index, .file = null }).?; const target = SymbolWithLoc{ .sym_index = sym_index, .file = null }; - try atom.addRelocation(self, .{ + try Atom.addRelocation(self, atom_index, .{ .type = .direct, .target = target, .offset = @intCast(u32, reloc_info.offset), @@ -1478,7 +1518,7 @@ pub fn getDeclVAddr( .pcrel = false, .length = 3, }); - try atom.addBaseRelocation(self, @intCast(u32, reloc_info.offset)); + try Atom.addBaseRelocation(self, atom_index, @intCast(u32, reloc_info.offset)); return 0; } @@ -1529,7 +1569,8 @@ fn writeBaseRelocations(self: *Coff) !void { var it = self.base_relocs.iterator(); while (it.next()) |entry| { - const atom = entry.key_ptr.*; + const atom_index = entry.key_ptr.*; + const atom = self.getAtom(atom_index); const offsets = entry.value_ptr.*; for (offsets.items) |offset| { @@ -1613,7 +1654,8 @@ fn writeImportTable(self: *Coff) !void { const gpa = self.base.allocator; const section = self.sections.get(self.idata_section_index.?); - const last_atom = section.last_atom orelse return; + const last_atom_index = section.last_atom_index orelse return; + const last_atom = self.getAtom(last_atom_index); const iat_rva = section.header.virtual_address; const iat_size = last_atom.getSymbol(self).value + last_atom.size * 2 - iat_rva; // account for sentinel zero pointer @@ -2051,27 +2093,37 @@ pub fn getOrPutGlobalPtr(self: *Coff, name: []const u8) !GetOrPutGlobalPtrResult return GetOrPutGlobalPtrResult{ .found_existing = false, .value_ptr = ptr }; } +pub fn getAtom(self: *const Coff, atom_index: Atom.Index) Atom { + assert(atom_index < self.atoms.items.len); + return self.atoms.items[atom_index]; +} + +pub fn getAtomPtr(self: *Coff, atom_index: Atom.Index) *Atom { + assert(atom_index < self.atoms.items.len); + return &self.atoms.items[atom_index]; +} + /// Returns atom if there is an atom referenced by the symbol described by `sym_loc` descriptor. /// Returns null on failure. -pub fn getAtomForSymbol(self: *Coff, sym_loc: SymbolWithLoc) ?*Atom { +pub fn getAtomIndexForSymbol(self: *const Coff, sym_loc: SymbolWithLoc) ?Atom.Index { assert(sym_loc.file == null); // TODO linking with object files return self.atom_by_index_table.get(sym_loc.sym_index); } /// Returns GOT atom that references `sym_loc` if one exists. /// Returns null otherwise. -pub fn getGotAtomForSymbol(self: *Coff, sym_loc: SymbolWithLoc) ?*Atom { +pub fn getGotAtomIndexForSymbol(self: *const Coff, sym_loc: SymbolWithLoc) ?Atom.Index { const got_index = self.got_entries_table.get(sym_loc) orelse return null; const got_entry = self.got_entries.items[got_index]; - return self.getAtomForSymbol(.{ .sym_index = got_entry.sym_index, .file = null }); + return self.getAtomIndexForSymbol(.{ .sym_index = got_entry.sym_index, .file = null }); } /// Returns import atom that references `sym_loc` if one exists. /// Returns null otherwise. -pub fn getImportAtomForSymbol(self: *Coff, sym_loc: SymbolWithLoc) ?*Atom { +pub fn getImportAtomIndexForSymbol(self: *const Coff, sym_loc: SymbolWithLoc) ?Atom.Index { const imports_index = self.imports_table.get(sym_loc) orelse return null; const imports_entry = self.imports.items[imports_index]; - return self.getAtomForSymbol(.{ .sym_index = imports_entry.sym_index, .file = null }); + return self.getAtomIndexForSymbol(.{ .sym_index = imports_entry.sym_index, .file = null }); } fn setSectionName(self: *Coff, header: *coff.SectionHeader, name: []const u8) !void { diff --git a/src/link/Coff/Atom.zig b/src/link/Coff/Atom.zig index 78824eac1dc3d9de6346c66fe2c90991a50be483..1ee31cccaadc03dcd1363cb348d3ae9892365755 100644 --- a/src/link/Coff/Atom.zig +++ b/src/link/Coff/Atom.zig @@ -27,23 +27,10 @@ alignment: 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 `Atom`. -prev: ?*Atom, -next: ?*Atom, +prev_index: ?Index, +next_index: ?Index, -pub const empty = Atom{ - .sym_index = 0, - .file = null, - .size = 0, - .alignment = 0, - .prev = null, - .next = null, -}; - -pub fn ensureInitialized(self: *Atom, coff_file: *Coff) !void { - if (self.getSymbolIndex() != null) return; // Already initialized - self.sym_index = try coff_file.allocateSymbol(); - try coff_file.atom_by_index_table.putNoClobber(coff_file.base.allocator, self.sym_index, self); -} +pub const Index = u32; pub fn getSymbolIndex(self: Atom) ?u32 { if (self.sym_index == 0) return null; @@ -85,7 +72,8 @@ pub fn getName(self: Atom, coff_file: *const Coff) []const u8 { /// Returns how much room there is to grow in virtual address space. pub fn capacity(self: Atom, coff_file: *const Coff) u32 { const self_sym = self.getSymbol(coff_file); - if (self.next) |next| { + if (self.next_index) |next_index| { + const next = coff_file.getAtom(next_index); const next_sym = next.getSymbol(coff_file); return next_sym.value - self_sym.value; } else { @@ -97,7 +85,8 @@ pub fn capacity(self: Atom, coff_file: *const Coff) u32 { pub fn freeListEligible(self: Atom, coff_file: *const Coff) bool { // No need to keep a free list node for the last atom. - const next = self.next orelse return false; + const next_index = self.next_index orelse return false; + const next = coff_file.getAtom(next_index); const self_sym = self.getSymbol(coff_file); const next_sym = next.getSymbol(coff_file); const cap = next_sym.value - self_sym.value; @@ -107,22 +96,33 @@ pub fn freeListEligible(self: Atom, coff_file: *const Coff) bool { return surplus >= Coff.min_text_capacity; } -pub fn addRelocation(self: *Atom, coff_file: *Coff, reloc: Relocation) !void { +pub fn addRelocation(coff_file: *Coff, atom_index: Index, reloc: Relocation) !void { const gpa = coff_file.base.allocator; log.debug(" (adding reloc of type {s} to target %{d})", .{ @tagName(reloc.type), reloc.target.sym_index }); - const gop = try coff_file.relocs.getOrPut(gpa, self); + const gop = try coff_file.relocs.getOrPut(gpa, atom_index); if (!gop.found_existing) { gop.value_ptr.* = .{}; } try gop.value_ptr.append(gpa, reloc); } -pub fn addBaseRelocation(self: *Atom, coff_file: *Coff, offset: u32) !void { +pub fn addBaseRelocation(coff_file: *Coff, atom_index: Index, offset: u32) !void { const gpa = coff_file.base.allocator; - log.debug(" (adding base relocation at offset 0x{x} in %{d})", .{ offset, self.sym_index }); - const gop = try coff_file.base_relocs.getOrPut(gpa, self); + log.debug(" (adding base relocation at offset 0x{x} in %{d})", .{ + offset, + coff_file.getAtom(atom_index).getSymbolIndex().?, + }); + const gop = try coff_file.base_relocs.getOrPut(gpa, atom_index); if (!gop.found_existing) { gop.value_ptr.* = .{}; } try gop.value_ptr.append(gpa, offset); } + +pub fn freeRelocations(coff_file: *Coff, atom_index: Atom.Index) void { + const gpa = coff_file.base.allocator; + var removed_relocs = coff_file.relocs.fetchRemove(atom_index); + if (removed_relocs) |*relocs| relocs.value.deinit(gpa); + var removed_base_relocs = coff_file.base_relocs.fetchRemove(atom_index); + if (removed_base_relocs) |*base_relocs| base_relocs.value.deinit(gpa); +} diff --git a/src/link/Coff/Relocation.zig b/src/link/Coff/Relocation.zig index 12a34b332d82a02444d123c661991a84a0f4a660..1ba1d7a1c1e4e5b671f7e71004e0579dba2c5fb1 100644 --- a/src/link/Coff/Relocation.zig +++ b/src/link/Coff/Relocation.zig @@ -46,33 +46,35 @@ length: u2, dirty: bool = true, /// Returns an Atom which is the target node of this relocation edge (if any). -pub fn getTargetAtom(self: Relocation, coff_file: *Coff) ?*Atom { +pub fn getTargetAtomIndex(self: Relocation, coff_file: *const Coff) ?Atom.Index { switch (self.type) { .got, .got_page, .got_pageoff, - => return coff_file.getGotAtomForSymbol(self.target), + => return coff_file.getGotAtomIndexForSymbol(self.target), .direct, .page, .pageoff, - => return coff_file.getAtomForSymbol(self.target), + => return coff_file.getAtomIndexForSymbol(self.target), .import, .import_page, .import_pageoff, - => return coff_file.getImportAtomForSymbol(self.target), + => return coff_file.getImportAtomIndexForSymbol(self.target), } } -pub fn resolve(self: *Relocation, atom: *Atom, coff_file: *Coff) !void { +pub fn resolve(self: *Relocation, atom_index: Atom.Index, coff_file: *Coff) !void { + const atom = coff_file.getAtom(atom_index); const source_sym = atom.getSymbol(coff_file); const source_section = coff_file.sections.get(@enumToInt(source_sym.section_number) - 1).header; const source_vaddr = source_sym.value + self.offset; const file_offset = source_section.pointer_to_raw_data + source_sym.value - source_section.virtual_address; - const target_atom = self.getTargetAtom(coff_file) orelse return; + const target_atom_index = self.getTargetAtomIndex(coff_file) orelse return; + const target_atom = coff_file.getAtom(target_atom_index); const target_vaddr = target_atom.getSymbol(coff_file).value; const target_vaddr_with_addend = target_vaddr + self.addend; @@ -107,7 +109,7 @@ const Context = struct { image_base: u64, }; -fn resolveAarch64(self: *Relocation, ctx: Context, coff_file: *Coff) !void { +fn resolveAarch64(self: Relocation, ctx: Context, coff_file: *Coff) !void { var buffer: [@sizeOf(u64)]u8 = undefined; switch (self.length) { 2 => { @@ -197,7 +199,7 @@ fn resolveAarch64(self: *Relocation, ctx: Context, coff_file: *Coff) !void { } } -fn resolveX86(self: *Relocation, ctx: Context, coff_file: *Coff) !void { +fn resolveX86(self: Relocation, ctx: Context, coff_file: *Coff) !void { switch (self.type) { .got_page => unreachable, .got_pageoff => unreachable, diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 0b8128aa3308413498246533904835027be6c125..747120ac5d818ec53c3d0f201c09b0665022bedb 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -71,14 +71,14 @@ const DeclMetadata = struct { fn getExport(m: DeclMetadata, elf_file: *const Elf, name: []const u8) ?u32 { for (m.exports.items) |exp| { - if (mem.eql(u8, name, elf_file.getSymbolName(exp))) return exp; + if (mem.eql(u8, name, elf_file.getGlobalName(exp))) return exp; } return null; } fn getExportPtr(m: *DeclMetadata, elf_file: *Elf, name: []const u8) ?*u32 { for (m.exports.items) |*exp| { - if (mem.eql(u8, name, elf_file.getSymbolName(exp.*))) return exp; + if (mem.eql(u8, name, elf_file.getGlobalName(exp.*))) return exp; } return null; } @@ -3276,6 +3276,12 @@ pub fn getSymbolName(self: *const Elf, sym_index: u32) []const u8 { return self.shstrtab.get(sym.st_name).?; } +/// Returns name of the global symbol at index. +pub fn getGlobalName(self: *const Elf, index: u32) []const u8 { + const sym = self.global_symbols.items[index]; + return self.shstrtab.get(sym.st_name).?; +} + pub fn getAtom(self: *const Elf, atom_index: Atom.Index) Atom { assert(atom_index < self.atoms.items.len); return self.atoms.items[atom_index]; diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 11a1119449dd640959b9f4673f6ecf7d4c2bb73e..42aaa3a275810c02fdc1828ef726133679492099 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -3015,6 +3015,11 @@ fn allocateAtom(self: *MachO, atom_index: Atom.Index, new_atom_size: u64, alignm if (header.@"align" < align_pow) { header.@"align" = align_pow; } + { + const atom_ptr = self.getAtomPtr(atom_index); + atom_ptr.size = new_atom_size; + atom_ptr.alignment = @intCast(u32, alignment); + } if (atom.prev_index) |prev_index| { const prev = self.getAtomPtr(prev_index); -- 2.54.0 From 063888afff75f9d91fd221d84e1b74b111304ac3 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 27 Jan 2023 19:46:45 -0700 Subject: [PATCH 44/84] std.build: implement passing options to dependency packages * introduce the concept of maps to user input options, but don't implement it for command line arg parsing yet. * remove setPreferredReleaseMode and standardReleaseOptions in favor of standardOptimizeOption which has a future-proof options parameter. --- lib/std/build.zig | 209 ++++++++++++++++++++------------ lib/std/build/LibExeObjStep.zig | 35 +----- 2 files changed, 135 insertions(+), 109 deletions(-) diff --git a/lib/std/build.zig b/lib/std/build.zig index 8137b7684675088a3170932a349ea19197882a20..f1b60f1469eb3e50b279a91a5516da75a4f2d91d 100644 --- a/lib/std/build.zig +++ b/lib/std/build.zig @@ -73,8 +73,6 @@ pub const Builder = struct { build_root: []const u8, cache_root: []const u8, global_cache_root: []const u8, - release_mode: ?std.builtin.Mode, - is_release: bool, /// zig lib dir override_lib_dir: ?[]const u8, vcpkg_root: VcpkgRoot = .unattempted, @@ -150,6 +148,7 @@ pub const Builder = struct { flag: void, scalar: []const u8, list: ArrayList([]const u8), + map: StringHashMap(*const UserValue), }; const TypeId = enum { @@ -223,8 +222,6 @@ pub const Builder = struct { .step = Step.init(.top_level, "uninstall", allocator, makeUninstall), .description = "Remove build artifacts from prefix path", }, - .release_mode = null, - .is_release = false, .override_lib_dir = null, .install_path = undefined, .args = null, @@ -291,8 +288,6 @@ pub const Builder = struct { .build_root = build_root, .cache_root = parent.cache_root, .global_cache_root = parent.global_cache_root, - .release_mode = parent.release_mode, - .is_release = parent.is_release, .override_lib_dir = parent.override_lib_dir, .debug_log_scopes = parent.debug_log_scopes, .debug_compile_errors = parent.debug_compile_errors, @@ -312,10 +307,55 @@ pub const Builder = struct { } fn applyArgs(b: *Builder, args: anytype) !void { - // TODO this function is the way that a build.zig file communicates - // options to its dependencies. It is the programmatic way to give - // command line arguments to a build.zig script. - _ = args; + inline for (@typeInfo(@TypeOf(args)).Struct.fields) |field| { + const v = @field(args, field.name); + const T = @TypeOf(v); + switch (T) { + CrossTarget => { + try b.user_input_options.put(field.name, .{ + .name = field.name, + .value = .{ .scalar = try v.zigTriple(b.allocator) }, + .used = false, + }); + try b.user_input_options.put("cpu", .{ + .name = "cpu", + .value = .{ .scalar = try serializeCpu(b.allocator, v.getCpu()) }, + .used = false, + }); + }, + []const u8 => { + try b.user_input_options.put(field.name, .{ + .name = field.name, + .value = .{ .scalar = v }, + .used = false, + }); + }, + else => switch (@typeInfo(T)) { + .Bool => { + try b.user_input_options.put(field.name, .{ + .name = field.name, + .value = .{ .scalar = if (v) "true" else "false" }, + .used = false, + }); + }, + .Enum => { + try b.user_input_options.put(field.name, .{ + .name = field.name, + .value = .{ .scalar = @tagName(v) }, + .used = false, + }); + }, + .Int => { + try b.user_input_options.put(field.name, .{ + .name = field.name, + .value = .{ .scalar = try std.fmt.allocPrint(b.allocator, "{d}", .{v}) }, + .used = false, + }); + }, + else => @compileError("option '" ++ field.name ++ "' has unsupported type: " ++ @typeName(T)), + }, + } + } const Hasher = std.crypto.auth.siphash.SipHash128(1, 3); // Random bytes to make unique. Refresh this with new random bytes when // implementation is modified in a non-backwards-compatible way. @@ -679,15 +719,19 @@ pub const Builder = struct { return null; } }, - .list => { - log.err("Expected -D{s} to be a boolean, but received a list.\n", .{name}); + .list, .map => { + log.err("Expected -D{s} to be a boolean, but received a {s}.\n", .{ + name, @tagName(option_ptr.value), + }); self.markInvalidUserInput(); return null; }, }, .int => switch (option_ptr.value) { - .flag => { - log.err("Expected -D{s} to be an integer, but received a boolean.\n", .{name}); + .flag, .list, .map => { + log.err("Expected -D{s} to be an integer, but received a {s}.\n", .{ + name, @tagName(option_ptr.value), + }); self.markInvalidUserInput(); return null; }, @@ -706,15 +750,12 @@ pub const Builder = struct { }; return n; }, - .list => { - log.err("Expected -D{s} to be an integer, but received a list.\n", .{name}); - self.markInvalidUserInput(); - return null; - }, }, .float => switch (option_ptr.value) { - .flag => { - log.err("Expected -D{s} to be a float, but received a boolean.\n", .{name}); + .flag, .map, .list => { + log.err("Expected -D{s} to be a float, but received a {s}.\n", .{ + name, @tagName(option_ptr.value), + }); self.markInvalidUserInput(); return null; }, @@ -726,15 +767,12 @@ pub const Builder = struct { }; return n; }, - .list => { - log.err("Expected -D{s} to be a float, but received a list.\n", .{name}); - self.markInvalidUserInput(); - return null; - }, }, .@"enum" => switch (option_ptr.value) { - .flag => { - log.err("Expected -D{s} to be a string, but received a boolean.\n", .{name}); + .flag, .map, .list => { + log.err("Expected -D{s} to be an enum, but received a {s}.\n", .{ + name, @tagName(option_ptr.value), + }); self.markInvalidUserInput(); return null; }, @@ -747,28 +785,22 @@ pub const Builder = struct { return null; } }, - .list => { - log.err("Expected -D{s} to be a string, but received a list.\n", .{name}); - self.markInvalidUserInput(); - return null; - }, }, .string => switch (option_ptr.value) { - .flag => { - log.err("Expected -D{s} to be a string, but received a boolean.\n", .{name}); - self.markInvalidUserInput(); - return null; - }, - .list => { - log.err("Expected -D{s} to be a string, but received a list.\n", .{name}); + .flag, .list, .map => { + log.err("Expected -D{s} to be a string, but received a {s}.\n", .{ + name, @tagName(option_ptr.value), + }); self.markInvalidUserInput(); return null; }, .scalar => |s| return s, }, .list => switch (option_ptr.value) { - .flag => { - log.err("Expected -D{s} to be a list, but received a boolean.\n", .{name}); + .flag, .map => { + log.err("Expected -D{s} to be a list, but received a {s}.\n", .{ + name, @tagName(option_ptr.value), + }); self.markInvalidUserInput(); return null; }, @@ -790,41 +822,24 @@ pub const Builder = struct { return &step_info.step; } - /// This provides the -Drelease option to the build user and does not give them the choice. - pub fn setPreferredReleaseMode(self: *Builder, mode: std.builtin.Mode) void { - if (self.release_mode != null) { - @panic("setPreferredReleaseMode must be called before standardReleaseOptions and may not be called twice"); + pub const StandardOptimizeOptionOptions = struct { + preferred_optimize_mode: ?std.builtin.Mode = null, + }; + + pub fn standardOptimizeOption(self: *Builder, options: StandardOptimizeOptionOptions) std.builtin.Mode { + if (options.preferred_optimize_mode) |mode| { + if (self.option(bool, "release", "optimize for end users") orelse false) { + return mode; + } else { + return .Debug; + } + } else { + return self.option( + std.builtin.Mode, + "optimize", + "prioritize performance, safety, or binary size (-O flag)", + ) orelse .Debug; } - const description = self.fmt("Create a release build ({s})", .{@tagName(mode)}); - self.is_release = self.option(bool, "release", description) orelse false; - self.release_mode = if (self.is_release) mode else std.builtin.Mode.Debug; - } - - /// If you call this without first calling `setPreferredReleaseMode` then it gives the build user - /// the choice of what kind of release. - pub fn standardReleaseOptions(self: *Builder) std.builtin.Mode { - if (self.release_mode) |mode| return mode; - - const release_safe = self.option(bool, "release-safe", "Optimizations on and safety on") orelse false; - const release_fast = self.option(bool, "release-fast", "Optimizations on and safety off") orelse false; - const release_small = self.option(bool, "release-small", "Size optimizations on and safety off") orelse false; - - const mode = if (release_safe and !release_fast and !release_small) - std.builtin.Mode.ReleaseSafe - else if (release_fast and !release_safe and !release_small) - std.builtin.Mode.ReleaseFast - else if (release_small and !release_fast and !release_safe) - std.builtin.Mode.ReleaseSmall - else if (!release_fast and !release_safe and !release_small) - std.builtin.Mode.Debug - else x: { - log.err("Multiple release modes (of -Drelease-safe, -Drelease-fast and -Drelease-small)\n", .{}); - self.markInvalidUserInput(); - break :x std.builtin.Mode.Debug; - }; - self.is_release = mode != .Debug; - self.release_mode = mode; - return mode; } pub const StandardTargetOptionsArgs = struct { @@ -1004,6 +1019,11 @@ pub const Builder = struct { log.warn("Option '-D{s}={s}' conflicts with flag '-D{s}'.", .{ name, value, name }); return true; }, + .map => |*map| { + _ = map; + log.warn("TODO maps as command line arguments is not implemented yet.", .{}); + return true; + }, } return false; } @@ -1026,7 +1046,7 @@ pub const Builder = struct { log.err("Flag '-D{s}' conflicts with option '-D{s}={s}'.", .{ name, name, s }); return true; }, - .list => { + .list, .map => { log.err("Flag '-D{s}' conflicts with multiple options of the same name.", .{name}); return true; }, @@ -1058,7 +1078,7 @@ pub const Builder = struct { var it = self.user_input_options.iterator(); while (it.next()) |entry| { if (!entry.value_ptr.used) { - log.err("Invalid option: -D{s}\n", .{entry.key_ptr.*}); + log.err("Invalid option: -D{s}", .{entry.key_ptr.*}); self.markInvalidUserInput(); } } @@ -1456,6 +1476,11 @@ pub const Builder = struct { ) *Dependency { const sub_builder = b.createChild(name, build_root, args) catch unreachable; sub_builder.runBuild(build_zig) catch unreachable; + + if (sub_builder.validateUserInputDidItFail()) { + std.debug.dumpCurrentStackTrace(@returnAddress()); + } + const dep = b.allocator.create(Dependency) catch unreachable; dep.* = .{ .builder = sub_builder }; return dep; @@ -1718,6 +1743,34 @@ pub const InstalledFile = struct { } }; +pub fn serializeCpu(allocator: Allocator, cpu: std.Target.Cpu) ![]const u8 { + // TODO this logic can disappear if cpu model + features becomes part of the target triple + const all_features = cpu.arch.allFeaturesList(); + var populated_cpu_features = cpu.model.features; + populated_cpu_features.populateDependencies(all_features); + + if (populated_cpu_features.eql(cpu.features)) { + // The CPU name alone is sufficient. + return cpu.model.name; + } else { + var mcpu_buffer = ArrayList(u8).init(allocator); + try mcpu_buffer.appendSlice(cpu.model.name); + + for (all_features) |feature, i_usize| { + const i = @intCast(std.Target.Cpu.Feature.Set.Index, i_usize); + const in_cpu_set = populated_cpu_features.isEnabled(i); + const in_actual_set = cpu.features.isEnabled(i); + if (in_cpu_set and !in_actual_set) { + try mcpu_buffer.writer().print("-{s}", .{feature.name}); + } else if (!in_cpu_set and in_actual_set) { + try mcpu_buffer.writer().print("+{s}", .{feature.name}); + } + } + + return try mcpu_buffer.toOwnedSlice(); + } +} + test "dupePkg()" { if (builtin.os.tag == .wasi) return error.SkipZigTest; diff --git a/lib/std/build/LibExeObjStep.zig b/lib/std/build/LibExeObjStep.zig index cb37b248857e8d5846a43c770482c2dd96d18048..b1e6f3bdac1ca0ba49e33f9f0f2ace4f7629261a 100644 --- a/lib/std/build/LibExeObjStep.zig +++ b/lib/std/build/LibExeObjStep.zig @@ -1495,37 +1495,10 @@ fn make(step: *Step) !void { } if (!self.target.isNative()) { - try zig_args.append("-target"); - try zig_args.append(try self.target.zigTriple(builder.allocator)); - - // TODO this logic can disappear if cpu model + features becomes part of the target triple - const cross = self.target.toTarget(); - const all_features = cross.cpu.arch.allFeaturesList(); - var populated_cpu_features = cross.cpu.model.features; - populated_cpu_features.populateDependencies(all_features); - - if (populated_cpu_features.eql(cross.cpu.features)) { - // The CPU name alone is sufficient. - try zig_args.append("-mcpu"); - try zig_args.append(cross.cpu.model.name); - } else { - var mcpu_buffer = ArrayList(u8).init(builder.allocator); - - try mcpu_buffer.writer().print("-mcpu={s}", .{cross.cpu.model.name}); - - for (all_features) |feature, i_usize| { - const i = @intCast(std.Target.Cpu.Feature.Set.Index, i_usize); - const in_cpu_set = populated_cpu_features.isEnabled(i); - const in_actual_set = cross.cpu.features.isEnabled(i); - if (in_cpu_set and !in_actual_set) { - try mcpu_buffer.writer().print("-{s}", .{feature.name}); - } else if (!in_cpu_set and in_actual_set) { - try mcpu_buffer.writer().print("+{s}", .{feature.name}); - } - } - - try zig_args.append(try mcpu_buffer.toOwnedSlice()); - } + try zig_args.appendSlice(&.{ + "-target", try self.target.zigTriple(builder.allocator), + "-mcpu", try build.serializeCpu(builder.allocator, self.target.getCpu()), + }); if (self.target.dynamic_linker.get()) |dynamic_linker| { try zig_args.append("--dynamic-linker"); -- 2.54.0 From 71ff60f1265da83e619b1b6b2488ecb448fdfd36 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 28 Jan 2023 17:14:06 -0700 Subject: [PATCH 45/84] std.build: eliminate setTarget and setBuildMode This is a breaking change that makes the API for creating build artifacts no longer have any period of time where the target and optimization mode are not set. --- lib/std/build.zig | 162 +++++++++++++++++++------------- lib/std/build/LibExeObjStep.zig | 81 +++++----------- 2 files changed, 118 insertions(+), 125 deletions(-) diff --git a/lib/std/build.zig b/lib/std/build.zig index f1b60f1469eb3e50b279a91a5516da75a4f2d91d..a4ad599d93e3b291e6e314364868db35a568304e 100644 --- a/lib/std/build.zig +++ b/lib/std/build.zig @@ -414,82 +414,123 @@ pub const Builder = struct { self.h_dir = self.pathJoin(&h_list); } - fn convertOptionalPathToFileSource(path: ?[]const u8) ?FileSource { - return if (path) |p| - FileSource{ .path = p } - else - null; - } - - pub fn addExecutable(self: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep { - return addExecutableSource(self, name, convertOptionalPathToFileSource(root_src)); - } - - pub fn addExecutableSource(builder: *Builder, name: []const u8, root_src: ?FileSource) *LibExeObjStep { - return LibExeObjStep.createExecutable(builder, name, root_src); - } - pub fn addOptions(self: *Builder) *OptionsStep { return OptionsStep.create(self); } - pub fn addObject(self: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep { - return addObjectSource(self, name, convertOptionalPathToFileSource(root_src)); - } + pub const ExecutableOptions = struct { + name: []const u8, + root_source_file: ?FileSource, + version: ?std.builtin.Version = null, + target: CrossTarget, + optimize: std.builtin.Mode, + linkage: ?LibExeObjStep.Linkage = null, + }; - pub fn addObjectSource(builder: *Builder, name: []const u8, root_src: ?FileSource) *LibExeObjStep { - return LibExeObjStep.createObject(builder, name, root_src); + pub fn addExecutable(b: *Builder, options: ExecutableOptions) *LibExeObjStep { + return LibExeObjStep.create(b, .{ + .name = options.name, + .root_source_file = options.root_source_file, + .version = options.version, + .target = options.target, + .optimize = options.optimize, + .kind = .exe, + .linkage = options.linkage, + .version = options.version, + }); } - pub fn addSharedLibrary( - self: *Builder, + pub const ObjectOptions = struct { name: []const u8, - root_src: ?[]const u8, - kind: LibExeObjStep.SharedLibKind, - ) *LibExeObjStep { - return addSharedLibrarySource(self, name, convertOptionalPathToFileSource(root_src), kind); - } + root_source_file: ?FileSource, + target: CrossTarget, + optimize: std.builtin.Mode, + }; - pub fn addSharedLibrarySource( - self: *Builder, - name: []const u8, - root_src: ?FileSource, - kind: LibExeObjStep.SharedLibKind, - ) *LibExeObjStep { - return LibExeObjStep.createSharedLibrary(self, name, root_src, kind); + pub fn addObject(b: *Builder, options: ObjectOptions) *LibExeObjStep { + return LibExeObjStep.create(b, .{ + .name = options.name, + .root_source_file = options.root_source_file, + .target = options.target, + .optimize = options.optimize, + .kind = .obj, + }); } - pub fn addStaticLibrary(self: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep { - return addStaticLibrarySource(self, name, convertOptionalPathToFileSource(root_src)); - } + pub const SharedLibraryOptions = struct { + name: []const u8, + root_source_file: ?FileSource, + version: ?std.builtin.Version = null, + target: CrossTarget, + optimize: std.builtin.Mode, + }; - pub fn addStaticLibrarySource(self: *Builder, name: []const u8, root_src: ?FileSource) *LibExeObjStep { - return LibExeObjStep.createStaticLibrary(self, name, root_src); + pub fn addSharedLibrary(b: *Builder, options: SharedLibraryOptions) *LibExeObjStep { + return LibExeObjStep.create(b, .{ + .name = options.name, + .root_source_file = options.root_source_file, + .kind = .lib, + .linkage = .dynamic, + .version = options.version, + .target = options.target, + .optimize = options.optimize, + }); } - pub fn addTest(self: *Builder, root_src: []const u8) *LibExeObjStep { - return LibExeObjStep.createTest(self, "test", .{ .path = root_src }); - } + pub const StaticLibraryOptions = struct { + name: []const u8, + root_source_file: ?FileSource = null, + target: CrossTarget, + optimize: std.builtin.Mode, + version: ?std.builtin.Version = null, + }; - pub fn addTestSource(self: *Builder, root_src: FileSource) *LibExeObjStep { - return LibExeObjStep.createTest(self, "test", root_src.dupe(self)); + pub fn addStaticLibrary(b: *Builder, options: StaticLibraryOptions) *LibExeObjStep { + return LibExeObjStep.create(b, .{ + .name = options.name, + .root_source_file = options.root_source_file, + .kind = .lib, + .linkage = .static, + .version = options.version, + .target = options.target, + .optimize = options.optimize, + }); } - pub fn addTestExe(self: *Builder, name: []const u8, root_src: []const u8) *LibExeObjStep { - return LibExeObjStep.createTestExe(self, name, .{ .path = root_src }); - } + pub const TestOptions = struct { + name: []const u8 = "test", + kind: LibExeObjStep.Kind = .@"test", + root_source_file: FileSource, + target: CrossTarget, + optimize: std.builtin.Mode, + version: ?std.builtin.Version = null, + }; - pub fn addTestExeSource(self: *Builder, name: []const u8, root_src: FileSource) *LibExeObjStep { - return LibExeObjStep.createTestExe(self, name, root_src.dupe(self)); + pub fn addTest(b: *Builder, options: TestOptions) *LibExeObjStep { + return LibExeObjStep.create(b, .{ + .name = options.name, + .kind = options.kind, + .root_source_file = options.root_source_file, + .target = options.target, + .optimize = options.optimize, + }); } - pub fn addAssemble(self: *Builder, name: []const u8, src: []const u8) *LibExeObjStep { - return addAssembleSource(self, name, .{ .path = src }); - } + pub const AssemblyOptions = struct { + name: []const u8, + source_file: FileSource, + target: CrossTarget, + optimize: std.builtin.Mode, + }; - pub fn addAssembleSource(self: *Builder, name: []const u8, src: FileSource) *LibExeObjStep { - const obj_step = LibExeObjStep.createObject(self, name, null); - obj_step.addAssemblyFileSource(src.dupe(self)); + pub fn addAssembly(b: *Builder, options: AssemblyOptions) *LibExeObjStep { + const obj_step = LibExeObjStep.create(b, .{ + .name = options.name, + .root_source_file = null, + .target = options.target, + .optimize = options.optimize, + }); + obj_step.addAssemblyFileSource(options.source_file.dupe(b)); return obj_step; } @@ -593,17 +634,6 @@ pub const Builder = struct { return TranslateCStep.create(self, source.dupe(self)); } - pub fn version(self: *const Builder, major: u32, minor: u32, patch: u32) LibExeObjStep.SharedLibKind { - _ = self; - return .{ - .versioned = .{ - .major = major, - .minor = minor, - .patch = patch, - }, - }; - } - pub fn make(self: *Builder, step_names: []const []const u8) !void { try self.makePath(self.cache_root); diff --git a/lib/std/build/LibExeObjStep.zig b/lib/std/build/LibExeObjStep.zig index b1e6f3bdac1ca0ba49e33f9f0f2ace4f7629261a..6ee5205b50403bec9a3b3a3640ee9d76e2ab088a 100644 --- a/lib/std/build/LibExeObjStep.zig +++ b/lib/std/build/LibExeObjStep.zig @@ -36,14 +36,14 @@ pub const base_id = .lib_exe_obj; step: Step, builder: *Builder, name: []const u8, -target: CrossTarget = CrossTarget{}, +target: CrossTarget, target_info: NativeTargetInfo, +optimize: std.builtin.Mode, linker_script: ?FileSource = null, version_script: ?[]const u8 = null, out_filename: []const u8, linkage: ?Linkage = null, version: ?std.builtin.Version, -build_mode: std.builtin.Mode, kind: Kind, major_only_filename: ?[]const u8, name_only_filename: ?[]const u8, @@ -271,6 +271,16 @@ pub const IncludeDir = union(enum) { config_header_step: *ConfigHeaderStep, }; +pub const Options = struct { + name: []const u8, + root_source_file: ?FileSource = null, + target: CrossTarget, + optimize: std.builtin.Mode, + kind: Kind, + linkage: ?Linkage = null, + version: ?std.builtin.Version = null, +}; + pub const Kind = enum { exe, lib, @@ -279,11 +289,6 @@ pub const Kind = enum { test_exe, }; -pub const SharedLibKind = union(enum) { - versioned: std.builtin.Version, - unversioned: void, -}; - pub const Linkage = enum { dynamic, static }; pub const EmitOption = union(enum) { @@ -302,43 +307,9 @@ pub const EmitOption = union(enum) { } }; -pub fn createSharedLibrary(builder: *Builder, name: []const u8, root_src: ?FileSource, kind: SharedLibKind) *LibExeObjStep { - return initExtraArgs(builder, name, root_src, .lib, .dynamic, switch (kind) { - .versioned => |ver| ver, - .unversioned => null, - }); -} - -pub fn createStaticLibrary(builder: *Builder, name: []const u8, root_src: ?FileSource) *LibExeObjStep { - return initExtraArgs(builder, name, root_src, .lib, .static, null); -} - -pub fn createObject(builder: *Builder, name: []const u8, root_src: ?FileSource) *LibExeObjStep { - return initExtraArgs(builder, name, root_src, .obj, null, null); -} - -pub fn createExecutable(builder: *Builder, name: []const u8, root_src: ?FileSource) *LibExeObjStep { - return initExtraArgs(builder, name, root_src, .exe, null, null); -} - -pub fn createTest(builder: *Builder, name: []const u8, root_src: FileSource) *LibExeObjStep { - return initExtraArgs(builder, name, root_src, .@"test", null, null); -} - -pub fn createTestExe(builder: *Builder, name: []const u8, root_src: FileSource) *LibExeObjStep { - return initExtraArgs(builder, name, root_src, .test_exe, null, null); -} - -fn initExtraArgs( - builder: *Builder, - name_raw: []const u8, - root_src_raw: ?FileSource, - kind: Kind, - linkage: ?Linkage, - ver: ?std.builtin.Version, -) *LibExeObjStep { - const name = builder.dupe(name_raw); - const root_src: ?FileSource = if (root_src_raw) |rsrc| rsrc.dupe(builder) else null; +pub fn create(builder: *Builder, options: Options) *LibExeObjStep { + const name = builder.dupe(options.name); + const root_src: ?FileSource = if (options.root_source_file) |rsrc| rsrc.dupe(builder) else null; if (mem.indexOf(u8, name, "/") != null or mem.indexOf(u8, name, "\\") != null) { panic("invalid name: '{s}'. It looks like a file path, but it is supposed to be the library or application name.", .{name}); } @@ -350,14 +321,15 @@ fn initExtraArgs( .builder = builder, .verbose_link = false, .verbose_cc = false, - .build_mode = std.builtin.Mode.Debug, - .linkage = linkage, - .kind = kind, + .optimize = options.optimize, + .target = options.target, + .linkage = options.linkage, + .kind = options.kind, .root_src = root_src, .name = name, .frameworks = StringHashMap(FrameworkLinkInfo).init(builder.allocator), .step = Step.init(base_id, name, builder.allocator, make), - .version = ver, + .version = options.version, .out_filename = undefined, .out_h_filename = builder.fmt("{s}.h", .{name}), .out_lib_filename = undefined, @@ -457,11 +429,6 @@ fn computeOutFileNames(self: *LibExeObjStep) void { } } -pub fn setTarget(self: *LibExeObjStep, target: CrossTarget) void { - self.target = target; - self.computeOutFileNames(); -} - pub fn setOutputDir(self: *LibExeObjStep, dir: []const u8) void { self.output_dir = self.builder.dupePath(dir); } @@ -889,10 +856,6 @@ pub fn setVerboseCC(self: *LibExeObjStep, value: bool) void { self.verbose_cc = value; } -pub fn setBuildMode(self: *LibExeObjStep, mode: std.builtin.Mode) void { - self.build_mode = mode; -} - pub fn overrideZigLibDir(self: *LibExeObjStep, dir_path: []const u8) void { self.override_lib_dir = self.builder.dupePath(dir_path); } @@ -1376,9 +1339,9 @@ fn make(step: *Step) !void { try zig_args.append(libc_file); } - switch (self.build_mode) { + switch (self.optimize) { .Debug => {}, // Skip since it's the default. - else => zig_args.append(builder.fmt("-O{s}", .{@tagName(self.build_mode)})) catch unreachable, + else => zig_args.append(builder.fmt("-O{s}", .{@tagName(self.optimize)})) catch unreachable, } try zig_args.append("--cache-dir"); -- 2.54.0 From 73cf7b64291ed8b5dcb4cb52df103be08f15a347 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 30 Jan 2023 21:39:43 -0700 Subject: [PATCH 46/84] update build.zig API usage --- build.zig | 72 ++++---- doc/langref.html.in | 42 +++-- lib/init-exe/build.zig | 51 +++++- lib/init-lib/build.zig | 41 ++++- lib/std/build.zig | 19 +-- lib/std/build/TranslateCStep.zig | 40 ++++- lib/std/builtin.zig | 5 +- src/link/MachO/zld.zig | 11 +- test/link/bss/build.zig | 9 +- test/link/common_symbols/build.zig | 15 +- test/link/common_symbols_alignment/build.zig | 17 +- .../interdependent_static_c_libs/build.zig | 24 ++- test/link/macho/bugs/13056/build.zig | 8 +- test/link/macho/bugs/13457/build.zig | 11 +- test/link/macho/dead_strip/build.zig | 16 +- test/link/macho/dead_strip_dylibs/build.zig | 14 +- test/link/macho/dylib/build.zig | 19 ++- test/link/macho/empty/build.zig | 10 +- test/link/macho/entry/build.zig | 10 +- test/link/macho/headerpad/build.zig | 18 +- test/link/macho/linksection/build.zig | 13 +- test/link/macho/needed_framework/build.zig | 8 +- test/link/macho/needed_library/build.zig | 19 ++- test/link/macho/objc/build.zig | 8 +- test/link/macho/objcpp/build.zig | 8 +- test/link/macho/pagezero/build.zig | 18 +- test/link/macho/search_strategy/build.zig | 33 ++-- test/link/macho/stack_size/build.zig | 10 +- test/link/macho/strict_validation/build.zig | 11 +- test/link/macho/tls/build.zig | 19 ++- test/link/macho/unwind_info/build.zig | 20 ++- test/link/macho/uuid/build.zig | 17 +- test/link/macho/weak_framework/build.zig | 8 +- test/link/macho/weak_library/build.zig | 19 ++- test/link/static_lib_as_system_lib/build.zig | 17 +- test/link/wasm/archive/build.zig | 11 +- test/link/wasm/basic-features/build.zig | 18 +- test/link/wasm/bss/build.zig | 11 +- test/link/wasm/export-data/build.zig | 9 +- test/link/wasm/export/build.zig | 29 ++-- test/link/wasm/extern-mangle/build.zig | 11 +- test/link/wasm/extern/build.zig | 10 +- test/link/wasm/function-table/build.zig | 29 ++-- test/link/wasm/infer-features/build.zig | 29 +++- test/link/wasm/producers/build.zig | 11 +- test/link/wasm/segments/build.zig | 11 +- test/link/wasm/stack_pointer/build.zig | 11 +- test/link/wasm/type/build.zig | 11 +- test/src/compare_output.zig | 31 +++- test/src/run_translated_c.zig | 9 +- test/src/translate_c.zig | 7 +- test/standalone/brace_expansion/build.zig | 6 +- test/standalone/c_compiler/build.zig | 18 +- test/standalone/emit_asm_and_bin/build.zig | 6 +- test/standalone/empty_env/build.zig | 7 +- test/standalone/global_linkage/build.zig | 24 ++- test/standalone/install_raw_hex/build.zig | 11 +- test/standalone/issue_11595/build.zig | 11 +- test/standalone/issue_12588/build.zig | 11 +- test/standalone/issue_12706/build.zig | 11 +- test/standalone/issue_13030/build.zig | 12 +- test/standalone/issue_339/build.zig | 7 +- test/standalone/issue_5825/build.zig | 19 ++- test/standalone/issue_7030/build.zig | 11 +- test/standalone/issue_794/build.zig | 4 +- test/standalone/issue_8550/build.zig | 11 +- test/standalone/issue_9812/build.zig | 8 +- .../standalone/load_dynamic_library/build.zig | 20 ++- test/standalone/main_pkg_path/build.zig | 4 +- test/standalone/mix_c_files/build.zig | 11 +- test/standalone/mix_o_files/build.zig | 14 +- test/standalone/options/build.zig | 10 +- test/standalone/pie/build.zig | 6 +- test/standalone/pkg_import/build.zig | 13 +- test/standalone/shared_library/build.zig | 17 +- test/standalone/static_c_lib/build.zig | 15 +- test/standalone/test_runner_path/build.zig | 5 +- test/standalone/use_alias/build.zig | 6 +- test/standalone/windows_spawn/build.zig | 17 +- test/tests.zig | 156 ++++++++++-------- 80 files changed, 905 insertions(+), 494 deletions(-) diff --git a/build.zig b/build.zig index 3a7468243f490119a46fd32cda119da80f3ebf18..98da9f31ee85aa6677e49002d0880364666caff5 100644 --- a/build.zig +++ b/build.zig @@ -23,7 +23,7 @@ pub fn build(b: *Builder) !void { } break :t b.standardTargetOptions(.{ .default_target = default_target }); }; - const mode: std.builtin.Mode = if (release) switch (target.getCpuArch()) { + const optimize: std.builtin.OptimizeMode = if (release) switch (target.getCpuArch()) { .wasm32 => .ReleaseSmall, else => .ReleaseFast, } else .Debug; @@ -33,7 +33,12 @@ pub fn build(b: *Builder) !void { const test_step = b.step("test", "Run all the tests"); - const docgen_exe = b.addExecutable("docgen", "doc/docgen.zig"); + const docgen_exe = b.addExecutable(.{ + .name = "docgen", + .root_source_file = .{ .path = "doc/docgen.zig" }, + .target = .{}, + .optimize = .Debug, + }); docgen_exe.single_threaded = single_threaded; const rel_zig_exe = try fs.path.relative(b.allocator, b.build_root, b.zig_exe); @@ -53,10 +58,12 @@ pub fn build(b: *Builder) !void { const docs_step = b.step("docs", "Build documentation"); docs_step.dependOn(&docgen_cmd.step); - const test_cases = b.addTest("src/test.zig"); + const test_cases = b.addTest(.{ + .root_source_file = .{ .path = "src/test.zig" }, + .optimize = optimize, + }); test_cases.main_pkg_path = "."; test_cases.stack_size = stack_size; - test_cases.setBuildMode(mode); test_cases.single_threaded = single_threaded; const fmt_build_zig = b.addFmt(&[_][]const u8{"build.zig"}); @@ -149,17 +156,15 @@ pub fn build(b: *Builder) !void { const mem_leak_frames: u32 = b.option(u32, "mem-leak-frames", "How many stack frames to print when a memory leak occurs. Tests get 2x this amount.") orelse blk: { if (strip == true) break :blk @as(u32, 0); - if (mode != .Debug) break :blk 0; + if (optimize != .Debug) break :blk 0; break :blk 4; }; - const exe = addCompilerStep(b); + const exe = addCompilerStep(b, optimize, target); exe.strip = strip; exe.sanitize_thread = sanitize_thread; exe.build_id = b.option(bool, "build-id", "Include a build id note") orelse false; exe.install(); - exe.setBuildMode(mode); - exe.setTarget(target); const compile_step = b.step("compile", "Build the self-hosted compiler"); compile_step.dependOn(&exe.step); @@ -195,7 +200,7 @@ pub fn build(b: *Builder) !void { test_cases.linkLibC(); } - const is_debug = mode == .Debug; + const is_debug = optimize == .Debug; const enable_logging = b.option(bool, "log", "Enable debug logging with --debug-log") orelse is_debug; const enable_link_snapshots = b.option(bool, "link-snapshot", "Whether to enable linker state snapshots") orelse false; @@ -360,25 +365,25 @@ pub fn build(b: *Builder) !void { test_step.dependOn(test_cases_step); } - var chosen_modes: [4]builtin.Mode = undefined; + var chosen_opt_modes_buf: [4]builtin.Mode = undefined; var chosen_mode_index: usize = 0; if (!skip_debug) { - chosen_modes[chosen_mode_index] = builtin.Mode.Debug; + chosen_opt_modes_buf[chosen_mode_index] = builtin.Mode.Debug; chosen_mode_index += 1; } if (!skip_release_safe) { - chosen_modes[chosen_mode_index] = builtin.Mode.ReleaseSafe; + chosen_opt_modes_buf[chosen_mode_index] = builtin.Mode.ReleaseSafe; chosen_mode_index += 1; } if (!skip_release_fast) { - chosen_modes[chosen_mode_index] = builtin.Mode.ReleaseFast; + chosen_opt_modes_buf[chosen_mode_index] = builtin.Mode.ReleaseFast; chosen_mode_index += 1; } if (!skip_release_small) { - chosen_modes[chosen_mode_index] = builtin.Mode.ReleaseSmall; + chosen_opt_modes_buf[chosen_mode_index] = builtin.Mode.ReleaseSmall; chosen_mode_index += 1; } - const modes = chosen_modes[0..chosen_mode_index]; + const optimization_modes = chosen_opt_modes_buf[0..chosen_mode_index]; // run stage1 `zig fmt` on this build.zig file just to make sure it works test_step.dependOn(&fmt_build_zig.step); @@ -391,7 +396,7 @@ pub fn build(b: *Builder) !void { "test/behavior.zig", "behavior", "Run the behavior tests", - modes, + optimization_modes, skip_single_threaded, skip_non_native, skip_libc, @@ -405,7 +410,7 @@ pub fn build(b: *Builder) !void { "lib/compiler_rt.zig", "compiler-rt", "Run the compiler_rt tests", - modes, + optimization_modes, true, // skip_single_threaded skip_non_native, true, // skip_libc @@ -419,7 +424,7 @@ pub fn build(b: *Builder) !void { "lib/c.zig", "universal-libc", "Run the universal libc tests", - modes, + optimization_modes, true, // skip_single_threaded skip_non_native, true, // skip_libc @@ -427,11 +432,11 @@ pub fn build(b: *Builder) !void { skip_stage2_tests or true, // TODO get these all passing )); - test_step.dependOn(tests.addCompareOutputTests(b, test_filter, modes)); + test_step.dependOn(tests.addCompareOutputTests(b, test_filter, optimization_modes)); test_step.dependOn(tests.addStandaloneTests( b, test_filter, - modes, + optimization_modes, skip_non_native, enable_macos_sdk, target, @@ -444,10 +449,10 @@ pub fn build(b: *Builder) !void { enable_symlinks_windows, )); test_step.dependOn(tests.addCAbiTests(b, skip_non_native, skip_release)); - test_step.dependOn(tests.addLinkTests(b, test_filter, modes, enable_macos_sdk, skip_stage2_tests, enable_symlinks_windows)); - test_step.dependOn(tests.addStackTraceTests(b, test_filter, modes)); - test_step.dependOn(tests.addCliTests(b, test_filter, modes)); - test_step.dependOn(tests.addAssembleAndLinkTests(b, test_filter, modes)); + test_step.dependOn(tests.addLinkTests(b, test_filter, optimization_modes, enable_macos_sdk, skip_stage2_tests, enable_symlinks_windows)); + test_step.dependOn(tests.addStackTraceTests(b, test_filter, optimization_modes)); + test_step.dependOn(tests.addCliTests(b, test_filter, optimization_modes)); + test_step.dependOn(tests.addAssembleAndLinkTests(b, test_filter, optimization_modes)); test_step.dependOn(tests.addTranslateCTests(b, test_filter)); if (!skip_run_translated_c) { test_step.dependOn(tests.addRunTranslatedCTests(b, test_filter, target)); @@ -461,7 +466,7 @@ pub fn build(b: *Builder) !void { "lib/std/std.zig", "std", "Run the standard library tests", - modes, + optimization_modes, skip_single_threaded, skip_non_native, skip_libc, @@ -481,9 +486,7 @@ fn addWasiUpdateStep(b: *Builder, version: [:0]const u8) !void { }; target.cpu_features_add.addFeature(@enumToInt(std.Target.wasm.Feature.bulk_memory)); - const exe = addCompilerStep(b); - exe.setBuildMode(.ReleaseSmall); - exe.setTarget(target); + const exe = addCompilerStep(b, .ReleaseSmall, target); const exe_options = b.addOptions(); exe.addOptions("build_options", exe_options); @@ -510,8 +513,17 @@ fn addWasiUpdateStep(b: *Builder, version: [:0]const u8) !void { update_zig1_step.dependOn(&run_opt.step); } -fn addCompilerStep(b: *Builder) *std.build.LibExeObjStep { - const exe = b.addExecutable("zig", "src/main.zig"); +fn addCompilerStep( + b: *Builder, + optimize: std.builtin.OptimizeMode, + target: std.zig.CrossTarget, +) *std.build.LibExeObjStep { + const exe = b.addExecutable(.{ + .name = "zig", + .root_source_file = .{ .path = "src/main.zig" }, + .target = target, + .optimize = optimize, + }); exe.stack_size = stack_size; return exe; } diff --git a/doc/langref.html.in b/doc/langref.html.in index fd4aa8ae7615d4bd77861885c3bf711ad7f57459..c008149f4192f02d37303b50670c75635680056a 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -9531,8 +9531,12 @@ fn foo(comptime T: type, ptr: *T) T { const Builder = @import("std").build.Builder; pub fn build(b: *Builder) void { - const exe = b.addExecutable("example", "example.zig"); - exe.setBuildMode(b.standardReleaseOptions()); + const optimize = b.standardOptimizeOption(.{}); + const exe = b.addExecutable(.{ + .name = "example", + .root_source_file = .{ .path = "example.zig" }, + .optimize = optimize, + }); b.default_step.dependOn(&exe.step); } {#code_end#} @@ -10558,11 +10562,14 @@ pub fn build(b: *Builder) void { // Standard release options allow the person running `zig build` to select // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. - const mode = b.standardReleaseOptions(); + const optimize = b.standardOptimizeOption(.{}); - const exe = b.addExecutable("example", "src/main.zig"); - exe.setTarget(target); - exe.setBuildMode(mode); + const exe = b.addExecutable(.{ + .name = "example", + .root_source_file = .{ .path = "src/main.zig" }, + .target = target, + .optimize = optimize, + }); exe.install(); const run_cmd = exe.run(); @@ -10584,13 +10591,18 @@ pub fn build(b: *Builder) void { const Builder = @import("std").build.Builder; pub fn build(b: *Builder) void { - const mode = b.standardReleaseOptions(); - const lib = b.addStaticLibrary("example", "src/main.zig"); - lib.setBuildMode(mode); + const optimize = b.standardOptimizeOption(.{}); + const lib = b.addStaticLibrary(.{ + .name = "example", + .root_source_file = .{ .path = "src/main.zig" }, + .optimize = optimize, + }); lib.install(); - var main_tests = b.addTest("src/main.zig"); - main_tests.setBuildMode(mode); + const main_tests = b.addTest(.{ + .root_source_file = .{ .path = "src/main.zig" }, + .optimize = optimize, + }); const test_step = b.step("test", "Run library tests"); test_step.dependOn(&main_tests.step); @@ -10954,7 +10966,9 @@ const Builder = @import("std").build.Builder; pub fn build(b: *Builder) void { const lib = b.addSharedLibrary("mathtest", "mathtest.zig", b.version(1, 0, 0)); - const exe = b.addExecutable("test", null); + const exe = b.addExecutable(.{ + .name = "test", + }); exe.addCSourceFile("test.c", &[_][]const u8{"-std=c99"}); exe.linkLibrary(lib); exe.linkSystemLibrary("c"); @@ -11016,7 +11030,9 @@ const Builder = @import("std").build.Builder; pub fn build(b: *Builder) void { const obj = b.addObject("base64", "base64.zig"); - const exe = b.addExecutable("test", null); + const exe = b.addExecutable(.{ + .name = "test", + }); exe.addCSourceFile("test.c", &[_][]const u8{"-std=c99"}); exe.addObject(obj); exe.linkSystemLibrary("c"); diff --git a/lib/init-exe/build.zig b/lib/init-exe/build.zig index 29b50b5cc40863e80f276c2b07833031ec1089dd..36e5feddecab57256d61ecaf553fd3a13f5adc2d 100644 --- a/lib/init-exe/build.zig +++ b/lib/init-exe/build.zig @@ -1,5 +1,8 @@ const std = @import("std"); +// Although this function looks imperative, note that its job is to +// declaratively construct a build graph that will be executed by an external +// runner. pub fn build(b: *std.build.Builder) void { // Standard target options allows the person running `zig build` to choose // what target to build for. Here we do not override the defaults, which @@ -7,28 +10,58 @@ pub fn build(b: *std.build.Builder) void { // for restricting supported target set are available. const target = b.standardTargetOptions(.{}); - // Standard release options allow the person running `zig build` to select - // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. - const mode = b.standardReleaseOptions(); + // Standard optimization options allow the person running `zig build` to select + // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not + // set a preferred release mode, allowing the user to decide how to optimize. + const optimize = b.standardOptimizeOption(); - const exe = b.addExecutable("$", "src/main.zig"); - exe.setTarget(target); - exe.setBuildMode(mode); + const exe = b.addExecutable(.{ + .name = "$", + // In this case the main source file is merely a path, however, in more + // complicated build scripts, this could be a generated file. + .root_source_file = .{ .path = "src/main.zig" }, + .target = target, + .optimize = optimize, + }); + + // This declares intent for the executable to be installed into the + // standard location when the user invokes the "install" step (the default + // step when running `zig build`). exe.install(); + // This *creates* a RunStep in the build graph, to be executed when another + // step is evaluated that depends on it. The next line below will establish + // such a dependency. const run_cmd = exe.run(); + + // By making the run step depend on the install step, it will be run from the + // installation directory rather than directly from within the cache directory. + // This is not necessary, however, if the application depends on other installed + // files, this ensures they will be present and in the expected location. run_cmd.step.dependOn(b.getInstallStep()); + + // This allows the user to pass arguments to the application in the build + // command itself, like this: `zig build run -- arg1 arg2 etc` if (b.args) |args| { run_cmd.addArgs(args); } + // This creates a build step. It will be visible in the `zig build --help` menu, + // and can be selected like this: `zig build run` + // This will evaluate the `run` step rather than the default, which is "install". const run_step = b.step("run", "Run the app"); run_step.dependOn(&run_cmd.step); - const exe_tests = b.addTest("src/main.zig"); - exe_tests.setTarget(target); - exe_tests.setBuildMode(mode); + // Creates a step for unit testing. + const exe_tests = b.addTest(.{ + .root_source_file = .{ .path = "src/main.zig" }, + .target = target, + .optimize = optimize, + }); + // Similar to creating the run step earlier, this exposes a `test` step to + // the `zig build --help` menu, providing a way for the user to request + // running the unit tests. const test_step = b.step("test", "Run unit tests"); test_step.dependOn(&exe_tests.step); } diff --git a/lib/init-lib/build.zig b/lib/init-lib/build.zig index b3876691a266449f05972e04c5eee30f1e5c08a3..4a7b700dc200d15c0bb2c065eb69192c670ae3bc 100644 --- a/lib/init-lib/build.zig +++ b/lib/init-lib/build.zig @@ -1,17 +1,44 @@ const std = @import("std"); +// Although this function looks imperative, note that its job is to +// declaratively construct a build graph that will be executed by an external +// runner. pub fn build(b: *std.build.Builder) void { - // Standard release options allow the person running `zig build` to select - // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. - const mode = b.standardReleaseOptions(); + // Standard target options allows the person running `zig build` to choose + // what target to build for. Here we do not override the defaults, which + // means any target is allowed, and the default is native. Other options + // for restricting supported target set are available. + const target = b.standardTargetOptions(.{}); - const lib = b.addStaticLibrary("$", "src/main.zig"); - lib.setBuildMode(mode); + // Standard optimization options allow the person running `zig build` to select + // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not + // set a preferred release mode, allowing the user to decide how to optimize. + const optimize = b.standardOptimizeOption(); + + const lib = b.addStaticLibrary(.{ + .name = "$", + // In this case the main source file is merely a path, however, in more + // complicated build scripts, this could be a generated file. + .root_source_file = .{ .path = "src/main.zig" }, + .target = target, + .optimize = optimize, + }); + + // This declares intent for the library to be installed into the standard + // location when the user invokes the "install" step (the default step when + // running `zig build`). lib.install(); - const main_tests = b.addTest("src/main.zig"); - main_tests.setBuildMode(mode); + // Creates a step for unit testing. + const main_tests = b.addTest(.{ + .root_source_file = .{ .path = "src/main.zig" }, + .target = target, + .optimize = optimize, + }); + // This creates a build step. It will be visible in the `zig build --help` menu, + // and can be selected like this: `zig build test` + // This will evaluate the `test` step rather than the default, which is "install". const test_step = b.step("test", "Run library tests"); test_step.dependOn(&main_tests.step); } diff --git a/lib/std/build.zig b/lib/std/build.zig index a4ad599d93e3b291e6e314364868db35a568304e..4ee00a47107857e9f75fea4b85e69dc93ccfdf94 100644 --- a/lib/std/build.zig +++ b/lib/std/build.zig @@ -420,10 +420,10 @@ pub const Builder = struct { pub const ExecutableOptions = struct { name: []const u8, - root_source_file: ?FileSource, + root_source_file: ?FileSource = null, version: ?std.builtin.Version = null, - target: CrossTarget, - optimize: std.builtin.Mode, + target: CrossTarget = .{}, + optimize: std.builtin.Mode = .Debug, linkage: ?LibExeObjStep.Linkage = null, }; @@ -436,13 +436,12 @@ pub const Builder = struct { .optimize = options.optimize, .kind = .exe, .linkage = options.linkage, - .version = options.version, }); } pub const ObjectOptions = struct { name: []const u8, - root_source_file: ?FileSource, + root_source_file: ?FileSource = null, target: CrossTarget, optimize: std.builtin.Mode, }; @@ -459,7 +458,7 @@ pub const Builder = struct { pub const SharedLibraryOptions = struct { name: []const u8, - root_source_file: ?FileSource, + root_source_file: ?FileSource = null, version: ?std.builtin.Version = null, target: CrossTarget, optimize: std.builtin.Mode, @@ -501,8 +500,8 @@ pub const Builder = struct { name: []const u8 = "test", kind: LibExeObjStep.Kind = .@"test", root_source_file: FileSource, - target: CrossTarget, - optimize: std.builtin.Mode, + target: CrossTarget = .{}, + optimize: std.builtin.Mode = .Debug, version: ?std.builtin.Version = null, }; @@ -630,8 +629,8 @@ pub const Builder = struct { return FmtStep.create(self, paths); } - pub fn addTranslateC(self: *Builder, source: FileSource) *TranslateCStep { - return TranslateCStep.create(self, source.dupe(self)); + pub fn addTranslateC(self: *Builder, options: TranslateCStep.Options) *TranslateCStep { + return TranslateCStep.create(self, options); } pub fn make(self: *Builder, step_names: []const []const u8) !void { diff --git a/lib/std/build/TranslateCStep.zig b/lib/std/build/TranslateCStep.zig index 1f9bee463c7497cd93b3ff3ffd04806793c4576c..9f45d606a19889ea1a0dc7c88fbf287f3cff7a82 100644 --- a/lib/std/build/TranslateCStep.zig +++ b/lib/std/build/TranslateCStep.zig @@ -19,11 +19,19 @@ include_dirs: std.ArrayList([]const u8), c_macros: std.ArrayList([]const u8), output_dir: ?[]const u8, out_basename: []const u8, -target: CrossTarget = CrossTarget{}, +target: CrossTarget, +optimize: std.builtin.OptimizeMode, output_file: build.GeneratedFile, -pub fn create(builder: *Builder, source: build.FileSource) *TranslateCStep { +pub const Options = struct { + source_file: build.FileSource, + target: CrossTarget, + optimize: std.builtin.OptimizeMode, +}; + +pub fn create(builder: *Builder, options: Options) *TranslateCStep { const self = builder.allocator.create(TranslateCStep) catch unreachable; + const source = options.source_file.dupe(builder); self.* = TranslateCStep{ .step = Step.init(.translate_c, "translate-c", builder.allocator, make), .builder = builder, @@ -32,19 +40,32 @@ pub fn create(builder: *Builder, source: build.FileSource) *TranslateCStep { .c_macros = std.ArrayList([]const u8).init(builder.allocator), .output_dir = null, .out_basename = undefined, + .target = options.target, + .optimize = options.optimize, .output_file = build.GeneratedFile{ .step = &self.step }, }; source.addStepDependencies(&self.step); return self; } -pub fn setTarget(self: *TranslateCStep, target: CrossTarget) void { - self.target = target; -} +pub const AddExecutableOptions = struct { + name: ?[]const u8 = null, + version: ?std.builtin.Version = null, + target: ?CrossTarget = null, + optimize: ?std.builtin.Mode = null, + linkage: ?LibExeObjStep.Linkage = null, +}; /// Creates a step to build an executable from the translated source. -pub fn addExecutable(self: *TranslateCStep) *LibExeObjStep { - return self.builder.addExecutableSource("translated_c", build.FileSource{ .generated = &self.output_file }); +pub fn addExecutable(self: *TranslateCStep, options: AddExecutableOptions) *LibExeObjStep { + return self.builder.addExecutable(.{ + .root_source_file = .{ .generated = &self.output_file }, + .name = options.name orelse "translated_c", + .version = options.version, + .target = options.target orelse self.target, + .optimize = options.optimize orelse self.optimize, + .linkage = options.linkage, + }); } pub fn addIncludeDir(self: *TranslateCStep, include_dir: []const u8) void { @@ -82,6 +103,11 @@ fn make(step: *Step) !void { try argv_list.append(try self.target.zigTriple(self.builder.allocator)); } + switch (self.optimize) { + .Debug => {}, // Skip since it's the default. + else => try argv_list.append(self.builder.fmt("-O{s}", .{@tagName(self.optimize)})), + } + for (self.include_dirs.items) |include_dir| { try argv_list.append("-I"); try argv_list.append(include_dir); diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig index 4d949946d8fbc8821ddcac0c7da952bd26f37f15..74c61d229b440db30469c1c66f8879b04f35f097 100644 --- a/lib/std/builtin.zig +++ b/lib/std/builtin.zig @@ -131,13 +131,16 @@ pub const CodeModel = enum { /// This data structure is used by the Zig language code generation and /// therefore must be kept in sync with the compiler implementation. -pub const Mode = enum { +pub const OptimizeMode = enum { Debug, ReleaseSafe, ReleaseFast, ReleaseSmall, }; +/// Deprecated; use OptimizeMode. +pub const Mode = OptimizeMode; + /// This data structure is used by the Zig language code generation and /// therefore must be kept in sync with the compiler implementation. pub const CallingConvention = enum { diff --git a/src/link/MachO/zld.zig b/src/link/MachO/zld.zig index 4cb346aa4740fdedc3c45dfcf071b45c89ccad0b..81fae399ef338982cb62120c4d2770f4fba3fefc 100644 --- a/src/link/MachO/zld.zig +++ b/src/link/MachO/zld.zig @@ -3596,7 +3596,8 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr man.hash.addOptionalBytes(options.sysroot); try man.addOptionalFile(options.entitlements); - // We don't actually care whether it's a cache hit or miss; we just need the digest and the lock. + // We don't actually care whether it's a cache hit or miss; we just + // need the digest and the lock. _ = try man.hit(); digest = man.final(); @@ -4177,9 +4178,11 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr log.debug("failed to save linking hash digest file: {s}", .{@errorName(err)}); }; // Again failure here only means an unnecessary cache miss. - man.writeManifest() catch |err| { - log.debug("failed to write cache manifest when linking: {s}", .{@errorName(err)}); - }; + if (man.have_exclusive_lock) { + man.writeManifest() catch |err| { + log.debug("failed to write cache manifest when linking: {s}", .{@errorName(err)}); + }; + } // We hang on to this lock so that the output file path can be used without // other processes clobbering it. macho_file.base.lock = man.toOwnedLock(); diff --git a/test/link/bss/build.zig b/test/link/bss/build.zig index 76e9bdb305f50e5e875a63dca3fc310e206a4dd4..c31fa7faf553f558c88c3cfe045b97582ce32a64 100644 --- a/test/link/bss/build.zig +++ b/test/link/bss/build.zig @@ -1,12 +1,15 @@ const Builder = @import("std").build.Builder; pub fn build(b: *Builder) void { - const mode = b.standardReleaseOptions(); + const optimize = b.standardOptimizeOption(.{}); const test_step = b.step("test", "Test"); - const exe = b.addExecutable("bss", "main.zig"); + const exe = b.addExecutable(.{ + .name = "bss", + .root_source_file = .{ .path = "main.zig" }, + .optimize = optimize, + }); b.default_step.dependOn(&exe.step); - exe.setBuildMode(mode); const run = exe.run(); run.expectStdOutEqual("0, 1, 0\n"); diff --git a/test/link/common_symbols/build.zig b/test/link/common_symbols/build.zig index 2f9f892e86c9f69bbd12df6712194bacd724ec50..068c3f9c57e5162c15a9b97964a54bd53e41d753 100644 --- a/test/link/common_symbols/build.zig +++ b/test/link/common_symbols/build.zig @@ -1,14 +1,19 @@ const Builder = @import("std").build.Builder; pub fn build(b: *Builder) void { - const mode = b.standardReleaseOptions(); + const optimize = b.standardOptimizeOption(.{}); - const lib_a = b.addStaticLibrary("a", null); + const lib_a = b.addStaticLibrary(.{ + .name = "a", + .optimize = optimize, + .target = .{}, + }); lib_a.addCSourceFiles(&.{ "c.c", "a.c", "b.c" }, &.{"-fcommon"}); - lib_a.setBuildMode(mode); - const test_exe = b.addTest("main.zig"); - test_exe.setBuildMode(mode); + const test_exe = b.addTest(.{ + .root_source_file = .{ .path = "main.zig" }, + .optimize = optimize, + }); test_exe.linkLibrary(lib_a); const test_step = b.step("test", "Test it"); diff --git a/test/link/common_symbols_alignment/build.zig b/test/link/common_symbols_alignment/build.zig index a62d86af4fdfb9cf2142336ba91240a64b8a7bdd..b6dd39801cd6fbc95597ef748598320c55d030a1 100644 --- a/test/link/common_symbols_alignment/build.zig +++ b/test/link/common_symbols_alignment/build.zig @@ -1,14 +1,21 @@ const Builder = @import("std").build.Builder; pub fn build(b: *Builder) void { - const mode = b.standardReleaseOptions(); + const optimize = b.standardOptimizeOption(.{}); + const target = b.standardTargetOptions(.{}); - const lib_a = b.addStaticLibrary("a", null); + const lib_a = b.addStaticLibrary(.{ + .name = "a", + .optimize = optimize, + .target = target, + }); lib_a.addCSourceFiles(&.{"a.c"}, &.{"-fcommon"}); - lib_a.setBuildMode(mode); - const test_exe = b.addTest("main.zig"); - test_exe.setBuildMode(mode); + const test_exe = b.addTest(.{ + .root_source_file = .{ .path = "main.zig" }, + .optimize = optimize, + .target = target, + }); test_exe.linkLibrary(lib_a); const test_step = b.step("test", "Test it"); diff --git a/test/link/interdependent_static_c_libs/build.zig b/test/link/interdependent_static_c_libs/build.zig index bd1b6100daffd71d53876dcd8002866f9fac2f04..50a214490de256272fb6dbaf6cc52fba804b4289 100644 --- a/test/link/interdependent_static_c_libs/build.zig +++ b/test/link/interdependent_static_c_libs/build.zig @@ -1,20 +1,30 @@ const Builder = @import("std").build.Builder; pub fn build(b: *Builder) void { - const mode = b.standardReleaseOptions(); + const optimize = b.standardOptimizeOption(.{}); + const target = b.standardTargetOptions(.{}); - const lib_a = b.addStaticLibrary("a", null); + const lib_a = b.addStaticLibrary(.{ + .name = "a", + .optimize = optimize, + .target = target, + }); lib_a.addCSourceFile("a.c", &[_][]const u8{}); - lib_a.setBuildMode(mode); lib_a.addIncludePath("."); - const lib_b = b.addStaticLibrary("b", null); + const lib_b = b.addStaticLibrary(.{ + .name = "b", + .optimize = optimize, + .target = target, + }); lib_b.addCSourceFile("b.c", &[_][]const u8{}); - lib_b.setBuildMode(mode); lib_b.addIncludePath("."); - const test_exe = b.addTest("main.zig"); - test_exe.setBuildMode(mode); + const test_exe = b.addTest(.{ + .root_source_file = .{ .path = "main.zig" }, + .optimize = optimize, + .target = target, + }); test_exe.linkLibrary(lib_a); test_exe.linkLibrary(lib_b); test_exe.addIncludePath("."); diff --git a/test/link/macho/bugs/13056/build.zig b/test/link/macho/bugs/13056/build.zig index 751a7c4db6407bd86eb102ff785086bcbe49b5fb..a65cd6076604cca7b12cb432209ed6ae8820946b 100644 --- a/test/link/macho/bugs/13056/build.zig +++ b/test/link/macho/bugs/13056/build.zig @@ -2,7 +2,7 @@ const std = @import("std"); const Builder = std.build.Builder; pub fn build(b: *Builder) void { - const mode = b.standardReleaseOptions(); + const optimize = b.standardOptimizeOption(.{}); const target: std.zig.CrossTarget = .{ .os_tag = .macos }; const target_info = std.zig.system.NativeTargetInfo.detect(target) catch unreachable; @@ -11,7 +11,10 @@ pub fn build(b: *Builder) void { const test_step = b.step("test", "Test the program"); - const exe = b.addExecutable("test", null); + const exe = b.addExecutable(.{ + .name = "test", + .optimize = optimize, + }); b.default_step.dependOn(&exe.step); exe.addIncludePath(std.fs.path.join(b.allocator, &.{ sdk.path, "/usr/include" }) catch unreachable); exe.addIncludePath(std.fs.path.join(b.allocator, &.{ sdk.path, "/usr/include/c++/v1" }) catch unreachable); @@ -20,7 +23,6 @@ pub fn build(b: *Builder) void { "-nostdinc++", }); exe.addObjectFile(std.fs.path.join(b.allocator, &.{ sdk.path, "/usr/lib/libc++.tbd" }) catch unreachable); - exe.setBuildMode(mode); const run_cmd = exe.run(); run_cmd.expectStdErrEqual("x: 5\n"); diff --git a/test/link/macho/bugs/13457/build.zig b/test/link/macho/bugs/13457/build.zig index 2de8c01c6a6fd4712a684a76c8d26ab1c4af816e..4c1ce89261ea84441793b0b01a4cfe27de9aa880 100644 --- a/test/link/macho/bugs/13457/build.zig +++ b/test/link/macho/bugs/13457/build.zig @@ -3,14 +3,17 @@ const Builder = std.build.Builder; const LibExeObjectStep = std.build.LibExeObjStep; pub fn build(b: *Builder) void { - const mode = b.standardReleaseOptions(); + const optimize = b.standardOptimizeOption(.{}); const target: std.zig.CrossTarget = .{ .os_tag = .macos }; const test_step = b.step("test", "Test the program"); - const exe = b.addExecutable("test", "main.zig"); - exe.setBuildMode(mode); - exe.setTarget(target); + const exe = b.addExecutable(.{ + .name = "test", + .root_source_file = .{ .path = "main.zig" }, + .optimize = optimize, + .target = target, + }); const run = exe.runEmulatable(); test_step.dependOn(&run.step); diff --git a/test/link/macho/dead_strip/build.zig b/test/link/macho/dead_strip/build.zig index 25759f56192a874d08166af689e0f8b9af22d3c7..a4c3575e45c7eba43d48be571d5ad4e3c95362fa 100644 --- a/test/link/macho/dead_strip/build.zig +++ b/test/link/macho/dead_strip/build.zig @@ -3,7 +3,7 @@ const Builder = std.build.Builder; const LibExeObjectStep = std.build.LibExeObjStep; pub fn build(b: *Builder) void { - const mode = b.standardReleaseOptions(); + const optimize = b.standardOptimizeOption(.{}); const target: std.zig.CrossTarget = .{ .os_tag = .macos }; const test_step = b.step("test", "Test the program"); @@ -11,7 +11,7 @@ pub fn build(b: *Builder) void { { // Without -dead_strip, we expect `iAmUnused` symbol present - const exe = createScenario(b, mode, target); + const exe = createScenario(b, optimize, target); const check = exe.checkObject(.macho); check.checkInSymtab(); @@ -24,7 +24,7 @@ pub fn build(b: *Builder) void { { // With -dead_strip, no `iAmUnused` symbol should be present - const exe = createScenario(b, mode, target); + const exe = createScenario(b, optimize, target); exe.link_gc_sections = true; const check = exe.checkObject(.macho); @@ -37,11 +37,13 @@ pub fn build(b: *Builder) void { } } -fn createScenario(b: *Builder, mode: std.builtin.Mode, target: std.zig.CrossTarget) *LibExeObjectStep { - const exe = b.addExecutable("test", null); +fn createScenario(b: *Builder, optimize: std.builtin.OptimizeMode, target: std.zig.CrossTarget) *LibExeObjectStep { + const exe = b.addExecutable(.{ + .name = "test", + .optimize = optimize, + .target = target, + }); exe.addCSourceFile("main.c", &[0][]const u8{}); - exe.setBuildMode(mode); - exe.setTarget(target); exe.linkLibC(); return exe; } diff --git a/test/link/macho/dead_strip_dylibs/build.zig b/test/link/macho/dead_strip_dylibs/build.zig index efdaf191bd5a9f91fb28a3d18b3ac0c546556134..0127b575fce7e4fc6742b940beb4c93d845a07c9 100644 --- a/test/link/macho/dead_strip_dylibs/build.zig +++ b/test/link/macho/dead_strip_dylibs/build.zig @@ -3,14 +3,14 @@ const Builder = std.build.Builder; const LibExeObjectStep = std.build.LibExeObjStep; pub fn build(b: *Builder) void { - const mode = b.standardReleaseOptions(); + const optimize = b.standardOptimizeOption(.{}); const test_step = b.step("test", "Test the program"); test_step.dependOn(b.getInstallStep()); { // Without -dead_strip_dylibs we expect `-la` to include liba.dylib in the final executable - const exe = createScenario(b, mode); + const exe = createScenario(b, optimize); const check = exe.checkObject(.macho); check.checkStart("cmd LOAD_DYLIB"); @@ -27,7 +27,7 @@ pub fn build(b: *Builder) void { { // With -dead_strip_dylibs, we should include liba.dylib as it's unreachable - const exe = createScenario(b, mode); + const exe = createScenario(b, optimize); exe.dead_strip_dylibs = true; const run_cmd = exe.run(); @@ -36,10 +36,12 @@ pub fn build(b: *Builder) void { } } -fn createScenario(b: *Builder, mode: std.builtin.Mode) *LibExeObjectStep { - const exe = b.addExecutable("test", null); +fn createScenario(b: *Builder, optimize: std.builtin.OptimizeMode) *LibExeObjectStep { + const exe = b.addExecutable(.{ + .name = "test", + .optimize = optimize, + }); exe.addCSourceFile("main.c", &[0][]const u8{}); - exe.setBuildMode(mode); exe.linkLibC(); exe.linkFramework("Cocoa"); return exe; diff --git a/test/link/macho/dylib/build.zig b/test/link/macho/dylib/build.zig index a5baf255c6422d61fa8c76583fb119c4a6ed2cd3..acd27a507f93cebd804016fbe0f1318498c1c000 100644 --- a/test/link/macho/dylib/build.zig +++ b/test/link/macho/dylib/build.zig @@ -2,15 +2,18 @@ const std = @import("std"); const Builder = std.build.Builder; pub fn build(b: *Builder) void { - const mode = b.standardReleaseOptions(); + const optimize = b.standardOptimizeOption(.{}); const target: std.zig.CrossTarget = .{ .os_tag = .macos }; const test_step = b.step("test", "Test"); test_step.dependOn(b.getInstallStep()); - const dylib = b.addSharedLibrary("a", null, b.version(1, 0, 0)); - dylib.setBuildMode(mode); - dylib.setTarget(target); + const dylib = b.addSharedLibrary(.{ + .name = "a", + .version = .{ .major = 1, .minor = 0 }, + .optimize = optimize, + .target = target, + }); dylib.addCSourceFile("a.c", &.{}); dylib.linkLibC(); dylib.install(); @@ -24,9 +27,11 @@ pub fn build(b: *Builder) void { test_step.dependOn(&check_dylib.step); - const exe = b.addExecutable("main", null); - exe.setTarget(target); - exe.setBuildMode(mode); + const exe = b.addExecutable(.{ + .name = "main", + .optimize = optimize, + .target = target, + }); exe.addCSourceFile("main.c", &.{}); exe.linkSystemLibrary("a"); exe.linkLibC(); diff --git a/test/link/macho/empty/build.zig b/test/link/macho/empty/build.zig index ab016fd4bd9a99b12398448b03e4d196b924c8bf..8b2d047371cc29b7666fcab0de4c644540edae5f 100644 --- a/test/link/macho/empty/build.zig +++ b/test/link/macho/empty/build.zig @@ -2,17 +2,19 @@ const std = @import("std"); const Builder = std.build.Builder; pub fn build(b: *Builder) void { - const mode = b.standardReleaseOptions(); + const optimize = b.standardOptimizeOption(.{}); const target: std.zig.CrossTarget = .{ .os_tag = .macos }; const test_step = b.step("test", "Test the program"); test_step.dependOn(b.getInstallStep()); - const exe = b.addExecutable("test", null); + const exe = b.addExecutable(.{ + .name = "test", + .optimize = optimize, + .target = target, + }); exe.addCSourceFile("main.c", &[0][]const u8{}); exe.addCSourceFile("empty.c", &[0][]const u8{}); - exe.setBuildMode(mode); - exe.setTarget(target); exe.linkLibC(); const run_cmd = std.build.EmulatableRunStep.create(b, "run", exe); diff --git a/test/link/macho/entry/build.zig b/test/link/macho/entry/build.zig index 0ecca14aa292b56201288635a2f791a855ddfae5..87e4d1b5daedf660e45e8a2b9372a91b73d9facb 100644 --- a/test/link/macho/entry/build.zig +++ b/test/link/macho/entry/build.zig @@ -2,14 +2,16 @@ const std = @import("std"); const Builder = std.build.Builder; pub fn build(b: *Builder) void { - const mode = b.standardReleaseOptions(); + const optimize = b.standardOptimizeOption(.{}); const test_step = b.step("test", "Test"); test_step.dependOn(b.getInstallStep()); - const exe = b.addExecutable("main", null); - exe.setTarget(.{ .os_tag = .macos }); - exe.setBuildMode(mode); + const exe = b.addExecutable(.{ + .name = "main", + .optimize = optimize, + .target = .{ .os_tag = .macos }, + }); exe.addCSourceFile("main.c", &.{}); exe.linkLibC(); exe.entry_symbol_name = "_non_main"; diff --git a/test/link/macho/headerpad/build.zig b/test/link/macho/headerpad/build.zig index 0730a01d442e87e6cb29cf7c60a214a62f34984d..74efb5d5801e3968547cb4b36d411dedf9db337b 100644 --- a/test/link/macho/headerpad/build.zig +++ b/test/link/macho/headerpad/build.zig @@ -4,14 +4,14 @@ const Builder = std.build.Builder; const LibExeObjectStep = std.build.LibExeObjStep; pub fn build(b: *Builder) void { - const mode = b.standardReleaseOptions(); + const optimize = b.standardOptimizeOption(.{}); const test_step = b.step("test", "Test"); test_step.dependOn(b.getInstallStep()); { // Test -headerpad_max_install_names - const exe = simpleExe(b, mode); + const exe = simpleExe(b, optimize); exe.headerpad_max_install_names = true; const check = exe.checkObject(.macho); @@ -36,7 +36,7 @@ pub fn build(b: *Builder) void { { // Test -headerpad - const exe = simpleExe(b, mode); + const exe = simpleExe(b, optimize); exe.headerpad_size = 0x10000; const check = exe.checkObject(.macho); @@ -52,7 +52,7 @@ pub fn build(b: *Builder) void { { // Test both flags with -headerpad overriding -headerpad_max_install_names - const exe = simpleExe(b, mode); + const exe = simpleExe(b, optimize); exe.headerpad_max_install_names = true; exe.headerpad_size = 0x10000; @@ -69,7 +69,7 @@ pub fn build(b: *Builder) void { { // Test both flags with -headerpad_max_install_names overriding -headerpad - const exe = simpleExe(b, mode); + const exe = simpleExe(b, optimize); exe.headerpad_size = 0x1000; exe.headerpad_max_install_names = true; @@ -94,9 +94,11 @@ pub fn build(b: *Builder) void { } } -fn simpleExe(b: *Builder, mode: std.builtin.Mode) *LibExeObjectStep { - const exe = b.addExecutable("main", null); - exe.setBuildMode(mode); +fn simpleExe(b: *Builder, optimize: std.builtin.OptimizeMode) *LibExeObjectStep { + const exe = b.addExecutable(.{ + .name = "main", + .optimize = optimize, + }); exe.addCSourceFile("main.c", &.{}); exe.linkLibC(); exe.linkFramework("CoreFoundation"); diff --git a/test/link/macho/linksection/build.zig b/test/link/macho/linksection/build.zig index 9204499803e55d302861160bc42b5ab63420484c..eebb31a21ee53489bdc8aeb4a9241d378d88882b 100644 --- a/test/link/macho/linksection/build.zig +++ b/test/link/macho/linksection/build.zig @@ -1,15 +1,18 @@ const std = @import("std"); pub fn build(b: *std.build.Builder) void { - const mode = b.standardReleaseOptions(); + const optimize = b.standardOptimizeOption(.{}); const target = std.zig.CrossTarget{ .os_tag = .macos }; const test_step = b.step("test", "Test"); test_step.dependOn(b.getInstallStep()); - const obj = b.addObject("test", "main.zig"); - obj.setBuildMode(mode); - obj.setTarget(target); + const obj = b.addObject(.{ + .name = "test", + .root_source_file = .{ .path = "main.zig" }, + .optimize = optimize, + .target = target, + }); const check = obj.checkObject(.macho); @@ -19,7 +22,7 @@ pub fn build(b: *std.build.Builder) void { check.checkInSymtab(); check.checkNext("{*} (__TEXT,__TestFn) external _testFn"); - if (mode == .Debug) { + if (optimize == .Debug) { check.checkInSymtab(); check.checkNext("{*} (__TEXT,__TestGenFnA) _main.testGenericFn__anon_{*}"); } diff --git a/test/link/macho/needed_framework/build.zig b/test/link/macho/needed_framework/build.zig index 43159359412e3da2cd62e61b745c2efeca1d9468..33965a92726dc71af806abe59dbe9f6f7f295c78 100644 --- a/test/link/macho/needed_framework/build.zig +++ b/test/link/macho/needed_framework/build.zig @@ -3,16 +3,18 @@ const Builder = std.build.Builder; const LibExeObjectStep = std.build.LibExeObjStep; pub fn build(b: *Builder) void { - const mode = b.standardReleaseOptions(); + const optimize = b.standardOptimizeOption(.{}); const test_step = b.step("test", "Test the program"); test_step.dependOn(b.getInstallStep()); // -dead_strip_dylibs // -needed_framework Cocoa - const exe = b.addExecutable("test", null); + const exe = b.addExecutable(.{ + .name = "test", + .optimize = optimize, + }); exe.addCSourceFile("main.c", &[0][]const u8{}); - exe.setBuildMode(mode); exe.linkLibC(); exe.linkFrameworkNeeded("Cocoa"); exe.dead_strip_dylibs = true; diff --git a/test/link/macho/needed_library/build.zig b/test/link/macho/needed_library/build.zig index a314fd22019884e335f912b0eca67160e4e46b6b..137239d2926f3cc62490100cd1320c48c738ce7f 100644 --- a/test/link/macho/needed_library/build.zig +++ b/test/link/macho/needed_library/build.zig @@ -3,25 +3,30 @@ const Builder = std.build.Builder; const LibExeObjectStep = std.build.LibExeObjStep; pub fn build(b: *Builder) void { - const mode = b.standardReleaseOptions(); + const optimize = b.standardOptimizeOption(.{}); const target: std.zig.CrossTarget = .{ .os_tag = .macos }; const test_step = b.step("test", "Test the program"); test_step.dependOn(b.getInstallStep()); - const dylib = b.addSharedLibrary("a", null, b.version(1, 0, 0)); - dylib.setTarget(target); - dylib.setBuildMode(mode); + const dylib = b.addSharedLibrary(.{ + .name = "a", + .version = .{ .major = 1, .minor = 0 }, + .optimize = optimize, + .target = target, + }); dylib.addCSourceFile("a.c", &.{}); dylib.linkLibC(); dylib.install(); // -dead_strip_dylibs // -needed-la - const exe = b.addExecutable("test", null); + const exe = b.addExecutable(.{ + .name = "test", + .optimize = optimize, + .target = target, + }); exe.addCSourceFile("main.c", &[0][]const u8{}); - exe.setBuildMode(mode); - exe.setTarget(target); exe.linkLibC(); exe.linkSystemLibraryNeeded("a"); exe.addLibraryPath(b.pathFromRoot("zig-out/lib")); diff --git a/test/link/macho/objc/build.zig b/test/link/macho/objc/build.zig index d7fd872f77579f01ccbd986962549d100feecfe3..9c38739a5c9881a0cba6f10574fa765183717765 100644 --- a/test/link/macho/objc/build.zig +++ b/test/link/macho/objc/build.zig @@ -2,15 +2,17 @@ const std = @import("std"); const Builder = std.build.Builder; pub fn build(b: *Builder) void { - const mode = b.standardReleaseOptions(); + const optimize = b.standardOptimizeOption(.{}); const test_step = b.step("test", "Test the program"); - const exe = b.addExecutable("test", null); + const exe = b.addExecutable(.{ + .name = "test", + .optimize = optimize, + }); exe.addIncludePath("."); exe.addCSourceFile("Foo.m", &[0][]const u8{}); exe.addCSourceFile("test.m", &[0][]const u8{}); - exe.setBuildMode(mode); exe.linkLibC(); // TODO when we figure out how to ship framework stubs for cross-compilation, // populate paths to the sysroot here. diff --git a/test/link/macho/objcpp/build.zig b/test/link/macho/objcpp/build.zig index 767578e225adce2a787cb7c7bf07567ef2b2d6dc..f4c88b286238c640e5eb5d92a7032fbc20242894 100644 --- a/test/link/macho/objcpp/build.zig +++ b/test/link/macho/objcpp/build.zig @@ -2,16 +2,18 @@ const std = @import("std"); const Builder = std.build.Builder; pub fn build(b: *Builder) void { - const mode = b.standardReleaseOptions(); + const optimize = b.standardOptimizeOption(.{}); const test_step = b.step("test", "Test the program"); - const exe = b.addExecutable("test", null); + const exe = b.addExecutable(.{ + .name = "test", + .optimize = optimize, + }); b.default_step.dependOn(&exe.step); exe.addIncludePath("."); exe.addCSourceFile("Foo.mm", &[0][]const u8{}); exe.addCSourceFile("test.mm", &[0][]const u8{}); - exe.setBuildMode(mode); exe.linkLibCpp(); // TODO when we figure out how to ship framework stubs for cross-compilation, // populate paths to the sysroot here. diff --git a/test/link/macho/pagezero/build.zig b/test/link/macho/pagezero/build.zig index 5a7044d960c29becc56acaf16e44e6110dfa8f75..f61aa34a93ff8141c9d8ea076f4299606945b1c7 100644 --- a/test/link/macho/pagezero/build.zig +++ b/test/link/macho/pagezero/build.zig @@ -2,16 +2,18 @@ const std = @import("std"); const Builder = std.build.Builder; pub fn build(b: *Builder) void { - const mode = b.standardReleaseOptions(); + const optimize = b.standardOptimizeOption(.{}); const target: std.zig.CrossTarget = .{ .os_tag = .macos }; const test_step = b.step("test", "Test"); test_step.dependOn(b.getInstallStep()); { - const exe = b.addExecutable("pagezero", null); - exe.setTarget(target); - exe.setBuildMode(mode); + const exe = b.addExecutable(.{ + .name = "pagezero", + .optimize = optimize, + .target = target, + }); exe.addCSourceFile("main.c", &.{}); exe.linkLibC(); exe.pagezero_size = 0x4000; @@ -29,9 +31,11 @@ pub fn build(b: *Builder) void { } { - const exe = b.addExecutable("no_pagezero", null); - exe.setTarget(target); - exe.setBuildMode(mode); + const exe = b.addExecutable(.{ + .name = "no_pagezero", + .optimize = optimize, + .target = target, + }); exe.addCSourceFile("main.c", &.{}); exe.linkLibC(); exe.pagezero_size = 0; diff --git a/test/link/macho/search_strategy/build.zig b/test/link/macho/search_strategy/build.zig index e556b5bb23538c22c5be38252bf42248a3897f33..db894b6ae30a3a3805462378c6e22a69c8109181 100644 --- a/test/link/macho/search_strategy/build.zig +++ b/test/link/macho/search_strategy/build.zig @@ -3,7 +3,7 @@ const Builder = std.build.Builder; const LibExeObjectStep = std.build.LibExeObjStep; pub fn build(b: *Builder) void { - const mode = b.standardReleaseOptions(); + const optimize = b.standardOptimizeOption(.{}); const target: std.zig.CrossTarget = .{ .os_tag = .macos }; const test_step = b.step("test", "Test"); @@ -11,7 +11,7 @@ pub fn build(b: *Builder) void { { // -search_dylibs_first - const exe = createScenario(b, mode, target); + const exe = createScenario(b, optimize, target); exe.search_strategy = .dylibs_first; const check = exe.checkObject(.macho); @@ -26,7 +26,7 @@ pub fn build(b: *Builder) void { { // -search_paths_first - const exe = createScenario(b, mode, target); + const exe = createScenario(b, optimize, target); exe.search_strategy = .paths_first; const run = std.build.EmulatableRunStep.create(b, "run", exe); @@ -36,10 +36,12 @@ pub fn build(b: *Builder) void { } } -fn createScenario(b: *Builder, mode: std.builtin.Mode, target: std.zig.CrossTarget) *LibExeObjectStep { - const static = b.addStaticLibrary("a", null); - static.setTarget(target); - static.setBuildMode(mode); +fn createScenario(b: *Builder, optimize: std.builtin.OptimizeMode, target: std.zig.CrossTarget) *LibExeObjectStep { + const static = b.addStaticLibrary(.{ + .name = "a", + .optimize = optimize, + .target = target, + }); static.addCSourceFile("a.c", &.{}); static.linkLibC(); static.override_dest_dir = std.build.InstallDir{ @@ -47,9 +49,12 @@ fn createScenario(b: *Builder, mode: std.builtin.Mode, target: std.zig.CrossTarg }; static.install(); - const dylib = b.addSharedLibrary("a", null, b.version(1, 0, 0)); - dylib.setTarget(target); - dylib.setBuildMode(mode); + const dylib = b.addSharedLibrary(.{ + .name = "a", + .version = .{ .major = 1, .minor = 0 }, + .optimize = optimize, + .target = target, + }); dylib.addCSourceFile("a.c", &.{}); dylib.linkLibC(); dylib.override_dest_dir = std.build.InstallDir{ @@ -57,9 +62,11 @@ fn createScenario(b: *Builder, mode: std.builtin.Mode, target: std.zig.CrossTarg }; dylib.install(); - const exe = b.addExecutable("main", null); - exe.setTarget(target); - exe.setBuildMode(mode); + const exe = b.addExecutable(.{ + .name = "main", + .optimize = optimize, + .target = target, + }); exe.addCSourceFile("main.c", &.{}); exe.linkSystemLibraryName("a"); exe.linkLibC(); diff --git a/test/link/macho/stack_size/build.zig b/test/link/macho/stack_size/build.zig index 91c44baf5212de27b1934971602df431653df730..74e9a86e94ea7fa6e9b6b9a1be9024d5ad35ec8f 100644 --- a/test/link/macho/stack_size/build.zig +++ b/test/link/macho/stack_size/build.zig @@ -2,15 +2,17 @@ const std = @import("std"); const Builder = std.build.Builder; pub fn build(b: *Builder) void { - const mode = b.standardReleaseOptions(); + const optimize = b.standardOptimizeOption(.{}); const target: std.zig.CrossTarget = .{ .os_tag = .macos }; const test_step = b.step("test", "Test"); test_step.dependOn(b.getInstallStep()); - const exe = b.addExecutable("main", null); - exe.setTarget(target); - exe.setBuildMode(mode); + const exe = b.addExecutable(.{ + .name = "main", + .optimize = optimize, + .target = target, + }); exe.addCSourceFile("main.c", &.{}); exe.linkLibC(); exe.stack_size = 0x100000000; diff --git a/test/link/macho/strict_validation/build.zig b/test/link/macho/strict_validation/build.zig index 0ea150252c5f9aee3f8714fcc53645c0f6507d31..b6baf63c11116477810bb2244fad00aa8e7b6ef1 100644 --- a/test/link/macho/strict_validation/build.zig +++ b/test/link/macho/strict_validation/build.zig @@ -4,15 +4,18 @@ const Builder = std.build.Builder; const LibExeObjectStep = std.build.LibExeObjStep; pub fn build(b: *Builder) void { - const mode = b.standardReleaseOptions(); + const optimize = b.standardOptimizeOption(.{}); const target: std.zig.CrossTarget = .{ .os_tag = .macos }; const test_step = b.step("test", "Test"); test_step.dependOn(b.getInstallStep()); - const exe = b.addExecutable("main", "main.zig"); - exe.setBuildMode(mode); - exe.setTarget(target); + const exe = b.addExecutable(.{ + .name = "main", + .root_source_file = .{ .path = "main.zig" }, + .optimize = optimize, + .target = target, + }); exe.linkLibC(); const check_exe = exe.checkObject(.macho); diff --git a/test/link/macho/tls/build.zig b/test/link/macho/tls/build.zig index 031a05cedf9907407592cce3c2e9b1e7ad8b536e..9b2fe952bf0f6e06545e464b6a8918779db22737 100644 --- a/test/link/macho/tls/build.zig +++ b/test/link/macho/tls/build.zig @@ -2,18 +2,23 @@ const std = @import("std"); const Builder = std.build.Builder; pub fn build(b: *Builder) void { - const mode = b.standardReleaseOptions(); + const optimize = b.standardOptimizeOption(.{}); const target: std.zig.CrossTarget = .{ .os_tag = .macos }; - const lib = b.addSharedLibrary("a", null, b.version(1, 0, 0)); - lib.setBuildMode(mode); - lib.setTarget(target); + const lib = b.addSharedLibrary(.{ + .name = "a", + .version = .{ .major = 1, .minor = 0 }, + .optimize = optimize, + .target = target, + }); lib.addCSourceFile("a.c", &.{}); lib.linkLibC(); - const test_exe = b.addTest("main.zig"); - test_exe.setBuildMode(mode); - test_exe.setTarget(target); + const test_exe = b.addTest(.{ + .root_source_file = .{ .path = "main.zig" }, + .optimize = optimize, + .target = target, + }); test_exe.linkLibrary(lib); test_exe.linkLibC(); diff --git a/test/link/macho/unwind_info/build.zig b/test/link/macho/unwind_info/build.zig index cc00854465657728524598652b9794f94838b888..dbbdbb3e51ccb5662977dde5f16ef86a911d9573 100644 --- a/test/link/macho/unwind_info/build.zig +++ b/test/link/macho/unwind_info/build.zig @@ -4,23 +4,23 @@ const Builder = std.build.Builder; const LibExeObjectStep = std.build.LibExeObjStep; pub fn build(b: *Builder) void { - const mode = b.standardReleaseOptions(); + const optimize = b.standardOptimizeOption(.{}); const target: std.zig.CrossTarget = .{ .os_tag = .macos }; const test_step = b.step("test", "Test the program"); - testUnwindInfo(b, test_step, mode, target, false); - testUnwindInfo(b, test_step, mode, target, true); + testUnwindInfo(b, test_step, optimize, target, false); + testUnwindInfo(b, test_step, optimize, target, true); } fn testUnwindInfo( b: *Builder, test_step: *std.build.Step, - mode: std.builtin.Mode, + optimize: std.builtin.OptimizeMode, target: std.zig.CrossTarget, dead_strip: bool, ) void { - const exe = createScenario(b, mode, target); + const exe = createScenario(b, optimize, target); exe.link_gc_sections = dead_strip; const check = exe.checkObject(.macho); @@ -52,8 +52,12 @@ fn testUnwindInfo( test_step.dependOn(&run_cmd.step); } -fn createScenario(b: *Builder, mode: std.builtin.Mode, target: std.zig.CrossTarget) *LibExeObjectStep { - const exe = b.addExecutable("test", null); +fn createScenario(b: *Builder, optimize: std.builtin.OptimizeMode, target: std.zig.CrossTarget) *LibExeObjectStep { + const exe = b.addExecutable(.{ + .name = "test", + .optimize = optimize, + .target = target, + }); b.default_step.dependOn(&exe.step); exe.addIncludePath("."); exe.addCSourceFiles(&[_][]const u8{ @@ -61,8 +65,6 @@ fn createScenario(b: *Builder, mode: std.builtin.Mode, target: std.zig.CrossTarg "simple_string.cpp", "simple_string_owner.cpp", }, &[0][]const u8{}); - exe.setBuildMode(mode); - exe.setTarget(target); exe.linkLibCpp(); return exe; } diff --git a/test/link/macho/uuid/build.zig b/test/link/macho/uuid/build.zig index 314febdb20de14c881f41252c3166b1968fb6d2c..86ff99e8b12ca043375354e33f0691d37be8847d 100644 --- a/test/link/macho/uuid/build.zig +++ b/test/link/macho/uuid/build.zig @@ -29,21 +29,21 @@ pub fn build(b: *Builder) void { fn testUuid( b: *Builder, test_step: *std.build.Step, - mode: std.builtin.Mode, + optimize: std.builtin.OptimizeMode, target: std.zig.CrossTarget, comptime exp: []const u8, ) void { // The calculated UUID value is independent of debug info and so it should // stay the same across builds. { - const dylib = simpleDylib(b, mode, target); + const dylib = simpleDylib(b, optimize, target); const check_dylib = dylib.checkObject(.macho); check_dylib.checkStart("cmd UUID"); check_dylib.checkNext("uuid " ++ exp); test_step.dependOn(&check_dylib.step); } { - const dylib = simpleDylib(b, mode, target); + const dylib = simpleDylib(b, optimize, target); dylib.strip = true; const check_dylib = dylib.checkObject(.macho); check_dylib.checkStart("cmd UUID"); @@ -52,10 +52,13 @@ fn testUuid( } } -fn simpleDylib(b: *Builder, mode: std.builtin.Mode, target: std.zig.CrossTarget) *LibExeObjectStep { - const dylib = b.addSharedLibrary("test", null, b.version(1, 0, 0)); - dylib.setTarget(target); - dylib.setBuildMode(mode); +fn simpleDylib(b: *Builder, optimize: std.builtin.OptimizeMode, target: std.zig.CrossTarget) *LibExeObjectStep { + const dylib = b.addSharedLibrary(.{ + .name = "test", + .version = .{ .major = 1, .minor = 0 }, + .optimize = optimize, + .target = target, + }); dylib.addCSourceFile("test.c", &.{}); dylib.linkLibC(); return dylib; diff --git a/test/link/macho/weak_framework/build.zig b/test/link/macho/weak_framework/build.zig index 44675a15f8e7597fb43f2790abfaea5dc92fa2da..f8460c4e827081f30f5c05fd41b4202374b33947 100644 --- a/test/link/macho/weak_framework/build.zig +++ b/test/link/macho/weak_framework/build.zig @@ -3,14 +3,16 @@ const Builder = std.build.Builder; const LibExeObjectStep = std.build.LibExeObjStep; pub fn build(b: *Builder) void { - const mode = b.standardReleaseOptions(); + const optimize = b.standardOptimizeOption(.{}); const test_step = b.step("test", "Test the program"); test_step.dependOn(b.getInstallStep()); - const exe = b.addExecutable("test", null); + const exe = b.addExecutable(.{ + .name = "test", + .optimize = optimize, + }); exe.addCSourceFile("main.c", &[0][]const u8{}); - exe.setBuildMode(mode); exe.linkLibC(); exe.linkFrameworkWeak("Cocoa"); diff --git a/test/link/macho/weak_library/build.zig b/test/link/macho/weak_library/build.zig index 79f67bd7df28216c279a78e74652091ecfc10d96..229d965e48d6fee4ec758b55b7ad06172c40e97a 100644 --- a/test/link/macho/weak_library/build.zig +++ b/test/link/macho/weak_library/build.zig @@ -3,23 +3,28 @@ const Builder = std.build.Builder; const LibExeObjectStep = std.build.LibExeObjStep; pub fn build(b: *Builder) void { - const mode = b.standardReleaseOptions(); + const optimize = b.standardOptimizeOption(.{}); const target: std.zig.CrossTarget = .{ .os_tag = .macos }; const test_step = b.step("test", "Test the program"); test_step.dependOn(b.getInstallStep()); - const dylib = b.addSharedLibrary("a", null, b.version(1, 0, 0)); - dylib.setTarget(target); - dylib.setBuildMode(mode); + const dylib = b.addSharedLibrary(.{ + .name = "a", + .version = .{ .major = 1, .minor = 0, .patch = 0 }, + .target = target, + .optimize = optimize, + }); dylib.addCSourceFile("a.c", &.{}); dylib.linkLibC(); dylib.install(); - const exe = b.addExecutable("test", null); + const exe = b.addExecutable(.{ + .name = "test", + .target = target, + .optimize = optimize, + }); exe.addCSourceFile("main.c", &[0][]const u8{}); - exe.setTarget(target); - exe.setBuildMode(mode); exe.linkLibC(); exe.linkSystemLibraryWeak("a"); exe.addLibraryPath(b.pathFromRoot("zig-out/lib")); diff --git a/test/link/static_lib_as_system_lib/build.zig b/test/link/static_lib_as_system_lib/build.zig index f39f3fac2ae871ba7f229e0e652fd89b55c4cd33..895cdcf316a4b29fa189178a65ab67c71d744699 100644 --- a/test/link/static_lib_as_system_lib/build.zig +++ b/test/link/static_lib_as_system_lib/build.zig @@ -2,16 +2,23 @@ const std = @import("std"); const Builder = std.build.Builder; pub fn build(b: *Builder) void { - const mode = b.standardReleaseOptions(); + const optimize = b.standardOptimizeOption(.{}); + const target = b.standardTargetOptions(.{}); - const lib_a = b.addStaticLibrary("a", null); + const lib_a = b.addStaticLibrary(.{ + .name = "a", + .optimize = optimize, + .target = target, + }); lib_a.addCSourceFile("a.c", &[_][]const u8{}); - lib_a.setBuildMode(mode); lib_a.addIncludePath("."); lib_a.install(); - const test_exe = b.addTest("main.zig"); - test_exe.setBuildMode(mode); + const test_exe = b.addTest(.{ + .root_source_file = .{ .path = "main.zig" }, + .optimize = optimize, + .target = target, + }); test_exe.linkSystemLibrary("a"); // force linking liba.a as -la test_exe.addSystemIncludePath("."); const search_path = std.fs.path.join(b.allocator, &[_][]const u8{ b.install_path, "lib" }) catch unreachable; diff --git a/test/link/wasm/archive/build.zig b/test/link/wasm/archive/build.zig index 7efa88999ad8dae8552075fd20178bb4f71ba713..7401ba22dc77c1d9d0cec7fa9766ee23808a28df 100644 --- a/test/link/wasm/archive/build.zig +++ b/test/link/wasm/archive/build.zig @@ -2,16 +2,17 @@ const std = @import("std"); const Builder = std.build.Builder; pub fn build(b: *Builder) void { - const mode = b.standardReleaseOptions(); - const test_step = b.step("test", "Test"); test_step.dependOn(b.getInstallStep()); // The code in question will pull-in compiler-rt, // and therefore link with its archive file. - const lib = b.addSharedLibrary("main", "main.zig", .unversioned); - lib.setBuildMode(mode); - lib.setTarget(.{ .cpu_arch = .wasm32, .os_tag = .freestanding }); + const lib = b.addSharedLibrary(.{ + .name = "main", + .root_source_file = .{ .path = "main.zig" }, + .optimize = b.standardOptimizeOption(.{}), + .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding }, + }); lib.use_llvm = false; lib.use_lld = false; lib.strip = false; diff --git a/test/link/wasm/basic-features/build.zig b/test/link/wasm/basic-features/build.zig index 2c565f92633066baecdf4ad89917fd30fef0e18a..69e88aefae66a30acf0483625219da513bbfd6cc 100644 --- a/test/link/wasm/basic-features/build.zig +++ b/test/link/wasm/basic-features/build.zig @@ -1,14 +1,18 @@ const std = @import("std"); pub fn build(b: *std.build.Builder) void { - const mode = b.standardReleaseOptions(); - // Library with explicitly set cpu features - const lib = b.addSharedLibrary("lib", "main.zig", .unversioned); - lib.setTarget(.{ .cpu_arch = .wasm32, .os_tag = .freestanding }); - lib.target.cpu_model = .{ .explicit = &std.Target.wasm.cpu.mvp }; - lib.target.cpu_features_add.addFeature(0); // index 0 == atomics (see std.Target.wasm.Features) - lib.setBuildMode(mode); + const lib = b.addSharedLibrary(.{ + .name = "lib", + .root_source_file = .{ .path = "main.zig" }, + .optimize = b.standardOptimizeOption(.{}), + .target = .{ + .cpu_arch = .wasm32, + .cpu_model = .{ .explicit = &std.Target.wasm.cpu.mvp }, + .cpu_features_add = std.Target.wasm.featureSet(&.{.atomics}), + .os_tag = .freestanding, + }, + }); lib.use_llvm = false; lib.use_lld = false; diff --git a/test/link/wasm/bss/build.zig b/test/link/wasm/bss/build.zig index e234a3f40254346d253d6846da92aba19e87100c..6b29fd0dc3c8d31aeba8d562b1f9eb641dfbe6b1 100644 --- a/test/link/wasm/bss/build.zig +++ b/test/link/wasm/bss/build.zig @@ -2,14 +2,15 @@ const std = @import("std"); const Builder = std.build.Builder; pub fn build(b: *Builder) void { - const mode = b.standardReleaseOptions(); - const test_step = b.step("test", "Test"); test_step.dependOn(b.getInstallStep()); - const lib = b.addSharedLibrary("lib", "lib.zig", .unversioned); - lib.setBuildMode(mode); - lib.setTarget(.{ .cpu_arch = .wasm32, .os_tag = .freestanding }); + const lib = b.addSharedLibrary(.{ + .name = "lib", + .root_source_file = .{ .path = "lib.zig" }, + .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding }, + .optimize = b.standardOptimizeOption(.{}), + }); lib.use_llvm = false; lib.use_lld = false; lib.strip = false; diff --git a/test/link/wasm/export-data/build.zig b/test/link/wasm/export-data/build.zig index 283566dab3aaff0fbd33da647a9a38e7cf5450bf..8eab283ec212a0cb16a2539bdc7a66f371ac9ec7 100644 --- a/test/link/wasm/export-data/build.zig +++ b/test/link/wasm/export-data/build.zig @@ -5,9 +5,12 @@ pub fn build(b: *Builder) void { const test_step = b.step("test", "Test"); test_step.dependOn(b.getInstallStep()); - const lib = b.addSharedLibrary("lib", "lib.zig", .unversioned); - lib.setBuildMode(.ReleaseSafe); // to make the output deterministic in address positions - lib.setTarget(.{ .cpu_arch = .wasm32, .os_tag = .freestanding }); + const lib = b.addSharedLibrary(.{ + .name = "lib", + .root_source_file = .{ .path = "lib.zig" }, + .optimize = .ReleaseSafe, // to make the output deterministic in address positions + .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding }, + }); lib.use_lld = false; lib.export_symbol_names = &.{ "foo", "bar" }; lib.global_base = 0; // put data section at address 0 to make data symbols easier to parse diff --git a/test/link/wasm/export/build.zig b/test/link/wasm/export/build.zig index 181e77e2966fe6d7ec295de2e7d7c88093a3821a..2b9a91d728c2afd3d70d548effbe003a8233fda7 100644 --- a/test/link/wasm/export/build.zig +++ b/test/link/wasm/export/build.zig @@ -1,24 +1,33 @@ const std = @import("std"); pub fn build(b: *std.build.Builder) void { - const mode = b.standardReleaseOptions(); + const optimize = b.standardOptimizeOption(.{}); - const no_export = b.addSharedLibrary("no-export", "main.zig", .unversioned); - no_export.setTarget(.{ .cpu_arch = .wasm32, .os_tag = .freestanding }); - no_export.setBuildMode(mode); + const no_export = b.addSharedLibrary(.{ + .name = "no-export", + .root_source_file = .{ .path = "main.zig" }, + .optimize = optimize, + .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding }, + }); no_export.use_llvm = false; no_export.use_lld = false; - const dynamic_export = b.addSharedLibrary("dynamic", "main.zig", .unversioned); - dynamic_export.setTarget(.{ .cpu_arch = .wasm32, .os_tag = .freestanding }); - dynamic_export.setBuildMode(mode); + const dynamic_export = b.addSharedLibrary(.{ + .name = "dynamic", + .root_source_file = .{ .path = "main.zig" }, + .optimize = optimize, + .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding }, + }); dynamic_export.rdynamic = true; dynamic_export.use_llvm = false; dynamic_export.use_lld = false; - const force_export = b.addSharedLibrary("force", "main.zig", .unversioned); - force_export.setTarget(.{ .cpu_arch = .wasm32, .os_tag = .freestanding }); - force_export.setBuildMode(mode); + const force_export = b.addSharedLibrary(.{ + .name = "force", + .root_source_file = .{ .path = "main.zig" }, + .optimize = optimize, + .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding }, + }); force_export.export_symbol_names = &.{"foo"}; force_export.use_llvm = false; force_export.use_lld = false; diff --git a/test/link/wasm/extern-mangle/build.zig b/test/link/wasm/extern-mangle/build.zig index ae46117f186891555cc85d29e6646b1d1ccde317..71bb986dff36294c0b003a3b53d55f0e859caa75 100644 --- a/test/link/wasm/extern-mangle/build.zig +++ b/test/link/wasm/extern-mangle/build.zig @@ -2,14 +2,15 @@ const std = @import("std"); const Builder = std.build.Builder; pub fn build(b: *Builder) void { - const mode = b.standardReleaseOptions(); - const test_step = b.step("test", "Test"); test_step.dependOn(b.getInstallStep()); - const lib = b.addSharedLibrary("lib", "lib.zig", .unversioned); - lib.setBuildMode(mode); - lib.setTarget(.{ .cpu_arch = .wasm32, .os_tag = .freestanding }); + const lib = b.addSharedLibrary(.{ + .name = "lib", + .root_source_file = .{ .path = "lib.zig" }, + .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding }, + .optimize = b.standardOptimizeOption(.{}), + }); lib.import_symbols = true; // import `a` and `b` lib.rdynamic = true; // export `foo` lib.install(); diff --git a/test/link/wasm/extern/build.zig b/test/link/wasm/extern/build.zig index 88cce88d98954aa51ebddeb040c1cf189dcbd931..800c76a31c580f54efd9ac2789478f5643f96e43 100644 --- a/test/link/wasm/extern/build.zig +++ b/test/link/wasm/extern/build.zig @@ -1,10 +1,12 @@ const std = @import("std"); pub fn build(b: *std.build.Builder) void { - const mode = b.standardReleaseOptions(); - const exe = b.addExecutable("extern", "main.zig"); - exe.setTarget(.{ .cpu_arch = .wasm32, .os_tag = .wasi }); - exe.setBuildMode(mode); + const exe = b.addExecutable(.{ + .name = "extern", + .root_source_file = .{ .path = "main.zig" }, + .optimize = b.standardOptimizeOption(.{}), + .target = .{ .cpu_arch = .wasm32, .os_tag = .wasi }, + }); exe.addCSourceFile("foo.c", &.{}); exe.use_llvm = false; exe.use_lld = false; diff --git a/test/link/wasm/function-table/build.zig b/test/link/wasm/function-table/build.zig index f7572bd6b1238ff3015b470bcf571d027c6a01fc..804aaf0b098190a8d0f5899749131b396e48770e 100644 --- a/test/link/wasm/function-table/build.zig +++ b/test/link/wasm/function-table/build.zig @@ -2,28 +2,37 @@ const std = @import("std"); const Builder = std.build.Builder; pub fn build(b: *Builder) void { - const mode = b.standardReleaseOptions(); + const optimize = b.standardOptimizeOption(.{}); const test_step = b.step("test", "Test"); test_step.dependOn(b.getInstallStep()); - const import_table = b.addSharedLibrary("lib", "lib.zig", .unversioned); - import_table.setBuildMode(mode); - import_table.setTarget(.{ .cpu_arch = .wasm32, .os_tag = .freestanding }); + const import_table = b.addSharedLibrary(.{ + .name = "lib", + .root_source_file = .{ .path = "lib.zig" }, + .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding }, + .optimize = optimize, + }); import_table.use_llvm = false; import_table.use_lld = false; import_table.import_table = true; - const export_table = b.addSharedLibrary("lib", "lib.zig", .unversioned); - export_table.setBuildMode(mode); - export_table.setTarget(.{ .cpu_arch = .wasm32, .os_tag = .freestanding }); + const export_table = b.addSharedLibrary(.{ + .name = "lib", + .root_source_file = .{ .path = "lib.zig" }, + .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding }, + .optimize = optimize, + }); export_table.use_llvm = false; export_table.use_lld = false; export_table.export_table = true; - const regular_table = b.addSharedLibrary("lib", "lib.zig", .unversioned); - regular_table.setBuildMode(mode); - regular_table.setTarget(.{ .cpu_arch = .wasm32, .os_tag = .freestanding }); + const regular_table = b.addSharedLibrary(.{ + .name = "lib", + .root_source_file = .{ .path = "lib.zig" }, + .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding }, + .optimize = optimize, + }); regular_table.use_llvm = false; regular_table.use_lld = false; diff --git a/test/link/wasm/infer-features/build.zig b/test/link/wasm/infer-features/build.zig index b50caf7264ff693e96b3a9a6f1e7b480bed67fe4..147fb55fdae2def902f76f0bf4f986a6da4724d8 100644 --- a/test/link/wasm/infer-features/build.zig +++ b/test/link/wasm/infer-features/build.zig @@ -1,21 +1,32 @@ const std = @import("std"); pub fn build(b: *std.build.Builder) void { - const mode = b.standardReleaseOptions(); + const optimize = b.standardOptimizeOption(.{}); // Wasm Object file which we will use to infer the features from - const c_obj = b.addObject("c_obj", null); - c_obj.setTarget(.{ .cpu_arch = .wasm32, .os_tag = .freestanding }); - c_obj.target.cpu_model = .{ .explicit = &std.Target.wasm.cpu.bleeding_edge }; + const c_obj = b.addObject(.{ + .name = "c_obj", + .optimize = optimize, + .target = .{ + .cpu_arch = .wasm32, + .cpu_model = .{ .explicit = &std.Target.wasm.cpu.bleeding_edge }, + .os_tag = .freestanding, + }, + }); c_obj.addCSourceFile("foo.c", &.{}); - c_obj.setBuildMode(mode); // Wasm library that doesn't have any features specified. This will // infer its featureset from other linked object files. - const lib = b.addSharedLibrary("lib", "main.zig", .unversioned); - lib.setTarget(.{ .cpu_arch = .wasm32, .os_tag = .freestanding }); - lib.target.cpu_model = .{ .explicit = &std.Target.wasm.cpu.mvp }; - lib.setBuildMode(mode); + const lib = b.addSharedLibrary(.{ + .name = "lib", + .root_source_file = .{ .path = "main.zig" }, + .optimize = optimize, + .target = .{ + .cpu_arch = .wasm32, + .cpu_model = .{ .explicit = &std.Target.wasm.cpu.mvp }, + .os_tag = .freestanding, + }, + }); lib.use_llvm = false; lib.use_lld = false; lib.addObject(c_obj); diff --git a/test/link/wasm/producers/build.zig b/test/link/wasm/producers/build.zig index 7557b4fa4144cd9eef161f195a3f8fd3da9b6309..57ee6acd184e9866453551ac912e24c906218323 100644 --- a/test/link/wasm/producers/build.zig +++ b/test/link/wasm/producers/build.zig @@ -3,14 +3,15 @@ const builtin = @import("builtin"); const Builder = std.build.Builder; pub fn build(b: *Builder) void { - const mode = b.standardReleaseOptions(); - const test_step = b.step("test", "Test"); test_step.dependOn(b.getInstallStep()); - const lib = b.addSharedLibrary("lib", "lib.zig", .unversioned); - lib.setBuildMode(mode); - lib.setTarget(.{ .cpu_arch = .wasm32, .os_tag = .freestanding }); + const lib = b.addSharedLibrary(.{ + .name = "lib", + .root_source_file = .{ .path = "lib.zig" }, + .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding }, + .optimize = b.standardOptimizeOption(.{}), + }); lib.use_llvm = false; lib.use_lld = false; lib.strip = false; diff --git a/test/link/wasm/segments/build.zig b/test/link/wasm/segments/build.zig index 1b2cdf87ab4f71d6b67a45652a6dc98314c208be..8f7d9e0583a7b3ac0ed4c3a8da7890690501e930 100644 --- a/test/link/wasm/segments/build.zig +++ b/test/link/wasm/segments/build.zig @@ -2,14 +2,15 @@ const std = @import("std"); const Builder = std.build.Builder; pub fn build(b: *Builder) void { - const mode = b.standardReleaseOptions(); - const test_step = b.step("test", "Test"); test_step.dependOn(b.getInstallStep()); - const lib = b.addSharedLibrary("lib", "lib.zig", .unversioned); - lib.setBuildMode(mode); - lib.setTarget(.{ .cpu_arch = .wasm32, .os_tag = .freestanding }); + const lib = b.addSharedLibrary(.{ + .name = "lib", + .root_source_file = .{ .path = "lib.zig" }, + .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding }, + .optimize = b.standardOptimizeOption(.{}), + }); lib.use_llvm = false; lib.use_lld = false; lib.strip = false; diff --git a/test/link/wasm/stack_pointer/build.zig b/test/link/wasm/stack_pointer/build.zig index 5b67c3caa3f42a8cbbfa9c470b934d9e47e14787..42971c607de734e1ac5eb1607c5a1522b3c3243b 100644 --- a/test/link/wasm/stack_pointer/build.zig +++ b/test/link/wasm/stack_pointer/build.zig @@ -2,14 +2,15 @@ const std = @import("std"); const Builder = std.build.Builder; pub fn build(b: *Builder) void { - const mode = b.standardReleaseOptions(); - const test_step = b.step("test", "Test"); test_step.dependOn(b.getInstallStep()); - const lib = b.addSharedLibrary("lib", "lib.zig", .unversioned); - lib.setBuildMode(mode); - lib.setTarget(.{ .cpu_arch = .wasm32, .os_tag = .freestanding }); + const lib = b.addSharedLibrary(.{ + .name = "lib", + .root_source_file = .{ .path = "lib.zig" }, + .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding }, + .optimize = b.standardOptimizeOption(.{}), + }); lib.use_llvm = false; lib.use_lld = false; lib.strip = false; diff --git a/test/link/wasm/type/build.zig b/test/link/wasm/type/build.zig index fbae6dc741da26a9f4ec51de54d56c157b139dcb..7fa384908398841fcbba9a37d91d85f47bab9990 100644 --- a/test/link/wasm/type/build.zig +++ b/test/link/wasm/type/build.zig @@ -2,14 +2,15 @@ const std = @import("std"); const Builder = std.build.Builder; pub fn build(b: *Builder) void { - const mode = b.standardReleaseOptions(); - const test_step = b.step("test", "Test"); test_step.dependOn(b.getInstallStep()); - const lib = b.addSharedLibrary("lib", "lib.zig", .unversioned); - lib.setBuildMode(mode); - lib.setTarget(.{ .cpu_arch = .wasm32, .os_tag = .freestanding }); + const lib = b.addSharedLibrary(.{ + .name = "lib", + .root_source_file = .{ .path = "lib.zig" }, + .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding }, + .optimize = b.standardOptimizeOption(.{}), + }); lib.use_llvm = false; lib.use_lld = false; lib.strip = false; diff --git a/test/src/compare_output.zig b/test/src/compare_output.zig index 538e4023f0f32615383a1cb2fe59de271f9b5daf..a885faaadffb58109274a14fdbd3807f7685500e 100644 --- a/test/src/compare_output.zig +++ b/test/src/compare_output.zig @@ -6,14 +6,14 @@ const ArrayList = std.ArrayList; const fmt = std.fmt; const mem = std.mem; const fs = std.fs; -const Mode = std.builtin.Mode; +const OptimizeMode = std.builtin.OptimizeMode; pub const CompareOutputContext = struct { b: *build.Builder, step: *build.Step, test_index: usize, test_filter: ?[]const u8, - modes: []const Mode, + optimize_modes: []const OptimizeMode, const Special = enum { None, @@ -102,7 +102,11 @@ pub const CompareOutputContext = struct { if (mem.indexOf(u8, annotated_case_name, filter) == null) return; } - const exe = b.addExecutable("test", null); + const exe = b.addExecutable(.{ + .name = "test", + .target = .{}, + .optimize = .Debug, + }); exe.addAssemblyFileSource(write_src.getFileSource(case.sources.items[0].filename).?); const run = exe.run(); @@ -113,19 +117,23 @@ pub const CompareOutputContext = struct { self.step.dependOn(&run.step); }, Special.None => { - for (self.modes) |mode| { + for (self.optimize_modes) |optimize| { const annotated_case_name = fmt.allocPrint(self.b.allocator, "{s} {s} ({s})", .{ "compare-output", case.name, - @tagName(mode), + @tagName(optimize), }) catch unreachable; if (self.test_filter) |filter| { if (mem.indexOf(u8, annotated_case_name, filter) == null) continue; } const basename = case.sources.items[0].filename; - const exe = b.addExecutableSource("test", write_src.getFileSource(basename).?); - exe.setBuildMode(mode); + const exe = b.addExecutable(.{ + .name = "test", + .root_source_file = write_src.getFileSource(basename).?, + .optimize = optimize, + .target = .{}, + }); if (case.link_libc) { exe.linkSystemLibrary("c"); } @@ -139,13 +147,20 @@ pub const CompareOutputContext = struct { } }, Special.RuntimeSafety => { + // TODO iterate over self.optimize_modes and test this in both + // debug and release safe mode const annotated_case_name = fmt.allocPrint(self.b.allocator, "safety {s}", .{case.name}) catch unreachable; if (self.test_filter) |filter| { if (mem.indexOf(u8, annotated_case_name, filter) == null) return; } const basename = case.sources.items[0].filename; - const exe = b.addExecutableSource("test", write_src.getFileSource(basename).?); + const exe = b.addExecutable(.{ + .name = "test", + .root_source_file = write_src.getFileSource(basename).?, + .target = .{}, + .optimize = .Debug, + }); if (case.link_libc) { exe.linkSystemLibrary("c"); } diff --git a/test/src/run_translated_c.zig b/test/src/run_translated_c.zig index 0204272f9716f9227f420a079125cc0e6365c9f6..0c54655b32bfe8695efd9af2644adc02c91ed5ae 100644 --- a/test/src/run_translated_c.zig +++ b/test/src/run_translated_c.zig @@ -85,11 +85,14 @@ pub const RunTranslatedCContext = struct { for (case.sources.items) |src_file| { write_src.add(src_file.filename, src_file.source); } - const translate_c = b.addTranslateC(write_src.getFileSource(case.sources.items[0].filename).?); + const translate_c = b.addTranslateC(.{ + .source_file = write_src.getFileSource(case.sources.items[0].filename).?, + .target = .{}, + .optimize = .Debug, + }); translate_c.step.name = b.fmt("{s} translate-c", .{annotated_case_name}); - const exe = translate_c.addExecutable(); - exe.setTarget(self.target); + const exe = translate_c.addExecutable(.{}); exe.step.name = b.fmt("{s} build-exe", .{annotated_case_name}); exe.linkLibC(); const run = exe.run(); diff --git a/test/src/translate_c.zig b/test/src/translate_c.zig index f0f6f30c57cf51789c87de7a89e8bbac8a53b139..ad5fbb709140afd5d455cfb0e2eb4a4f5e3b5d78 100644 --- a/test/src/translate_c.zig +++ b/test/src/translate_c.zig @@ -108,10 +108,13 @@ pub const TranslateCContext = struct { write_src.add(src_file.filename, src_file.source); } - const translate_c = b.addTranslateC(write_src.getFileSource(case.sources.items[0].filename).?); + const translate_c = b.addTranslateC(.{ + .source_file = write_src.getFileSource(case.sources.items[0].filename).?, + .target = case.target, + .optimize = .Debug, + }); translate_c.step.name = annotated_case_name; - translate_c.setTarget(case.target); const check_file = translate_c.addCheckFile(case.expected_lines.items); diff --git a/test/standalone/brace_expansion/build.zig b/test/standalone/brace_expansion/build.zig index 64f3c08583ce5bf926e33df76c6b6d9779b9d332..89250ff96fe489da24d7b968c26d0b3cf9a938a5 100644 --- a/test/standalone/brace_expansion/build.zig +++ b/test/standalone/brace_expansion/build.zig @@ -1,8 +1,10 @@ const Builder = @import("std").build.Builder; pub fn build(b: *Builder) void { - const main = b.addTest("main.zig"); - main.setBuildMode(b.standardReleaseOptions()); + const main = b.addTest(.{ + .root_source_file = .{ .path = "main.zig" }, + .optimize = b.standardOptimizeOption(.{}), + }); const test_step = b.step("test", "Test it"); test_step.dependOn(&main.step); diff --git a/test/standalone/c_compiler/build.zig b/test/standalone/c_compiler/build.zig index 240d53518204e3928406dd59bec94d41d9b1f7a5..6959f810d63fbebe247cdea393206d8067a6a83d 100644 --- a/test/standalone/c_compiler/build.zig +++ b/test/standalone/c_compiler/build.zig @@ -12,23 +12,27 @@ fn isRunnableTarget(t: CrossTarget) bool { } pub fn build(b: *Builder) void { - const mode = b.standardReleaseOptions(); + const optimize = b.standardOptimizeOption(.{}); const target = b.standardTargetOptions(.{}); const test_step = b.step("test", "Test the program"); - const exe_c = b.addExecutable("test_c", null); + const exe_c = b.addExecutable(.{ + .name = "test_c", + .optimize = optimize, + .target = target, + }); b.default_step.dependOn(&exe_c.step); exe_c.addCSourceFile("test.c", &[0][]const u8{}); - exe_c.setBuildMode(mode); - exe_c.setTarget(target); exe_c.linkLibC(); - const exe_cpp = b.addExecutable("test_cpp", null); + const exe_cpp = b.addExecutable(.{ + .name = "test_cpp", + .optimize = optimize, + .target = target, + }); b.default_step.dependOn(&exe_cpp.step); exe_cpp.addCSourceFile("test.cpp", &[0][]const u8{}); - exe_cpp.setBuildMode(mode); - exe_cpp.setTarget(target); exe_cpp.linkLibCpp(); switch (target.getOsTag()) { diff --git a/test/standalone/emit_asm_and_bin/build.zig b/test/standalone/emit_asm_and_bin/build.zig index 43b7bb791d82038f4ebd67f5fd3d0d6c8defc3ba..b8cbd5fc176152616ef08f966c5da80cc79eb25b 100644 --- a/test/standalone/emit_asm_and_bin/build.zig +++ b/test/standalone/emit_asm_and_bin/build.zig @@ -1,8 +1,10 @@ const Builder = @import("std").build.Builder; pub fn build(b: *Builder) void { - const main = b.addTest("main.zig"); - main.setBuildMode(b.standardReleaseOptions()); + const main = b.addTest(.{ + .root_source_file = .{ .path = "main.zig" }, + .optimize = b.standardOptimizeOption(.{}), + }); main.emit_asm = .{ .emit_to = b.pathFromRoot("main.s") }; main.emit_bin = .{ .emit_to = b.pathFromRoot("main") }; diff --git a/test/standalone/empty_env/build.zig b/test/standalone/empty_env/build.zig index 2a184dcd2ef482e00c551739dac922f50536be53..ecdd74aa90c81227f5d007a7d5584f4aadbacde6 100644 --- a/test/standalone/empty_env/build.zig +++ b/test/standalone/empty_env/build.zig @@ -1,8 +1,11 @@ const Builder = @import("std").build.Builder; pub fn build(b: *Builder) void { - const main = b.addExecutable("main", "main.zig"); - main.setBuildMode(b.standardReleaseOptions()); + const main = b.addExecutable(.{ + .name = "main", + .root_source_file = .{ .path = "main.zig" }, + .optimize = b.standardOptimizeOption(.{}), + }); const run = main.run(); run.clearEnvironment(); diff --git a/test/standalone/global_linkage/build.zig b/test/standalone/global_linkage/build.zig index e13c0e8873b9212e24a9f692ef777d9c01e48fca..3064c6cc084ef49d3c7e6867c243bcdb8b0b8086 100644 --- a/test/standalone/global_linkage/build.zig +++ b/test/standalone/global_linkage/build.zig @@ -1,16 +1,26 @@ const Builder = @import("std").build.Builder; pub fn build(b: *Builder) void { - const mode = b.standardReleaseOptions(); + const optimize = b.standardOptimizeOption(.{}); - const obj1 = b.addStaticLibrary("obj1", "obj1.zig"); - obj1.setBuildMode(mode); + const obj1 = b.addStaticLibrary(.{ + .name = "obj1", + .root_source_file = .{ .path = "obj1.zig" }, + .optimize = optimize, + .target = .{}, + }); - const obj2 = b.addStaticLibrary("obj2", "obj2.zig"); - obj2.setBuildMode(mode); + const obj2 = b.addStaticLibrary(.{ + .name = "obj2", + .root_source_file = .{ .path = "obj2.zig" }, + .optimize = optimize, + .target = .{}, + }); - const main = b.addTest("main.zig"); - main.setBuildMode(mode); + const main = b.addTest(.{ + .root_source_file = .{ .path = "main.zig" }, + .optimize = optimize, + }); main.linkLibrary(obj1); main.linkLibrary(obj2); diff --git a/test/standalone/install_raw_hex/build.zig b/test/standalone/install_raw_hex/build.zig index 0038c4c2981ee38c9f83ec8d37e1e7a14894826c..94016b1d747bddbfe14c0fe247337ca100e6d254 100644 --- a/test/standalone/install_raw_hex/build.zig +++ b/test/standalone/install_raw_hex/build.zig @@ -10,11 +10,14 @@ pub fn build(b: *std.build.Builder) void { .abi = .gnueabihf, }; - const mode = b.standardReleaseOptions(); + const optimize = b.standardOptimizeOption(.{}); - const elf = b.addExecutable("zig-nrf52-blink.elf", "main.zig"); - elf.setTarget(target); - elf.setBuildMode(mode); + const elf = b.addExecutable(.{ + .name = "zig-nrf52-blink.elf", + .root_source_file = .{ .path = "main.zig" }, + .target = target, + .optimize = optimize, + }); const test_step = b.step("test", "Test the program"); b.default_step.dependOn(test_step); diff --git a/test/standalone/issue_11595/build.zig b/test/standalone/issue_11595/build.zig index d636f63ebcdfff3b5696addf9a9842255ab64166..b0310947f67394078fb4fac09696170ccafd8cea 100644 --- a/test/standalone/issue_11595/build.zig +++ b/test/standalone/issue_11595/build.zig @@ -12,11 +12,15 @@ fn isRunnableTarget(t: CrossTarget) bool { } pub fn build(b: *Builder) void { - const mode = b.standardReleaseOptions(); + const optimize = b.standardOptimizeOption(.{}); const target = b.standardTargetOptions(.{}); - const exe = b.addExecutable("zigtest", "main.zig"); - exe.setBuildMode(mode); + const exe = b.addExecutable(.{ + .name = "zigtest", + .root_source_file = .{ .path = "main.zig" }, + .target = target, + .optimize = optimize, + }); exe.install(); const c_sources = [_][]const u8{ @@ -39,7 +43,6 @@ pub fn build(b: *Builder) void { exe.defineCMacro("QUX", "\"Q\" \"UX\""); exe.defineCMacro("QUUX", "\"QU\\\"UX\""); - exe.setTarget(target); b.default_step.dependOn(&exe.step); const test_step = b.step("test", "Test the program"); diff --git a/test/standalone/issue_12588/build.zig b/test/standalone/issue_12588/build.zig index 02fa5e1680d3c5725311a394ab566d60715cbdb1..27a23d5a76f1c6a5a0347dedcc02f5ca6b4dba59 100644 --- a/test/standalone/issue_12588/build.zig +++ b/test/standalone/issue_12588/build.zig @@ -2,12 +2,15 @@ const std = @import("std"); const Builder = std.build.Builder; pub fn build(b: *Builder) void { - const mode = b.standardReleaseOptions(); + const optimize = b.standardOptimizeOption(.{}); const target = b.standardTargetOptions(.{}); - const obj = b.addObject("main", "main.zig"); - obj.setBuildMode(mode); - obj.setTarget(target); + const obj = b.addObject(.{ + .name = "main", + .root_source_file = .{ .path = "main.zig" }, + .optimize = optimize, + .target = target, + }); obj.emit_llvm_ir = .{ .emit_to = b.pathFromRoot("main.ll") }; obj.emit_llvm_bc = .{ .emit_to = b.pathFromRoot("main.bc") }; obj.emit_bin = .no_emit; diff --git a/test/standalone/issue_12706/build.zig b/test/standalone/issue_12706/build.zig index d84160a4f499a6baf119fe7916eadffb0f545daa..e3c40d34c6c4ea8e30acfb6c3ebc39dd178dc590 100644 --- a/test/standalone/issue_12706/build.zig +++ b/test/standalone/issue_12706/build.zig @@ -12,11 +12,15 @@ fn isRunnableTarget(t: CrossTarget) bool { } pub fn build(b: *Builder) void { - const mode = b.standardReleaseOptions(); + const optimize = b.standardOptimizeOption(.{}); const target = b.standardTargetOptions(.{}); - const exe = b.addExecutable("main", "main.zig"); - exe.setBuildMode(mode); + const exe = b.addExecutable(.{ + .name = "main", + .root_source_file = .{ .path = "main.zig" }, + .optimize = optimize, + .target = target, + }); exe.install(); const c_sources = [_][]const u8{ @@ -26,7 +30,6 @@ pub fn build(b: *Builder) void { exe.addCSourceFiles(&c_sources, &.{}); exe.linkLibC(); - exe.setTarget(target); b.default_step.dependOn(&exe.step); const test_step = b.step("test", "Test the program"); diff --git a/test/standalone/issue_13030/build.zig b/test/standalone/issue_13030/build.zig index 8c05e47cf60af186527860502799dbf2b0e8a5ae..510c7610d9c2c61e9847322c6732c84e65e016ae 100644 --- a/test/standalone/issue_13030/build.zig +++ b/test/standalone/issue_13030/build.zig @@ -4,13 +4,15 @@ const Builder = std.build.Builder; const CrossTarget = std.zig.CrossTarget; pub fn build(b: *Builder) void { - const mode = b.standardReleaseOptions(); + const optimize = b.standardOptimizeOption(.{}); const target = b.standardTargetOptions(.{}); - const obj = b.addObject("main", "main.zig"); - obj.setBuildMode(mode); - - obj.setTarget(target); + const obj = b.addObject(.{ + .name = "main", + .root_source_file = .{ .path = "main.zig" }, + .optimize = optimize, + .target = target, + }); b.default_step.dependOn(&obj.step); const test_step = b.step("test", "Test the program"); diff --git a/test/standalone/issue_339/build.zig b/test/standalone/issue_339/build.zig index 733b3729c14aa28c090dbbdc98afb95e0ac4a23a..34c555cfdbc91e8f786189efcb977dd36565b415 100644 --- a/test/standalone/issue_339/build.zig +++ b/test/standalone/issue_339/build.zig @@ -1,7 +1,12 @@ const Builder = @import("std").build.Builder; pub fn build(b: *Builder) void { - const obj = b.addObject("test", "test.zig"); + const obj = b.addObject(.{ + .name = "test", + .root_source_file = .{ .path = "test.zig" }, + .target = b.standardTargetOptions(.{}), + .optimize = b.standardOptimizeOption(.{}), + }); const test_step = b.step("test", "Test the program"); test_step.dependOn(&obj.step); diff --git a/test/standalone/issue_5825/build.zig b/test/standalone/issue_5825/build.zig index 8f43ae13581893a47fc52f792138407bc03f646c..8d7acc3e9a7e30ef20cf904183cccfe86dd01408 100644 --- a/test/standalone/issue_5825/build.zig +++ b/test/standalone/issue_5825/build.zig @@ -6,17 +6,22 @@ pub fn build(b: *Builder) void { .os_tag = .windows, .abi = .msvc, }; - const mode = b.standardReleaseOptions(); - const obj = b.addObject("issue_5825", "main.zig"); - obj.setTarget(target); - obj.setBuildMode(mode); + const optimize = b.standardOptimizeOption(.{}); + const obj = b.addObject(.{ + .name = "issue_5825", + .root_source_file = .{ .path = "main.zig" }, + .optimize = optimize, + .target = target, + }); - const exe = b.addExecutable("issue_5825", null); + const exe = b.addExecutable(.{ + .name = "issue_5825", + .optimize = optimize, + .target = target, + }); exe.subsystem = .Console; exe.linkSystemLibrary("kernel32"); exe.linkSystemLibrary("ntdll"); - exe.setTarget(target); - exe.setBuildMode(mode); exe.addObject(obj); const test_step = b.step("test", "Test the program"); diff --git a/test/standalone/issue_7030/build.zig b/test/standalone/issue_7030/build.zig index ab3677370a06dba81892aa1b148e7a850df36a76..41a646abe8469870e4fe4a979c0a341c85a91bfd 100644 --- a/test/standalone/issue_7030/build.zig +++ b/test/standalone/issue_7030/build.zig @@ -1,10 +1,13 @@ const Builder = @import("std").build.Builder; pub fn build(b: *Builder) void { - const exe = b.addExecutable("issue_7030", "main.zig"); - exe.setTarget(.{ - .cpu_arch = .wasm32, - .os_tag = .freestanding, + const exe = b.addExecutable(.{ + .name = "issue_7030", + .root_source_file = .{ .path = "main.zig" }, + .target = .{ + .cpu_arch = .wasm32, + .os_tag = .freestanding, + }, }); exe.install(); b.default_step.dependOn(&exe.step); diff --git a/test/standalone/issue_794/build.zig b/test/standalone/issue_794/build.zig index ece74f0e986f02a761e5878fdcf4eaaca5fe425d..59ff7ea9abd73805af066b86741c1c6e5f29f687 100644 --- a/test/standalone/issue_794/build.zig +++ b/test/standalone/issue_794/build.zig @@ -1,7 +1,9 @@ const Builder = @import("std").build.Builder; pub fn build(b: *Builder) void { - const test_artifact = b.addTest("main.zig"); + const test_artifact = b.addTest(.{ + .root_source_file = .{ .path = "main.zig" }, + }); test_artifact.addIncludePath("a_directory"); b.default_step.dependOn(&test_artifact.step); diff --git a/test/standalone/issue_8550/build.zig b/test/standalone/issue_8550/build.zig index 03e8d04bfb61c9e6062836c5c9dfb55c9bf4b9e2..233f701661315fb30879c2dba25bb34b99095b39 100644 --- a/test/standalone/issue_8550/build.zig +++ b/test/standalone/issue_8550/build.zig @@ -8,12 +8,15 @@ pub fn build(b: *std.build.Builder) !void { .explicit = &std.Target.arm.cpu.arm1176jz_s, }, }; - const mode = b.standardReleaseOptions(); - const kernel = b.addExecutable("kernel", "./main.zig"); + const optimize = b.standardOptimizeOption(.{}); + const kernel = b.addExecutable(.{ + .name = "kernel", + .root_source_file = .{ .path = "./main.zig" }, + .optimize = optimize, + .target = target, + }); kernel.addObjectFile("./boot.S"); kernel.setLinkerScriptPath(.{ .path = "./linker.ld" }); - kernel.setBuildMode(mode); - kernel.setTarget(target); kernel.install(); const test_step = b.step("test", "Test it"); diff --git a/test/standalone/issue_9812/build.zig b/test/standalone/issue_9812/build.zig index 677c589a844f24b1a6f4e4530cca2b231400cd24..50eefe846c52d4e3609d8e9b9d2149bf84aa2e67 100644 --- a/test/standalone/issue_9812/build.zig +++ b/test/standalone/issue_9812/build.zig @@ -1,9 +1,11 @@ const std = @import("std"); pub fn build(b: *std.build.Builder) !void { - const mode = b.standardReleaseOptions(); - const zip_add = b.addTest("main.zig"); - zip_add.setBuildMode(mode); + const optimize = b.standardOptimizeOption(.{}); + const zip_add = b.addTest(.{ + .root_source_file = .{ .path = "main.zig" }, + .optimize = optimize, + }); zip_add.addCSourceFile("vendor/kuba-zip/zip.c", &[_][]const u8{ "-std=c99", "-fno-sanitize=undefined", diff --git a/test/standalone/load_dynamic_library/build.zig b/test/standalone/load_dynamic_library/build.zig index 109c742c6f559d1f76e982db7644c7813d2ab11f..1aca02bc715f5967b465f0d00968a436d5af918c 100644 --- a/test/standalone/load_dynamic_library/build.zig +++ b/test/standalone/load_dynamic_library/build.zig @@ -1,13 +1,23 @@ const Builder = @import("std").build.Builder; pub fn build(b: *Builder) void { - const opts = b.standardReleaseOptions(); + const target = b.standardTargetOptions(.{}); + const optimize = b.standardOptimizeOption(.{}); - const lib = b.addSharedLibrary("add", "add.zig", b.version(1, 0, 0)); - lib.setBuildMode(opts); + const lib = b.addSharedLibrary(.{ + .name = "add", + .root_source_file = .{ .path = "add.zig" }, + .version = .{ .major = 1, .minor = 0 }, + .optimize = optimize, + .target = target, + }); - const main = b.addExecutable("main", "main.zig"); - main.setBuildMode(opts); + const main = b.addExecutable(.{ + .name = "main", + .root_source_file = .{ .path = "main.zig" }, + .optimize = optimize, + .target = target, + }); const run = main.run(); run.addArtifactArg(lib); diff --git a/test/standalone/main_pkg_path/build.zig b/test/standalone/main_pkg_path/build.zig index c4ac18f967b3ffd5b904bc5d05d86bfc579939dc..baee74052edde7ccd9a565d52bb5e2ef0f81dafe 100644 --- a/test/standalone/main_pkg_path/build.zig +++ b/test/standalone/main_pkg_path/build.zig @@ -1,7 +1,9 @@ const Builder = @import("std").build.Builder; pub fn build(b: *Builder) void { - const test_exe = b.addTest("a/test.zig"); + const test_exe = b.addTest(.{ + .root_source_file = .{ .path = "a/test.zig" }, + }); test_exe.setMainPkgPath("."); const test_step = b.step("test", "Test the program"); diff --git a/test/standalone/mix_c_files/build.zig b/test/standalone/mix_c_files/build.zig index 68486ea18d74cc6f9e2dcfa9960e6a3964090eaf..ad69f05ff65630eea871d26900454eb319cd5756 100644 --- a/test/standalone/mix_c_files/build.zig +++ b/test/standalone/mix_c_files/build.zig @@ -12,14 +12,17 @@ fn isRunnableTarget(t: CrossTarget) bool { } pub fn build(b: *Builder) void { - const mode = b.standardReleaseOptions(); + const optimize = b.standardOptimizeOption(.{}); const target = b.standardTargetOptions(.{}); - const exe = b.addExecutable("test", "main.zig"); + const exe = b.addExecutable(.{ + .name = "test", + .root_source_file = .{ .path = "main.zig" }, + .optimize = optimize, + .target = target, + }); exe.addCSourceFile("test.c", &[_][]const u8{"-std=c11"}); - exe.setBuildMode(mode); exe.linkLibC(); - exe.setTarget(target); b.default_step.dependOn(&exe.step); const test_step = b.step("test", "Test the program"); diff --git a/test/standalone/mix_o_files/build.zig b/test/standalone/mix_o_files/build.zig index d498e2e20a116c1788cc1260bc8542dbe858da90..de3726538825e2e19a3da5305dfbdce07c1444ca 100644 --- a/test/standalone/mix_o_files/build.zig +++ b/test/standalone/mix_o_files/build.zig @@ -1,9 +1,19 @@ const Builder = @import("std").build.Builder; pub fn build(b: *Builder) void { - const obj = b.addObject("base64", "base64.zig"); + const optimize = b.standardOptimizeOption(.{}); - const exe = b.addExecutable("test", null); + const obj = b.addObject(.{ + .name = "base64", + .root_source_file = .{ .path = "base64.zig" }, + .optimize = optimize, + .target = .{}, + }); + + const exe = b.addExecutable(.{ + .name = "test", + .optimize = optimize, + }); exe.addCSourceFile("test.c", &[_][]const u8{"-std=c99"}); exe.addObject(obj); exe.linkSystemLibrary("c"); diff --git a/test/standalone/options/build.zig b/test/standalone/options/build.zig index 087aceff019a2fc91b74c4fc2a0f4913a024b484..87a584a8875e65be4171052edafe2a817a67b18f 100644 --- a/test/standalone/options/build.zig +++ b/test/standalone/options/build.zig @@ -2,11 +2,13 @@ const std = @import("std"); pub fn build(b: *std.build.Builder) void { const target = b.standardTargetOptions(.{}); - const mode = b.standardReleaseOptions(); + const optimize = b.standardOptimizeOption(.{}); - const main = b.addTest("src/main.zig"); - main.setTarget(target); - main.setBuildMode(mode); + const main = b.addTest(.{ + .root_source_file = .{ .path = "src/main.zig" }, + .target = target, + .optimize = optimize, + }); const options = b.addOptions(); main.addOptions("build_options", options); diff --git a/test/standalone/pie/build.zig b/test/standalone/pie/build.zig index d008fd31c9469989c4eabee2aa2bbc77d0667737..3f0b8b9f2f2287b319b0f5d9f50ebcbecaf86637 100644 --- a/test/standalone/pie/build.zig +++ b/test/standalone/pie/build.zig @@ -1,8 +1,10 @@ const Builder = @import("std").build.Builder; pub fn build(b: *Builder) void { - const main = b.addTest("main.zig"); - main.setBuildMode(b.standardReleaseOptions()); + const main = b.addTest(.{ + .root_source_file = .{ .path = "main.zig" }, + .optimize = b.standardOptimizeOption(.{}), + }); main.pie = true; const test_step = b.step("test", "Test the program"); diff --git a/test/standalone/pkg_import/build.zig b/test/standalone/pkg_import/build.zig index 7529d106f9595b39b833326c9db3d9def2db33bb..8dcfaeded00b10fd33e1d1c37f4479f7c868aa3e 100644 --- a/test/standalone/pkg_import/build.zig +++ b/test/standalone/pkg_import/build.zig @@ -1,14 +1,15 @@ const Builder = @import("std").build.Builder; pub fn build(b: *Builder) void { - const exe = b.addExecutable("test", "test.zig"); + const optimize = b.standardOptimizeOption(.{}); + + const exe = b.addExecutable(.{ + .name = "test", + .root_source_file = .{ .path = "test.zig" }, + .optimize = optimize, + }); exe.addPackagePath("my_pkg", "pkg.zig"); - // This is duplicated to test that you are allowed to call - // b.standardReleaseOptions() twice. - exe.setBuildMode(b.standardReleaseOptions()); - exe.setBuildMode(b.standardReleaseOptions()); - const run = exe.run(); const test_step = b.step("test", "Test it"); diff --git a/test/standalone/shared_library/build.zig b/test/standalone/shared_library/build.zig index 18188311c7b2ba22e9c078ba5b1759854e066b94..135be095bc36385a4223309730aca18499a45963 100644 --- a/test/standalone/shared_library/build.zig +++ b/test/standalone/shared_library/build.zig @@ -1,12 +1,21 @@ const Builder = @import("std").build.Builder; pub fn build(b: *Builder) void { + const optimize = b.standardOptimizeOption(.{}); const target = b.standardTargetOptions(.{}); - const lib = b.addSharedLibrary("mathtest", "mathtest.zig", b.version(1, 0, 0)); - lib.setTarget(target); + const lib = b.addSharedLibrary(.{ + .name = "mathtest", + .root_source_file = .{ .path = "mathtest.zig" }, + .version = .{ .major = 1, .minor = 0 }, + .target = target, + .optimize = optimize, + }); - const exe = b.addExecutable("test", null); - exe.setTarget(target); + const exe = b.addExecutable(.{ + .name = "test", + .target = target, + .optimize = optimize, + }); exe.addCSourceFile("test.c", &[_][]const u8{"-std=c99"}); exe.linkLibrary(lib); exe.linkSystemLibrary("c"); diff --git a/test/standalone/static_c_lib/build.zig b/test/standalone/static_c_lib/build.zig index c64ae48dba0aadc7c5fc0fb04ab618a509d31fa2..81b4349e20f731b8bca00068a52d0e9828463e31 100644 --- a/test/standalone/static_c_lib/build.zig +++ b/test/standalone/static_c_lib/build.zig @@ -1,15 +1,20 @@ const Builder = @import("std").build.Builder; pub fn build(b: *Builder) void { - const mode = b.standardReleaseOptions(); + const optimize = b.standardOptimizeOption(.{}); - const foo = b.addStaticLibrary("foo", null); + const foo = b.addStaticLibrary(.{ + .name = "foo", + .optimize = optimize, + .target = .{}, + }); foo.addCSourceFile("foo.c", &[_][]const u8{}); - foo.setBuildMode(mode); foo.addIncludePath("."); - const test_exe = b.addTest("foo.zig"); - test_exe.setBuildMode(mode); + const test_exe = b.addTest(.{ + .root_source_file = .{ .path = "foo.zig" }, + .optimize = optimize, + }); test_exe.linkLibrary(foo); test_exe.addIncludePath("."); diff --git a/test/standalone/test_runner_path/build.zig b/test/standalone/test_runner_path/build.zig index 738cac9783e0cd9f2fa0c57ec854264764d5469a..9b02da50c1d87775d13b77a715a2f151b33f780f 100644 --- a/test/standalone/test_runner_path/build.zig +++ b/test/standalone/test_runner_path/build.zig @@ -1,7 +1,10 @@ const Builder = @import("std").build.Builder; pub fn build(b: *Builder) void { - const test_exe = b.addTestExe("test", "test.zig"); + const test_exe = b.addTest(.{ + .root_source_file = .{ .path = "test.zig" }, + .kind = .test_exe, + }); test_exe.test_runner = "test_runner.zig"; const test_run = test_exe.run(); diff --git a/test/standalone/use_alias/build.zig b/test/standalone/use_alias/build.zig index da4e8bef4b5471af23fad3f79d2da090e23b77b4..d2ca90f3abff15df958ca5cf27a056b9c085f037 100644 --- a/test/standalone/use_alias/build.zig +++ b/test/standalone/use_alias/build.zig @@ -1,8 +1,10 @@ const Builder = @import("std").build.Builder; pub fn build(b: *Builder) void { - const main = b.addTest("main.zig"); - main.setBuildMode(b.standardReleaseOptions()); + const main = b.addTest(.{ + .root_source_file = .{ .path = "main.zig" }, + .optimize = b.standardOptimizeOption(.{}), + }); main.addIncludePath("."); const test_step = b.step("test", "Test it"); diff --git a/test/standalone/windows_spawn/build.zig b/test/standalone/windows_spawn/build.zig index 10a1132d3af69fb9ce6e625e1231c0860e424fbe..de58a602c3e38516951495807d1a891674f6a835 100644 --- a/test/standalone/windows_spawn/build.zig +++ b/test/standalone/windows_spawn/build.zig @@ -1,13 +1,20 @@ const Builder = @import("std").build.Builder; pub fn build(b: *Builder) void { - const mode = b.standardReleaseOptions(); + const optimize = b.standardOptimizeOption(.{}); - const hello = b.addExecutable("hello", "hello.zig"); - hello.setBuildMode(mode); + const hello = b.addExecutable(.{ + .name = "hello", + .root_source_file = .{ .path = "hello.zig" }, + .optimize = optimize, + }); + + const main = b.addExecutable(.{ + .name = "main", + .root_source_file = .{ .path = "main.zig" }, + .optimize = optimize, + }); - const main = b.addExecutable("main", "main.zig"); - main.setBuildMode(mode); const run = main.run(); run.addArtifactArg(hello); diff --git a/test/tests.zig b/test/tests.zig index 8e972b9ba679bfecf503c30908879c6d02e98362..575550be0275fdb69f1b820a69d5899110b137c6 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -8,7 +8,7 @@ const fs = std.fs; const mem = std.mem; const fmt = std.fmt; const ArrayList = std.ArrayList; -const Mode = std.builtin.Mode; +const OptimizeMode = std.builtin.OptimizeMode; const LibExeObjStep = build.LibExeObjStep; const Allocator = mem.Allocator; const ExecError = build.Builder.ExecError; @@ -30,7 +30,7 @@ pub const CompareOutputContext = @import("src/compare_output.zig").CompareOutput const TestTarget = struct { target: CrossTarget = @as(CrossTarget, .{}), - mode: std.builtin.Mode = .Debug, + optimize_mode: std.builtin.OptimizeMode = .Debug, link_libc: bool = false, single_threaded: bool = false, disable_native: bool = false, @@ -423,38 +423,38 @@ const test_targets = blk: { // Do the release tests last because they take a long time .{ - .mode = .ReleaseFast, + .optimize_mode = .ReleaseFast, }, .{ .link_libc = true, - .mode = .ReleaseFast, + .optimize_mode = .ReleaseFast, }, .{ - .mode = .ReleaseFast, + .optimize_mode = .ReleaseFast, .single_threaded = true, }, .{ - .mode = .ReleaseSafe, + .optimize_mode = .ReleaseSafe, }, .{ .link_libc = true, - .mode = .ReleaseSafe, + .optimize_mode = .ReleaseSafe, }, .{ - .mode = .ReleaseSafe, + .optimize_mode = .ReleaseSafe, .single_threaded = true, }, .{ - .mode = .ReleaseSmall, + .optimize_mode = .ReleaseSmall, }, .{ .link_libc = true, - .mode = .ReleaseSmall, + .optimize_mode = .ReleaseSmall, }, .{ - .mode = .ReleaseSmall, + .optimize_mode = .ReleaseSmall, .single_threaded = true, }, }; @@ -462,14 +462,14 @@ const test_targets = blk: { const max_stdout_size = 1 * 1024 * 1024; // 1 MB -pub fn addCompareOutputTests(b: *build.Builder, test_filter: ?[]const u8, modes: []const Mode) *build.Step { +pub fn addCompareOutputTests(b: *build.Builder, test_filter: ?[]const u8, optimize_modes: []const OptimizeMode) *build.Step { const cases = b.allocator.create(CompareOutputContext) catch unreachable; cases.* = CompareOutputContext{ .b = b, .step = b.step("test-compare-output", "Run the compare output tests"), .test_index = 0, .test_filter = test_filter, - .modes = modes, + .optimize_modes = optimize_modes, }; compare_output.addCases(cases); @@ -477,14 +477,14 @@ pub fn addCompareOutputTests(b: *build.Builder, test_filter: ?[]const u8, modes: return cases.step; } -pub fn addStackTraceTests(b: *build.Builder, test_filter: ?[]const u8, modes: []const Mode) *build.Step { +pub fn addStackTraceTests(b: *build.Builder, test_filter: ?[]const u8, optimize_modes: []const OptimizeMode) *build.Step { const cases = b.allocator.create(StackTracesContext) catch unreachable; cases.* = StackTracesContext{ .b = b, .step = b.step("test-stack-traces", "Run the stack trace tests"), .test_index = 0, .test_filter = test_filter, - .modes = modes, + .optimize_modes = optimize_modes, }; stack_traces.addCases(cases); @@ -495,7 +495,7 @@ pub fn addStackTraceTests(b: *build.Builder, test_filter: ?[]const u8, modes: [] pub fn addStandaloneTests( b: *build.Builder, test_filter: ?[]const u8, - modes: []const Mode, + optimize_modes: []const OptimizeMode, skip_non_native: bool, enable_macos_sdk: bool, target: std.zig.CrossTarget, @@ -513,7 +513,7 @@ pub fn addStandaloneTests( .step = b.step("test-standalone", "Run the standalone tests"), .test_index = 0, .test_filter = test_filter, - .modes = modes, + .optimize_modes = optimize_modes, .skip_non_native = skip_non_native, .enable_macos_sdk = enable_macos_sdk, .target = target, @@ -534,7 +534,7 @@ pub fn addStandaloneTests( pub fn addLinkTests( b: *build.Builder, test_filter: ?[]const u8, - modes: []const Mode, + optimize_modes: []const OptimizeMode, enable_macos_sdk: bool, omit_stage2: bool, enable_symlinks_windows: bool, @@ -545,7 +545,7 @@ pub fn addLinkTests( .step = b.step("test-link", "Run the linker tests"), .test_index = 0, .test_filter = test_filter, - .modes = modes, + .optimize_modes = optimize_modes, .skip_non_native = true, .enable_macos_sdk = enable_macos_sdk, .target = .{}, @@ -556,12 +556,17 @@ pub fn addLinkTests( return cases.step; } -pub fn addCliTests(b: *build.Builder, test_filter: ?[]const u8, modes: []const Mode) *build.Step { +pub fn addCliTests(b: *build.Builder, test_filter: ?[]const u8, optimize_modes: []const OptimizeMode) *build.Step { _ = test_filter; - _ = modes; + _ = optimize_modes; const step = b.step("test-cli", "Test the command line interface"); - const exe = b.addExecutable("test-cli", "test/cli.zig"); + const exe = b.addExecutable(.{ + .name = "test-cli", + .root_source_file = .{ .path = "test/cli.zig" }, + .target = .{}, + .optimize = .Debug, + }); const run_cmd = exe.run(); run_cmd.addArgs(&[_][]const u8{ fs.realpathAlloc(b.allocator, b.zig_exe) catch unreachable, @@ -572,14 +577,14 @@ pub fn addCliTests(b: *build.Builder, test_filter: ?[]const u8, modes: []const M return step; } -pub fn addAssembleAndLinkTests(b: *build.Builder, test_filter: ?[]const u8, modes: []const Mode) *build.Step { +pub fn addAssembleAndLinkTests(b: *build.Builder, test_filter: ?[]const u8, optimize_modes: []const OptimizeMode) *build.Step { const cases = b.allocator.create(CompareOutputContext) catch unreachable; cases.* = CompareOutputContext{ .b = b, .step = b.step("test-asm-link", "Run the assemble and link tests"), .test_index = 0, .test_filter = test_filter, - .modes = modes, + .optimize_modes = optimize_modes, }; assemble_and_link.addCases(cases); @@ -640,7 +645,7 @@ pub fn addPkgTests( root_src: []const u8, name: []const u8, desc: []const u8, - modes: []const Mode, + optimize_modes: []const OptimizeMode, skip_single_threaded: bool, skip_non_native: bool, skip_libc: bool, @@ -677,8 +682,8 @@ pub fn addPkgTests( else => if (skip_stage2) continue, }; - const want_this_mode = for (modes) |m| { - if (m == test_target.mode) break true; + const want_this_mode = for (optimize_modes) |m| { + if (m == test_target.optimize_mode) break true; } else false; if (!want_this_mode) continue; @@ -691,21 +696,23 @@ pub fn addPkgTests( const triple_prefix = test_target.target.zigTriple(b.allocator) catch unreachable; - const these_tests = b.addTest(root_src); + const these_tests = b.addTest(.{ + .root_source_file = .{ .path = root_src }, + .optimize = test_target.optimize_mode, + .target = test_target.target, + }); const single_threaded_txt = if (test_target.single_threaded) "single" else "multi"; const backend_txt = if (test_target.backend) |backend| @tagName(backend) else "default"; these_tests.setNamePrefix(b.fmt("{s}-{s}-{s}-{s}-{s}-{s} ", .{ name, triple_prefix, - @tagName(test_target.mode), + @tagName(test_target.optimize_mode), libc_prefix, single_threaded_txt, backend_txt, })); these_tests.single_threaded = test_target.single_threaded; these_tests.setFilter(test_filter); - these_tests.setBuildMode(test_target.mode); - these_tests.setTarget(test_target.target); if (test_target.link_libc) { these_tests.linkSystemLibrary("c"); } @@ -739,9 +746,9 @@ pub const StackTracesContext = struct { step: *build.Step, test_index: usize, test_filter: ?[]const u8, - modes: []const Mode, + optimize_modes: []const OptimizeMode, - const Expect = [@typeInfo(Mode).Enum.fields.len][]const u8; + const Expect = [@typeInfo(OptimizeMode).Enum.fields.len][]const u8; pub fn addCase(self: *StackTracesContext, config: anytype) void { if (@hasField(@TypeOf(config), "exclude")) { @@ -755,26 +762,26 @@ pub const StackTracesContext = struct { const exclude_os: []const std.Target.Os.Tag = &config.exclude_os; for (exclude_os) |os| if (os == builtin.os.tag) return; } - for (self.modes) |mode| { - switch (mode) { + for (self.optimize_modes) |optimize_mode| { + switch (optimize_mode) { .Debug => { if (@hasField(@TypeOf(config), "Debug")) { - self.addExpect(config.name, config.source, mode, config.Debug); + self.addExpect(config.name, config.source, optimize_mode, config.Debug); } }, .ReleaseSafe => { if (@hasField(@TypeOf(config), "ReleaseSafe")) { - self.addExpect(config.name, config.source, mode, config.ReleaseSafe); + self.addExpect(config.name, config.source, optimize_mode, config.ReleaseSafe); } }, .ReleaseFast => { if (@hasField(@TypeOf(config), "ReleaseFast")) { - self.addExpect(config.name, config.source, mode, config.ReleaseFast); + self.addExpect(config.name, config.source, optimize_mode, config.ReleaseFast); } }, .ReleaseSmall => { if (@hasField(@TypeOf(config), "ReleaseSmall")) { - self.addExpect(config.name, config.source, mode, config.ReleaseSmall); + self.addExpect(config.name, config.source, optimize_mode, config.ReleaseSmall); } }, } @@ -785,7 +792,7 @@ pub const StackTracesContext = struct { self: *StackTracesContext, name: []const u8, source: []const u8, - mode: Mode, + optimize_mode: OptimizeMode, mode_config: anytype, ) void { if (@hasField(@TypeOf(mode_config), "exclude")) { @@ -803,7 +810,7 @@ pub const StackTracesContext = struct { const annotated_case_name = fmt.allocPrint(self.b.allocator, "{s} {s} ({s})", .{ "stack-trace", name, - @tagName(mode), + @tagName(optimize_mode), }) catch unreachable; if (self.test_filter) |filter| { if (mem.indexOf(u8, annotated_case_name, filter) == null) return; @@ -812,14 +819,18 @@ pub const StackTracesContext = struct { const b = self.b; const src_basename = "source.zig"; const write_src = b.addWriteFile(src_basename, source); - const exe = b.addExecutableSource("test", write_src.getFileSource(src_basename).?); - exe.setBuildMode(mode); + const exe = b.addExecutable(.{ + .name = "test", + .root_source_file = write_src.getFileSource(src_basename).?, + .optimize = optimize_mode, + .target = .{}, + }); const run_and_compare = RunAndCompareStep.create( self, exe, annotated_case_name, - mode, + optimize_mode, mode_config.expect, ); @@ -833,7 +844,7 @@ pub const StackTracesContext = struct { context: *StackTracesContext, exe: *LibExeObjStep, name: []const u8, - mode: Mode, + optimize_mode: OptimizeMode, expect_output: []const u8, test_index: usize, @@ -841,7 +852,7 @@ pub const StackTracesContext = struct { context: *StackTracesContext, exe: *LibExeObjStep, name: []const u8, - mode: Mode, + optimize_mode: OptimizeMode, expect_output: []const u8, ) *RunAndCompareStep { const allocator = context.b.allocator; @@ -851,7 +862,7 @@ pub const StackTracesContext = struct { .context = context, .exe = exe, .name = name, - .mode = mode, + .optimize_mode = optimize_mode, .expect_output = expect_output, .test_index = context.test_index, }; @@ -932,7 +943,7 @@ pub const StackTracesContext = struct { // process result // - keep only basename of source file path // - replace address with symbolic string - // - replace function name with symbolic string when mode != .Debug + // - replace function name with symbolic string when optimize_mode != .Debug // - skip empty lines const got: []const u8 = got_result: { var buf = ArrayList(u8).init(b.allocator); @@ -968,7 +979,7 @@ pub const StackTracesContext = struct { // emit substituted line try buf.appendSlice(line[pos + 1 .. marks[2] + delims[2].len]); try buf.appendSlice(" [address]"); - if (self.mode == .Debug) { + if (self.optimize_mode == .Debug) { // On certain platforms (windows) or possibly depending on how we choose to link main // the object file extension may be present so we simply strip any extension. if (mem.indexOfScalar(u8, line[marks[4]..marks[5]], '.')) |idot| { @@ -1007,7 +1018,7 @@ pub const StandaloneContext = struct { step: *build.Step, test_index: usize, test_filter: ?[]const u8, - modes: []const Mode, + optimize_modes: []const OptimizeMode, skip_non_native: bool, enable_macos_sdk: bool, target: std.zig.CrossTarget, @@ -1087,13 +1098,13 @@ pub const StandaloneContext = struct { } } - const modes = if (features.build_modes) self.modes else &[1]Mode{.Debug}; - for (modes) |mode| { - const arg = switch (mode) { + const optimize_modes = if (features.build_modes) self.optimize_modes else &[1]OptimizeMode{.Debug}; + for (optimize_modes) |optimize_mode| { + const arg = switch (optimize_mode) { .Debug => "", - .ReleaseFast => "-Drelease-fast", - .ReleaseSafe => "-Drelease-safe", - .ReleaseSmall => "-Drelease-small", + .ReleaseFast => "-Doptimize=ReleaseFast", + .ReleaseSafe => "-Doptimize=ReleaseSafe", + .ReleaseSmall => "-Doptimize=ReleaseSmall", }; const zig_args_base_len = zig_args.items.len; if (arg.len > 0) @@ -1101,7 +1112,7 @@ pub const StandaloneContext = struct { defer zig_args.resize(zig_args_base_len) catch unreachable; const run_cmd = b.addSystemCommand(zig_args.items); - const log_step = b.addLog("PASS {s} ({s})", .{ annotated_case_name, @tagName(mode) }); + const log_step = b.addLog("PASS {s} ({s})", .{ annotated_case_name, @tagName(optimize_mode) }); log_step.step.dependOn(&run_cmd.step); self.step.dependOn(&log_step.step); @@ -1111,17 +1122,21 @@ pub const StandaloneContext = struct { pub fn addAllArgs(self: *StandaloneContext, root_src: []const u8, link_libc: bool) void { const b = self.b; - for (self.modes) |mode| { + for (self.optimize_modes) |optimize| { const annotated_case_name = fmt.allocPrint(self.b.allocator, "build {s} ({s})", .{ root_src, - @tagName(mode), + @tagName(optimize), }) catch unreachable; if (self.test_filter) |filter| { if (mem.indexOf(u8, annotated_case_name, filter) == null) continue; } - const exe = b.addExecutable("test", root_src); - exe.setBuildMode(mode); + const exe = b.addExecutable(.{ + .name = "test", + .root_source_file = .{ .path = root_src }, + .optimize = optimize, + .target = .{}, + }); if (link_libc) { exe.linkSystemLibrary("c"); } @@ -1247,8 +1262,8 @@ pub const GenHContext = struct { pub fn addCase(self: *GenHContext, case: *const TestCase) void { const b = self.b; - const mode = std.builtin.Mode.Debug; - const annotated_case_name = fmt.allocPrint(self.b.allocator, "gen-h {s} ({s})", .{ case.name, @tagName(mode) }) catch unreachable; + const optimize_mode = std.builtin.OptimizeMode.Debug; + const annotated_case_name = fmt.allocPrint(self.b.allocator, "gen-h {s} ({s})", .{ case.name, @tagName(optimize_mode) }) catch unreachable; if (self.test_filter) |filter| { if (mem.indexOf(u8, annotated_case_name, filter) == null) return; } @@ -1259,7 +1274,7 @@ pub const GenHContext = struct { } const obj = b.addObjectFromWriteFileStep("test", write_src, case.sources.items[0].filename); - obj.setBuildMode(mode); + obj.setBuildMode(optimize_mode); const cmp_h = GenHCmpOutputStep.create(self, obj, annotated_case_name, case); @@ -1336,14 +1351,16 @@ const c_abi_targets = [_]CrossTarget{ pub fn addCAbiTests(b: *build.Builder, skip_non_native: bool, skip_release: bool) *build.Step { const step = b.step("test-c-abi", "Run the C ABI tests"); - const modes: [2]Mode = .{ .Debug, .ReleaseFast }; + const optimize_modes: [2]OptimizeMode = .{ .Debug, .ReleaseFast }; - for (modes[0 .. @as(u8, 1) + @boolToInt(!skip_release)]) |mode| for (c_abi_targets) |c_abi_target| { + for (optimize_modes[0 .. @as(u8, 1) + @boolToInt(!skip_release)]) |optimize_mode| for (c_abi_targets) |c_abi_target| { if (skip_non_native and !c_abi_target.isNative()) continue; - const test_step = b.addTest("test/c_abi/main.zig"); - test_step.setTarget(c_abi_target); + const test_step = b.addTest(.{ + .root_source_file = .{ .path = "test/c_abi/main.zig" }, + .optimize = optimize_mode, + }); if (c_abi_target.abi != null and c_abi_target.abi.?.isMusl()) { // TODO NativeTargetInfo insists on dynamically linking musl // for some reason? @@ -1351,7 +1368,6 @@ pub fn addCAbiTests(b: *build.Builder, skip_non_native: bool, skip_release: bool } test_step.linkLibC(); test_step.addCSourceFile("test/c_abi/cfuncs.c", &.{"-std=c99"}); - test_step.setBuildMode(mode); if (c_abi_target.isWindows() and (c_abi_target.getCpuArch() == .x86 or builtin.target.os.tag == .linux)) { // LTO currently incorrectly strips stdcall name-mangled functions @@ -1363,7 +1379,7 @@ pub fn addCAbiTests(b: *build.Builder, skip_non_native: bool, skip_release: bool test_step.setNamePrefix(b.fmt("{s}-{s}-{s} ", .{ "test-c-abi", triple_prefix, - @tagName(mode), + @tagName(optimize_mode), })); step.dependOn(&test_step.step); -- 2.54.0 From 36e2d992dd8c45ca89a51d508c6c413cff5ad2cd Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 31 Jan 2023 00:19:51 -0700 Subject: [PATCH 47/84] combine std.build and std.build.Builder into std.Build I've been wanting to do this for along time. --- build.zig | 31 +- doc/langref.html.in | 20 +- lib/build_runner.zig | 9 +- lib/init-exe/build.zig | 2 +- lib/init-lib/build.zig | 2 +- lib/std/Build.zig | 1771 ++++++++++++++++ lib/std/{build => Build}/CheckFileStep.zig | 12 +- lib/std/{build => Build}/CheckObjectStep.zig | 18 +- lib/std/{build => Build}/ConfigHeaderStep.zig | 9 +- .../{build => Build}/EmulatableRunStep.zig | 12 +- lib/std/{build => Build}/FmtStep.zig | 11 +- .../{build => Build}/InstallArtifactStep.zig | 21 +- lib/std/{build => Build}/InstallDirStep.zig | 14 +- lib/std/{build => Build}/InstallFileStep.zig | 14 +- lib/std/{build => Build}/InstallRawStep.zig | 24 +- lib/std/{build => Build}/LibExeObjStep.zig | 62 +- lib/std/{build => Build}/LogStep.zig | 8 +- lib/std/{build => Build}/OptionsStep.zig | 18 +- lib/std/{build => Build}/RemoveDirStep.zig | 8 +- lib/std/{build => Build}/RunStep.zig | 26 +- lib/std/Build/Step.zig | 97 + lib/std/{build => Build}/TranslateCStep.zig | 22 +- lib/std/{build => Build}/WriteFileStep.zig | 16 +- lib/std/build.zig | 1863 ----------------- lib/std/std.zig | 8 +- test/link/bss/build.zig | 4 +- test/link/common_symbols/build.zig | 4 +- test/link/common_symbols_alignment/build.zig | 4 +- .../interdependent_static_c_libs/build.zig | 4 +- test/link/macho/bugs/13056/build.zig | 3 +- test/link/macho/bugs/13457/build.zig | 5 +- test/link/macho/dead_strip/build.zig | 7 +- test/link/macho/dead_strip_dylibs/build.zig | 7 +- test/link/macho/dylib/build.zig | 3 +- test/link/macho/empty/build.zig | 5 +- test/link/macho/entry/build.zig | 3 +- test/link/macho/headerpad/build.zig | 7 +- test/link/macho/linksection/build.zig | 2 +- test/link/macho/needed_framework/build.zig | 5 +- test/link/macho/needed_library/build.zig | 5 +- test/link/macho/objc/build.zig | 5 +- test/link/macho/objcpp/build.zig | 3 +- test/link/macho/pagezero/build.zig | 3 +- test/link/macho/search_strategy/build.zig | 13 +- test/link/macho/stack_size/build.zig | 3 +- test/link/macho/strict_validation/build.zig | 5 +- test/link/macho/tls/build.zig | 3 +- test/link/macho/unwind_info/build.zig | 11 +- test/link/macho/uuid/build.zig | 11 +- test/link/macho/weak_framework/build.zig | 5 +- test/link/macho/weak_library/build.zig | 5 +- test/link/static_lib_as_system_lib/build.zig | 3 +- test/link/wasm/archive/build.zig | 3 +- test/link/wasm/basic-features/build.zig | 2 +- test/link/wasm/bss/build.zig | 3 +- test/link/wasm/export-data/build.zig | 3 +- test/link/wasm/export/build.zig | 2 +- test/link/wasm/extern-mangle/build.zig | 3 +- test/link/wasm/extern/build.zig | 2 +- test/link/wasm/function-table/build.zig | 3 +- test/link/wasm/infer-features/build.zig | 2 +- test/link/wasm/producers/build.zig | 3 +- test/link/wasm/segments/build.zig | 3 +- test/link/wasm/stack_pointer/build.zig | 3 +- test/link/wasm/type/build.zig | 3 +- test/src/compare_output.zig | 5 +- test/src/run_translated_c.zig | 5 +- test/src/translate_c.zig | 5 +- test/standalone/brace_expansion/build.zig | 4 +- test/standalone/c_compiler/build.zig | 5 +- test/standalone/emit_asm_and_bin/build.zig | 4 +- test/standalone/empty_env/build.zig | 4 +- test/standalone/global_linkage/build.zig | 4 +- test/standalone/install_raw_hex/build.zig | 4 +- test/standalone/issue_11595/build.zig | 5 +- test/standalone/issue_12588/build.zig | 3 +- test/standalone/issue_12706/build.zig | 5 +- test/standalone/issue_13030/build.zig | 3 +- test/standalone/issue_339/build.zig | 4 +- test/standalone/issue_5825/build.zig | 4 +- test/standalone/issue_7030/build.zig | 4 +- test/standalone/issue_794/build.zig | 4 +- test/standalone/issue_8550/build.zig | 2 +- test/standalone/issue_9812/build.zig | 2 +- .../standalone/load_dynamic_library/build.zig | 4 +- test/standalone/main_pkg_path/build.zig | 4 +- test/standalone/mix_c_files/build.zig | 5 +- test/standalone/mix_o_files/build.zig | 4 +- test/standalone/options/build.zig | 2 +- test/standalone/pie/build.zig | 4 +- test/standalone/pkg_import/build.zig | 4 +- test/standalone/shared_library/build.zig | 4 +- test/standalone/static_c_lib/build.zig | 4 +- test/standalone/test_runner_path/build.zig | 4 +- test/standalone/use_alias/build.zig | 4 +- test/standalone/windows_spawn/build.zig | 4 +- test/tests.zig | 60 +- 97 files changed, 2197 insertions(+), 2257 deletions(-) create mode 100644 lib/std/Build.zig rename lib/std/{build => Build}/CheckFileStep.zig (88%) rename lib/std/{build => Build}/CheckObjectStep.zig (98%) rename lib/std/{build => Build}/ConfigHeaderStep.zig (97%) rename lib/std/{build => Build}/EmulatableRunStep.zig (96%) rename lib/std/{build => Build}/FmtStep.zig (75%) rename lib/std/{build => Build}/InstallArtifactStep.zig (88%) rename lib/std/{build => Build}/InstallDirStep.zig (92%) rename lib/std/{build => Build}/InstallFileStep.zig (82%) rename lib/std/{build => Build}/InstallRawStep.zig (84%) rename lib/std/{build => Build}/LibExeObjStep.zig (97%) rename lib/std/{build => Build}/LogStep.zig (72%) rename lib/std/{build => Build}/OptionsStep.zig (97%) rename lib/std/{build => Build}/RemoveDirStep.zig (79%) rename lib/std/{build => Build}/RunStep.zig (94%) create mode 100644 lib/std/Build/Step.zig rename lib/std/{build => Build}/TranslateCStep.zig (90%) rename lib/std/{build => Build}/WriteFileStep.zig (91%) delete mode 100644 lib/std/build.zig diff --git a/build.zig b/build.zig index 98da9f31ee85aa6677e49002d0880364666caff5..6b6c384fc4b81d1cb60a9bb44b2004871bc4bf5f 100644 --- a/build.zig +++ b/build.zig @@ -1,19 +1,18 @@ const std = @import("std"); const builtin = std.builtin; -const Builder = std.build.Builder; const tests = @import("test/tests.zig"); const BufMap = std.BufMap; const mem = std.mem; const ArrayList = std.ArrayList; const io = std.io; const fs = std.fs; -const InstallDirectoryOptions = std.build.InstallDirectoryOptions; +const InstallDirectoryOptions = std.Build.InstallDirectoryOptions; const assert = std.debug.assert; const zig_version = std.builtin.Version{ .major = 0, .minor = 11, .patch = 0 }; const stack_size = 32 * 1024 * 1024; -pub fn build(b: *Builder) !void { +pub fn build(b: *std.Build) !void { const release = b.option(bool, "release", "Build in release mode") orelse false; const only_c = b.option(bool, "only-c", "Translate the Zig compiler to C code, with only the C backend enabled") orelse false; const target = t: { @@ -477,7 +476,7 @@ pub fn build(b: *Builder) !void { try addWasiUpdateStep(b, version); } -fn addWasiUpdateStep(b: *Builder, version: [:0]const u8) !void { +fn addWasiUpdateStep(b: *std.Build, version: [:0]const u8) !void { const semver = try std.SemanticVersion.parse(version); var target: std.zig.CrossTarget = .{ @@ -514,10 +513,10 @@ fn addWasiUpdateStep(b: *Builder, version: [:0]const u8) !void { } fn addCompilerStep( - b: *Builder, + b: *std.Build, optimize: std.builtin.OptimizeMode, target: std.zig.CrossTarget, -) *std.build.LibExeObjStep { +) *std.Build.LibExeObjStep { const exe = b.addExecutable(.{ .name = "zig", .root_source_file = .{ .path = "src/main.zig" }, @@ -543,9 +542,9 @@ const exe_cflags = [_][]const u8{ }; fn addCmakeCfgOptionsToExe( - b: *Builder, + b: *std.Build, cfg: CMakeConfig, - exe: *std.build.LibExeObjStep, + exe: *std.Build.LibExeObjStep, use_zig_libcxx: bool, ) !void { if (exe.target.isDarwin()) { @@ -624,7 +623,7 @@ fn addCmakeCfgOptionsToExe( } } -fn addStaticLlvmOptionsToExe(exe: *std.build.LibExeObjStep) !void { +fn addStaticLlvmOptionsToExe(exe: *std.Build.LibExeObjStep) !void { // Adds the Zig C++ sources which both stage1 and stage2 need. // // We need this because otherwise zig_clang_cc1_main.cpp ends up pulling @@ -661,9 +660,9 @@ fn addStaticLlvmOptionsToExe(exe: *std.build.LibExeObjStep) !void { } fn addCxxKnownPath( - b: *Builder, + b: *std.Build, ctx: CMakeConfig, - exe: *std.build.LibExeObjStep, + exe: *std.Build.LibExeObjStep, objname: []const u8, errtxt: ?[]const u8, need_cpp_includes: bool, @@ -696,7 +695,7 @@ fn addCxxKnownPath( } } -fn addCMakeLibraryList(exe: *std.build.LibExeObjStep, list: []const u8) void { +fn addCMakeLibraryList(exe: *std.Build.LibExeObjStep, list: []const u8) void { var it = mem.tokenize(u8, list, ";"); while (it.next()) |lib| { if (mem.startsWith(u8, lib, "-l")) { @@ -710,7 +709,7 @@ fn addCMakeLibraryList(exe: *std.build.LibExeObjStep, list: []const u8) void { } const CMakeConfig = struct { - llvm_linkage: std.build.LibExeObjStep.Linkage, + llvm_linkage: std.Build.LibExeObjStep.Linkage, cmake_binary_dir: []const u8, cmake_prefix_path: []const u8, cmake_static_library_prefix: []const u8, @@ -727,7 +726,7 @@ const CMakeConfig = struct { const max_config_h_bytes = 1 * 1024 * 1024; -fn findConfigH(b: *Builder, config_h_path_option: ?[]const u8) ?[]const u8 { +fn findConfigH(b: *std.Build, config_h_path_option: ?[]const u8) ?[]const u8 { if (config_h_path_option) |path| { var config_h_or_err = fs.cwd().openFile(path, .{}); if (config_h_or_err) |*file| { @@ -773,7 +772,7 @@ fn findConfigH(b: *Builder, config_h_path_option: ?[]const u8) ?[]const u8 { } else unreachable; // TODO should not need `else unreachable`. } -fn parseConfigH(b: *Builder, config_h_text: []const u8) ?CMakeConfig { +fn parseConfigH(b: *std.Build, config_h_text: []const u8) ?CMakeConfig { var ctx: CMakeConfig = .{ .llvm_linkage = undefined, .cmake_binary_dir = undefined, @@ -862,7 +861,7 @@ fn parseConfigH(b: *Builder, config_h_text: []const u8) ?CMakeConfig { return ctx; } -fn toNativePathSep(b: *Builder, s: []const u8) []u8 { +fn toNativePathSep(b: *std.Build, s: []const u8) []u8 { const duplicated = b.allocator.dupe(u8, s) catch unreachable; for (duplicated) |*byte| switch (byte.*) { '/' => byte.* = fs.path.sep, diff --git a/doc/langref.html.in b/doc/langref.html.in index c008149f4192f02d37303b50670c75635680056a..1163ad0200db89ec1645e414912d6b5684a2d940 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -9528,9 +9528,9 @@ fn foo(comptime T: type, ptr: *T) T { To add standard build options to a build.zig file:

{#code_begin|syntax|build#} -const Builder = @import("std").build.Builder; +const std = @import("std"); -pub fn build(b: *Builder) void { +pub fn build(b: *std.Build) void { const optimize = b.standardOptimizeOption(.{}); const exe = b.addExecutable(.{ .name = "example", @@ -10551,9 +10551,9 @@ const separator = if (builtin.os.tag == .windows) '\\' else '/';

This build.zig file is automatically generated by zig init-exe.

{#code_begin|syntax|build_executable#} -const Builder = @import("std").build.Builder; +const std = @import("std"); -pub fn build(b: *Builder) void { +pub fn build(b: *std.Build) void { // Standard target options allows the person running `zig build` to choose // what target to build for. Here we do not override the defaults, which // means any target is allowed, and the default is native. Other options @@ -10588,9 +10588,9 @@ pub fn build(b: *Builder) void {

This build.zig file is automatically generated by zig init-lib.

{#code_begin|syntax|build_library#} -const Builder = @import("std").build.Builder; +const std = @import("std"); -pub fn build(b: *Builder) void { +pub fn build(b: *std.Build) void { const optimize = b.standardOptimizeOption(.{}); const lib = b.addStaticLibrary(.{ .name = "example", @@ -10961,9 +10961,9 @@ int main(int argc, char **argv) { } {#end_syntax_block#} {#code_begin|syntax|build_c#} -const Builder = @import("std").build.Builder; +const std = @import("std"); -pub fn build(b: *Builder) void { +pub fn build(b: *std.Build) void { const lib = b.addSharedLibrary("mathtest", "mathtest.zig", b.version(1, 0, 0)); const exe = b.addExecutable(.{ @@ -11025,9 +11025,9 @@ int main(int argc, char **argv) { } {#end_syntax_block#} {#code_begin|syntax|build_object#} -const Builder = @import("std").build.Builder; +const std = @import("std"); -pub fn build(b: *Builder) void { +pub fn build(b: *std.Build) void { const obj = b.addObject("base64", "base64.zig"); const exe = b.addExecutable(.{ diff --git a/lib/build_runner.zig b/lib/build_runner.zig index 4df2eb1d6292316e98665f9da05ae6c5bba4d03f..189b1187874242c17a22800dca579ca482ca88fc 100644 --- a/lib/build_runner.zig +++ b/lib/build_runner.zig @@ -3,7 +3,6 @@ const std = @import("std"); const builtin = @import("builtin"); const io = std.io; const fmt = std.fmt; -const Builder = std.build.Builder; const mem = std.mem; const process = std.process; const ArrayList = std.ArrayList; @@ -42,7 +41,7 @@ pub fn main() !void { return error.InvalidArgs; }; - const builder = try Builder.create( + const builder = try std.Build.create( allocator, zig_exe, build_root, @@ -58,7 +57,7 @@ pub fn main() !void { const stdout_stream = io.getStdOut().writer(); var install_prefix: ?[]const u8 = null; - var dir_list = Builder.DirList{}; + var dir_list = std.Build.DirList{}; // before arg parsing, check for the NO_COLOR environment variable // if it exists, default the color setting to .off @@ -230,7 +229,7 @@ pub fn main() !void { }; } -fn usage(builder: *Builder, already_ran_build: bool, out_stream: anytype) !void { +fn usage(builder: *std.Build, already_ran_build: bool, out_stream: anytype) !void { // run the build script to collect the options if (!already_ran_build) { builder.resolveInstallPrefix(null, .{}); @@ -330,7 +329,7 @@ fn usage(builder: *Builder, already_ran_build: bool, out_stream: anytype) !void ); } -fn usageAndErr(builder: *Builder, already_ran_build: bool, out_stream: anytype) void { +fn usageAndErr(builder: *std.Build, already_ran_build: bool, out_stream: anytype) void { usage(builder, already_ran_build, out_stream) catch {}; process.exit(1); } diff --git a/lib/init-exe/build.zig b/lib/init-exe/build.zig index 36e5feddecab57256d61ecaf553fd3a13f5adc2d..b88515b403500780437fb6af08e2b5d2dd5ba155 100644 --- a/lib/init-exe/build.zig +++ b/lib/init-exe/build.zig @@ -3,7 +3,7 @@ const std = @import("std"); // Although this function looks imperative, note that its job is to // declaratively construct a build graph that will be executed by an external // runner. -pub fn build(b: *std.build.Builder) void { +pub fn build(b: *std.Build) void { // Standard target options allows the person running `zig build` to choose // what target to build for. Here we do not override the defaults, which // means any target is allowed, and the default is native. Other options diff --git a/lib/init-lib/build.zig b/lib/init-lib/build.zig index 4a7b700dc200d15c0bb2c065eb69192c670ae3bc..5ebb55373f86e28b5fa4751050e11f318ad18ebc 100644 --- a/lib/init-lib/build.zig +++ b/lib/init-lib/build.zig @@ -3,7 +3,7 @@ const std = @import("std"); // Although this function looks imperative, note that its job is to // declaratively construct a build graph that will be executed by an external // runner. -pub fn build(b: *std.build.Builder) void { +pub fn build(b: *std.Build) void { // Standard target options allows the person running `zig build` to choose // what target to build for. Here we do not override the defaults, which // means any target is allowed, and the default is native. Other options diff --git a/lib/std/Build.zig b/lib/std/Build.zig new file mode 100644 index 0000000000000000000000000000000000000000..a3c579c743867396c8194b9e55f52a11ae438d4a --- /dev/null +++ b/lib/std/Build.zig @@ -0,0 +1,1771 @@ +const std = @import("std.zig"); +const builtin = @import("builtin"); +const io = std.io; +const fs = std.fs; +const mem = std.mem; +const debug = std.debug; +const panic = std.debug.panic; +const assert = debug.assert; +const log = std.log; +const ArrayList = std.ArrayList; +const StringHashMap = std.StringHashMap; +const Allocator = mem.Allocator; +const process = std.process; +const EnvMap = std.process.EnvMap; +const fmt_lib = std.fmt; +const File = std.fs.File; +const CrossTarget = std.zig.CrossTarget; +const NativeTargetInfo = std.zig.system.NativeTargetInfo; +const Sha256 = std.crypto.hash.sha2.Sha256; +const Build = @This(); + +pub const Step = @import("Build/Step.zig"); +pub const CheckFileStep = @import("Build/CheckFileStep.zig"); +pub const CheckObjectStep = @import("Build/CheckObjectStep.zig"); +pub const ConfigHeaderStep = @import("Build/ConfigHeaderStep.zig"); +pub const EmulatableRunStep = @import("Build/EmulatableRunStep.zig"); +pub const FmtStep = @import("Build/FmtStep.zig"); +pub const InstallArtifactStep = @import("Build/InstallArtifactStep.zig"); +pub const InstallDirStep = @import("Build/InstallDirStep.zig"); +pub const InstallFileStep = @import("Build/InstallFileStep.zig"); +pub const InstallRawStep = @import("Build/InstallRawStep.zig"); +pub const LibExeObjStep = @import("Build/LibExeObjStep.zig"); +pub const LogStep = @import("Build/LogStep.zig"); +pub const OptionsStep = @import("Build/OptionsStep.zig"); +pub const RemoveDirStep = @import("Build/RemoveDirStep.zig"); +pub const RunStep = @import("Build/RunStep.zig"); +pub const TranslateCStep = @import("Build/TranslateCStep.zig"); +pub const WriteFileStep = @import("Build/WriteFileStep.zig"); + +install_tls: TopLevelStep, +uninstall_tls: TopLevelStep, +allocator: Allocator, +user_input_options: UserInputOptionsMap, +available_options_map: AvailableOptionsMap, +available_options_list: ArrayList(AvailableOption), +verbose: bool, +verbose_link: bool, +verbose_cc: bool, +verbose_air: bool, +verbose_llvm_ir: bool, +verbose_cimport: bool, +verbose_llvm_cpu_features: bool, +/// The purpose of executing the command is for a human to read compile errors from the terminal +prominent_compile_errors: bool, +color: enum { auto, on, off } = .auto, +reference_trace: ?u32 = null, +invalid_user_input: bool, +zig_exe: []const u8, +default_step: *Step, +env_map: *EnvMap, +top_level_steps: ArrayList(*TopLevelStep), +install_prefix: []const u8, +dest_dir: ?[]const u8, +lib_dir: []const u8, +exe_dir: []const u8, +h_dir: []const u8, +install_path: []const u8, +sysroot: ?[]const u8 = null, +search_prefixes: ArrayList([]const u8), +libc_file: ?[]const u8 = null, +installed_files: ArrayList(InstalledFile), +/// Path to the directory containing build.zig. +build_root: []const u8, +cache_root: []const u8, +global_cache_root: []const u8, +/// zig lib dir +override_lib_dir: ?[]const u8, +vcpkg_root: VcpkgRoot = .unattempted, +pkg_config_pkg_list: ?(PkgConfigError![]const PkgConfigPkg) = null, +args: ?[][]const u8 = null, +debug_log_scopes: []const []const u8 = &.{}, +debug_compile_errors: bool = false, + +/// Experimental. Use system Darling installation to run cross compiled macOS build artifacts. +enable_darling: bool = false, +/// Use system QEMU installation to run cross compiled foreign architecture build artifacts. +enable_qemu: bool = false, +/// Darwin. Use Rosetta to run x86_64 macOS build artifacts on arm64 macOS. +enable_rosetta: bool = false, +/// Use system Wasmtime installation to run cross compiled wasm/wasi build artifacts. +enable_wasmtime: bool = false, +/// Use system Wine installation to run cross compiled Windows build artifacts. +enable_wine: bool = false, +/// After following the steps in https://github.com/ziglang/zig/wiki/Updating-libc#glibc, +/// this will be the directory $glibc-build-dir/install/glibcs +/// Given the example of the aarch64 target, this is the directory +/// that contains the path `aarch64-linux-gnu/lib/ld-linux-aarch64.so.1`. +glibc_runtimes_dir: ?[]const u8 = null, + +/// Information about the native target. Computed before build() is invoked. +host: NativeTargetInfo, + +dep_prefix: []const u8 = "", + +pub const ExecError = error{ + ReadFailure, + ExitCodeFailure, + ProcessTerminated, + ExecNotSupported, +} || std.ChildProcess.SpawnError; + +pub const PkgConfigError = error{ + PkgConfigCrashed, + PkgConfigFailed, + PkgConfigNotInstalled, + PkgConfigInvalidOutput, +}; + +pub const PkgConfigPkg = struct { + name: []const u8, + desc: []const u8, +}; + +pub const CStd = enum { + C89, + C99, + C11, +}; + +const UserInputOptionsMap = StringHashMap(UserInputOption); +const AvailableOptionsMap = StringHashMap(AvailableOption); + +const AvailableOption = struct { + name: []const u8, + type_id: TypeId, + description: []const u8, + /// If the `type_id` is `enum` this provides the list of enum options + enum_options: ?[]const []const u8, +}; + +const UserInputOption = struct { + name: []const u8, + value: UserValue, + used: bool, +}; + +const UserValue = union(enum) { + flag: void, + scalar: []const u8, + list: ArrayList([]const u8), + map: StringHashMap(*const UserValue), +}; + +const TypeId = enum { + bool, + int, + float, + @"enum", + string, + list, +}; + +const TopLevelStep = struct { + pub const base_id = .top_level; + + step: Step, + description: []const u8, +}; + +pub const DirList = struct { + lib_dir: ?[]const u8 = null, + exe_dir: ?[]const u8 = null, + include_dir: ?[]const u8 = null, +}; + +pub fn create( + allocator: Allocator, + zig_exe: []const u8, + build_root: []const u8, + cache_root: []const u8, + global_cache_root: []const u8, +) !*Build { + const env_map = try allocator.create(EnvMap); + env_map.* = try process.getEnvMap(allocator); + + const host = try NativeTargetInfo.detect(.{}); + + const self = try allocator.create(Build); + self.* = Build{ + .zig_exe = zig_exe, + .build_root = build_root, + .cache_root = try fs.path.relative(allocator, build_root, cache_root), + .global_cache_root = global_cache_root, + .verbose = false, + .verbose_link = false, + .verbose_cc = false, + .verbose_air = false, + .verbose_llvm_ir = false, + .verbose_cimport = false, + .verbose_llvm_cpu_features = false, + .prominent_compile_errors = false, + .invalid_user_input = false, + .allocator = allocator, + .user_input_options = UserInputOptionsMap.init(allocator), + .available_options_map = AvailableOptionsMap.init(allocator), + .available_options_list = ArrayList(AvailableOption).init(allocator), + .top_level_steps = ArrayList(*TopLevelStep).init(allocator), + .default_step = undefined, + .env_map = env_map, + .search_prefixes = ArrayList([]const u8).init(allocator), + .install_prefix = undefined, + .lib_dir = undefined, + .exe_dir = undefined, + .h_dir = undefined, + .dest_dir = env_map.get("DESTDIR"), + .installed_files = ArrayList(InstalledFile).init(allocator), + .install_tls = TopLevelStep{ + .step = Step.initNoOp(.top_level, "install", allocator), + .description = "Copy build artifacts to prefix path", + }, + .uninstall_tls = TopLevelStep{ + .step = Step.init(.top_level, "uninstall", allocator, makeUninstall), + .description = "Remove build artifacts from prefix path", + }, + .override_lib_dir = null, + .install_path = undefined, + .args = null, + .host = host, + }; + try self.top_level_steps.append(&self.install_tls); + try self.top_level_steps.append(&self.uninstall_tls); + self.default_step = &self.install_tls.step; + return self; +} + +fn createChild( + parent: *Build, + dep_name: []const u8, + build_root: []const u8, + args: anytype, +) !*Build { + const child = try createChildOnly(parent, dep_name, build_root); + try applyArgs(child, args); + return child; +} + +fn createChildOnly(parent: *Build, dep_name: []const u8, build_root: []const u8) !*Build { + const allocator = parent.allocator; + const child = try allocator.create(Build); + child.* = .{ + .allocator = allocator, + .install_tls = .{ + .step = Step.initNoOp(.top_level, "install", allocator), + .description = "Copy build artifacts to prefix path", + }, + .uninstall_tls = .{ + .step = Step.init(.top_level, "uninstall", allocator, makeUninstall), + .description = "Remove build artifacts from prefix path", + }, + .user_input_options = UserInputOptionsMap.init(allocator), + .available_options_map = AvailableOptionsMap.init(allocator), + .available_options_list = ArrayList(AvailableOption).init(allocator), + .verbose = parent.verbose, + .verbose_link = parent.verbose_link, + .verbose_cc = parent.verbose_cc, + .verbose_air = parent.verbose_air, + .verbose_llvm_ir = parent.verbose_llvm_ir, + .verbose_cimport = parent.verbose_cimport, + .verbose_llvm_cpu_features = parent.verbose_llvm_cpu_features, + .prominent_compile_errors = parent.prominent_compile_errors, + .color = parent.color, + .reference_trace = parent.reference_trace, + .invalid_user_input = false, + .zig_exe = parent.zig_exe, + .default_step = undefined, + .env_map = parent.env_map, + .top_level_steps = ArrayList(*TopLevelStep).init(allocator), + .install_prefix = undefined, + .dest_dir = parent.dest_dir, + .lib_dir = parent.lib_dir, + .exe_dir = parent.exe_dir, + .h_dir = parent.h_dir, + .install_path = parent.install_path, + .sysroot = parent.sysroot, + .search_prefixes = ArrayList([]const u8).init(allocator), + .libc_file = parent.libc_file, + .installed_files = ArrayList(InstalledFile).init(allocator), + .build_root = build_root, + .cache_root = parent.cache_root, + .global_cache_root = parent.global_cache_root, + .override_lib_dir = parent.override_lib_dir, + .debug_log_scopes = parent.debug_log_scopes, + .debug_compile_errors = parent.debug_compile_errors, + .enable_darling = parent.enable_darling, + .enable_qemu = parent.enable_qemu, + .enable_rosetta = parent.enable_rosetta, + .enable_wasmtime = parent.enable_wasmtime, + .enable_wine = parent.enable_wine, + .glibc_runtimes_dir = parent.glibc_runtimes_dir, + .host = parent.host, + .dep_prefix = parent.fmt("{s}{s}.", .{ parent.dep_prefix, dep_name }), + }; + try child.top_level_steps.append(&child.install_tls); + try child.top_level_steps.append(&child.uninstall_tls); + child.default_step = &child.install_tls.step; + return child; +} + +fn applyArgs(b: *Build, args: anytype) !void { + inline for (@typeInfo(@TypeOf(args)).Struct.fields) |field| { + const v = @field(args, field.name); + const T = @TypeOf(v); + switch (T) { + CrossTarget => { + try b.user_input_options.put(field.name, .{ + .name = field.name, + .value = .{ .scalar = try v.zigTriple(b.allocator) }, + .used = false, + }); + try b.user_input_options.put("cpu", .{ + .name = "cpu", + .value = .{ .scalar = try serializeCpu(b.allocator, v.getCpu()) }, + .used = false, + }); + }, + []const u8 => { + try b.user_input_options.put(field.name, .{ + .name = field.name, + .value = .{ .scalar = v }, + .used = false, + }); + }, + else => switch (@typeInfo(T)) { + .Bool => { + try b.user_input_options.put(field.name, .{ + .name = field.name, + .value = .{ .scalar = if (v) "true" else "false" }, + .used = false, + }); + }, + .Enum => { + try b.user_input_options.put(field.name, .{ + .name = field.name, + .value = .{ .scalar = @tagName(v) }, + .used = false, + }); + }, + .Int => { + try b.user_input_options.put(field.name, .{ + .name = field.name, + .value = .{ .scalar = try std.fmt.allocPrint(b.allocator, "{d}", .{v}) }, + .used = false, + }); + }, + else => @compileError("option '" ++ field.name ++ "' has unsupported type: " ++ @typeName(T)), + }, + } + } + const Hasher = std.crypto.auth.siphash.SipHash128(1, 3); + // Random bytes to make unique. Refresh this with new random bytes when + // implementation is modified in a non-backwards-compatible way. + var hash = Hasher.init("ZaEsvQ5ClaA2IdH9"); + hash.update(b.dep_prefix); + // TODO additionally update the hash with `args`. + + var digest: [16]u8 = undefined; + hash.final(&digest); + var hash_basename: [digest.len * 2]u8 = undefined; + _ = std.fmt.bufPrint(&hash_basename, "{s}", .{std.fmt.fmtSliceHexLower(&digest)}) catch + unreachable; + + const install_prefix = b.pathJoin(&.{ b.cache_root, "i", &hash_basename }); + b.resolveInstallPrefix(install_prefix, .{}); +} + +pub fn destroy(self: *Build) void { + self.env_map.deinit(); + self.top_level_steps.deinit(); + self.allocator.destroy(self); +} + +/// This function is intended to be called by lib/build_runner.zig, not a build.zig file. +pub fn resolveInstallPrefix(self: *Build, install_prefix: ?[]const u8, dir_list: DirList) void { + if (self.dest_dir) |dest_dir| { + self.install_prefix = install_prefix orelse "/usr"; + self.install_path = self.pathJoin(&.{ dest_dir, self.install_prefix }); + } else { + self.install_prefix = install_prefix orelse + (self.pathJoin(&.{ self.build_root, "zig-out" })); + self.install_path = self.install_prefix; + } + + var lib_list = [_][]const u8{ self.install_path, "lib" }; + var exe_list = [_][]const u8{ self.install_path, "bin" }; + var h_list = [_][]const u8{ self.install_path, "include" }; + + if (dir_list.lib_dir) |dir| { + if (std.fs.path.isAbsolute(dir)) lib_list[0] = self.dest_dir orelse ""; + lib_list[1] = dir; + } + + if (dir_list.exe_dir) |dir| { + if (std.fs.path.isAbsolute(dir)) exe_list[0] = self.dest_dir orelse ""; + exe_list[1] = dir; + } + + if (dir_list.include_dir) |dir| { + if (std.fs.path.isAbsolute(dir)) h_list[0] = self.dest_dir orelse ""; + h_list[1] = dir; + } + + self.lib_dir = self.pathJoin(&lib_list); + self.exe_dir = self.pathJoin(&exe_list); + self.h_dir = self.pathJoin(&h_list); +} + +pub fn addOptions(self: *Build) *OptionsStep { + return OptionsStep.create(self); +} + +pub const ExecutableOptions = struct { + name: []const u8, + root_source_file: ?FileSource = null, + version: ?std.builtin.Version = null, + target: CrossTarget = .{}, + optimize: std.builtin.Mode = .Debug, + linkage: ?LibExeObjStep.Linkage = null, +}; + +pub fn addExecutable(b: *Build, options: ExecutableOptions) *LibExeObjStep { + return LibExeObjStep.create(b, .{ + .name = options.name, + .root_source_file = options.root_source_file, + .version = options.version, + .target = options.target, + .optimize = options.optimize, + .kind = .exe, + .linkage = options.linkage, + }); +} + +pub const ObjectOptions = struct { + name: []const u8, + root_source_file: ?FileSource = null, + target: CrossTarget, + optimize: std.builtin.Mode, +}; + +pub fn addObject(b: *Build, options: ObjectOptions) *LibExeObjStep { + return LibExeObjStep.create(b, .{ + .name = options.name, + .root_source_file = options.root_source_file, + .target = options.target, + .optimize = options.optimize, + .kind = .obj, + }); +} + +pub const SharedLibraryOptions = struct { + name: []const u8, + root_source_file: ?FileSource = null, + version: ?std.builtin.Version = null, + target: CrossTarget, + optimize: std.builtin.Mode, +}; + +pub fn addSharedLibrary(b: *Build, options: SharedLibraryOptions) *LibExeObjStep { + return LibExeObjStep.create(b, .{ + .name = options.name, + .root_source_file = options.root_source_file, + .kind = .lib, + .linkage = .dynamic, + .version = options.version, + .target = options.target, + .optimize = options.optimize, + }); +} + +pub const StaticLibraryOptions = struct { + name: []const u8, + root_source_file: ?FileSource = null, + target: CrossTarget, + optimize: std.builtin.Mode, + version: ?std.builtin.Version = null, +}; + +pub fn addStaticLibrary(b: *Build, options: StaticLibraryOptions) *LibExeObjStep { + return LibExeObjStep.create(b, .{ + .name = options.name, + .root_source_file = options.root_source_file, + .kind = .lib, + .linkage = .static, + .version = options.version, + .target = options.target, + .optimize = options.optimize, + }); +} + +pub const TestOptions = struct { + name: []const u8 = "test", + kind: LibExeObjStep.Kind = .@"test", + root_source_file: FileSource, + target: CrossTarget = .{}, + optimize: std.builtin.Mode = .Debug, + version: ?std.builtin.Version = null, +}; + +pub fn addTest(b: *Build, options: TestOptions) *LibExeObjStep { + return LibExeObjStep.create(b, .{ + .name = options.name, + .kind = options.kind, + .root_source_file = options.root_source_file, + .target = options.target, + .optimize = options.optimize, + }); +} + +pub const AssemblyOptions = struct { + name: []const u8, + source_file: FileSource, + target: CrossTarget, + optimize: std.builtin.Mode, +}; + +pub fn addAssembly(b: *Build, options: AssemblyOptions) *LibExeObjStep { + const obj_step = LibExeObjStep.create(b, .{ + .name = options.name, + .root_source_file = null, + .target = options.target, + .optimize = options.optimize, + }); + obj_step.addAssemblyFileSource(options.source_file.dupe(b)); + return obj_step; +} + +/// Initializes a RunStep with argv, which must at least have the path to the +/// executable. More command line arguments can be added with `addArg`, +/// `addArgs`, and `addArtifactArg`. +/// Be careful using this function, as it introduces a system dependency. +/// To run an executable built with zig build, see `LibExeObjStep.run`. +pub fn addSystemCommand(self: *Build, argv: []const []const u8) *RunStep { + assert(argv.len >= 1); + const run_step = RunStep.create(self, self.fmt("run {s}", .{argv[0]})); + run_step.addArgs(argv); + return run_step; +} + +pub fn addConfigHeader( + b: *Build, + source: FileSource, + style: ConfigHeaderStep.Style, + values: anytype, +) *ConfigHeaderStep { + const config_header_step = ConfigHeaderStep.create(b, source, style); + config_header_step.addValues(values); + return config_header_step; +} + +/// Allocator.dupe without the need to handle out of memory. +pub fn dupe(self: *Build, bytes: []const u8) []u8 { + return self.allocator.dupe(u8, bytes) catch unreachable; +} + +/// Duplicates an array of strings without the need to handle out of memory. +pub fn dupeStrings(self: *Build, strings: []const []const u8) [][]u8 { + const array = self.allocator.alloc([]u8, strings.len) catch unreachable; + for (strings) |s, i| { + array[i] = self.dupe(s); + } + return array; +} + +/// Duplicates a path and converts all slashes to the OS's canonical path separator. +pub fn dupePath(self: *Build, bytes: []const u8) []u8 { + const the_copy = self.dupe(bytes); + for (the_copy) |*byte| { + switch (byte.*) { + '/', '\\' => byte.* = fs.path.sep, + else => {}, + } + } + return the_copy; +} + +/// Duplicates a package recursively. +pub fn dupePkg(self: *Build, package: Pkg) Pkg { + var the_copy = Pkg{ + .name = self.dupe(package.name), + .source = package.source.dupe(self), + }; + + if (package.dependencies) |dependencies| { + const new_dependencies = self.allocator.alloc(Pkg, dependencies.len) catch unreachable; + the_copy.dependencies = new_dependencies; + + for (dependencies) |dep_package, i| { + new_dependencies[i] = self.dupePkg(dep_package); + } + } + return the_copy; +} + +pub fn addWriteFile(self: *Build, file_path: []const u8, data: []const u8) *WriteFileStep { + const write_file_step = self.addWriteFiles(); + write_file_step.add(file_path, data); + return write_file_step; +} + +pub fn addWriteFiles(self: *Build) *WriteFileStep { + const write_file_step = self.allocator.create(WriteFileStep) catch unreachable; + write_file_step.* = WriteFileStep.init(self); + return write_file_step; +} + +pub fn addLog(self: *Build, comptime format: []const u8, args: anytype) *LogStep { + const data = self.fmt(format, args); + const log_step = self.allocator.create(LogStep) catch unreachable; + log_step.* = LogStep.init(self, data); + return log_step; +} + +pub fn addRemoveDirTree(self: *Build, dir_path: []const u8) *RemoveDirStep { + const remove_dir_step = self.allocator.create(RemoveDirStep) catch unreachable; + remove_dir_step.* = RemoveDirStep.init(self, dir_path); + return remove_dir_step; +} + +pub fn addFmt(self: *Build, paths: []const []const u8) *FmtStep { + return FmtStep.create(self, paths); +} + +pub fn addTranslateC(self: *Build, options: TranslateCStep.Options) *TranslateCStep { + return TranslateCStep.create(self, options); +} + +pub fn make(self: *Build, step_names: []const []const u8) !void { + try self.makePath(self.cache_root); + + var wanted_steps = ArrayList(*Step).init(self.allocator); + defer wanted_steps.deinit(); + + if (step_names.len == 0) { + try wanted_steps.append(self.default_step); + } else { + for (step_names) |step_name| { + const s = try self.getTopLevelStepByName(step_name); + try wanted_steps.append(s); + } + } + + for (wanted_steps.items) |s| { + try self.makeOneStep(s); + } +} + +pub fn getInstallStep(self: *Build) *Step { + return &self.install_tls.step; +} + +pub fn getUninstallStep(self: *Build) *Step { + return &self.uninstall_tls.step; +} + +fn makeUninstall(uninstall_step: *Step) anyerror!void { + const uninstall_tls = @fieldParentPtr(TopLevelStep, "step", uninstall_step); + const self = @fieldParentPtr(Build, "uninstall_tls", uninstall_tls); + + for (self.installed_files.items) |installed_file| { + const full_path = self.getInstallPath(installed_file.dir, installed_file.path); + if (self.verbose) { + log.info("rm {s}", .{full_path}); + } + fs.cwd().deleteTree(full_path) catch {}; + } + + // TODO remove empty directories +} + +fn makeOneStep(self: *Build, s: *Step) anyerror!void { + if (s.loop_flag) { + log.err("Dependency loop detected:\n {s}", .{s.name}); + return error.DependencyLoopDetected; + } + s.loop_flag = true; + + for (s.dependencies.items) |dep| { + self.makeOneStep(dep) catch |err| { + if (err == error.DependencyLoopDetected) { + log.err(" {s}", .{s.name}); + } + return err; + }; + } + + s.loop_flag = false; + + try s.make(); +} + +fn getTopLevelStepByName(self: *Build, name: []const u8) !*Step { + for (self.top_level_steps.items) |top_level_step| { + if (mem.eql(u8, top_level_step.step.name, name)) { + return &top_level_step.step; + } + } + log.err("Cannot run step '{s}' because it does not exist", .{name}); + return error.InvalidStepName; +} + +pub fn option(self: *Build, comptime T: type, name_raw: []const u8, description_raw: []const u8) ?T { + const name = self.dupe(name_raw); + const description = self.dupe(description_raw); + const type_id = comptime typeToEnum(T); + const enum_options = if (type_id == .@"enum") blk: { + const fields = comptime std.meta.fields(T); + var options = ArrayList([]const u8).initCapacity(self.allocator, fields.len) catch unreachable; + + inline for (fields) |field| { + options.appendAssumeCapacity(field.name); + } + + break :blk options.toOwnedSlice() catch unreachable; + } else null; + const available_option = AvailableOption{ + .name = name, + .type_id = type_id, + .description = description, + .enum_options = enum_options, + }; + if ((self.available_options_map.fetchPut(name, available_option) catch unreachable) != null) { + panic("Option '{s}' declared twice", .{name}); + } + self.available_options_list.append(available_option) catch unreachable; + + const option_ptr = self.user_input_options.getPtr(name) orelse return null; + option_ptr.used = true; + switch (type_id) { + .bool => switch (option_ptr.value) { + .flag => return true, + .scalar => |s| { + if (mem.eql(u8, s, "true")) { + return true; + } else if (mem.eql(u8, s, "false")) { + return false; + } else { + log.err("Expected -D{s} to be a boolean, but received '{s}'\n", .{ name, s }); + self.markInvalidUserInput(); + return null; + } + }, + .list, .map => { + log.err("Expected -D{s} to be a boolean, but received a {s}.\n", .{ + name, @tagName(option_ptr.value), + }); + self.markInvalidUserInput(); + return null; + }, + }, + .int => switch (option_ptr.value) { + .flag, .list, .map => { + log.err("Expected -D{s} to be an integer, but received a {s}.\n", .{ + name, @tagName(option_ptr.value), + }); + self.markInvalidUserInput(); + return null; + }, + .scalar => |s| { + const n = std.fmt.parseInt(T, s, 10) catch |err| switch (err) { + error.Overflow => { + log.err("-D{s} value {s} cannot fit into type {s}.\n", .{ name, s, @typeName(T) }); + self.markInvalidUserInput(); + return null; + }, + else => { + log.err("Expected -D{s} to be an integer of type {s}.\n", .{ name, @typeName(T) }); + self.markInvalidUserInput(); + return null; + }, + }; + return n; + }, + }, + .float => switch (option_ptr.value) { + .flag, .map, .list => { + log.err("Expected -D{s} to be a float, but received a {s}.\n", .{ + name, @tagName(option_ptr.value), + }); + self.markInvalidUserInput(); + return null; + }, + .scalar => |s| { + const n = std.fmt.parseFloat(T, s) catch { + log.err("Expected -D{s} to be a float of type {s}.\n", .{ name, @typeName(T) }); + self.markInvalidUserInput(); + return null; + }; + return n; + }, + }, + .@"enum" => switch (option_ptr.value) { + .flag, .map, .list => { + log.err("Expected -D{s} to be an enum, but received a {s}.\n", .{ + name, @tagName(option_ptr.value), + }); + self.markInvalidUserInput(); + return null; + }, + .scalar => |s| { + if (std.meta.stringToEnum(T, s)) |enum_lit| { + return enum_lit; + } else { + log.err("Expected -D{s} to be of type {s}.\n", .{ name, @typeName(T) }); + self.markInvalidUserInput(); + return null; + } + }, + }, + .string => switch (option_ptr.value) { + .flag, .list, .map => { + log.err("Expected -D{s} to be a string, but received a {s}.\n", .{ + name, @tagName(option_ptr.value), + }); + self.markInvalidUserInput(); + return null; + }, + .scalar => |s| return s, + }, + .list => switch (option_ptr.value) { + .flag, .map => { + log.err("Expected -D{s} to be a list, but received a {s}.\n", .{ + name, @tagName(option_ptr.value), + }); + self.markInvalidUserInput(); + return null; + }, + .scalar => |s| { + return self.allocator.dupe([]const u8, &[_][]const u8{s}) catch unreachable; + }, + .list => |lst| return lst.items, + }, + } +} + +pub fn step(self: *Build, name: []const u8, description: []const u8) *Step { + const step_info = self.allocator.create(TopLevelStep) catch unreachable; + step_info.* = TopLevelStep{ + .step = Step.initNoOp(.top_level, name, self.allocator), + .description = self.dupe(description), + }; + self.top_level_steps.append(step_info) catch unreachable; + return &step_info.step; +} + +pub const StandardOptimizeOptionOptions = struct { + preferred_optimize_mode: ?std.builtin.Mode = null, +}; + +pub fn standardOptimizeOption(self: *Build, options: StandardOptimizeOptionOptions) std.builtin.Mode { + if (options.preferred_optimize_mode) |mode| { + if (self.option(bool, "release", "optimize for end users") orelse false) { + return mode; + } else { + return .Debug; + } + } else { + return self.option( + std.builtin.Mode, + "optimize", + "prioritize performance, safety, or binary size (-O flag)", + ) orelse .Debug; + } +} + +pub const StandardTargetOptionsArgs = struct { + whitelist: ?[]const CrossTarget = null, + + default_target: CrossTarget = CrossTarget{}, +}; + +/// Exposes standard `zig build` options for choosing a target. +pub fn standardTargetOptions(self: *Build, args: StandardTargetOptionsArgs) CrossTarget { + const maybe_triple = self.option( + []const u8, + "target", + "The CPU architecture, OS, and ABI to build for", + ); + const mcpu = self.option([]const u8, "cpu", "Target CPU features to add or subtract"); + + if (maybe_triple == null and mcpu == null) { + return args.default_target; + } + + const triple = maybe_triple orelse "native"; + + var diags: CrossTarget.ParseOptions.Diagnostics = .{}; + const selected_target = CrossTarget.parse(.{ + .arch_os_abi = triple, + .cpu_features = mcpu, + .diagnostics = &diags, + }) catch |err| switch (err) { + error.UnknownCpuModel => { + log.err("Unknown CPU: '{s}'\nAvailable CPUs for architecture '{s}':", .{ + diags.cpu_name.?, + @tagName(diags.arch.?), + }); + for (diags.arch.?.allCpuModels()) |cpu| { + log.err(" {s}", .{cpu.name}); + } + self.markInvalidUserInput(); + return args.default_target; + }, + error.UnknownCpuFeature => { + log.err( + \\Unknown CPU feature: '{s}' + \\Available CPU features for architecture '{s}': + \\ + , .{ + diags.unknown_feature_name.?, + @tagName(diags.arch.?), + }); + for (diags.arch.?.allFeaturesList()) |feature| { + log.err(" {s}: {s}", .{ feature.name, feature.description }); + } + self.markInvalidUserInput(); + return args.default_target; + }, + error.UnknownOperatingSystem => { + log.err( + \\Unknown OS: '{s}' + \\Available operating systems: + \\ + , .{diags.os_name.?}); + inline for (std.meta.fields(std.Target.Os.Tag)) |field| { + log.err(" {s}", .{field.name}); + } + self.markInvalidUserInput(); + return args.default_target; + }, + else => |e| { + log.err("Unable to parse target '{s}': {s}\n", .{ triple, @errorName(e) }); + self.markInvalidUserInput(); + return args.default_target; + }, + }; + + const selected_canonicalized_triple = selected_target.zigTriple(self.allocator) catch unreachable; + + if (args.whitelist) |list| whitelist_check: { + // Make sure it's a match of one of the list. + var mismatch_triple = true; + var mismatch_cpu_features = true; + var whitelist_item = CrossTarget{}; + for (list) |t| { + mismatch_cpu_features = true; + mismatch_triple = true; + + const t_triple = t.zigTriple(self.allocator) catch unreachable; + if (mem.eql(u8, t_triple, selected_canonicalized_triple)) { + mismatch_triple = false; + whitelist_item = t; + if (t.getCpuFeatures().isSuperSetOf(selected_target.getCpuFeatures())) { + mismatch_cpu_features = false; + break :whitelist_check; + } else { + break; + } + } + } + if (mismatch_triple) { + log.err("Chosen target '{s}' does not match one of the supported targets:", .{ + selected_canonicalized_triple, + }); + for (list) |t| { + const t_triple = t.zigTriple(self.allocator) catch unreachable; + log.err(" {s}", .{t_triple}); + } + } else { + assert(mismatch_cpu_features); + const whitelist_cpu = whitelist_item.getCpu(); + const selected_cpu = selected_target.getCpu(); + log.err("Chosen CPU model '{s}' does not match one of the supported targets:", .{ + selected_cpu.model.name, + }); + log.err(" Supported feature Set: ", .{}); + const all_features = whitelist_cpu.arch.allFeaturesList(); + var populated_cpu_features = whitelist_cpu.model.features; + populated_cpu_features.populateDependencies(all_features); + for (all_features) |feature, i_usize| { + const i = @intCast(std.Target.Cpu.Feature.Set.Index, i_usize); + const in_cpu_set = populated_cpu_features.isEnabled(i); + if (in_cpu_set) { + log.err("{s} ", .{feature.name}); + } + } + log.err(" Remove: ", .{}); + for (all_features) |feature, i_usize| { + const i = @intCast(std.Target.Cpu.Feature.Set.Index, i_usize); + const in_cpu_set = populated_cpu_features.isEnabled(i); + const in_actual_set = selected_cpu.features.isEnabled(i); + if (in_actual_set and !in_cpu_set) { + log.err("{s} ", .{feature.name}); + } + } + } + self.markInvalidUserInput(); + return args.default_target; + } + + return selected_target; +} + +pub fn addUserInputOption(self: *Build, name_raw: []const u8, value_raw: []const u8) !bool { + const name = self.dupe(name_raw); + const value = self.dupe(value_raw); + const gop = try self.user_input_options.getOrPut(name); + if (!gop.found_existing) { + gop.value_ptr.* = UserInputOption{ + .name = name, + .value = .{ .scalar = value }, + .used = false, + }; + return false; + } + + // option already exists + switch (gop.value_ptr.value) { + .scalar => |s| { + // turn it into a list + var list = ArrayList([]const u8).init(self.allocator); + list.append(s) catch unreachable; + list.append(value) catch unreachable; + self.user_input_options.put(name, .{ + .name = name, + .value = .{ .list = list }, + .used = false, + }) catch unreachable; + }, + .list => |*list| { + // append to the list + list.append(value) catch unreachable; + self.user_input_options.put(name, .{ + .name = name, + .value = .{ .list = list.* }, + .used = false, + }) catch unreachable; + }, + .flag => { + log.warn("Option '-D{s}={s}' conflicts with flag '-D{s}'.", .{ name, value, name }); + return true; + }, + .map => |*map| { + _ = map; + log.warn("TODO maps as command line arguments is not implemented yet.", .{}); + return true; + }, + } + return false; +} + +pub fn addUserInputFlag(self: *Build, name_raw: []const u8) !bool { + const name = self.dupe(name_raw); + const gop = try self.user_input_options.getOrPut(name); + if (!gop.found_existing) { + gop.value_ptr.* = .{ + .name = name, + .value = .{ .flag = {} }, + .used = false, + }; + return false; + } + + // option already exists + switch (gop.value_ptr.value) { + .scalar => |s| { + log.err("Flag '-D{s}' conflicts with option '-D{s}={s}'.", .{ name, name, s }); + return true; + }, + .list, .map => { + log.err("Flag '-D{s}' conflicts with multiple options of the same name.", .{name}); + return true; + }, + .flag => {}, + } + return false; +} + +fn typeToEnum(comptime T: type) TypeId { + return switch (@typeInfo(T)) { + .Int => .int, + .Float => .float, + .Bool => .bool, + .Enum => .@"enum", + else => switch (T) { + []const u8 => .string, + []const []const u8 => .list, + else => @compileError("Unsupported type: " ++ @typeName(T)), + }, + }; +} + +fn markInvalidUserInput(self: *Build) void { + self.invalid_user_input = true; +} + +pub fn validateUserInputDidItFail(self: *Build) bool { + // make sure all args are used + var it = self.user_input_options.iterator(); + while (it.next()) |entry| { + if (!entry.value_ptr.used) { + log.err("Invalid option: -D{s}", .{entry.key_ptr.*}); + self.markInvalidUserInput(); + } + } + + return self.invalid_user_input; +} + +pub fn spawnChild(self: *Build, argv: []const []const u8) !void { + return self.spawnChildEnvMap(null, self.env_map, argv); +} + +fn printCmd(cwd: ?[]const u8, argv: []const []const u8) void { + if (cwd) |yes_cwd| std.debug.print("cd {s} && ", .{yes_cwd}); + for (argv) |arg| { + std.debug.print("{s} ", .{arg}); + } + std.debug.print("\n", .{}); +} + +pub fn spawnChildEnvMap(self: *Build, cwd: ?[]const u8, env_map: *const EnvMap, argv: []const []const u8) !void { + if (self.verbose) { + printCmd(cwd, argv); + } + + if (!std.process.can_spawn) + return error.ExecNotSupported; + + var child = std.ChildProcess.init(argv, self.allocator); + child.cwd = cwd; + child.env_map = env_map; + + const term = child.spawnAndWait() catch |err| { + log.err("Unable to spawn {s}: {s}", .{ argv[0], @errorName(err) }); + return err; + }; + + switch (term) { + .Exited => |code| { + if (code != 0) { + log.err("The following command exited with error code {}:", .{code}); + printCmd(cwd, argv); + return error.UncleanExit; + } + }, + else => { + log.err("The following command terminated unexpectedly:", .{}); + printCmd(cwd, argv); + + return error.UncleanExit; + }, + } +} + +pub fn makePath(self: *Build, path: []const u8) !void { + fs.cwd().makePath(self.pathFromRoot(path)) catch |err| { + log.err("Unable to create path {s}: {s}", .{ path, @errorName(err) }); + return err; + }; +} + +pub fn installArtifact(self: *Build, artifact: *LibExeObjStep) void { + self.getInstallStep().dependOn(&self.addInstallArtifact(artifact).step); +} + +pub fn addInstallArtifact(self: *Build, artifact: *LibExeObjStep) *InstallArtifactStep { + return InstallArtifactStep.create(self, artifact); +} + +///`dest_rel_path` is relative to prefix path +pub fn installFile(self: *Build, src_path: []const u8, dest_rel_path: []const u8) void { + self.getInstallStep().dependOn(&self.addInstallFileWithDir(.{ .path = src_path }, .prefix, dest_rel_path).step); +} + +pub fn installDirectory(self: *Build, options: InstallDirectoryOptions) void { + self.getInstallStep().dependOn(&self.addInstallDirectory(options).step); +} + +///`dest_rel_path` is relative to bin path +pub fn installBinFile(self: *Build, src_path: []const u8, dest_rel_path: []const u8) void { + self.getInstallStep().dependOn(&self.addInstallFileWithDir(.{ .path = src_path }, .bin, dest_rel_path).step); +} + +///`dest_rel_path` is relative to lib path +pub fn installLibFile(self: *Build, src_path: []const u8, dest_rel_path: []const u8) void { + self.getInstallStep().dependOn(&self.addInstallFileWithDir(.{ .path = src_path }, .lib, dest_rel_path).step); +} + +/// Output format (BIN vs Intel HEX) determined by filename +pub fn installRaw(self: *Build, artifact: *LibExeObjStep, dest_filename: []const u8, options: InstallRawStep.CreateOptions) *InstallRawStep { + const raw = self.addInstallRaw(artifact, dest_filename, options); + self.getInstallStep().dependOn(&raw.step); + return raw; +} + +///`dest_rel_path` is relative to install prefix path +pub fn addInstallFile(self: *Build, source: FileSource, dest_rel_path: []const u8) *InstallFileStep { + return self.addInstallFileWithDir(source.dupe(self), .prefix, dest_rel_path); +} + +///`dest_rel_path` is relative to bin path +pub fn addInstallBinFile(self: *Build, source: FileSource, dest_rel_path: []const u8) *InstallFileStep { + return self.addInstallFileWithDir(source.dupe(self), .bin, dest_rel_path); +} + +///`dest_rel_path` is relative to lib path +pub fn addInstallLibFile(self: *Build, source: FileSource, dest_rel_path: []const u8) *InstallFileStep { + return self.addInstallFileWithDir(source.dupe(self), .lib, dest_rel_path); +} + +pub fn addInstallHeaderFile(b: *Build, src_path: []const u8, dest_rel_path: []const u8) *InstallFileStep { + return b.addInstallFileWithDir(.{ .path = src_path }, .header, dest_rel_path); +} + +pub fn addInstallRaw(self: *Build, artifact: *LibExeObjStep, dest_filename: []const u8, options: InstallRawStep.CreateOptions) *InstallRawStep { + return InstallRawStep.create(self, artifact, dest_filename, options); +} + +pub fn addInstallFileWithDir( + self: *Build, + source: FileSource, + install_dir: InstallDir, + dest_rel_path: []const u8, +) *InstallFileStep { + if (dest_rel_path.len == 0) { + panic("dest_rel_path must be non-empty", .{}); + } + const install_step = self.allocator.create(InstallFileStep) catch unreachable; + install_step.* = InstallFileStep.init(self, source.dupe(self), install_dir, dest_rel_path); + return install_step; +} + +pub fn addInstallDirectory(self: *Build, options: InstallDirectoryOptions) *InstallDirStep { + const install_step = self.allocator.create(InstallDirStep) catch unreachable; + install_step.* = InstallDirStep.init(self, options); + return install_step; +} + +pub fn pushInstalledFile(self: *Build, dir: InstallDir, dest_rel_path: []const u8) void { + const file = InstalledFile{ + .dir = dir, + .path = dest_rel_path, + }; + self.installed_files.append(file.dupe(self)) catch unreachable; +} + +pub fn updateFile(self: *Build, source_path: []const u8, dest_path: []const u8) !void { + if (self.verbose) { + log.info("cp {s} {s} ", .{ source_path, dest_path }); + } + const cwd = fs.cwd(); + const prev_status = try fs.Dir.updateFile(cwd, source_path, cwd, dest_path, .{}); + if (self.verbose) switch (prev_status) { + .stale => log.info("# installed", .{}), + .fresh => log.info("# up-to-date", .{}), + }; +} + +pub fn truncateFile(self: *Build, dest_path: []const u8) !void { + if (self.verbose) { + log.info("truncate {s}", .{dest_path}); + } + const cwd = fs.cwd(); + var src_file = cwd.createFile(dest_path, .{}) catch |err| switch (err) { + error.FileNotFound => blk: { + if (fs.path.dirname(dest_path)) |dirname| { + try cwd.makePath(dirname); + } + break :blk try cwd.createFile(dest_path, .{}); + }, + else => |e| return e, + }; + src_file.close(); +} + +pub fn pathFromRoot(self: *Build, rel_path: []const u8) []u8 { + return fs.path.resolve(self.allocator, &[_][]const u8{ self.build_root, rel_path }) catch unreachable; +} + +/// Shorthand for `std.fs.path.join(Build.allocator, paths) catch unreachable` +pub fn pathJoin(self: *Build, paths: []const []const u8) []u8 { + return fs.path.join(self.allocator, paths) catch unreachable; +} + +pub fn fmt(self: *Build, comptime format: []const u8, args: anytype) []u8 { + return fmt_lib.allocPrint(self.allocator, format, args) catch unreachable; +} + +pub fn findProgram(self: *Build, names: []const []const u8, paths: []const []const u8) ![]const u8 { + // TODO report error for ambiguous situations + const exe_extension = @as(CrossTarget, .{}).exeFileExt(); + for (self.search_prefixes.items) |search_prefix| { + for (names) |name| { + if (fs.path.isAbsolute(name)) { + return name; + } + const full_path = self.pathJoin(&.{ + search_prefix, + "bin", + self.fmt("{s}{s}", .{ name, exe_extension }), + }); + return fs.realpathAlloc(self.allocator, full_path) catch continue; + } + } + if (self.env_map.get("PATH")) |PATH| { + for (names) |name| { + if (fs.path.isAbsolute(name)) { + return name; + } + var it = mem.tokenize(u8, PATH, &[_]u8{fs.path.delimiter}); + while (it.next()) |path| { + const full_path = self.pathJoin(&.{ + path, + self.fmt("{s}{s}", .{ name, exe_extension }), + }); + return fs.realpathAlloc(self.allocator, full_path) catch continue; + } + } + } + for (names) |name| { + if (fs.path.isAbsolute(name)) { + return name; + } + for (paths) |path| { + const full_path = self.pathJoin(&.{ + path, + self.fmt("{s}{s}", .{ name, exe_extension }), + }); + return fs.realpathAlloc(self.allocator, full_path) catch continue; + } + } + return error.FileNotFound; +} + +pub fn execAllowFail( + self: *Build, + argv: []const []const u8, + out_code: *u8, + stderr_behavior: std.ChildProcess.StdIo, +) ExecError![]u8 { + assert(argv.len != 0); + + if (!std.process.can_spawn) + return error.ExecNotSupported; + + const max_output_size = 400 * 1024; + var child = std.ChildProcess.init(argv, self.allocator); + child.stdin_behavior = .Ignore; + child.stdout_behavior = .Pipe; + child.stderr_behavior = stderr_behavior; + child.env_map = self.env_map; + + try child.spawn(); + + const stdout = child.stdout.?.reader().readAllAlloc(self.allocator, max_output_size) catch { + return error.ReadFailure; + }; + errdefer self.allocator.free(stdout); + + const term = try child.wait(); + switch (term) { + .Exited => |code| { + if (code != 0) { + out_code.* = @truncate(u8, code); + return error.ExitCodeFailure; + } + return stdout; + }, + .Signal, .Stopped, .Unknown => |code| { + out_code.* = @truncate(u8, code); + return error.ProcessTerminated; + }, + } +} + +pub fn execFromStep(self: *Build, argv: []const []const u8, src_step: ?*Step) ![]u8 { + assert(argv.len != 0); + + if (self.verbose) { + printCmd(null, argv); + } + + if (!std.process.can_spawn) { + if (src_step) |s| log.err("{s}...", .{s.name}); + log.err("Unable to spawn the following command: cannot spawn child process", .{}); + printCmd(null, argv); + std.os.abort(); + } + + var code: u8 = undefined; + return self.execAllowFail(argv, &code, .Inherit) catch |err| switch (err) { + error.ExecNotSupported => { + if (src_step) |s| log.err("{s}...", .{s.name}); + log.err("Unable to spawn the following command: cannot spawn child process", .{}); + printCmd(null, argv); + std.os.abort(); + }, + error.FileNotFound => { + if (src_step) |s| log.err("{s}...", .{s.name}); + log.err("Unable to spawn the following command: file not found", .{}); + printCmd(null, argv); + std.os.exit(@truncate(u8, code)); + }, + error.ExitCodeFailure => { + if (src_step) |s| log.err("{s}...", .{s.name}); + if (self.prominent_compile_errors) { + log.err("The step exited with error code {d}", .{code}); + } else { + log.err("The following command exited with error code {d}:", .{code}); + printCmd(null, argv); + } + + std.os.exit(@truncate(u8, code)); + }, + error.ProcessTerminated => { + if (src_step) |s| log.err("{s}...", .{s.name}); + log.err("The following command terminated unexpectedly:", .{}); + printCmd(null, argv); + std.os.exit(@truncate(u8, code)); + }, + else => |e| return e, + }; +} + +pub fn exec(self: *Build, argv: []const []const u8) ![]u8 { + return self.execFromStep(argv, null); +} + +pub fn addSearchPrefix(self: *Build, search_prefix: []const u8) void { + self.search_prefixes.append(self.dupePath(search_prefix)) catch unreachable; +} + +pub fn getInstallPath(self: *Build, dir: InstallDir, dest_rel_path: []const u8) []const u8 { + assert(!fs.path.isAbsolute(dest_rel_path)); // Install paths must be relative to the prefix + const base_dir = switch (dir) { + .prefix => self.install_path, + .bin => self.exe_dir, + .lib => self.lib_dir, + .header => self.h_dir, + .custom => |path| self.pathJoin(&.{ self.install_path, path }), + }; + return fs.path.resolve( + self.allocator, + &[_][]const u8{ base_dir, dest_rel_path }, + ) catch unreachable; +} + +pub const Dependency = struct { + builder: *Build, + + pub fn artifact(d: *Dependency, name: []const u8) *LibExeObjStep { + var found: ?*LibExeObjStep = null; + for (d.builder.install_tls.step.dependencies.items) |dep_step| { + const inst = dep_step.cast(InstallArtifactStep) orelse continue; + if (mem.eql(u8, inst.artifact.name, name)) { + if (found != null) panic("artifact name '{s}' is ambiguous", .{name}); + found = inst.artifact; + } + } + return found orelse { + for (d.builder.install_tls.step.dependencies.items) |dep_step| { + const inst = dep_step.cast(InstallArtifactStep) orelse continue; + log.info("available artifact: '{s}'", .{inst.artifact.name}); + } + panic("unable to find artifact '{s}'", .{name}); + }; + } +}; + +pub fn dependency(b: *Build, name: []const u8, args: anytype) *Dependency { + const build_runner = @import("root"); + const deps = build_runner.dependencies; + + inline for (@typeInfo(deps.imports).Struct.decls) |decl| { + if (mem.startsWith(u8, decl.name, b.dep_prefix) and + mem.endsWith(u8, decl.name, name) and + decl.name.len == b.dep_prefix.len + name.len) + { + const build_zig = @field(deps.imports, decl.name); + const build_root = @field(deps.build_root, decl.name); + return dependencyInner(b, name, build_root, build_zig, args); + } + } + + const full_path = b.pathFromRoot("build.zig.ini"); + std.debug.print("no dependency named '{s}' in '{s}'\n", .{ name, full_path }); + std.process.exit(1); +} + +fn dependencyInner( + b: *Build, + name: []const u8, + build_root: []const u8, + comptime build_zig: type, + args: anytype, +) *Dependency { + const sub_builder = b.createChild(name, build_root, args) catch unreachable; + sub_builder.runBuild(build_zig) catch unreachable; + + if (sub_builder.validateUserInputDidItFail()) { + std.debug.dumpCurrentStackTrace(@returnAddress()); + } + + const dep = b.allocator.create(Dependency) catch unreachable; + dep.* = .{ .builder = sub_builder }; + return dep; +} + +pub fn runBuild(b: *Build, build_zig: anytype) anyerror!void { + switch (@typeInfo(@typeInfo(@TypeOf(build_zig.build)).Fn.return_type.?)) { + .Void => build_zig.build(b), + .ErrorUnion => try build_zig.build(b), + else => @compileError("expected return type of build to be 'void' or '!void'"), + } +} + +test "builder.findProgram compiles" { + if (builtin.os.tag == .wasi) return error.SkipZigTest; + + var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); + defer arena.deinit(); + + const builder = try Build.create( + arena.allocator(), + "zig", + "zig-cache", + "zig-cache", + "zig-cache", + ); + defer builder.destroy(); + _ = builder.findProgram(&[_][]const u8{}, &[_][]const u8{}) catch null; +} + +pub const Pkg = struct { + name: []const u8, + source: FileSource, + dependencies: ?[]const Pkg = null, +}; + +/// A file that is generated by a build step. +/// This struct is an interface that is meant to be used with `@fieldParentPtr` to implement the actual path logic. +pub const GeneratedFile = struct { + /// The step that generates the file + step: *Step, + + /// The path to the generated file. Must be either absolute or relative to the build root. + /// This value must be set in the `fn make()` of the `step` and must not be `null` afterwards. + path: ?[]const u8 = null, + + pub fn getPath(self: GeneratedFile) []const u8 { + return self.path orelse std.debug.panic( + "getPath() was called on a GeneratedFile that wasn't build yet. Is there a missing Step dependency on step '{s}'?", + .{self.step.name}, + ); + } +}; + +/// A file source is a reference to an existing or future file. +/// +pub const FileSource = union(enum) { + /// A plain file path, relative to build root or absolute. + path: []const u8, + + /// A file that is generated by an interface. Those files usually are + /// not available until built by a build step. + generated: *const GeneratedFile, + + /// Returns a new file source that will have a relative path to the build root guaranteed. + /// This should be preferred over setting `.path` directly as it documents that the files are in the project directory. + pub fn relative(path: []const u8) FileSource { + std.debug.assert(!std.fs.path.isAbsolute(path)); + return FileSource{ .path = path }; + } + + /// Returns a string that can be shown to represent the file source. + /// Either returns the path or `"generated"`. + pub fn getDisplayName(self: FileSource) []const u8 { + return switch (self) { + .path => self.path, + .generated => "generated", + }; + } + + /// Adds dependencies this file source implies to the given step. + pub fn addStepDependencies(self: FileSource, other_step: *Step) void { + switch (self) { + .path => {}, + .generated => |gen| other_step.dependOn(gen.step), + } + } + + /// Should only be called during make(), returns a path relative to the build root or absolute. + pub fn getPath(self: FileSource, builder: *Build) []const u8 { + const path = switch (self) { + .path => |p| builder.pathFromRoot(p), + .generated => |gen| gen.getPath(), + }; + return path; + } + + /// Duplicates the file source for a given builder. + pub fn dupe(self: FileSource, b: *Build) FileSource { + return switch (self) { + .path => |p| .{ .path = b.dupePath(p) }, + .generated => |gen| .{ .generated = gen }, + }; + } +}; + +/// Allocates a new string for assigning a value to a named macro. +/// If the value is omitted, it is set to 1. +/// `name` and `value` need not live longer than the function call. +pub fn constructCMacro(allocator: Allocator, name: []const u8, value: ?[]const u8) []const u8 { + var macro = allocator.alloc( + u8, + name.len + if (value) |value_slice| value_slice.len + 1 else 0, + ) catch |err| if (err == error.OutOfMemory) @panic("Out of memory") else unreachable; + mem.copy(u8, macro, name); + if (value) |value_slice| { + macro[name.len] = '='; + mem.copy(u8, macro[name.len + 1 ..], value_slice); + } + return macro; +} + +/// deprecated: use `InstallDirStep.Options` +pub const InstallDirectoryOptions = InstallDirStep.Options; + +pub const VcpkgRoot = union(VcpkgRootStatus) { + unattempted: void, + not_found: void, + found: []const u8, +}; + +pub const VcpkgRootStatus = enum { + unattempted, + not_found, + found, +}; + +pub const InstallDir = union(enum) { + prefix: void, + lib: void, + bin: void, + header: void, + /// A path relative to the prefix + custom: []const u8, + + /// Duplicates the install directory including the path if set to custom. + pub fn dupe(self: InstallDir, builder: *Build) InstallDir { + if (self == .custom) { + // Written with this temporary to avoid RLS problems + const duped_path = builder.dupe(self.custom); + return .{ .custom = duped_path }; + } else { + return self; + } + } +}; + +pub const InstalledFile = struct { + dir: InstallDir, + path: []const u8, + + /// Duplicates the installed file path and directory. + pub fn dupe(self: InstalledFile, builder: *Build) InstalledFile { + return .{ + .dir = self.dir.dupe(builder), + .path = builder.dupe(self.path), + }; + } +}; + +pub fn serializeCpu(allocator: Allocator, cpu: std.Target.Cpu) ![]const u8 { + // TODO this logic can disappear if cpu model + features becomes part of the target triple + const all_features = cpu.arch.allFeaturesList(); + var populated_cpu_features = cpu.model.features; + populated_cpu_features.populateDependencies(all_features); + + if (populated_cpu_features.eql(cpu.features)) { + // The CPU name alone is sufficient. + return cpu.model.name; + } else { + var mcpu_buffer = ArrayList(u8).init(allocator); + try mcpu_buffer.appendSlice(cpu.model.name); + + for (all_features) |feature, i_usize| { + const i = @intCast(std.Target.Cpu.Feature.Set.Index, i_usize); + const in_cpu_set = populated_cpu_features.isEnabled(i); + const in_actual_set = cpu.features.isEnabled(i); + if (in_cpu_set and !in_actual_set) { + try mcpu_buffer.writer().print("-{s}", .{feature.name}); + } else if (!in_cpu_set and in_actual_set) { + try mcpu_buffer.writer().print("+{s}", .{feature.name}); + } + } + + return try mcpu_buffer.toOwnedSlice(); + } +} + +test "dupePkg()" { + if (builtin.os.tag == .wasi) return error.SkipZigTest; + + var arena = std.heap.ArenaAllocator.init(std.testing.allocator); + defer arena.deinit(); + var builder = try Build.create( + arena.allocator(), + "test", + "test", + "test", + "test", + ); + defer builder.destroy(); + + var pkg_dep = Pkg{ + .name = "pkg_dep", + .source = .{ .path = "/not/a/pkg_dep.zig" }, + }; + var pkg_top = Pkg{ + .name = "pkg_top", + .source = .{ .path = "/not/a/pkg_top.zig" }, + .dependencies = &[_]Pkg{pkg_dep}, + }; + const duped = builder.dupePkg(pkg_top); + + const original_deps = pkg_top.dependencies.?; + const dupe_deps = duped.dependencies.?; + + // probably the same top level package details + try std.testing.expectEqualStrings(pkg_top.name, duped.name); + + // probably the same dependencies + try std.testing.expectEqual(original_deps.len, dupe_deps.len); + try std.testing.expectEqual(original_deps[0].name, pkg_dep.name); + + // could segfault otherwise if pointers in duplicated package's fields are + // the same as those in stack allocated package's fields + try std.testing.expect(dupe_deps.ptr != original_deps.ptr); + try std.testing.expect(duped.name.ptr != pkg_top.name.ptr); + try std.testing.expect(duped.source.path.ptr != pkg_top.source.path.ptr); + try std.testing.expect(dupe_deps[0].name.ptr != pkg_dep.name.ptr); + try std.testing.expect(dupe_deps[0].source.path.ptr != pkg_dep.source.path.ptr); +} + +test { + _ = CheckFileStep; + _ = CheckObjectStep; + _ = EmulatableRunStep; + _ = FmtStep; + _ = InstallArtifactStep; + _ = InstallDirStep; + _ = InstallFileStep; + _ = InstallRawStep; + _ = LibExeObjStep; + _ = LogStep; + _ = OptionsStep; + _ = RemoveDirStep; + _ = RunStep; + _ = TranslateCStep; + _ = WriteFileStep; +} diff --git a/lib/std/build/CheckFileStep.zig b/lib/std/Build/CheckFileStep.zig similarity index 88% rename from lib/std/build/CheckFileStep.zig rename to lib/std/Build/CheckFileStep.zig index 2c06ab9279083f6709b1a4acef944e5e2300e783..3b8cfe5263ae53b14e53ced20a4b1306a60b23da 100644 --- a/lib/std/build/CheckFileStep.zig +++ b/lib/std/Build/CheckFileStep.zig @@ -1,7 +1,5 @@ const std = @import("../std.zig"); -const build = std.build; -const Step = build.Step; -const Builder = build.Builder; +const Step = std.Build.Step; const fs = std.fs; const mem = std.mem; @@ -10,14 +8,14 @@ const CheckFileStep = @This(); pub const base_id = .check_file; step: Step, -builder: *Builder, +builder: *std.Build, expected_matches: []const []const u8, -source: build.FileSource, +source: std.Build.FileSource, max_bytes: usize = 20 * 1024 * 1024, pub fn create( - builder: *Builder, - source: build.FileSource, + builder: *std.Build, + source: std.Build.FileSource, expected_matches: []const []const u8, ) *CheckFileStep { const self = builder.allocator.create(CheckFileStep) catch unreachable; diff --git a/lib/std/build/CheckObjectStep.zig b/lib/std/Build/CheckObjectStep.zig similarity index 98% rename from lib/std/build/CheckObjectStep.zig rename to lib/std/Build/CheckObjectStep.zig index 4ef350b41814ea9f646927e40900e0a6a73907fd..7907be1787e3e358364d90efafc9449dbadea5c6 100644 --- a/lib/std/build/CheckObjectStep.zig +++ b/lib/std/Build/CheckObjectStep.zig @@ -1,6 +1,5 @@ const std = @import("../std.zig"); const assert = std.debug.assert; -const build = std.build; const fs = std.fs; const macho = std.macho; const math = std.math; @@ -10,21 +9,20 @@ const testing = std.testing; const CheckObjectStep = @This(); const Allocator = mem.Allocator; -const Builder = build.Builder; -const Step = build.Step; -const EmulatableRunStep = build.EmulatableRunStep; +const Step = std.Build.Step; +const EmulatableRunStep = std.Build.EmulatableRunStep; pub const base_id = .check_object; step: Step, -builder: *Builder, -source: build.FileSource, +builder: *std.Build, +source: std.Build.FileSource, max_bytes: usize = 20 * 1024 * 1024, checks: std.ArrayList(Check), dump_symtab: bool = false, obj_format: std.Target.ObjectFormat, -pub fn create(builder: *Builder, source: build.FileSource, obj_format: std.Target.ObjectFormat) *CheckObjectStep { +pub fn create(builder: *std.Build, source: std.Build.FileSource, obj_format: std.Target.ObjectFormat) *CheckObjectStep { const gpa = builder.allocator; const self = gpa.create(CheckObjectStep) catch unreachable; self.* = .{ @@ -44,7 +42,7 @@ pub fn runAndCompare(self: *CheckObjectStep) *EmulatableRunStep { const dependencies_len = self.step.dependencies.items.len; assert(dependencies_len > 0); const exe_step = self.step.dependencies.items[dependencies_len - 1]; - const exe = exe_step.cast(std.build.LibExeObjStep).?; + const exe = exe_step.cast(std.Build.LibExeObjStep).?; const emulatable_step = EmulatableRunStep.create(self.builder, "EmulatableRun", exe); emulatable_step.step.dependOn(&self.step); return emulatable_step; @@ -216,10 +214,10 @@ const ComputeCompareExpected = struct { }; const Check = struct { - builder: *Builder, + builder: *std.Build, actions: std.ArrayList(Action), - fn create(b: *Builder) Check { + fn create(b: *std.Build) Check { return .{ .builder = b, .actions = std.ArrayList(Action).init(b.allocator), diff --git a/lib/std/build/ConfigHeaderStep.zig b/lib/std/Build/ConfigHeaderStep.zig similarity index 97% rename from lib/std/build/ConfigHeaderStep.zig rename to lib/std/Build/ConfigHeaderStep.zig index 400c06525e43bffe7be0d34b23102c3236648129..b961227c9c6de0ea39c9b5f9aa67d6345d0d5497 100644 --- a/lib/std/build/ConfigHeaderStep.zig +++ b/lib/std/Build/ConfigHeaderStep.zig @@ -1,7 +1,6 @@ const std = @import("../std.zig"); const ConfigHeaderStep = @This(); -const Step = std.build.Step; -const Builder = std.build.Builder; +const Step = std.Build.Step; pub const base_id: Step.Id = .config_header; @@ -24,15 +23,15 @@ pub const Value = union(enum) { }; step: Step, -builder: *Builder, -source: std.build.FileSource, +builder: *std.Build, +source: std.Build.FileSource, style: Style, values: std.StringHashMap(Value), max_bytes: usize = 2 * 1024 * 1024, output_dir: []const u8, output_basename: []const u8, -pub fn create(builder: *Builder, source: std.build.FileSource, style: Style) *ConfigHeaderStep { +pub fn create(builder: *std.Build, source: std.Build.FileSource, style: Style) *ConfigHeaderStep { const self = builder.allocator.create(ConfigHeaderStep) catch @panic("OOM"); const name = builder.fmt("configure header {s}", .{source.getDisplayName()}); self.* = .{ diff --git a/lib/std/build/EmulatableRunStep.zig b/lib/std/Build/EmulatableRunStep.zig similarity index 96% rename from lib/std/build/EmulatableRunStep.zig rename to lib/std/Build/EmulatableRunStep.zig index 52ce8edfac2a389973bff510523e1021361faf45..b7b12d791f7c2a612484a6208319b9a582c5cd3b 100644 --- a/lib/std/build/EmulatableRunStep.zig +++ b/lib/std/Build/EmulatableRunStep.zig @@ -5,11 +5,9 @@ //! without having to verify if it's possible to be ran against. const std = @import("../std.zig"); -const build = std.build; -const Step = std.build.Step; -const Builder = std.build.Builder; -const LibExeObjStep = std.build.LibExeObjStep; -const RunStep = std.build.RunStep; +const Step = std.Build.Step; +const LibExeObjStep = std.Build.LibExeObjStep; +const RunStep = std.Build.RunStep; const fs = std.fs; const process = std.process; @@ -22,7 +20,7 @@ pub const base_id = .emulatable_run; const max_stdout_size = 1 * 1024 * 1024; // 1 MiB step: Step, -builder: *Builder, +builder: *std.Build, /// The artifact (executable) to be run by this step exe: *LibExeObjStep, @@ -47,7 +45,7 @@ hide_foreign_binaries_warning: bool, /// binary through emulation when any of the emulation options such as `enable_rosetta` are set to true. /// When set to false, and the binary is foreign, running the executable is skipped. /// Asserts given artifact is an executable. -pub fn create(builder: *Builder, name: []const u8, artifact: *LibExeObjStep) *EmulatableRunStep { +pub fn create(builder: *std.Build, name: []const u8, artifact: *LibExeObjStep) *EmulatableRunStep { std.debug.assert(artifact.kind == .exe or artifact.kind == .test_exe); const self = builder.allocator.create(EmulatableRunStep) catch unreachable; diff --git a/lib/std/build/FmtStep.zig b/lib/std/Build/FmtStep.zig similarity index 75% rename from lib/std/build/FmtStep.zig rename to lib/std/Build/FmtStep.zig index 62923623f2aaea208be692355b6f7a651beddd99..44a93dee66db7f756f1b10d2856f55214a2eb3cd 100644 --- a/lib/std/build/FmtStep.zig +++ b/lib/std/Build/FmtStep.zig @@ -1,19 +1,14 @@ const std = @import("../std.zig"); -const build = @import("../build.zig"); -const Step = build.Step; -const Builder = build.Builder; -const BufMap = std.BufMap; -const mem = std.mem; - +const Step = std.Build.Step; const FmtStep = @This(); pub const base_id = .fmt; step: Step, -builder: *Builder, +builder: *std.Build, argv: [][]const u8, -pub fn create(builder: *Builder, paths: []const []const u8) *FmtStep { +pub fn create(builder: *std.Build, paths: []const []const u8) *FmtStep { const self = builder.allocator.create(FmtStep) catch unreachable; const name = "zig fmt"; self.* = FmtStep{ diff --git a/lib/std/build/InstallArtifactStep.zig b/lib/std/Build/InstallArtifactStep.zig similarity index 88% rename from lib/std/build/InstallArtifactStep.zig rename to lib/std/Build/InstallArtifactStep.zig index 537b8c8fd9af830ebd84f0f0bc1b82f4e9aa21d0..929b30e935fdd45893c5ce6ca77bf95fedac1b97 100644 --- a/lib/std/build/InstallArtifactStep.zig +++ b/lib/std/Build/InstallArtifactStep.zig @@ -1,26 +1,23 @@ const std = @import("../std.zig"); -const build = @import("../build.zig"); -const Step = build.Step; -const Builder = build.Builder; -const LibExeObjStep = std.build.LibExeObjStep; -const InstallDir = std.build.InstallDir; +const Step = std.Build.Step; +const LibExeObjStep = std.Build.LibExeObjStep; +const InstallDir = std.Build.InstallDir; +const InstallArtifactStep = @This(); pub const base_id = .install_artifact; step: Step, -builder: *Builder, +builder: *std.Build, artifact: *LibExeObjStep, dest_dir: InstallDir, pdb_dir: ?InstallDir, h_dir: ?InstallDir, -const Self = @This(); - -pub fn create(builder: *Builder, artifact: *LibExeObjStep) *Self { +pub fn create(builder: *std.Build, artifact: *LibExeObjStep) *InstallArtifactStep { if (artifact.install_step) |s| return s; - const self = builder.allocator.create(Self) catch unreachable; - self.* = Self{ + const self = builder.allocator.create(InstallArtifactStep) catch unreachable; + self.* = InstallArtifactStep{ .builder = builder, .step = Step.init(.install_artifact, builder.fmt("install {s}", .{artifact.step.name}), builder.allocator, make), .artifact = artifact, @@ -64,7 +61,7 @@ pub fn create(builder: *Builder, artifact: *LibExeObjStep) *Self { } fn make(step: *Step) !void { - const self = @fieldParentPtr(Self, "step", step); + const self = @fieldParentPtr(InstallArtifactStep, "step", step); const builder = self.builder; const full_dest_path = builder.getInstallPath(self.dest_dir, self.artifact.out_filename); diff --git a/lib/std/build/InstallDirStep.zig b/lib/std/Build/InstallDirStep.zig similarity index 92% rename from lib/std/build/InstallDirStep.zig rename to lib/std/Build/InstallDirStep.zig index 0a41e1aaefcd5a0f2d133f51cc86ac272f58c8be..41dbb3e35a5f1d455a6dac09f6d127e113989625 100644 --- a/lib/std/build/InstallDirStep.zig +++ b/lib/std/Build/InstallDirStep.zig @@ -1,19 +1,17 @@ const std = @import("../std.zig"); const mem = std.mem; const fs = std.fs; -const build = @import("../build.zig"); -const Step = build.Step; -const Builder = build.Builder; -const InstallDir = std.build.InstallDir; +const Step = std.Build.Step; +const InstallDir = std.Build.InstallDir; const InstallDirStep = @This(); const log = std.log; step: Step, -builder: *Builder, +builder: *std.Build, options: Options, /// This is used by the build system when a file being installed comes from one /// package but is being installed by another. -override_source_builder: ?*Builder = null, +override_source_builder: ?*std.Build = null, pub const base_id = .install_dir; @@ -31,7 +29,7 @@ pub const Options = struct { /// `@import("test.zig")` would be a compile error. blank_extensions: []const []const u8 = &.{}, - fn dupe(self: Options, b: *Builder) Options { + fn dupe(self: Options, b: *std.Build) Options { return .{ .source_dir = b.dupe(self.source_dir), .install_dir = self.install_dir.dupe(b), @@ -43,7 +41,7 @@ pub const Options = struct { }; pub fn init( - builder: *Builder, + builder: *std.Build, options: Options, ) InstallDirStep { builder.pushInstalledFile(options.install_dir, options.install_subdir); diff --git a/lib/std/build/InstallFileStep.zig b/lib/std/Build/InstallFileStep.zig similarity index 82% rename from lib/std/build/InstallFileStep.zig rename to lib/std/Build/InstallFileStep.zig index 37203e64c5e2676fb3b6a073a546533b007cf221..8c8d8ad2d45109f41d8a7be507f5468919f3717d 100644 --- a/lib/std/build/InstallFileStep.zig +++ b/lib/std/Build/InstallFileStep.zig @@ -1,24 +1,22 @@ const std = @import("../std.zig"); -const build = @import("../build.zig"); -const Step = build.Step; -const Builder = build.Builder; -const FileSource = std.build.FileSource; -const InstallDir = std.build.InstallDir; +const Step = std.Build.Step; +const FileSource = std.Build.FileSource; +const InstallDir = std.Build.InstallDir; const InstallFileStep = @This(); pub const base_id = .install_file; step: Step, -builder: *Builder, +builder: *std.Build, source: FileSource, dir: InstallDir, dest_rel_path: []const u8, /// This is used by the build system when a file being installed comes from one /// package but is being installed by another. -override_source_builder: ?*Builder = null, +override_source_builder: ?*std.Build = null, pub fn init( - builder: *Builder, + builder: *std.Build, source: FileSource, dir: InstallDir, dest_rel_path: []const u8, diff --git a/lib/std/build/InstallRawStep.zig b/lib/std/Build/InstallRawStep.zig similarity index 84% rename from lib/std/build/InstallRawStep.zig rename to lib/std/Build/InstallRawStep.zig index e8266dff5aecffbedd4caeffa7e3e480978d9dd9..08d646ff88b79c7a59ee03d43223136ee88db683 100644 --- a/lib/std/build/InstallRawStep.zig +++ b/lib/std/Build/InstallRawStep.zig @@ -7,11 +7,10 @@ const InstallRawStep = @This(); const Allocator = std.mem.Allocator; const ArenaAllocator = std.heap.ArenaAllocator; const ArrayListUnmanaged = std.ArrayListUnmanaged; -const Builder = std.build.Builder; const File = std.fs.File; -const InstallDir = std.build.InstallDir; -const LibExeObjStep = std.build.LibExeObjStep; -const Step = std.build.Step; +const InstallDir = std.Build.InstallDir; +const LibExeObjStep = std.Build.LibExeObjStep; +const Step = std.Build.Step; const elf = std.elf; const fs = std.fs; const io = std.io; @@ -25,12 +24,12 @@ pub const RawFormat = enum { }; step: Step, -builder: *Builder, +builder: *std.Build, artifact: *LibExeObjStep, dest_dir: InstallDir, dest_filename: []const u8, options: CreateOptions, -output_file: std.build.GeneratedFile, +output_file: std.Build.GeneratedFile, pub const CreateOptions = struct { format: ?RawFormat = null, @@ -39,7 +38,12 @@ pub const CreateOptions = struct { pad_to: ?u64 = null, }; -pub fn create(builder: *Builder, artifact: *LibExeObjStep, dest_filename: []const u8, options: CreateOptions) *InstallRawStep { +pub fn create( + builder: *std.Build, + artifact: *LibExeObjStep, + dest_filename: []const u8, + options: CreateOptions, +) *InstallRawStep { const self = builder.allocator.create(InstallRawStep) catch unreachable; self.* = InstallRawStep{ .step = Step.init(.install_raw, builder.fmt("install raw binary {s}", .{artifact.step.name}), builder.allocator, make), @@ -53,7 +57,7 @@ pub fn create(builder: *Builder, artifact: *LibExeObjStep, dest_filename: []cons }, .dest_filename = dest_filename, .options = options, - .output_file = std.build.GeneratedFile{ .step = &self.step }, + .output_file = std.Build.GeneratedFile{ .step = &self.step }, }; self.step.dependOn(&artifact.step); @@ -61,8 +65,8 @@ pub fn create(builder: *Builder, artifact: *LibExeObjStep, dest_filename: []cons return self; } -pub fn getOutputSource(self: *const InstallRawStep) std.build.FileSource { - return std.build.FileSource{ .generated = &self.output_file }; +pub fn getOutputSource(self: *const InstallRawStep) std.Build.FileSource { + return std.Build.FileSource{ .generated = &self.output_file }; } fn make(step: *Step) !void { diff --git a/lib/std/build/LibExeObjStep.zig b/lib/std/Build/LibExeObjStep.zig similarity index 97% rename from lib/std/build/LibExeObjStep.zig rename to lib/std/Build/LibExeObjStep.zig index 6ee5205b50403bec9a3b3a3640ee9d76e2ab088a..af9d34440da0b1517e4115f73510d5a56cf63a02 100644 --- a/lib/std/build/LibExeObjStep.zig +++ b/lib/std/Build/LibExeObjStep.zig @@ -9,32 +9,30 @@ const ArrayList = std.ArrayList; const StringHashMap = std.StringHashMap; const Sha256 = std.crypto.hash.sha2.Sha256; const Allocator = mem.Allocator; -const build = @import("../build.zig"); -const Step = build.Step; -const Builder = build.Builder; +const Step = std.Build.Step; const CrossTarget = std.zig.CrossTarget; const NativeTargetInfo = std.zig.system.NativeTargetInfo; -const FileSource = std.build.FileSource; -const PkgConfigPkg = Builder.PkgConfigPkg; -const PkgConfigError = Builder.PkgConfigError; -const ExecError = Builder.ExecError; -const Pkg = std.build.Pkg; -const VcpkgRoot = std.build.VcpkgRoot; -const InstallDir = std.build.InstallDir; -const InstallArtifactStep = std.build.InstallArtifactStep; -const GeneratedFile = std.build.GeneratedFile; -const InstallRawStep = std.build.InstallRawStep; -const EmulatableRunStep = std.build.EmulatableRunStep; -const CheckObjectStep = std.build.CheckObjectStep; -const RunStep = std.build.RunStep; -const OptionsStep = std.build.OptionsStep; -const ConfigHeaderStep = std.build.ConfigHeaderStep; +const FileSource = std.Build.FileSource; +const PkgConfigPkg = std.Build.PkgConfigPkg; +const PkgConfigError = std.Build.PkgConfigError; +const ExecError = std.Build.ExecError; +const Pkg = std.Build.Pkg; +const VcpkgRoot = std.Build.VcpkgRoot; +const InstallDir = std.Build.InstallDir; +const InstallArtifactStep = std.Build.InstallArtifactStep; +const GeneratedFile = std.Build.GeneratedFile; +const InstallRawStep = std.Build.InstallRawStep; +const EmulatableRunStep = std.Build.EmulatableRunStep; +const CheckObjectStep = std.Build.CheckObjectStep; +const RunStep = std.Build.RunStep; +const OptionsStep = std.Build.OptionsStep; +const ConfigHeaderStep = std.Build.ConfigHeaderStep; const LibExeObjStep = @This(); pub const base_id = .lib_exe_obj; step: Step, -builder: *Builder, +builder: *std.Build, name: []const u8, target: CrossTarget, target_info: NativeTargetInfo, @@ -84,7 +82,7 @@ initial_memory: ?u64 = null, max_memory: ?u64 = null, shared_memory: bool = false, global_base: ?u64 = null, -c_std: Builder.CStd, +c_std: std.Build.CStd, override_lib_dir: ?[]const u8, main_pkg_path: ?[]const u8, exec_cmd_args: ?[]const ?[]const u8, @@ -108,7 +106,7 @@ object_src: []const u8, link_objects: ArrayList(LinkObject), include_dirs: ArrayList(IncludeDir), c_macros: ArrayList([]const u8), -installed_headers: ArrayList(*std.build.Step), +installed_headers: ArrayList(*Step), output_dir: ?[]const u8, is_linking_libc: bool = false, is_linking_libcpp: bool = false, @@ -226,7 +224,7 @@ pub const CSourceFile = struct { source: FileSource, args: []const []const u8, - pub fn dupe(self: CSourceFile, b: *Builder) CSourceFile { + pub fn dupe(self: CSourceFile, b: *std.Build) CSourceFile { return .{ .source = self.source.dupe(b), .args = b.dupeStrings(self.args), @@ -297,7 +295,7 @@ pub const EmitOption = union(enum) { emit: void, emit_to: []const u8, - fn getArg(self: @This(), b: *Builder, arg_name: []const u8) ?[]const u8 { + fn getArg(self: @This(), b: *std.Build, arg_name: []const u8) ?[]const u8 { return switch (self) { .no_emit => b.fmt("-fno-{s}", .{arg_name}), .default => null, @@ -307,7 +305,7 @@ pub const EmitOption = union(enum) { } }; -pub fn create(builder: *Builder, options: Options) *LibExeObjStep { +pub fn create(builder: *std.Build, options: Options) *LibExeObjStep { const name = builder.dupe(options.name); const root_src: ?FileSource = if (options.root_source_file) |rsrc| rsrc.dupe(builder) else null; if (mem.indexOf(u8, name, "/") != null or mem.indexOf(u8, name, "\\") != null) { @@ -343,9 +341,9 @@ pub fn create(builder: *Builder, options: Options) *LibExeObjStep { .lib_paths = ArrayList([]const u8).init(builder.allocator), .rpaths = ArrayList([]const u8).init(builder.allocator), .framework_dirs = ArrayList([]const u8).init(builder.allocator), - .installed_headers = ArrayList(*std.build.Step).init(builder.allocator), + .installed_headers = ArrayList(*Step).init(builder.allocator), .object_src = undefined, - .c_std = Builder.CStd.C99, + .c_std = std.Build.CStd.C99, .override_lib_dir = null, .main_pkg_path = null, .exec_cmd_args = null, @@ -461,7 +459,7 @@ pub fn installHeadersDirectory( pub fn installHeadersDirectoryOptions( a: *LibExeObjStep, - options: std.build.InstallDirStep.Options, + options: std.Build.InstallDirStep.Options, ) void { const install_dir = a.builder.addInstallDirectory(options); a.builder.getInstallStep().dependOn(&install_dir.step); @@ -600,7 +598,7 @@ pub fn linkLibCpp(self: *LibExeObjStep) void { /// If the value is omitted, it is set to 1. /// `name` and `value` need not live longer than the function call. pub fn defineCMacro(self: *LibExeObjStep, name: []const u8, value: ?[]const u8) void { - const macro = std.build.constructCMacro(self.builder.allocator, name, value); + const macro = std.Build.constructCMacro(self.builder.allocator, name, value); self.c_macros.append(macro) catch unreachable; } @@ -1460,7 +1458,7 @@ fn make(step: *Step) !void { if (!self.target.isNative()) { try zig_args.appendSlice(&.{ "-target", try self.target.zigTriple(builder.allocator), - "-mcpu", try build.serializeCpu(builder.allocator, self.target.getCpu()), + "-mcpu", try std.Build.serializeCpu(builder.allocator, self.target.getCpu()), }); if (self.target.dynamic_linker.get()) |dynamic_linker| { @@ -1902,7 +1900,7 @@ pub fn doAtomicSymLinks(allocator: Allocator, output_path: []const u8, filename_ }; } -fn execPkgConfigList(self: *Builder, out_code: *u8) (PkgConfigError || ExecError)![]const PkgConfigPkg { +fn execPkgConfigList(self: *std.Build, out_code: *u8) (PkgConfigError || ExecError)![]const PkgConfigPkg { const stdout = try self.execAllowFail(&[_][]const u8{ "pkg-config", "--list-all" }, out_code, .Ignore); var list = ArrayList(PkgConfigPkg).init(self.allocator); errdefer list.deinit(); @@ -1918,7 +1916,7 @@ fn execPkgConfigList(self: *Builder, out_code: *u8) (PkgConfigError || ExecError return list.toOwnedSlice(); } -fn getPkgConfigList(self: *Builder) ![]const PkgConfigPkg { +fn getPkgConfigList(self: *std.Build) ![]const PkgConfigPkg { if (self.pkg_config_pkg_list) |res| { return res; } @@ -1948,7 +1946,7 @@ test "addPackage" { var arena = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena.deinit(); - var builder = try Builder.create( + var builder = try std.Build.create( arena.allocator(), "test", "test", diff --git a/lib/std/build/LogStep.zig b/lib/std/Build/LogStep.zig similarity index 72% rename from lib/std/build/LogStep.zig rename to lib/std/Build/LogStep.zig index fd937b00f98573bc3737b2263fb75f4b476f7480..6d51df8cbd47bb122e0b6b18665dc7c3d2b09e8c 100644 --- a/lib/std/build/LogStep.zig +++ b/lib/std/Build/LogStep.zig @@ -1,17 +1,15 @@ const std = @import("../std.zig"); const log = std.log; -const build = @import("../build.zig"); -const Step = build.Step; -const Builder = build.Builder; +const Step = std.Build.Step; const LogStep = @This(); pub const base_id = .log; step: Step, -builder: *Builder, +builder: *std.Build, data: []const u8, -pub fn init(builder: *Builder, data: []const u8) LogStep { +pub fn init(builder: *std.Build, data: []const u8) LogStep { return LogStep{ .builder = builder, .step = Step.init(.log, builder.fmt("log {s}", .{data}), builder.allocator, make), diff --git a/lib/std/build/OptionsStep.zig b/lib/std/Build/OptionsStep.zig similarity index 97% rename from lib/std/build/OptionsStep.zig rename to lib/std/Build/OptionsStep.zig index fb06cc21793100db104ba2dd2b28f3dba6964b11..3d26807411e649f5a5767367379f738705e89ca3 100644 --- a/lib/std/build/OptionsStep.zig +++ b/lib/std/Build/OptionsStep.zig @@ -1,12 +1,10 @@ const std = @import("../std.zig"); const builtin = @import("builtin"); -const build = std.build; const fs = std.fs; -const Step = build.Step; -const Builder = build.Builder; -const GeneratedFile = build.GeneratedFile; -const LibExeObjStep = build.LibExeObjStep; -const FileSource = build.FileSource; +const Step = std.Build.Step; +const GeneratedFile = std.Build.GeneratedFile; +const LibExeObjStep = std.Build.LibExeObjStep; +const FileSource = std.Build.FileSource; const OptionsStep = @This(); @@ -14,13 +12,13 @@ pub const base_id = .options; step: Step, generated_file: GeneratedFile, -builder: *Builder, +builder: *std.Build, contents: std.ArrayList(u8), artifact_args: std.ArrayList(OptionArtifactArg), file_source_args: std.ArrayList(OptionFileSourceArg), -pub fn create(builder: *Builder) *OptionsStep { +pub fn create(builder: *std.Build) *OptionsStep { const self = builder.allocator.create(OptionsStep) catch unreachable; self.* = .{ .builder = builder, @@ -202,7 +200,7 @@ pub fn addOptionArtifact(self: *OptionsStep, name: []const u8, artifact: *LibExe self.step.dependOn(&artifact.step); } -pub fn getPackage(self: *OptionsStep, package_name: []const u8) build.Pkg { +pub fn getPackage(self: *OptionsStep, package_name: []const u8) std.Build.Pkg { return .{ .name = package_name, .source = self.getSource() }; } @@ -281,7 +279,7 @@ test "OptionsStep" { var arena = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena.deinit(); - var builder = try Builder.create( + var builder = try std.Build.create( arena.allocator(), "test", "test", diff --git a/lib/std/build/RemoveDirStep.zig b/lib/std/Build/RemoveDirStep.zig similarity index 79% rename from lib/std/build/RemoveDirStep.zig rename to lib/std/Build/RemoveDirStep.zig index 959414e54fe435129d3df46136a8c0566b9da303..f3b71dcec16877cf0cf01d570c71e789e404172e 100644 --- a/lib/std/build/RemoveDirStep.zig +++ b/lib/std/Build/RemoveDirStep.zig @@ -1,18 +1,16 @@ const std = @import("../std.zig"); const log = std.log; const fs = std.fs; -const build = @import("../build.zig"); -const Step = build.Step; -const Builder = build.Builder; +const Step = std.Build.Step; const RemoveDirStep = @This(); pub const base_id = .remove_dir; step: Step, -builder: *Builder, +builder: *std.Build, dir_path: []const u8, -pub fn init(builder: *Builder, dir_path: []const u8) RemoveDirStep { +pub fn init(builder: *std.Build, dir_path: []const u8) RemoveDirStep { return RemoveDirStep{ .builder = builder, .step = Step.init(.remove_dir, builder.fmt("RemoveDir {s}", .{dir_path}), builder.allocator, make), diff --git a/lib/std/build/RunStep.zig b/lib/std/Build/RunStep.zig similarity index 94% rename from lib/std/build/RunStep.zig rename to lib/std/Build/RunStep.zig index 5183a328cd9ddaa651c9c10bd8102b59adf5c8f6..83e4f7f66c706ba0f7de6297e2f0602c3b8dced8 100644 --- a/lib/std/build/RunStep.zig +++ b/lib/std/Build/RunStep.zig @@ -1,17 +1,15 @@ const std = @import("../std.zig"); const builtin = @import("builtin"); -const build = std.build; -const Step = build.Step; -const Builder = build.Builder; -const LibExeObjStep = build.LibExeObjStep; -const WriteFileStep = build.WriteFileStep; +const Step = std.Build.Step; +const LibExeObjStep = std.Build.LibExeObjStep; +const WriteFileStep = std.Build.WriteFileStep; const fs = std.fs; const mem = std.mem; const process = std.process; const ArrayList = std.ArrayList; const EnvMap = process.EnvMap; const Allocator = mem.Allocator; -const ExecError = build.Builder.ExecError; +const ExecError = std.Build.ExecError; const max_stdout_size = 1 * 1024 * 1024; // 1 MiB @@ -20,7 +18,7 @@ const RunStep = @This(); pub const base_id: Step.Id = .run; step: Step, -builder: *Builder, +builder: *std.Build, /// See also addArg and addArgs to modifying this directly argv: ArrayList(Arg), @@ -51,11 +49,11 @@ pub const StdIoAction = union(enum) { pub const Arg = union(enum) { artifact: *LibExeObjStep, - file_source: build.FileSource, + file_source: std.Build.FileSource, bytes: []u8, }; -pub fn create(builder: *Builder, name: []const u8) *RunStep { +pub fn create(builder: *std.Build, name: []const u8) *RunStep { const self = builder.allocator.create(RunStep) catch unreachable; self.* = RunStep{ .builder = builder, @@ -73,7 +71,7 @@ pub fn addArtifactArg(self: *RunStep, artifact: *LibExeObjStep) void { self.step.dependOn(&artifact.step); } -pub fn addFileSourceArg(self: *RunStep, file_source: build.FileSource) void { +pub fn addFileSourceArg(self: *RunStep, file_source: std.Build.FileSource) void { self.argv.append(Arg{ .file_source = file_source.dupe(self.builder), }) catch unreachable; @@ -101,7 +99,7 @@ pub fn addPathDir(self: *RunStep, search_path: []const u8) void { } /// For internal use only, users of `RunStep` should use `addPathDir` directly. -pub fn addPathDirInternal(step: *Step, builder: *Builder, search_path: []const u8) void { +pub fn addPathDirInternal(step: *Step, builder: *std.Build, search_path: []const u8) void { const env_map = getEnvMapInternal(step, builder.allocator); const key = "PATH"; @@ -122,7 +120,7 @@ pub fn getEnvMap(self: *RunStep) *EnvMap { fn getEnvMapInternal(step: *Step, allocator: Allocator) *EnvMap { const maybe_env_map = switch (step.id) { .run => step.cast(RunStep).?.env_map, - .emulatable_run => step.cast(build.EmulatableRunStep).?.env_map, + .emulatable_run => step.cast(std.Build.EmulatableRunStep).?.env_map, else => unreachable, }; return maybe_env_map orelse { @@ -195,7 +193,7 @@ fn make(step: *Step) !void { pub fn runCommand( argv: []const []const u8, - builder: *Builder, + builder: *std.Build, expected_exit_code: ?u8, stdout_action: StdIoAction, stderr_action: StdIoAction, @@ -363,7 +361,7 @@ fn addPathForDynLibs(self: *RunStep, artifact: *LibExeObjStep) void { /// This should only be used for internal usage, this is called automatically /// for the user. -pub fn addPathForDynLibsInternal(step: *Step, builder: *Builder, artifact: *LibExeObjStep) void { +pub fn addPathForDynLibsInternal(step: *Step, builder: *std.Build, artifact: *LibExeObjStep) void { for (artifact.link_objects.items) |link_object| { switch (link_object) { .other_step => |other| { diff --git a/lib/std/Build/Step.zig b/lib/std/Build/Step.zig new file mode 100644 index 0000000000000000000000000000000000000000..86d6645c293278999cedd34eaaecdf07a97cbcab --- /dev/null +++ b/lib/std/Build/Step.zig @@ -0,0 +1,97 @@ +id: Id, +name: []const u8, +makeFn: *const fn (self: *Step) anyerror!void, +dependencies: std.ArrayList(*Step), +loop_flag: bool, +done_flag: bool, + +pub const Id = enum { + top_level, + lib_exe_obj, + install_artifact, + install_file, + install_dir, + log, + remove_dir, + fmt, + translate_c, + write_file, + run, + emulatable_run, + check_file, + check_object, + config_header, + install_raw, + options, + custom, + + pub fn Type(comptime id: Id) type { + return switch (id) { + .top_level => Build.TopLevelStep, + .lib_exe_obj => Build.LibExeObjStep, + .install_artifact => Build.InstallArtifactStep, + .install_file => Build.InstallFileStep, + .install_dir => Build.InstallDirStep, + .log => Build.LogStep, + .remove_dir => Build.RemoveDirStep, + .fmt => Build.FmtStep, + .translate_c => Build.TranslateCStep, + .write_file => Build.WriteFileStep, + .run => Build.RunStep, + .emulatable_run => Build.EmulatableRunStep, + .check_file => Build.CheckFileStep, + .check_object => Build.CheckObjectStep, + .config_header => Build.ConfigHeaderStep, + .install_raw => Build.InstallRawStep, + .options => Build.OptionsStep, + .custom => @compileError("no type available for custom step"), + }; + } +}; + +pub fn init( + id: Id, + name: []const u8, + allocator: Allocator, + makeFn: *const fn (self: *Step) anyerror!void, +) Step { + return Step{ + .id = id, + .name = allocator.dupe(u8, name) catch unreachable, + .makeFn = makeFn, + .dependencies = std.ArrayList(*Step).init(allocator), + .loop_flag = false, + .done_flag = false, + }; +} + +pub fn initNoOp(id: Id, name: []const u8, allocator: Allocator) Step { + return init(id, name, allocator, makeNoOp); +} + +pub fn make(self: *Step) !void { + if (self.done_flag) return; + + try self.makeFn(self); + self.done_flag = true; +} + +pub fn dependOn(self: *Step, other: *Step) void { + self.dependencies.append(other) catch unreachable; +} + +fn makeNoOp(self: *Step) anyerror!void { + _ = self; +} + +pub fn cast(step: *Step, comptime T: type) ?*T { + if (step.id == T.base_id) { + return @fieldParentPtr(T, "step", step); + } + return null; +} + +const Step = @This(); +const std = @import("../std.zig"); +const Build = std.Build; +const Allocator = std.mem.Allocator; diff --git a/lib/std/build/TranslateCStep.zig b/lib/std/Build/TranslateCStep.zig similarity index 90% rename from lib/std/build/TranslateCStep.zig rename to lib/std/Build/TranslateCStep.zig index 9f45d606a19889ea1a0dc7c88fbf287f3cff7a82..5404747846c70f91f9f6da5f3782c16439029121 100644 --- a/lib/std/build/TranslateCStep.zig +++ b/lib/std/Build/TranslateCStep.zig @@ -1,9 +1,7 @@ const std = @import("../std.zig"); -const build = std.build; -const Step = build.Step; -const Builder = build.Builder; -const LibExeObjStep = build.LibExeObjStep; -const CheckFileStep = build.CheckFileStep; +const Step = std.Build.Step; +const LibExeObjStep = std.Build.LibExeObjStep; +const CheckFileStep = std.Build.CheckFileStep; const fs = std.fs; const mem = std.mem; const CrossTarget = std.zig.CrossTarget; @@ -13,23 +11,23 @@ const TranslateCStep = @This(); pub const base_id = .translate_c; step: Step, -builder: *Builder, -source: build.FileSource, +builder: *std.Build, +source: std.Build.FileSource, include_dirs: std.ArrayList([]const u8), c_macros: std.ArrayList([]const u8), output_dir: ?[]const u8, out_basename: []const u8, target: CrossTarget, optimize: std.builtin.OptimizeMode, -output_file: build.GeneratedFile, +output_file: std.Build.GeneratedFile, pub const Options = struct { - source_file: build.FileSource, + source_file: std.Build.FileSource, target: CrossTarget, optimize: std.builtin.OptimizeMode, }; -pub fn create(builder: *Builder, options: Options) *TranslateCStep { +pub fn create(builder: *std.Build, options: Options) *TranslateCStep { const self = builder.allocator.create(TranslateCStep) catch unreachable; const source = options.source_file.dupe(builder); self.* = TranslateCStep{ @@ -42,7 +40,7 @@ pub fn create(builder: *Builder, options: Options) *TranslateCStep { .out_basename = undefined, .target = options.target, .optimize = options.optimize, - .output_file = build.GeneratedFile{ .step = &self.step }, + .output_file = std.Build.GeneratedFile{ .step = &self.step }, }; source.addStepDependencies(&self.step); return self; @@ -79,7 +77,7 @@ pub fn addCheckFile(self: *TranslateCStep, expected_matches: []const []const u8) /// If the value is omitted, it is set to 1. /// `name` and `value` need not live longer than the function call. pub fn defineCMacro(self: *TranslateCStep, name: []const u8, value: ?[]const u8) void { - const macro = build.constructCMacro(self.builder.allocator, name, value); + const macro = std.Build.constructCMacro(self.builder.allocator, name, value); self.c_macros.append(macro) catch unreachable; } diff --git a/lib/std/build/WriteFileStep.zig b/lib/std/Build/WriteFileStep.zig similarity index 91% rename from lib/std/build/WriteFileStep.zig rename to lib/std/Build/WriteFileStep.zig index 4faae8f74ebb4c8410b88b7e46a88d6d9d9bb845..59ac568221f52e0c36485fc1f8cec7dcb3993471 100644 --- a/lib/std/build/WriteFileStep.zig +++ b/lib/std/Build/WriteFileStep.zig @@ -1,7 +1,5 @@ const std = @import("../std.zig"); -const build = @import("../build.zig"); -const Step = build.Step; -const Builder = build.Builder; +const Step = std.Build.Step; const fs = std.fs; const ArrayList = std.ArrayList; @@ -10,17 +8,17 @@ const WriteFileStep = @This(); pub const base_id = .write_file; step: Step, -builder: *Builder, +builder: *std.Build, output_dir: []const u8, files: std.TailQueue(File), pub const File = struct { - source: build.GeneratedFile, + source: std.Build.GeneratedFile, basename: []const u8, bytes: []const u8, }; -pub fn init(builder: *Builder) WriteFileStep { +pub fn init(builder: *std.Build) WriteFileStep { return WriteFileStep{ .builder = builder, .step = Step.init(.write_file, "writefile", builder.allocator, make), @@ -33,7 +31,7 @@ pub fn add(self: *WriteFileStep, basename: []const u8, bytes: []const u8) void { const node = self.builder.allocator.create(std.TailQueue(File).Node) catch unreachable; node.* = .{ .data = .{ - .source = build.GeneratedFile{ .step = &self.step }, + .source = std.Build.GeneratedFile{ .step = &self.step }, .basename = self.builder.dupePath(basename), .bytes = self.builder.dupe(bytes), }, @@ -43,11 +41,11 @@ pub fn add(self: *WriteFileStep, basename: []const u8, bytes: []const u8) void { } /// Gets a file source for the given basename. If the file does not exist, returns `null`. -pub fn getFileSource(step: *WriteFileStep, basename: []const u8) ?build.FileSource { +pub fn getFileSource(step: *WriteFileStep, basename: []const u8) ?std.Build.FileSource { var it = step.files.first; while (it) |node| : (it = node.next) { if (std.mem.eql(u8, node.data.basename, basename)) - return build.FileSource{ .generated = &node.data.source }; + return std.Build.FileSource{ .generated = &node.data.source }; } return null; } diff --git a/lib/std/build.zig b/lib/std/build.zig deleted file mode 100644 index 4ee00a47107857e9f75fea4b85e69dc93ccfdf94..0000000000000000000000000000000000000000 --- a/lib/std/build.zig +++ /dev/null @@ -1,1863 +0,0 @@ -const std = @import("std.zig"); -const builtin = @import("builtin"); -const io = std.io; -const fs = std.fs; -const mem = std.mem; -const debug = std.debug; -const panic = std.debug.panic; -const assert = debug.assert; -const log = std.log; -const ArrayList = std.ArrayList; -const StringHashMap = std.StringHashMap; -const Allocator = mem.Allocator; -const process = std.process; -const EnvMap = std.process.EnvMap; -const fmt_lib = std.fmt; -const File = std.fs.File; -const CrossTarget = std.zig.CrossTarget; -const NativeTargetInfo = std.zig.system.NativeTargetInfo; -const Sha256 = std.crypto.hash.sha2.Sha256; -const ThisModule = @This(); - -pub const CheckFileStep = @import("build/CheckFileStep.zig"); -pub const CheckObjectStep = @import("build/CheckObjectStep.zig"); -pub const ConfigHeaderStep = @import("build/ConfigHeaderStep.zig"); -pub const EmulatableRunStep = @import("build/EmulatableRunStep.zig"); -pub const FmtStep = @import("build/FmtStep.zig"); -pub const InstallArtifactStep = @import("build/InstallArtifactStep.zig"); -pub const InstallDirStep = @import("build/InstallDirStep.zig"); -pub const InstallFileStep = @import("build/InstallFileStep.zig"); -pub const InstallRawStep = @import("build/InstallRawStep.zig"); -pub const LibExeObjStep = @import("build/LibExeObjStep.zig"); -pub const LogStep = @import("build/LogStep.zig"); -pub const OptionsStep = @import("build/OptionsStep.zig"); -pub const RemoveDirStep = @import("build/RemoveDirStep.zig"); -pub const RunStep = @import("build/RunStep.zig"); -pub const TranslateCStep = @import("build/TranslateCStep.zig"); -pub const WriteFileStep = @import("build/WriteFileStep.zig"); - -pub const Builder = struct { - install_tls: TopLevelStep, - uninstall_tls: TopLevelStep, - allocator: Allocator, - user_input_options: UserInputOptionsMap, - available_options_map: AvailableOptionsMap, - available_options_list: ArrayList(AvailableOption), - verbose: bool, - verbose_link: bool, - verbose_cc: bool, - verbose_air: bool, - verbose_llvm_ir: bool, - verbose_cimport: bool, - verbose_llvm_cpu_features: bool, - /// The purpose of executing the command is for a human to read compile errors from the terminal - prominent_compile_errors: bool, - color: enum { auto, on, off } = .auto, - reference_trace: ?u32 = null, - invalid_user_input: bool, - zig_exe: []const u8, - default_step: *Step, - env_map: *EnvMap, - top_level_steps: ArrayList(*TopLevelStep), - install_prefix: []const u8, - dest_dir: ?[]const u8, - lib_dir: []const u8, - exe_dir: []const u8, - h_dir: []const u8, - install_path: []const u8, - sysroot: ?[]const u8 = null, - search_prefixes: ArrayList([]const u8), - libc_file: ?[]const u8 = null, - installed_files: ArrayList(InstalledFile), - /// Path to the directory containing build.zig. - build_root: []const u8, - cache_root: []const u8, - global_cache_root: []const u8, - /// zig lib dir - override_lib_dir: ?[]const u8, - vcpkg_root: VcpkgRoot = .unattempted, - pkg_config_pkg_list: ?(PkgConfigError![]const PkgConfigPkg) = null, - args: ?[][]const u8 = null, - debug_log_scopes: []const []const u8 = &.{}, - debug_compile_errors: bool = false, - - /// Experimental. Use system Darling installation to run cross compiled macOS build artifacts. - enable_darling: bool = false, - /// Use system QEMU installation to run cross compiled foreign architecture build artifacts. - enable_qemu: bool = false, - /// Darwin. Use Rosetta to run x86_64 macOS build artifacts on arm64 macOS. - enable_rosetta: bool = false, - /// Use system Wasmtime installation to run cross compiled wasm/wasi build artifacts. - enable_wasmtime: bool = false, - /// Use system Wine installation to run cross compiled Windows build artifacts. - enable_wine: bool = false, - /// After following the steps in https://github.com/ziglang/zig/wiki/Updating-libc#glibc, - /// this will be the directory $glibc-build-dir/install/glibcs - /// Given the example of the aarch64 target, this is the directory - /// that contains the path `aarch64-linux-gnu/lib/ld-linux-aarch64.so.1`. - glibc_runtimes_dir: ?[]const u8 = null, - - /// Information about the native target. Computed before build() is invoked. - host: NativeTargetInfo, - - dep_prefix: []const u8 = "", - - pub const ExecError = error{ - ReadFailure, - ExitCodeFailure, - ProcessTerminated, - ExecNotSupported, - } || std.ChildProcess.SpawnError; - - pub const PkgConfigError = error{ - PkgConfigCrashed, - PkgConfigFailed, - PkgConfigNotInstalled, - PkgConfigInvalidOutput, - }; - - pub const PkgConfigPkg = struct { - name: []const u8, - desc: []const u8, - }; - - pub const CStd = enum { - C89, - C99, - C11, - }; - - const UserInputOptionsMap = StringHashMap(UserInputOption); - const AvailableOptionsMap = StringHashMap(AvailableOption); - - const AvailableOption = struct { - name: []const u8, - type_id: TypeId, - description: []const u8, - /// If the `type_id` is `enum` this provides the list of enum options - enum_options: ?[]const []const u8, - }; - - const UserInputOption = struct { - name: []const u8, - value: UserValue, - used: bool, - }; - - const UserValue = union(enum) { - flag: void, - scalar: []const u8, - list: ArrayList([]const u8), - map: StringHashMap(*const UserValue), - }; - - const TypeId = enum { - bool, - int, - float, - @"enum", - string, - list, - }; - - const TopLevelStep = struct { - pub const base_id = .top_level; - - step: Step, - description: []const u8, - }; - - pub const DirList = struct { - lib_dir: ?[]const u8 = null, - exe_dir: ?[]const u8 = null, - include_dir: ?[]const u8 = null, - }; - - pub fn create( - allocator: Allocator, - zig_exe: []const u8, - build_root: []const u8, - cache_root: []const u8, - global_cache_root: []const u8, - ) !*Builder { - const env_map = try allocator.create(EnvMap); - env_map.* = try process.getEnvMap(allocator); - - const host = try NativeTargetInfo.detect(.{}); - - const self = try allocator.create(Builder); - self.* = Builder{ - .zig_exe = zig_exe, - .build_root = build_root, - .cache_root = try fs.path.relative(allocator, build_root, cache_root), - .global_cache_root = global_cache_root, - .verbose = false, - .verbose_link = false, - .verbose_cc = false, - .verbose_air = false, - .verbose_llvm_ir = false, - .verbose_cimport = false, - .verbose_llvm_cpu_features = false, - .prominent_compile_errors = false, - .invalid_user_input = false, - .allocator = allocator, - .user_input_options = UserInputOptionsMap.init(allocator), - .available_options_map = AvailableOptionsMap.init(allocator), - .available_options_list = ArrayList(AvailableOption).init(allocator), - .top_level_steps = ArrayList(*TopLevelStep).init(allocator), - .default_step = undefined, - .env_map = env_map, - .search_prefixes = ArrayList([]const u8).init(allocator), - .install_prefix = undefined, - .lib_dir = undefined, - .exe_dir = undefined, - .h_dir = undefined, - .dest_dir = env_map.get("DESTDIR"), - .installed_files = ArrayList(InstalledFile).init(allocator), - .install_tls = TopLevelStep{ - .step = Step.initNoOp(.top_level, "install", allocator), - .description = "Copy build artifacts to prefix path", - }, - .uninstall_tls = TopLevelStep{ - .step = Step.init(.top_level, "uninstall", allocator, makeUninstall), - .description = "Remove build artifacts from prefix path", - }, - .override_lib_dir = null, - .install_path = undefined, - .args = null, - .host = host, - }; - try self.top_level_steps.append(&self.install_tls); - try self.top_level_steps.append(&self.uninstall_tls); - self.default_step = &self.install_tls.step; - return self; - } - - fn createChild( - parent: *Builder, - dep_name: []const u8, - build_root: []const u8, - args: anytype, - ) !*Builder { - const child = try createChildOnly(parent, dep_name, build_root); - try applyArgs(child, args); - return child; - } - - fn createChildOnly(parent: *Builder, dep_name: []const u8, build_root: []const u8) !*Builder { - const allocator = parent.allocator; - const child = try allocator.create(Builder); - child.* = .{ - .allocator = allocator, - .install_tls = .{ - .step = Step.initNoOp(.top_level, "install", allocator), - .description = "Copy build artifacts to prefix path", - }, - .uninstall_tls = .{ - .step = Step.init(.top_level, "uninstall", allocator, makeUninstall), - .description = "Remove build artifacts from prefix path", - }, - .user_input_options = UserInputOptionsMap.init(allocator), - .available_options_map = AvailableOptionsMap.init(allocator), - .available_options_list = ArrayList(AvailableOption).init(allocator), - .verbose = parent.verbose, - .verbose_link = parent.verbose_link, - .verbose_cc = parent.verbose_cc, - .verbose_air = parent.verbose_air, - .verbose_llvm_ir = parent.verbose_llvm_ir, - .verbose_cimport = parent.verbose_cimport, - .verbose_llvm_cpu_features = parent.verbose_llvm_cpu_features, - .prominent_compile_errors = parent.prominent_compile_errors, - .color = parent.color, - .reference_trace = parent.reference_trace, - .invalid_user_input = false, - .zig_exe = parent.zig_exe, - .default_step = undefined, - .env_map = parent.env_map, - .top_level_steps = ArrayList(*TopLevelStep).init(allocator), - .install_prefix = undefined, - .dest_dir = parent.dest_dir, - .lib_dir = parent.lib_dir, - .exe_dir = parent.exe_dir, - .h_dir = parent.h_dir, - .install_path = parent.install_path, - .sysroot = parent.sysroot, - .search_prefixes = ArrayList([]const u8).init(allocator), - .libc_file = parent.libc_file, - .installed_files = ArrayList(InstalledFile).init(allocator), - .build_root = build_root, - .cache_root = parent.cache_root, - .global_cache_root = parent.global_cache_root, - .override_lib_dir = parent.override_lib_dir, - .debug_log_scopes = parent.debug_log_scopes, - .debug_compile_errors = parent.debug_compile_errors, - .enable_darling = parent.enable_darling, - .enable_qemu = parent.enable_qemu, - .enable_rosetta = parent.enable_rosetta, - .enable_wasmtime = parent.enable_wasmtime, - .enable_wine = parent.enable_wine, - .glibc_runtimes_dir = parent.glibc_runtimes_dir, - .host = parent.host, - .dep_prefix = parent.fmt("{s}{s}.", .{ parent.dep_prefix, dep_name }), - }; - try child.top_level_steps.append(&child.install_tls); - try child.top_level_steps.append(&child.uninstall_tls); - child.default_step = &child.install_tls.step; - return child; - } - - fn applyArgs(b: *Builder, args: anytype) !void { - inline for (@typeInfo(@TypeOf(args)).Struct.fields) |field| { - const v = @field(args, field.name); - const T = @TypeOf(v); - switch (T) { - CrossTarget => { - try b.user_input_options.put(field.name, .{ - .name = field.name, - .value = .{ .scalar = try v.zigTriple(b.allocator) }, - .used = false, - }); - try b.user_input_options.put("cpu", .{ - .name = "cpu", - .value = .{ .scalar = try serializeCpu(b.allocator, v.getCpu()) }, - .used = false, - }); - }, - []const u8 => { - try b.user_input_options.put(field.name, .{ - .name = field.name, - .value = .{ .scalar = v }, - .used = false, - }); - }, - else => switch (@typeInfo(T)) { - .Bool => { - try b.user_input_options.put(field.name, .{ - .name = field.name, - .value = .{ .scalar = if (v) "true" else "false" }, - .used = false, - }); - }, - .Enum => { - try b.user_input_options.put(field.name, .{ - .name = field.name, - .value = .{ .scalar = @tagName(v) }, - .used = false, - }); - }, - .Int => { - try b.user_input_options.put(field.name, .{ - .name = field.name, - .value = .{ .scalar = try std.fmt.allocPrint(b.allocator, "{d}", .{v}) }, - .used = false, - }); - }, - else => @compileError("option '" ++ field.name ++ "' has unsupported type: " ++ @typeName(T)), - }, - } - } - const Hasher = std.crypto.auth.siphash.SipHash128(1, 3); - // Random bytes to make unique. Refresh this with new random bytes when - // implementation is modified in a non-backwards-compatible way. - var hash = Hasher.init("ZaEsvQ5ClaA2IdH9"); - hash.update(b.dep_prefix); - // TODO additionally update the hash with `args`. - - var digest: [16]u8 = undefined; - hash.final(&digest); - var hash_basename: [digest.len * 2]u8 = undefined; - _ = std.fmt.bufPrint(&hash_basename, "{s}", .{std.fmt.fmtSliceHexLower(&digest)}) catch - unreachable; - - const install_prefix = b.pathJoin(&.{ b.cache_root, "i", &hash_basename }); - b.resolveInstallPrefix(install_prefix, .{}); - } - - pub fn destroy(self: *Builder) void { - self.env_map.deinit(); - self.top_level_steps.deinit(); - self.allocator.destroy(self); - } - - /// This function is intended to be called by lib/build_runner.zig, not a build.zig file. - pub fn resolveInstallPrefix(self: *Builder, install_prefix: ?[]const u8, dir_list: DirList) void { - if (self.dest_dir) |dest_dir| { - self.install_prefix = install_prefix orelse "/usr"; - self.install_path = self.pathJoin(&.{ dest_dir, self.install_prefix }); - } else { - self.install_prefix = install_prefix orelse - (self.pathJoin(&.{ self.build_root, "zig-out" })); - self.install_path = self.install_prefix; - } - - var lib_list = [_][]const u8{ self.install_path, "lib" }; - var exe_list = [_][]const u8{ self.install_path, "bin" }; - var h_list = [_][]const u8{ self.install_path, "include" }; - - if (dir_list.lib_dir) |dir| { - if (std.fs.path.isAbsolute(dir)) lib_list[0] = self.dest_dir orelse ""; - lib_list[1] = dir; - } - - if (dir_list.exe_dir) |dir| { - if (std.fs.path.isAbsolute(dir)) exe_list[0] = self.dest_dir orelse ""; - exe_list[1] = dir; - } - - if (dir_list.include_dir) |dir| { - if (std.fs.path.isAbsolute(dir)) h_list[0] = self.dest_dir orelse ""; - h_list[1] = dir; - } - - self.lib_dir = self.pathJoin(&lib_list); - self.exe_dir = self.pathJoin(&exe_list); - self.h_dir = self.pathJoin(&h_list); - } - - pub fn addOptions(self: *Builder) *OptionsStep { - return OptionsStep.create(self); - } - - pub const ExecutableOptions = struct { - name: []const u8, - root_source_file: ?FileSource = null, - version: ?std.builtin.Version = null, - target: CrossTarget = .{}, - optimize: std.builtin.Mode = .Debug, - linkage: ?LibExeObjStep.Linkage = null, - }; - - pub fn addExecutable(b: *Builder, options: ExecutableOptions) *LibExeObjStep { - return LibExeObjStep.create(b, .{ - .name = options.name, - .root_source_file = options.root_source_file, - .version = options.version, - .target = options.target, - .optimize = options.optimize, - .kind = .exe, - .linkage = options.linkage, - }); - } - - pub const ObjectOptions = struct { - name: []const u8, - root_source_file: ?FileSource = null, - target: CrossTarget, - optimize: std.builtin.Mode, - }; - - pub fn addObject(b: *Builder, options: ObjectOptions) *LibExeObjStep { - return LibExeObjStep.create(b, .{ - .name = options.name, - .root_source_file = options.root_source_file, - .target = options.target, - .optimize = options.optimize, - .kind = .obj, - }); - } - - pub const SharedLibraryOptions = struct { - name: []const u8, - root_source_file: ?FileSource = null, - version: ?std.builtin.Version = null, - target: CrossTarget, - optimize: std.builtin.Mode, - }; - - pub fn addSharedLibrary(b: *Builder, options: SharedLibraryOptions) *LibExeObjStep { - return LibExeObjStep.create(b, .{ - .name = options.name, - .root_source_file = options.root_source_file, - .kind = .lib, - .linkage = .dynamic, - .version = options.version, - .target = options.target, - .optimize = options.optimize, - }); - } - - pub const StaticLibraryOptions = struct { - name: []const u8, - root_source_file: ?FileSource = null, - target: CrossTarget, - optimize: std.builtin.Mode, - version: ?std.builtin.Version = null, - }; - - pub fn addStaticLibrary(b: *Builder, options: StaticLibraryOptions) *LibExeObjStep { - return LibExeObjStep.create(b, .{ - .name = options.name, - .root_source_file = options.root_source_file, - .kind = .lib, - .linkage = .static, - .version = options.version, - .target = options.target, - .optimize = options.optimize, - }); - } - - pub const TestOptions = struct { - name: []const u8 = "test", - kind: LibExeObjStep.Kind = .@"test", - root_source_file: FileSource, - target: CrossTarget = .{}, - optimize: std.builtin.Mode = .Debug, - version: ?std.builtin.Version = null, - }; - - pub fn addTest(b: *Builder, options: TestOptions) *LibExeObjStep { - return LibExeObjStep.create(b, .{ - .name = options.name, - .kind = options.kind, - .root_source_file = options.root_source_file, - .target = options.target, - .optimize = options.optimize, - }); - } - - pub const AssemblyOptions = struct { - name: []const u8, - source_file: FileSource, - target: CrossTarget, - optimize: std.builtin.Mode, - }; - - pub fn addAssembly(b: *Builder, options: AssemblyOptions) *LibExeObjStep { - const obj_step = LibExeObjStep.create(b, .{ - .name = options.name, - .root_source_file = null, - .target = options.target, - .optimize = options.optimize, - }); - obj_step.addAssemblyFileSource(options.source_file.dupe(b)); - return obj_step; - } - - /// Initializes a RunStep with argv, which must at least have the path to the - /// executable. More command line arguments can be added with `addArg`, - /// `addArgs`, and `addArtifactArg`. - /// Be careful using this function, as it introduces a system dependency. - /// To run an executable built with zig build, see `LibExeObjStep.run`. - pub fn addSystemCommand(self: *Builder, argv: []const []const u8) *RunStep { - assert(argv.len >= 1); - const run_step = RunStep.create(self, self.fmt("run {s}", .{argv[0]})); - run_step.addArgs(argv); - return run_step; - } - - pub fn addConfigHeader( - b: *Builder, - source: FileSource, - style: ConfigHeaderStep.Style, - values: anytype, - ) *ConfigHeaderStep { - const config_header_step = ConfigHeaderStep.create(b, source, style); - config_header_step.addValues(values); - return config_header_step; - } - - /// Allocator.dupe without the need to handle out of memory. - pub fn dupe(self: *Builder, bytes: []const u8) []u8 { - return self.allocator.dupe(u8, bytes) catch unreachable; - } - - /// Duplicates an array of strings without the need to handle out of memory. - pub fn dupeStrings(self: *Builder, strings: []const []const u8) [][]u8 { - const array = self.allocator.alloc([]u8, strings.len) catch unreachable; - for (strings) |s, i| { - array[i] = self.dupe(s); - } - return array; - } - - /// Duplicates a path and converts all slashes to the OS's canonical path separator. - pub fn dupePath(self: *Builder, bytes: []const u8) []u8 { - const the_copy = self.dupe(bytes); - for (the_copy) |*byte| { - switch (byte.*) { - '/', '\\' => byte.* = fs.path.sep, - else => {}, - } - } - return the_copy; - } - - /// Duplicates a package recursively. - pub fn dupePkg(self: *Builder, package: Pkg) Pkg { - var the_copy = Pkg{ - .name = self.dupe(package.name), - .source = package.source.dupe(self), - }; - - if (package.dependencies) |dependencies| { - const new_dependencies = self.allocator.alloc(Pkg, dependencies.len) catch unreachable; - the_copy.dependencies = new_dependencies; - - for (dependencies) |dep_package, i| { - new_dependencies[i] = self.dupePkg(dep_package); - } - } - return the_copy; - } - - pub fn addWriteFile(self: *Builder, file_path: []const u8, data: []const u8) *WriteFileStep { - const write_file_step = self.addWriteFiles(); - write_file_step.add(file_path, data); - return write_file_step; - } - - pub fn addWriteFiles(self: *Builder) *WriteFileStep { - const write_file_step = self.allocator.create(WriteFileStep) catch unreachable; - write_file_step.* = WriteFileStep.init(self); - return write_file_step; - } - - pub fn addLog(self: *Builder, comptime format: []const u8, args: anytype) *LogStep { - const data = self.fmt(format, args); - const log_step = self.allocator.create(LogStep) catch unreachable; - log_step.* = LogStep.init(self, data); - return log_step; - } - - pub fn addRemoveDirTree(self: *Builder, dir_path: []const u8) *RemoveDirStep { - const remove_dir_step = self.allocator.create(RemoveDirStep) catch unreachable; - remove_dir_step.* = RemoveDirStep.init(self, dir_path); - return remove_dir_step; - } - - pub fn addFmt(self: *Builder, paths: []const []const u8) *FmtStep { - return FmtStep.create(self, paths); - } - - pub fn addTranslateC(self: *Builder, options: TranslateCStep.Options) *TranslateCStep { - return TranslateCStep.create(self, options); - } - - pub fn make(self: *Builder, step_names: []const []const u8) !void { - try self.makePath(self.cache_root); - - var wanted_steps = ArrayList(*Step).init(self.allocator); - defer wanted_steps.deinit(); - - if (step_names.len == 0) { - try wanted_steps.append(self.default_step); - } else { - for (step_names) |step_name| { - const s = try self.getTopLevelStepByName(step_name); - try wanted_steps.append(s); - } - } - - for (wanted_steps.items) |s| { - try self.makeOneStep(s); - } - } - - pub fn getInstallStep(self: *Builder) *Step { - return &self.install_tls.step; - } - - pub fn getUninstallStep(self: *Builder) *Step { - return &self.uninstall_tls.step; - } - - fn makeUninstall(uninstall_step: *Step) anyerror!void { - const uninstall_tls = @fieldParentPtr(TopLevelStep, "step", uninstall_step); - const self = @fieldParentPtr(Builder, "uninstall_tls", uninstall_tls); - - for (self.installed_files.items) |installed_file| { - const full_path = self.getInstallPath(installed_file.dir, installed_file.path); - if (self.verbose) { - log.info("rm {s}", .{full_path}); - } - fs.cwd().deleteTree(full_path) catch {}; - } - - // TODO remove empty directories - } - - fn makeOneStep(self: *Builder, s: *Step) anyerror!void { - if (s.loop_flag) { - log.err("Dependency loop detected:\n {s}", .{s.name}); - return error.DependencyLoopDetected; - } - s.loop_flag = true; - - for (s.dependencies.items) |dep| { - self.makeOneStep(dep) catch |err| { - if (err == error.DependencyLoopDetected) { - log.err(" {s}", .{s.name}); - } - return err; - }; - } - - s.loop_flag = false; - - try s.make(); - } - - fn getTopLevelStepByName(self: *Builder, name: []const u8) !*Step { - for (self.top_level_steps.items) |top_level_step| { - if (mem.eql(u8, top_level_step.step.name, name)) { - return &top_level_step.step; - } - } - log.err("Cannot run step '{s}' because it does not exist", .{name}); - return error.InvalidStepName; - } - - pub fn option(self: *Builder, comptime T: type, name_raw: []const u8, description_raw: []const u8) ?T { - const name = self.dupe(name_raw); - const description = self.dupe(description_raw); - const type_id = comptime typeToEnum(T); - const enum_options = if (type_id == .@"enum") blk: { - const fields = comptime std.meta.fields(T); - var options = ArrayList([]const u8).initCapacity(self.allocator, fields.len) catch unreachable; - - inline for (fields) |field| { - options.appendAssumeCapacity(field.name); - } - - break :blk options.toOwnedSlice() catch unreachable; - } else null; - const available_option = AvailableOption{ - .name = name, - .type_id = type_id, - .description = description, - .enum_options = enum_options, - }; - if ((self.available_options_map.fetchPut(name, available_option) catch unreachable) != null) { - panic("Option '{s}' declared twice", .{name}); - } - self.available_options_list.append(available_option) catch unreachable; - - const option_ptr = self.user_input_options.getPtr(name) orelse return null; - option_ptr.used = true; - switch (type_id) { - .bool => switch (option_ptr.value) { - .flag => return true, - .scalar => |s| { - if (mem.eql(u8, s, "true")) { - return true; - } else if (mem.eql(u8, s, "false")) { - return false; - } else { - log.err("Expected -D{s} to be a boolean, but received '{s}'\n", .{ name, s }); - self.markInvalidUserInput(); - return null; - } - }, - .list, .map => { - log.err("Expected -D{s} to be a boolean, but received a {s}.\n", .{ - name, @tagName(option_ptr.value), - }); - self.markInvalidUserInput(); - return null; - }, - }, - .int => switch (option_ptr.value) { - .flag, .list, .map => { - log.err("Expected -D{s} to be an integer, but received a {s}.\n", .{ - name, @tagName(option_ptr.value), - }); - self.markInvalidUserInput(); - return null; - }, - .scalar => |s| { - const n = std.fmt.parseInt(T, s, 10) catch |err| switch (err) { - error.Overflow => { - log.err("-D{s} value {s} cannot fit into type {s}.\n", .{ name, s, @typeName(T) }); - self.markInvalidUserInput(); - return null; - }, - else => { - log.err("Expected -D{s} to be an integer of type {s}.\n", .{ name, @typeName(T) }); - self.markInvalidUserInput(); - return null; - }, - }; - return n; - }, - }, - .float => switch (option_ptr.value) { - .flag, .map, .list => { - log.err("Expected -D{s} to be a float, but received a {s}.\n", .{ - name, @tagName(option_ptr.value), - }); - self.markInvalidUserInput(); - return null; - }, - .scalar => |s| { - const n = std.fmt.parseFloat(T, s) catch { - log.err("Expected -D{s} to be a float of type {s}.\n", .{ name, @typeName(T) }); - self.markInvalidUserInput(); - return null; - }; - return n; - }, - }, - .@"enum" => switch (option_ptr.value) { - .flag, .map, .list => { - log.err("Expected -D{s} to be an enum, but received a {s}.\n", .{ - name, @tagName(option_ptr.value), - }); - self.markInvalidUserInput(); - return null; - }, - .scalar => |s| { - if (std.meta.stringToEnum(T, s)) |enum_lit| { - return enum_lit; - } else { - log.err("Expected -D{s} to be of type {s}.\n", .{ name, @typeName(T) }); - self.markInvalidUserInput(); - return null; - } - }, - }, - .string => switch (option_ptr.value) { - .flag, .list, .map => { - log.err("Expected -D{s} to be a string, but received a {s}.\n", .{ - name, @tagName(option_ptr.value), - }); - self.markInvalidUserInput(); - return null; - }, - .scalar => |s| return s, - }, - .list => switch (option_ptr.value) { - .flag, .map => { - log.err("Expected -D{s} to be a list, but received a {s}.\n", .{ - name, @tagName(option_ptr.value), - }); - self.markInvalidUserInput(); - return null; - }, - .scalar => |s| { - return self.allocator.dupe([]const u8, &[_][]const u8{s}) catch unreachable; - }, - .list => |lst| return lst.items, - }, - } - } - - pub fn step(self: *Builder, name: []const u8, description: []const u8) *Step { - const step_info = self.allocator.create(TopLevelStep) catch unreachable; - step_info.* = TopLevelStep{ - .step = Step.initNoOp(.top_level, name, self.allocator), - .description = self.dupe(description), - }; - self.top_level_steps.append(step_info) catch unreachable; - return &step_info.step; - } - - pub const StandardOptimizeOptionOptions = struct { - preferred_optimize_mode: ?std.builtin.Mode = null, - }; - - pub fn standardOptimizeOption(self: *Builder, options: StandardOptimizeOptionOptions) std.builtin.Mode { - if (options.preferred_optimize_mode) |mode| { - if (self.option(bool, "release", "optimize for end users") orelse false) { - return mode; - } else { - return .Debug; - } - } else { - return self.option( - std.builtin.Mode, - "optimize", - "prioritize performance, safety, or binary size (-O flag)", - ) orelse .Debug; - } - } - - pub const StandardTargetOptionsArgs = struct { - whitelist: ?[]const CrossTarget = null, - - default_target: CrossTarget = CrossTarget{}, - }; - - /// Exposes standard `zig build` options for choosing a target. - pub fn standardTargetOptions(self: *Builder, args: StandardTargetOptionsArgs) CrossTarget { - const maybe_triple = self.option( - []const u8, - "target", - "The CPU architecture, OS, and ABI to build for", - ); - const mcpu = self.option([]const u8, "cpu", "Target CPU features to add or subtract"); - - if (maybe_triple == null and mcpu == null) { - return args.default_target; - } - - const triple = maybe_triple orelse "native"; - - var diags: CrossTarget.ParseOptions.Diagnostics = .{}; - const selected_target = CrossTarget.parse(.{ - .arch_os_abi = triple, - .cpu_features = mcpu, - .diagnostics = &diags, - }) catch |err| switch (err) { - error.UnknownCpuModel => { - log.err("Unknown CPU: '{s}'\nAvailable CPUs for architecture '{s}':", .{ - diags.cpu_name.?, - @tagName(diags.arch.?), - }); - for (diags.arch.?.allCpuModels()) |cpu| { - log.err(" {s}", .{cpu.name}); - } - self.markInvalidUserInput(); - return args.default_target; - }, - error.UnknownCpuFeature => { - log.err( - \\Unknown CPU feature: '{s}' - \\Available CPU features for architecture '{s}': - \\ - , .{ - diags.unknown_feature_name.?, - @tagName(diags.arch.?), - }); - for (diags.arch.?.allFeaturesList()) |feature| { - log.err(" {s}: {s}", .{ feature.name, feature.description }); - } - self.markInvalidUserInput(); - return args.default_target; - }, - error.UnknownOperatingSystem => { - log.err( - \\Unknown OS: '{s}' - \\Available operating systems: - \\ - , .{diags.os_name.?}); - inline for (std.meta.fields(std.Target.Os.Tag)) |field| { - log.err(" {s}", .{field.name}); - } - self.markInvalidUserInput(); - return args.default_target; - }, - else => |e| { - log.err("Unable to parse target '{s}': {s}\n", .{ triple, @errorName(e) }); - self.markInvalidUserInput(); - return args.default_target; - }, - }; - - const selected_canonicalized_triple = selected_target.zigTriple(self.allocator) catch unreachable; - - if (args.whitelist) |list| whitelist_check: { - // Make sure it's a match of one of the list. - var mismatch_triple = true; - var mismatch_cpu_features = true; - var whitelist_item = CrossTarget{}; - for (list) |t| { - mismatch_cpu_features = true; - mismatch_triple = true; - - const t_triple = t.zigTriple(self.allocator) catch unreachable; - if (mem.eql(u8, t_triple, selected_canonicalized_triple)) { - mismatch_triple = false; - whitelist_item = t; - if (t.getCpuFeatures().isSuperSetOf(selected_target.getCpuFeatures())) { - mismatch_cpu_features = false; - break :whitelist_check; - } else { - break; - } - } - } - if (mismatch_triple) { - log.err("Chosen target '{s}' does not match one of the supported targets:", .{ - selected_canonicalized_triple, - }); - for (list) |t| { - const t_triple = t.zigTriple(self.allocator) catch unreachable; - log.err(" {s}", .{t_triple}); - } - } else { - assert(mismatch_cpu_features); - const whitelist_cpu = whitelist_item.getCpu(); - const selected_cpu = selected_target.getCpu(); - log.err("Chosen CPU model '{s}' does not match one of the supported targets:", .{ - selected_cpu.model.name, - }); - log.err(" Supported feature Set: ", .{}); - const all_features = whitelist_cpu.arch.allFeaturesList(); - var populated_cpu_features = whitelist_cpu.model.features; - populated_cpu_features.populateDependencies(all_features); - for (all_features) |feature, i_usize| { - const i = @intCast(std.Target.Cpu.Feature.Set.Index, i_usize); - const in_cpu_set = populated_cpu_features.isEnabled(i); - if (in_cpu_set) { - log.err("{s} ", .{feature.name}); - } - } - log.err(" Remove: ", .{}); - for (all_features) |feature, i_usize| { - const i = @intCast(std.Target.Cpu.Feature.Set.Index, i_usize); - const in_cpu_set = populated_cpu_features.isEnabled(i); - const in_actual_set = selected_cpu.features.isEnabled(i); - if (in_actual_set and !in_cpu_set) { - log.err("{s} ", .{feature.name}); - } - } - } - self.markInvalidUserInput(); - return args.default_target; - } - - return selected_target; - } - - pub fn addUserInputOption(self: *Builder, name_raw: []const u8, value_raw: []const u8) !bool { - const name = self.dupe(name_raw); - const value = self.dupe(value_raw); - const gop = try self.user_input_options.getOrPut(name); - if (!gop.found_existing) { - gop.value_ptr.* = UserInputOption{ - .name = name, - .value = .{ .scalar = value }, - .used = false, - }; - return false; - } - - // option already exists - switch (gop.value_ptr.value) { - .scalar => |s| { - // turn it into a list - var list = ArrayList([]const u8).init(self.allocator); - list.append(s) catch unreachable; - list.append(value) catch unreachable; - self.user_input_options.put(name, .{ - .name = name, - .value = .{ .list = list }, - .used = false, - }) catch unreachable; - }, - .list => |*list| { - // append to the list - list.append(value) catch unreachable; - self.user_input_options.put(name, .{ - .name = name, - .value = .{ .list = list.* }, - .used = false, - }) catch unreachable; - }, - .flag => { - log.warn("Option '-D{s}={s}' conflicts with flag '-D{s}'.", .{ name, value, name }); - return true; - }, - .map => |*map| { - _ = map; - log.warn("TODO maps as command line arguments is not implemented yet.", .{}); - return true; - }, - } - return false; - } - - pub fn addUserInputFlag(self: *Builder, name_raw: []const u8) !bool { - const name = self.dupe(name_raw); - const gop = try self.user_input_options.getOrPut(name); - if (!gop.found_existing) { - gop.value_ptr.* = .{ - .name = name, - .value = .{ .flag = {} }, - .used = false, - }; - return false; - } - - // option already exists - switch (gop.value_ptr.value) { - .scalar => |s| { - log.err("Flag '-D{s}' conflicts with option '-D{s}={s}'.", .{ name, name, s }); - return true; - }, - .list, .map => { - log.err("Flag '-D{s}' conflicts with multiple options of the same name.", .{name}); - return true; - }, - .flag => {}, - } - return false; - } - - fn typeToEnum(comptime T: type) TypeId { - return switch (@typeInfo(T)) { - .Int => .int, - .Float => .float, - .Bool => .bool, - .Enum => .@"enum", - else => switch (T) { - []const u8 => .string, - []const []const u8 => .list, - else => @compileError("Unsupported type: " ++ @typeName(T)), - }, - }; - } - - fn markInvalidUserInput(self: *Builder) void { - self.invalid_user_input = true; - } - - pub fn validateUserInputDidItFail(self: *Builder) bool { - // make sure all args are used - var it = self.user_input_options.iterator(); - while (it.next()) |entry| { - if (!entry.value_ptr.used) { - log.err("Invalid option: -D{s}", .{entry.key_ptr.*}); - self.markInvalidUserInput(); - } - } - - return self.invalid_user_input; - } - - pub fn spawnChild(self: *Builder, argv: []const []const u8) !void { - return self.spawnChildEnvMap(null, self.env_map, argv); - } - - fn printCmd(cwd: ?[]const u8, argv: []const []const u8) void { - if (cwd) |yes_cwd| std.debug.print("cd {s} && ", .{yes_cwd}); - for (argv) |arg| { - std.debug.print("{s} ", .{arg}); - } - std.debug.print("\n", .{}); - } - - pub fn spawnChildEnvMap(self: *Builder, cwd: ?[]const u8, env_map: *const EnvMap, argv: []const []const u8) !void { - if (self.verbose) { - printCmd(cwd, argv); - } - - if (!std.process.can_spawn) - return error.ExecNotSupported; - - var child = std.ChildProcess.init(argv, self.allocator); - child.cwd = cwd; - child.env_map = env_map; - - const term = child.spawnAndWait() catch |err| { - log.err("Unable to spawn {s}: {s}", .{ argv[0], @errorName(err) }); - return err; - }; - - switch (term) { - .Exited => |code| { - if (code != 0) { - log.err("The following command exited with error code {}:", .{code}); - printCmd(cwd, argv); - return error.UncleanExit; - } - }, - else => { - log.err("The following command terminated unexpectedly:", .{}); - printCmd(cwd, argv); - - return error.UncleanExit; - }, - } - } - - pub fn makePath(self: *Builder, path: []const u8) !void { - fs.cwd().makePath(self.pathFromRoot(path)) catch |err| { - log.err("Unable to create path {s}: {s}", .{ path, @errorName(err) }); - return err; - }; - } - - pub fn installArtifact(self: *Builder, artifact: *LibExeObjStep) void { - self.getInstallStep().dependOn(&self.addInstallArtifact(artifact).step); - } - - pub fn addInstallArtifact(self: *Builder, artifact: *LibExeObjStep) *InstallArtifactStep { - return InstallArtifactStep.create(self, artifact); - } - - ///`dest_rel_path` is relative to prefix path - pub fn installFile(self: *Builder, src_path: []const u8, dest_rel_path: []const u8) void { - self.getInstallStep().dependOn(&self.addInstallFileWithDir(.{ .path = src_path }, .prefix, dest_rel_path).step); - } - - pub fn installDirectory(self: *Builder, options: InstallDirectoryOptions) void { - self.getInstallStep().dependOn(&self.addInstallDirectory(options).step); - } - - ///`dest_rel_path` is relative to bin path - pub fn installBinFile(self: *Builder, src_path: []const u8, dest_rel_path: []const u8) void { - self.getInstallStep().dependOn(&self.addInstallFileWithDir(.{ .path = src_path }, .bin, dest_rel_path).step); - } - - ///`dest_rel_path` is relative to lib path - pub fn installLibFile(self: *Builder, src_path: []const u8, dest_rel_path: []const u8) void { - self.getInstallStep().dependOn(&self.addInstallFileWithDir(.{ .path = src_path }, .lib, dest_rel_path).step); - } - - /// Output format (BIN vs Intel HEX) determined by filename - pub fn installRaw(self: *Builder, artifact: *LibExeObjStep, dest_filename: []const u8, options: InstallRawStep.CreateOptions) *InstallRawStep { - const raw = self.addInstallRaw(artifact, dest_filename, options); - self.getInstallStep().dependOn(&raw.step); - return raw; - } - - ///`dest_rel_path` is relative to install prefix path - pub fn addInstallFile(self: *Builder, source: FileSource, dest_rel_path: []const u8) *InstallFileStep { - return self.addInstallFileWithDir(source.dupe(self), .prefix, dest_rel_path); - } - - ///`dest_rel_path` is relative to bin path - pub fn addInstallBinFile(self: *Builder, source: FileSource, dest_rel_path: []const u8) *InstallFileStep { - return self.addInstallFileWithDir(source.dupe(self), .bin, dest_rel_path); - } - - ///`dest_rel_path` is relative to lib path - pub fn addInstallLibFile(self: *Builder, source: FileSource, dest_rel_path: []const u8) *InstallFileStep { - return self.addInstallFileWithDir(source.dupe(self), .lib, dest_rel_path); - } - - pub fn addInstallHeaderFile(b: *Builder, src_path: []const u8, dest_rel_path: []const u8) *InstallFileStep { - return b.addInstallFileWithDir(.{ .path = src_path }, .header, dest_rel_path); - } - - pub fn addInstallRaw(self: *Builder, artifact: *LibExeObjStep, dest_filename: []const u8, options: InstallRawStep.CreateOptions) *InstallRawStep { - return InstallRawStep.create(self, artifact, dest_filename, options); - } - - pub fn addInstallFileWithDir( - self: *Builder, - source: FileSource, - install_dir: InstallDir, - dest_rel_path: []const u8, - ) *InstallFileStep { - if (dest_rel_path.len == 0) { - panic("dest_rel_path must be non-empty", .{}); - } - const install_step = self.allocator.create(InstallFileStep) catch unreachable; - install_step.* = InstallFileStep.init(self, source.dupe(self), install_dir, dest_rel_path); - return install_step; - } - - pub fn addInstallDirectory(self: *Builder, options: InstallDirectoryOptions) *InstallDirStep { - const install_step = self.allocator.create(InstallDirStep) catch unreachable; - install_step.* = InstallDirStep.init(self, options); - return install_step; - } - - pub fn pushInstalledFile(self: *Builder, dir: InstallDir, dest_rel_path: []const u8) void { - const file = InstalledFile{ - .dir = dir, - .path = dest_rel_path, - }; - self.installed_files.append(file.dupe(self)) catch unreachable; - } - - pub fn updateFile(self: *Builder, source_path: []const u8, dest_path: []const u8) !void { - if (self.verbose) { - log.info("cp {s} {s} ", .{ source_path, dest_path }); - } - const cwd = fs.cwd(); - const prev_status = try fs.Dir.updateFile(cwd, source_path, cwd, dest_path, .{}); - if (self.verbose) switch (prev_status) { - .stale => log.info("# installed", .{}), - .fresh => log.info("# up-to-date", .{}), - }; - } - - pub fn truncateFile(self: *Builder, dest_path: []const u8) !void { - if (self.verbose) { - log.info("truncate {s}", .{dest_path}); - } - const cwd = fs.cwd(); - var src_file = cwd.createFile(dest_path, .{}) catch |err| switch (err) { - error.FileNotFound => blk: { - if (fs.path.dirname(dest_path)) |dirname| { - try cwd.makePath(dirname); - } - break :blk try cwd.createFile(dest_path, .{}); - }, - else => |e| return e, - }; - src_file.close(); - } - - pub fn pathFromRoot(self: *Builder, rel_path: []const u8) []u8 { - return fs.path.resolve(self.allocator, &[_][]const u8{ self.build_root, rel_path }) catch unreachable; - } - - /// Shorthand for `std.fs.path.join(builder.allocator, paths) catch unreachable` - pub fn pathJoin(self: *Builder, paths: []const []const u8) []u8 { - return fs.path.join(self.allocator, paths) catch unreachable; - } - - pub fn fmt(self: *Builder, comptime format: []const u8, args: anytype) []u8 { - return fmt_lib.allocPrint(self.allocator, format, args) catch unreachable; - } - - pub fn findProgram(self: *Builder, names: []const []const u8, paths: []const []const u8) ![]const u8 { - // TODO report error for ambiguous situations - const exe_extension = @as(CrossTarget, .{}).exeFileExt(); - for (self.search_prefixes.items) |search_prefix| { - for (names) |name| { - if (fs.path.isAbsolute(name)) { - return name; - } - const full_path = self.pathJoin(&.{ - search_prefix, - "bin", - self.fmt("{s}{s}", .{ name, exe_extension }), - }); - return fs.realpathAlloc(self.allocator, full_path) catch continue; - } - } - if (self.env_map.get("PATH")) |PATH| { - for (names) |name| { - if (fs.path.isAbsolute(name)) { - return name; - } - var it = mem.tokenize(u8, PATH, &[_]u8{fs.path.delimiter}); - while (it.next()) |path| { - const full_path = self.pathJoin(&.{ - path, - self.fmt("{s}{s}", .{ name, exe_extension }), - }); - return fs.realpathAlloc(self.allocator, full_path) catch continue; - } - } - } - for (names) |name| { - if (fs.path.isAbsolute(name)) { - return name; - } - for (paths) |path| { - const full_path = self.pathJoin(&.{ - path, - self.fmt("{s}{s}", .{ name, exe_extension }), - }); - return fs.realpathAlloc(self.allocator, full_path) catch continue; - } - } - return error.FileNotFound; - } - - pub fn execAllowFail( - self: *Builder, - argv: []const []const u8, - out_code: *u8, - stderr_behavior: std.ChildProcess.StdIo, - ) ExecError![]u8 { - assert(argv.len != 0); - - if (!std.process.can_spawn) - return error.ExecNotSupported; - - const max_output_size = 400 * 1024; - var child = std.ChildProcess.init(argv, self.allocator); - child.stdin_behavior = .Ignore; - child.stdout_behavior = .Pipe; - child.stderr_behavior = stderr_behavior; - child.env_map = self.env_map; - - try child.spawn(); - - const stdout = child.stdout.?.reader().readAllAlloc(self.allocator, max_output_size) catch { - return error.ReadFailure; - }; - errdefer self.allocator.free(stdout); - - const term = try child.wait(); - switch (term) { - .Exited => |code| { - if (code != 0) { - out_code.* = @truncate(u8, code); - return error.ExitCodeFailure; - } - return stdout; - }, - .Signal, .Stopped, .Unknown => |code| { - out_code.* = @truncate(u8, code); - return error.ProcessTerminated; - }, - } - } - - pub fn execFromStep(self: *Builder, argv: []const []const u8, src_step: ?*Step) ![]u8 { - assert(argv.len != 0); - - if (self.verbose) { - printCmd(null, argv); - } - - if (!std.process.can_spawn) { - if (src_step) |s| log.err("{s}...", .{s.name}); - log.err("Unable to spawn the following command: cannot spawn child process", .{}); - printCmd(null, argv); - std.os.abort(); - } - - var code: u8 = undefined; - return self.execAllowFail(argv, &code, .Inherit) catch |err| switch (err) { - error.ExecNotSupported => { - if (src_step) |s| log.err("{s}...", .{s.name}); - log.err("Unable to spawn the following command: cannot spawn child process", .{}); - printCmd(null, argv); - std.os.abort(); - }, - error.FileNotFound => { - if (src_step) |s| log.err("{s}...", .{s.name}); - log.err("Unable to spawn the following command: file not found", .{}); - printCmd(null, argv); - std.os.exit(@truncate(u8, code)); - }, - error.ExitCodeFailure => { - if (src_step) |s| log.err("{s}...", .{s.name}); - if (self.prominent_compile_errors) { - log.err("The step exited with error code {d}", .{code}); - } else { - log.err("The following command exited with error code {d}:", .{code}); - printCmd(null, argv); - } - - std.os.exit(@truncate(u8, code)); - }, - error.ProcessTerminated => { - if (src_step) |s| log.err("{s}...", .{s.name}); - log.err("The following command terminated unexpectedly:", .{}); - printCmd(null, argv); - std.os.exit(@truncate(u8, code)); - }, - else => |e| return e, - }; - } - - pub fn exec(self: *Builder, argv: []const []const u8) ![]u8 { - return self.execFromStep(argv, null); - } - - pub fn addSearchPrefix(self: *Builder, search_prefix: []const u8) void { - self.search_prefixes.append(self.dupePath(search_prefix)) catch unreachable; - } - - pub fn getInstallPath(self: *Builder, dir: InstallDir, dest_rel_path: []const u8) []const u8 { - assert(!fs.path.isAbsolute(dest_rel_path)); // Install paths must be relative to the prefix - const base_dir = switch (dir) { - .prefix => self.install_path, - .bin => self.exe_dir, - .lib => self.lib_dir, - .header => self.h_dir, - .custom => |path| self.pathJoin(&.{ self.install_path, path }), - }; - return fs.path.resolve( - self.allocator, - &[_][]const u8{ base_dir, dest_rel_path }, - ) catch unreachable; - } - - pub const Dependency = struct { - builder: *Builder, - - pub fn artifact(d: *Dependency, name: []const u8) *LibExeObjStep { - var found: ?*LibExeObjStep = null; - for (d.builder.install_tls.step.dependencies.items) |dep_step| { - const inst = dep_step.cast(InstallArtifactStep) orelse continue; - if (mem.eql(u8, inst.artifact.name, name)) { - if (found != null) panic("artifact name '{s}' is ambiguous", .{name}); - found = inst.artifact; - } - } - return found orelse { - for (d.builder.install_tls.step.dependencies.items) |dep_step| { - const inst = dep_step.cast(InstallArtifactStep) orelse continue; - log.info("available artifact: '{s}'", .{inst.artifact.name}); - } - panic("unable to find artifact '{s}'", .{name}); - }; - } - }; - - pub fn dependency(b: *Builder, name: []const u8, args: anytype) *Dependency { - const build_runner = @import("root"); - const deps = build_runner.dependencies; - - inline for (@typeInfo(deps.imports).Struct.decls) |decl| { - if (mem.startsWith(u8, decl.name, b.dep_prefix) and - mem.endsWith(u8, decl.name, name) and - decl.name.len == b.dep_prefix.len + name.len) - { - const build_zig = @field(deps.imports, decl.name); - const build_root = @field(deps.build_root, decl.name); - return dependencyInner(b, name, build_root, build_zig, args); - } - } - - const full_path = b.pathFromRoot("build.zig.ini"); - std.debug.print("no dependency named '{s}' in '{s}'\n", .{ name, full_path }); - std.process.exit(1); - } - - fn dependencyInner( - b: *Builder, - name: []const u8, - build_root: []const u8, - comptime build_zig: type, - args: anytype, - ) *Dependency { - const sub_builder = b.createChild(name, build_root, args) catch unreachable; - sub_builder.runBuild(build_zig) catch unreachable; - - if (sub_builder.validateUserInputDidItFail()) { - std.debug.dumpCurrentStackTrace(@returnAddress()); - } - - const dep = b.allocator.create(Dependency) catch unreachable; - dep.* = .{ .builder = sub_builder }; - return dep; - } - - pub fn runBuild(b: *Builder, build_zig: anytype) anyerror!void { - switch (@typeInfo(@typeInfo(@TypeOf(build_zig.build)).Fn.return_type.?)) { - .Void => build_zig.build(b), - .ErrorUnion => try build_zig.build(b), - else => @compileError("expected return type of build to be 'void' or '!void'"), - } - } -}; - -test "builder.findProgram compiles" { - if (builtin.os.tag == .wasi) return error.SkipZigTest; - - var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); - defer arena.deinit(); - - const builder = try Builder.create( - arena.allocator(), - "zig", - "zig-cache", - "zig-cache", - "zig-cache", - ); - defer builder.destroy(); - _ = builder.findProgram(&[_][]const u8{}, &[_][]const u8{}) catch null; -} - -pub const Pkg = struct { - name: []const u8, - source: FileSource, - dependencies: ?[]const Pkg = null, -}; - -/// A file that is generated by a build step. -/// This struct is an interface that is meant to be used with `@fieldParentPtr` to implement the actual path logic. -pub const GeneratedFile = struct { - /// The step that generates the file - step: *Step, - - /// The path to the generated file. Must be either absolute or relative to the build root. - /// This value must be set in the `fn make()` of the `step` and must not be `null` afterwards. - path: ?[]const u8 = null, - - pub fn getPath(self: GeneratedFile) []const u8 { - return self.path orelse std.debug.panic( - "getPath() was called on a GeneratedFile that wasn't build yet. Is there a missing Step dependency on step '{s}'?", - .{self.step.name}, - ); - } -}; - -/// A file source is a reference to an existing or future file. -/// -pub const FileSource = union(enum) { - /// A plain file path, relative to build root or absolute. - path: []const u8, - - /// A file that is generated by an interface. Those files usually are - /// not available until built by a build step. - generated: *const GeneratedFile, - - /// Returns a new file source that will have a relative path to the build root guaranteed. - /// This should be preferred over setting `.path` directly as it documents that the files are in the project directory. - pub fn relative(path: []const u8) FileSource { - std.debug.assert(!std.fs.path.isAbsolute(path)); - return FileSource{ .path = path }; - } - - /// Returns a string that can be shown to represent the file source. - /// Either returns the path or `"generated"`. - pub fn getDisplayName(self: FileSource) []const u8 { - return switch (self) { - .path => self.path, - .generated => "generated", - }; - } - - /// Adds dependencies this file source implies to the given step. - pub fn addStepDependencies(self: FileSource, step: *Step) void { - switch (self) { - .path => {}, - .generated => |gen| step.dependOn(gen.step), - } - } - - /// Should only be called during make(), returns a path relative to the build root or absolute. - pub fn getPath(self: FileSource, builder: *Builder) []const u8 { - const path = switch (self) { - .path => |p| builder.pathFromRoot(p), - .generated => |gen| gen.getPath(), - }; - return path; - } - - /// Duplicates the file source for a given builder. - pub fn dupe(self: FileSource, b: *Builder) FileSource { - return switch (self) { - .path => |p| .{ .path = b.dupePath(p) }, - .generated => |gen| .{ .generated = gen }, - }; - } -}; - -/// Allocates a new string for assigning a value to a named macro. -/// If the value is omitted, it is set to 1. -/// `name` and `value` need not live longer than the function call. -pub fn constructCMacro(allocator: Allocator, name: []const u8, value: ?[]const u8) []const u8 { - var macro = allocator.alloc( - u8, - name.len + if (value) |value_slice| value_slice.len + 1 else 0, - ) catch |err| if (err == error.OutOfMemory) @panic("Out of memory") else unreachable; - mem.copy(u8, macro, name); - if (value) |value_slice| { - macro[name.len] = '='; - mem.copy(u8, macro[name.len + 1 ..], value_slice); - } - return macro; -} - -/// deprecated: use `InstallDirStep.Options` -pub const InstallDirectoryOptions = InstallDirStep.Options; - -pub const Step = struct { - id: Id, - name: []const u8, - makeFn: MakeFn, - dependencies: ArrayList(*Step), - loop_flag: bool, - done_flag: bool, - - const MakeFn = *const fn (self: *Step) anyerror!void; - - pub const Id = enum { - top_level, - lib_exe_obj, - install_artifact, - install_file, - install_dir, - log, - remove_dir, - fmt, - translate_c, - write_file, - run, - emulatable_run, - check_file, - check_object, - config_header, - install_raw, - options, - custom, - - pub fn Type(comptime id: Id) type { - return switch (id) { - .top_level => Builder.TopLevelStep, - .lib_exe_obj => LibExeObjStep, - .install_artifact => InstallArtifactStep, - .install_file => InstallFileStep, - .install_dir => InstallDirStep, - .log => LogStep, - .remove_dir => RemoveDirStep, - .fmt => FmtStep, - .translate_c => TranslateCStep, - .write_file => WriteFileStep, - .run => RunStep, - .emulatable_run => EmulatableRunStep, - .check_file => CheckFileStep, - .check_object => CheckObjectStep, - .config_header => ConfigHeaderStep, - .install_raw => InstallRawStep, - .options => OptionsStep, - .custom => @compileError("no type available for custom step"), - }; - } - }; - - pub fn init(id: Id, name: []const u8, allocator: Allocator, makeFn: MakeFn) Step { - return Step{ - .id = id, - .name = allocator.dupe(u8, name) catch unreachable, - .makeFn = makeFn, - .dependencies = ArrayList(*Step).init(allocator), - .loop_flag = false, - .done_flag = false, - }; - } - pub fn initNoOp(id: Id, name: []const u8, allocator: Allocator) Step { - return init(id, name, allocator, makeNoOp); - } - - pub fn make(self: *Step) !void { - if (self.done_flag) return; - - try self.makeFn(self); - self.done_flag = true; - } - - pub fn dependOn(self: *Step, other: *Step) void { - self.dependencies.append(other) catch unreachable; - } - - fn makeNoOp(self: *Step) anyerror!void { - _ = self; - } - - pub fn cast(step: *Step, comptime T: type) ?*T { - if (step.id == T.base_id) { - return @fieldParentPtr(T, "step", step); - } - return null; - } -}; - -pub const VcpkgRoot = union(VcpkgRootStatus) { - unattempted: void, - not_found: void, - found: []const u8, -}; - -pub const VcpkgRootStatus = enum { - unattempted, - not_found, - found, -}; - -pub const InstallDir = union(enum) { - prefix: void, - lib: void, - bin: void, - header: void, - /// A path relative to the prefix - custom: []const u8, - - /// Duplicates the install directory including the path if set to custom. - pub fn dupe(self: InstallDir, builder: *Builder) InstallDir { - if (self == .custom) { - // Written with this temporary to avoid RLS problems - const duped_path = builder.dupe(self.custom); - return .{ .custom = duped_path }; - } else { - return self; - } - } -}; - -pub const InstalledFile = struct { - dir: InstallDir, - path: []const u8, - - /// Duplicates the installed file path and directory. - pub fn dupe(self: InstalledFile, builder: *Builder) InstalledFile { - return .{ - .dir = self.dir.dupe(builder), - .path = builder.dupe(self.path), - }; - } -}; - -pub fn serializeCpu(allocator: Allocator, cpu: std.Target.Cpu) ![]const u8 { - // TODO this logic can disappear if cpu model + features becomes part of the target triple - const all_features = cpu.arch.allFeaturesList(); - var populated_cpu_features = cpu.model.features; - populated_cpu_features.populateDependencies(all_features); - - if (populated_cpu_features.eql(cpu.features)) { - // The CPU name alone is sufficient. - return cpu.model.name; - } else { - var mcpu_buffer = ArrayList(u8).init(allocator); - try mcpu_buffer.appendSlice(cpu.model.name); - - for (all_features) |feature, i_usize| { - const i = @intCast(std.Target.Cpu.Feature.Set.Index, i_usize); - const in_cpu_set = populated_cpu_features.isEnabled(i); - const in_actual_set = cpu.features.isEnabled(i); - if (in_cpu_set and !in_actual_set) { - try mcpu_buffer.writer().print("-{s}", .{feature.name}); - } else if (!in_cpu_set and in_actual_set) { - try mcpu_buffer.writer().print("+{s}", .{feature.name}); - } - } - - return try mcpu_buffer.toOwnedSlice(); - } -} - -test "dupePkg()" { - if (builtin.os.tag == .wasi) return error.SkipZigTest; - - var arena = std.heap.ArenaAllocator.init(std.testing.allocator); - defer arena.deinit(); - var builder = try Builder.create( - arena.allocator(), - "test", - "test", - "test", - "test", - ); - defer builder.destroy(); - - var pkg_dep = Pkg{ - .name = "pkg_dep", - .source = .{ .path = "/not/a/pkg_dep.zig" }, - }; - var pkg_top = Pkg{ - .name = "pkg_top", - .source = .{ .path = "/not/a/pkg_top.zig" }, - .dependencies = &[_]Pkg{pkg_dep}, - }; - const dupe = builder.dupePkg(pkg_top); - - const original_deps = pkg_top.dependencies.?; - const dupe_deps = dupe.dependencies.?; - - // probably the same top level package details - try std.testing.expectEqualStrings(pkg_top.name, dupe.name); - - // probably the same dependencies - try std.testing.expectEqual(original_deps.len, dupe_deps.len); - try std.testing.expectEqual(original_deps[0].name, pkg_dep.name); - - // could segfault otherwise if pointers in duplicated package's fields are - // the same as those in stack allocated package's fields - try std.testing.expect(dupe_deps.ptr != original_deps.ptr); - try std.testing.expect(dupe.name.ptr != pkg_top.name.ptr); - try std.testing.expect(dupe.source.path.ptr != pkg_top.source.path.ptr); - try std.testing.expect(dupe_deps[0].name.ptr != pkg_dep.name.ptr); - try std.testing.expect(dupe_deps[0].source.path.ptr != pkg_dep.source.path.ptr); -} - -test { - _ = CheckFileStep; - _ = CheckObjectStep; - _ = EmulatableRunStep; - _ = FmtStep; - _ = InstallArtifactStep; - _ = InstallDirStep; - _ = InstallFileStep; - _ = InstallRawStep; - _ = LibExeObjStep; - _ = LogStep; - _ = OptionsStep; - _ = RemoveDirStep; - _ = RunStep; - _ = TranslateCStep; - _ = WriteFileStep; -} diff --git a/lib/std/std.zig b/lib/std/std.zig index ba52784b458a50f105f54f57382b13fcc48738de..e0318ceb438b4062f45af3a8a16a58af4ebdc514 100644 --- a/lib/std/std.zig +++ b/lib/std/std.zig @@ -9,6 +9,7 @@ pub const AutoArrayHashMapUnmanaged = array_hash_map.AutoArrayHashMapUnmanaged; pub const AutoHashMap = hash_map.AutoHashMap; pub const AutoHashMapUnmanaged = hash_map.AutoHashMapUnmanaged; pub const BoundedArray = @import("bounded_array.zig").BoundedArray; +pub const Build = @import("Build.zig"); pub const BufMap = @import("buf_map.zig").BufMap; pub const BufSet = @import("buf_set.zig").BufSet; pub const ChildProcess = @import("child_process.zig").ChildProcess; @@ -49,7 +50,6 @@ pub const array_hash_map = @import("array_hash_map.zig"); pub const atomic = @import("atomic.zig"); pub const base64 = @import("base64.zig"); pub const bit_set = @import("bit_set.zig"); -pub const build = @import("build.zig"); pub const builtin = @import("builtin.zig"); pub const c = @import("c.zig"); pub const coff = @import("coff.zig"); @@ -96,6 +96,12 @@ pub const wasm = @import("wasm.zig"); pub const zig = @import("zig.zig"); pub const start = @import("start.zig"); +///// Deprecated. Use `std.Build` instead. +//pub const build = struct { +// /// Deprecated. Use `std.Build` instead. +// pub const Builder = Build; +//}; + const root = @import("root"); const options_override = if (@hasDecl(root, "std_options")) root.std_options else struct {}; diff --git a/test/link/bss/build.zig b/test/link/bss/build.zig index c31fa7faf553f558c88c3cfe045b97582ce32a64..0df9c1d323ea2a399d426b7a87583f5b7bf00982 100644 --- a/test/link/bss/build.zig +++ b/test/link/bss/build.zig @@ -1,6 +1,6 @@ -const Builder = @import("std").build.Builder; +const std = @import("std"); -pub fn build(b: *Builder) void { +pub fn build(b: *std.Build) void { const optimize = b.standardOptimizeOption(.{}); const test_step = b.step("test", "Test"); diff --git a/test/link/common_symbols/build.zig b/test/link/common_symbols/build.zig index 068c3f9c57e5162c15a9b97964a54bd53e41d753..ee9dd94ebd12dc264611f8319548f147cf6ed4d5 100644 --- a/test/link/common_symbols/build.zig +++ b/test/link/common_symbols/build.zig @@ -1,6 +1,6 @@ -const Builder = @import("std").build.Builder; +const std = @import("std"); -pub fn build(b: *Builder) void { +pub fn build(b: *std.Build) void { const optimize = b.standardOptimizeOption(.{}); const lib_a = b.addStaticLibrary(.{ diff --git a/test/link/common_symbols_alignment/build.zig b/test/link/common_symbols_alignment/build.zig index b6dd39801cd6fbc95597ef748598320c55d030a1..f6efdc784b1586f1c4ab5b1a11ef7b0bf2e9be40 100644 --- a/test/link/common_symbols_alignment/build.zig +++ b/test/link/common_symbols_alignment/build.zig @@ -1,6 +1,6 @@ -const Builder = @import("std").build.Builder; +const std = @import("std"); -pub fn build(b: *Builder) void { +pub fn build(b: *std.Build) void { const optimize = b.standardOptimizeOption(.{}); const target = b.standardTargetOptions(.{}); diff --git a/test/link/interdependent_static_c_libs/build.zig b/test/link/interdependent_static_c_libs/build.zig index 50a214490de256272fb6dbaf6cc52fba804b4289..d8962a8e0842ab1a5a4754fc9ca5abbb3c6f85f9 100644 --- a/test/link/interdependent_static_c_libs/build.zig +++ b/test/link/interdependent_static_c_libs/build.zig @@ -1,6 +1,6 @@ -const Builder = @import("std").build.Builder; +const std = @import("std"); -pub fn build(b: *Builder) void { +pub fn build(b: *std.Build) void { const optimize = b.standardOptimizeOption(.{}); const target = b.standardTargetOptions(.{}); diff --git a/test/link/macho/bugs/13056/build.zig b/test/link/macho/bugs/13056/build.zig index a65cd6076604cca7b12cb432209ed6ae8820946b..662fd25c92bab84e840c5c03de91495e01599c0b 100644 --- a/test/link/macho/bugs/13056/build.zig +++ b/test/link/macho/bugs/13056/build.zig @@ -1,7 +1,6 @@ const std = @import("std"); -const Builder = std.build.Builder; -pub fn build(b: *Builder) void { +pub fn build(b: *std.Build) void { const optimize = b.standardOptimizeOption(.{}); const target: std.zig.CrossTarget = .{ .os_tag = .macos }; diff --git a/test/link/macho/bugs/13457/build.zig b/test/link/macho/bugs/13457/build.zig index 4c1ce89261ea84441793b0b01a4cfe27de9aa880..6ca1f31b86b1cf1314e06ed244627e37a73e2ef4 100644 --- a/test/link/macho/bugs/13457/build.zig +++ b/test/link/macho/bugs/13457/build.zig @@ -1,8 +1,7 @@ const std = @import("std"); -const Builder = std.build.Builder; -const LibExeObjectStep = std.build.LibExeObjStep; +const LibExeObjectStep = std.Build.LibExeObjStep; -pub fn build(b: *Builder) void { +pub fn build(b: *std.Build) void { const optimize = b.standardOptimizeOption(.{}); const target: std.zig.CrossTarget = .{ .os_tag = .macos }; diff --git a/test/link/macho/dead_strip/build.zig b/test/link/macho/dead_strip/build.zig index a4c3575e45c7eba43d48be571d5ad4e3c95362fa..b6c30024929db544fd5f3218f29b83aca01e59ce 100644 --- a/test/link/macho/dead_strip/build.zig +++ b/test/link/macho/dead_strip/build.zig @@ -1,8 +1,7 @@ const std = @import("std"); -const Builder = std.build.Builder; -const LibExeObjectStep = std.build.LibExeObjStep; +const LibExeObjectStep = std.Build.LibExeObjStep; -pub fn build(b: *Builder) void { +pub fn build(b: *std.Build) void { const optimize = b.standardOptimizeOption(.{}); const target: std.zig.CrossTarget = .{ .os_tag = .macos }; @@ -37,7 +36,7 @@ pub fn build(b: *Builder) void { } } -fn createScenario(b: *Builder, optimize: std.builtin.OptimizeMode, target: std.zig.CrossTarget) *LibExeObjectStep { +fn createScenario(b: *std.Build, optimize: std.builtin.OptimizeMode, target: std.zig.CrossTarget) *LibExeObjectStep { const exe = b.addExecutable(.{ .name = "test", .optimize = optimize, diff --git a/test/link/macho/dead_strip_dylibs/build.zig b/test/link/macho/dead_strip_dylibs/build.zig index 0127b575fce7e4fc6742b940beb4c93d845a07c9..f61b30ca4af62069cca42cdb8f62250a0e029b84 100644 --- a/test/link/macho/dead_strip_dylibs/build.zig +++ b/test/link/macho/dead_strip_dylibs/build.zig @@ -1,8 +1,7 @@ const std = @import("std"); -const Builder = std.build.Builder; -const LibExeObjectStep = std.build.LibExeObjStep; +const LibExeObjectStep = std.Build.LibExeObjStep; -pub fn build(b: *Builder) void { +pub fn build(b: *std.Build) void { const optimize = b.standardOptimizeOption(.{}); const test_step = b.step("test", "Test the program"); @@ -36,7 +35,7 @@ pub fn build(b: *Builder) void { } } -fn createScenario(b: *Builder, optimize: std.builtin.OptimizeMode) *LibExeObjectStep { +fn createScenario(b: *std.Build, optimize: std.builtin.OptimizeMode) *LibExeObjectStep { const exe = b.addExecutable(.{ .name = "test", .optimize = optimize, diff --git a/test/link/macho/dylib/build.zig b/test/link/macho/dylib/build.zig index acd27a507f93cebd804016fbe0f1318498c1c000..7a1e2d862c7a445ceab0bc3e9c52902fc79dcc4d 100644 --- a/test/link/macho/dylib/build.zig +++ b/test/link/macho/dylib/build.zig @@ -1,7 +1,6 @@ const std = @import("std"); -const Builder = std.build.Builder; -pub fn build(b: *Builder) void { +pub fn build(b: *std.Build) void { const optimize = b.standardOptimizeOption(.{}); const target: std.zig.CrossTarget = .{ .os_tag = .macos }; diff --git a/test/link/macho/empty/build.zig b/test/link/macho/empty/build.zig index 8b2d047371cc29b7666fcab0de4c644540edae5f..586da1511b0caf8a8a97e38617ebfdaaedc27b56 100644 --- a/test/link/macho/empty/build.zig +++ b/test/link/macho/empty/build.zig @@ -1,7 +1,6 @@ const std = @import("std"); -const Builder = std.build.Builder; -pub fn build(b: *Builder) void { +pub fn build(b: *std.Build) void { const optimize = b.standardOptimizeOption(.{}); const target: std.zig.CrossTarget = .{ .os_tag = .macos }; @@ -17,7 +16,7 @@ pub fn build(b: *Builder) void { exe.addCSourceFile("empty.c", &[0][]const u8{}); exe.linkLibC(); - const run_cmd = std.build.EmulatableRunStep.create(b, "run", exe); + const run_cmd = std.Build.EmulatableRunStep.create(b, "run", exe); run_cmd.expectStdOutEqual("Hello!\n"); test_step.dependOn(&run_cmd.step); } diff --git a/test/link/macho/entry/build.zig b/test/link/macho/entry/build.zig index 87e4d1b5daedf660e45e8a2b9372a91b73d9facb..4504da9c6ca165c2fd318d2ec710d6939769abef 100644 --- a/test/link/macho/entry/build.zig +++ b/test/link/macho/entry/build.zig @@ -1,7 +1,6 @@ const std = @import("std"); -const Builder = std.build.Builder; -pub fn build(b: *Builder) void { +pub fn build(b: *std.Build) void { const optimize = b.standardOptimizeOption(.{}); const test_step = b.step("test", "Test"); diff --git a/test/link/macho/headerpad/build.zig b/test/link/macho/headerpad/build.zig index 74efb5d5801e3968547cb4b36d411dedf9db337b..2b3c6abb8a92a9558b3f8bf71057854179e4bde1 100644 --- a/test/link/macho/headerpad/build.zig +++ b/test/link/macho/headerpad/build.zig @@ -1,9 +1,8 @@ const std = @import("std"); const builtin = @import("builtin"); -const Builder = std.build.Builder; -const LibExeObjectStep = std.build.LibExeObjStep; +const LibExeObjectStep = std.Build.LibExeObjStep; -pub fn build(b: *Builder) void { +pub fn build(b: *std.Build) void { const optimize = b.standardOptimizeOption(.{}); const test_step = b.step("test", "Test"); @@ -94,7 +93,7 @@ pub fn build(b: *Builder) void { } } -fn simpleExe(b: *Builder, optimize: std.builtin.OptimizeMode) *LibExeObjectStep { +fn simpleExe(b: *std.Build, optimize: std.builtin.OptimizeMode) *LibExeObjectStep { const exe = b.addExecutable(.{ .name = "main", .optimize = optimize, diff --git a/test/link/macho/linksection/build.zig b/test/link/macho/linksection/build.zig index eebb31a21ee53489bdc8aeb4a9241d378d88882b..227d4eeb63f1c697307e24b03bc389d32b6fc3d5 100644 --- a/test/link/macho/linksection/build.zig +++ b/test/link/macho/linksection/build.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn build(b: *std.build.Builder) void { +pub fn build(b: *std.Build) void { const optimize = b.standardOptimizeOption(.{}); const target = std.zig.CrossTarget{ .os_tag = .macos }; diff --git a/test/link/macho/needed_framework/build.zig b/test/link/macho/needed_framework/build.zig index 33965a92726dc71af806abe59dbe9f6f7f295c78..62b70b21f195dc995b371ed0dd3582ac419060fe 100644 --- a/test/link/macho/needed_framework/build.zig +++ b/test/link/macho/needed_framework/build.zig @@ -1,8 +1,7 @@ const std = @import("std"); -const Builder = std.build.Builder; -const LibExeObjectStep = std.build.LibExeObjStep; +const LibExeObjectStep = std.Build.LibExeObjStep; -pub fn build(b: *Builder) void { +pub fn build(b: *std.Build) void { const optimize = b.standardOptimizeOption(.{}); const test_step = b.step("test", "Test the program"); diff --git a/test/link/macho/needed_library/build.zig b/test/link/macho/needed_library/build.zig index 137239d2926f3cc62490100cd1320c48c738ce7f..cdad94357bc53af113c5381cea16fe58cf5351c1 100644 --- a/test/link/macho/needed_library/build.zig +++ b/test/link/macho/needed_library/build.zig @@ -1,8 +1,7 @@ const std = @import("std"); -const Builder = std.build.Builder; -const LibExeObjectStep = std.build.LibExeObjStep; +const LibExeObjectStep = std.Build.LibExeObjStep; -pub fn build(b: *Builder) void { +pub fn build(b: *std.Build) void { const optimize = b.standardOptimizeOption(.{}); const target: std.zig.CrossTarget = .{ .os_tag = .macos }; diff --git a/test/link/macho/objc/build.zig b/test/link/macho/objc/build.zig index 9c38739a5c9881a0cba6f10574fa765183717765..10d293baab7224eeafe69834ec7f57abbc184541 100644 --- a/test/link/macho/objc/build.zig +++ b/test/link/macho/objc/build.zig @@ -1,7 +1,6 @@ const std = @import("std"); -const Builder = std.build.Builder; -pub fn build(b: *Builder) void { +pub fn build(b: *std.Build) void { const optimize = b.standardOptimizeOption(.{}); const test_step = b.step("test", "Test the program"); @@ -18,6 +17,6 @@ pub fn build(b: *Builder) void { // populate paths to the sysroot here. exe.linkFramework("Foundation"); - const run_cmd = std.build.EmulatableRunStep.create(b, "run", exe); + const run_cmd = std.Build.EmulatableRunStep.create(b, "run", exe); test_step.dependOn(&run_cmd.step); } diff --git a/test/link/macho/objcpp/build.zig b/test/link/macho/objcpp/build.zig index f4c88b286238c640e5eb5d92a7032fbc20242894..2a3459be5051d8207a78c19be760e6b279bc7e79 100644 --- a/test/link/macho/objcpp/build.zig +++ b/test/link/macho/objcpp/build.zig @@ -1,7 +1,6 @@ const std = @import("std"); -const Builder = std.build.Builder; -pub fn build(b: *Builder) void { +pub fn build(b: *std.Build) void { const optimize = b.standardOptimizeOption(.{}); const test_step = b.step("test", "Test the program"); diff --git a/test/link/macho/pagezero/build.zig b/test/link/macho/pagezero/build.zig index f61aa34a93ff8141c9d8ea076f4299606945b1c7..0a8471b919f4c0fc3d7c847e4dd5e09fb90e1a11 100644 --- a/test/link/macho/pagezero/build.zig +++ b/test/link/macho/pagezero/build.zig @@ -1,7 +1,6 @@ const std = @import("std"); -const Builder = std.build.Builder; -pub fn build(b: *Builder) void { +pub fn build(b: *std.Build) void { const optimize = b.standardOptimizeOption(.{}); const target: std.zig.CrossTarget = .{ .os_tag = .macos }; diff --git a/test/link/macho/search_strategy/build.zig b/test/link/macho/search_strategy/build.zig index db894b6ae30a3a3805462378c6e22a69c8109181..eeda89446bc5a7b92a5545b6fd31b82ed9f8b1d0 100644 --- a/test/link/macho/search_strategy/build.zig +++ b/test/link/macho/search_strategy/build.zig @@ -1,8 +1,7 @@ const std = @import("std"); -const Builder = std.build.Builder; -const LibExeObjectStep = std.build.LibExeObjStep; +const LibExeObjectStep = std.Build.LibExeObjStep; -pub fn build(b: *Builder) void { +pub fn build(b: *std.Build) void { const optimize = b.standardOptimizeOption(.{}); const target: std.zig.CrossTarget = .{ .os_tag = .macos }; @@ -29,14 +28,14 @@ pub fn build(b: *Builder) void { const exe = createScenario(b, optimize, target); exe.search_strategy = .paths_first; - const run = std.build.EmulatableRunStep.create(b, "run", exe); + const run = std.Build.EmulatableRunStep.create(b, "run", exe); run.cwd = b.pathFromRoot("."); run.expectStdOutEqual("Hello world"); test_step.dependOn(&run.step); } } -fn createScenario(b: *Builder, optimize: std.builtin.OptimizeMode, target: std.zig.CrossTarget) *LibExeObjectStep { +fn createScenario(b: *std.Build, optimize: std.builtin.OptimizeMode, target: std.zig.CrossTarget) *LibExeObjectStep { const static = b.addStaticLibrary(.{ .name = "a", .optimize = optimize, @@ -44,7 +43,7 @@ fn createScenario(b: *Builder, optimize: std.builtin.OptimizeMode, target: std.z }); static.addCSourceFile("a.c", &.{}); static.linkLibC(); - static.override_dest_dir = std.build.InstallDir{ + static.override_dest_dir = std.Build.InstallDir{ .custom = "static", }; static.install(); @@ -57,7 +56,7 @@ fn createScenario(b: *Builder, optimize: std.builtin.OptimizeMode, target: std.z }); dylib.addCSourceFile("a.c", &.{}); dylib.linkLibC(); - dylib.override_dest_dir = std.build.InstallDir{ + dylib.override_dest_dir = std.Build.InstallDir{ .custom = "dynamic", }; dylib.install(); diff --git a/test/link/macho/stack_size/build.zig b/test/link/macho/stack_size/build.zig index 74e9a86e94ea7fa6e9b6b9a1be9024d5ad35ec8f..3529a134ebd19f53c69bb7a28688579d38241bb9 100644 --- a/test/link/macho/stack_size/build.zig +++ b/test/link/macho/stack_size/build.zig @@ -1,7 +1,6 @@ const std = @import("std"); -const Builder = std.build.Builder; -pub fn build(b: *Builder) void { +pub fn build(b: *std.Build) void { const optimize = b.standardOptimizeOption(.{}); const target: std.zig.CrossTarget = .{ .os_tag = .macos }; diff --git a/test/link/macho/strict_validation/build.zig b/test/link/macho/strict_validation/build.zig index b6baf63c11116477810bb2244fad00aa8e7b6ef1..6eabc02b5f8553b74da699aedc373b041d7b0e91 100644 --- a/test/link/macho/strict_validation/build.zig +++ b/test/link/macho/strict_validation/build.zig @@ -1,9 +1,8 @@ const std = @import("std"); const builtin = @import("builtin"); -const Builder = std.build.Builder; -const LibExeObjectStep = std.build.LibExeObjStep; +const LibExeObjectStep = std.Build.LibExeObjStep; -pub fn build(b: *Builder) void { +pub fn build(b: *std.Build) void { const optimize = b.standardOptimizeOption(.{}); const target: std.zig.CrossTarget = .{ .os_tag = .macos }; diff --git a/test/link/macho/tls/build.zig b/test/link/macho/tls/build.zig index 9b2fe952bf0f6e06545e464b6a8918779db22737..c77588cb5d3fe9df4e97658efa2364a3afc0604d 100644 --- a/test/link/macho/tls/build.zig +++ b/test/link/macho/tls/build.zig @@ -1,7 +1,6 @@ const std = @import("std"); -const Builder = std.build.Builder; -pub fn build(b: *Builder) void { +pub fn build(b: *std.Build) void { const optimize = b.standardOptimizeOption(.{}); const target: std.zig.CrossTarget = .{ .os_tag = .macos }; diff --git a/test/link/macho/unwind_info/build.zig b/test/link/macho/unwind_info/build.zig index dbbdbb3e51ccb5662977dde5f16ef86a911d9573..e43c002e2ea89c725137153b3f09edbca9bed90c 100644 --- a/test/link/macho/unwind_info/build.zig +++ b/test/link/macho/unwind_info/build.zig @@ -1,9 +1,8 @@ const std = @import("std"); const builtin = @import("builtin"); -const Builder = std.build.Builder; -const LibExeObjectStep = std.build.LibExeObjStep; +const LibExeObjectStep = std.Build.LibExeObjStep; -pub fn build(b: *Builder) void { +pub fn build(b: *std.Build) void { const optimize = b.standardOptimizeOption(.{}); const target: std.zig.CrossTarget = .{ .os_tag = .macos }; @@ -14,8 +13,8 @@ pub fn build(b: *Builder) void { } fn testUnwindInfo( - b: *Builder, - test_step: *std.build.Step, + b: *std.Build, + test_step: *std.Build.Step, optimize: std.builtin.OptimizeMode, target: std.zig.CrossTarget, dead_strip: bool, @@ -52,7 +51,7 @@ fn testUnwindInfo( test_step.dependOn(&run_cmd.step); } -fn createScenario(b: *Builder, optimize: std.builtin.OptimizeMode, target: std.zig.CrossTarget) *LibExeObjectStep { +fn createScenario(b: *std.Build, optimize: std.builtin.OptimizeMode, target: std.zig.CrossTarget) *LibExeObjectStep { const exe = b.addExecutable(.{ .name = "test", .optimize = optimize, diff --git a/test/link/macho/uuid/build.zig b/test/link/macho/uuid/build.zig index 86ff99e8b12ca043375354e33f0691d37be8847d..62c288f1a034476e5f0d867dbd3f014e5208b522 100644 --- a/test/link/macho/uuid/build.zig +++ b/test/link/macho/uuid/build.zig @@ -1,8 +1,7 @@ const std = @import("std"); -const Builder = std.build.Builder; -const LibExeObjectStep = std.build.LibExeObjStep; +const LibExeObjectStep = std.Build.LibExeObjStep; -pub fn build(b: *Builder) void { +pub fn build(b: *std.Build) void { const test_step = b.step("test", "Test"); test_step.dependOn(b.getInstallStep()); @@ -27,8 +26,8 @@ pub fn build(b: *Builder) void { } fn testUuid( - b: *Builder, - test_step: *std.build.Step, + b: *std.Build, + test_step: *std.Build.Step, optimize: std.builtin.OptimizeMode, target: std.zig.CrossTarget, comptime exp: []const u8, @@ -52,7 +51,7 @@ fn testUuid( } } -fn simpleDylib(b: *Builder, optimize: std.builtin.OptimizeMode, target: std.zig.CrossTarget) *LibExeObjectStep { +fn simpleDylib(b: *std.Build, optimize: std.builtin.OptimizeMode, target: std.zig.CrossTarget) *LibExeObjectStep { const dylib = b.addSharedLibrary(.{ .name = "test", .version = .{ .major = 1, .minor = 0 }, diff --git a/test/link/macho/weak_framework/build.zig b/test/link/macho/weak_framework/build.zig index f8460c4e827081f30f5c05fd41b4202374b33947..5be66991dde676d2ccf2292023ca122a9432abb0 100644 --- a/test/link/macho/weak_framework/build.zig +++ b/test/link/macho/weak_framework/build.zig @@ -1,8 +1,7 @@ const std = @import("std"); -const Builder = std.build.Builder; -const LibExeObjectStep = std.build.LibExeObjStep; +const LibExeObjectStep = std.Build.LibExeObjStep; -pub fn build(b: *Builder) void { +pub fn build(b: *std.Build) void { const optimize = b.standardOptimizeOption(.{}); const test_step = b.step("test", "Test the program"); diff --git a/test/link/macho/weak_library/build.zig b/test/link/macho/weak_library/build.zig index 229d965e48d6fee4ec758b55b7ad06172c40e97a..505ab5ae965ac921c6e8113a735631a0d0cd0c61 100644 --- a/test/link/macho/weak_library/build.zig +++ b/test/link/macho/weak_library/build.zig @@ -1,8 +1,7 @@ const std = @import("std"); -const Builder = std.build.Builder; -const LibExeObjectStep = std.build.LibExeObjStep; +const LibExeObjectStep = std.Build.LibExeObjStep; -pub fn build(b: *Builder) void { +pub fn build(b: *std.Build) void { const optimize = b.standardOptimizeOption(.{}); const target: std.zig.CrossTarget = .{ .os_tag = .macos }; diff --git a/test/link/static_lib_as_system_lib/build.zig b/test/link/static_lib_as_system_lib/build.zig index 895cdcf316a4b29fa189178a65ab67c71d744699..b6cf32d711380c3ee1816d66527c42bfcf8af330 100644 --- a/test/link/static_lib_as_system_lib/build.zig +++ b/test/link/static_lib_as_system_lib/build.zig @@ -1,7 +1,6 @@ const std = @import("std"); -const Builder = std.build.Builder; -pub fn build(b: *Builder) void { +pub fn build(b: *std.Build) void { const optimize = b.standardOptimizeOption(.{}); const target = b.standardTargetOptions(.{}); diff --git a/test/link/wasm/archive/build.zig b/test/link/wasm/archive/build.zig index 7401ba22dc77c1d9d0cec7fa9766ee23808a28df..342c4c08d19dabd448dc7c17db018a37dcc484f5 100644 --- a/test/link/wasm/archive/build.zig +++ b/test/link/wasm/archive/build.zig @@ -1,7 +1,6 @@ const std = @import("std"); -const Builder = std.build.Builder; -pub fn build(b: *Builder) void { +pub fn build(b: *std.Build) void { const test_step = b.step("test", "Test"); test_step.dependOn(b.getInstallStep()); diff --git a/test/link/wasm/basic-features/build.zig b/test/link/wasm/basic-features/build.zig index 69e88aefae66a30acf0483625219da513bbfd6cc..9f570665183ce7debff92b4b5323b231a6836aeb 100644 --- a/test/link/wasm/basic-features/build.zig +++ b/test/link/wasm/basic-features/build.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn build(b: *std.build.Builder) void { +pub fn build(b: *std.Build) void { // Library with explicitly set cpu features const lib = b.addSharedLibrary(.{ .name = "lib", diff --git a/test/link/wasm/bss/build.zig b/test/link/wasm/bss/build.zig index 6b29fd0dc3c8d31aeba8d562b1f9eb641dfbe6b1..1017e70a7192eab63d307d5c1f7ad659eefd99d2 100644 --- a/test/link/wasm/bss/build.zig +++ b/test/link/wasm/bss/build.zig @@ -1,7 +1,6 @@ const std = @import("std"); -const Builder = std.build.Builder; -pub fn build(b: *Builder) void { +pub fn build(b: *std.Build) void { const test_step = b.step("test", "Test"); test_step.dependOn(b.getInstallStep()); diff --git a/test/link/wasm/export-data/build.zig b/test/link/wasm/export-data/build.zig index 8eab283ec212a0cb16a2539bdc7a66f371ac9ec7..95caf42dd024ffa0dc9234e3a2f29bbd9a228492 100644 --- a/test/link/wasm/export-data/build.zig +++ b/test/link/wasm/export-data/build.zig @@ -1,7 +1,6 @@ const std = @import("std"); -const Builder = std.build.Builder; -pub fn build(b: *Builder) void { +pub fn build(b: *std.Build) void { const test_step = b.step("test", "Test"); test_step.dependOn(b.getInstallStep()); diff --git a/test/link/wasm/export/build.zig b/test/link/wasm/export/build.zig index 2b9a91d728c2afd3d70d548effbe003a8233fda7..69c34a320eeeeda8f58425b0fa2dfa4321f75b32 100644 --- a/test/link/wasm/export/build.zig +++ b/test/link/wasm/export/build.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn build(b: *std.build.Builder) void { +pub fn build(b: *std.Build) void { const optimize = b.standardOptimizeOption(.{}); const no_export = b.addSharedLibrary(.{ diff --git a/test/link/wasm/extern-mangle/build.zig b/test/link/wasm/extern-mangle/build.zig index 71bb986dff36294c0b003a3b53d55f0e859caa75..19913e6eca3dc3286f827b813dcb4d1ea03b1824 100644 --- a/test/link/wasm/extern-mangle/build.zig +++ b/test/link/wasm/extern-mangle/build.zig @@ -1,7 +1,6 @@ const std = @import("std"); -const Builder = std.build.Builder; -pub fn build(b: *Builder) void { +pub fn build(b: *std.Build) void { const test_step = b.step("test", "Test"); test_step.dependOn(b.getInstallStep()); diff --git a/test/link/wasm/extern/build.zig b/test/link/wasm/extern/build.zig index 800c76a31c580f54efd9ac2789478f5643f96e43..569d94091add69d37de965139f8c0b9de0154b45 100644 --- a/test/link/wasm/extern/build.zig +++ b/test/link/wasm/extern/build.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn build(b: *std.build.Builder) void { +pub fn build(b: *std.Build) void { const exe = b.addExecutable(.{ .name = "extern", .root_source_file = .{ .path = "main.zig" }, diff --git a/test/link/wasm/function-table/build.zig b/test/link/wasm/function-table/build.zig index 804aaf0b098190a8d0f5899749131b396e48770e..4c25d0d8609a9b332c0ac97d02a6797e0cfce483 100644 --- a/test/link/wasm/function-table/build.zig +++ b/test/link/wasm/function-table/build.zig @@ -1,7 +1,6 @@ const std = @import("std"); -const Builder = std.build.Builder; -pub fn build(b: *Builder) void { +pub fn build(b: *std.Build) void { const optimize = b.standardOptimizeOption(.{}); const test_step = b.step("test", "Test"); diff --git a/test/link/wasm/infer-features/build.zig b/test/link/wasm/infer-features/build.zig index 147fb55fdae2def902f76f0bf4f986a6da4724d8..d6d706a33d1fd65778afede41542c6c7b5125c20 100644 --- a/test/link/wasm/infer-features/build.zig +++ b/test/link/wasm/infer-features/build.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn build(b: *std.build.Builder) void { +pub fn build(b: *std.Build) void { const optimize = b.standardOptimizeOption(.{}); // Wasm Object file which we will use to infer the features from diff --git a/test/link/wasm/producers/build.zig b/test/link/wasm/producers/build.zig index 57ee6acd184e9866453551ac912e24c906218323..2589b0dfcf3b957a82d5b9d4f4e1a9f1b537a929 100644 --- a/test/link/wasm/producers/build.zig +++ b/test/link/wasm/producers/build.zig @@ -1,8 +1,7 @@ const std = @import("std"); const builtin = @import("builtin"); -const Builder = std.build.Builder; -pub fn build(b: *Builder) void { +pub fn build(b: *std.Build) void { const test_step = b.step("test", "Test"); test_step.dependOn(b.getInstallStep()); diff --git a/test/link/wasm/segments/build.zig b/test/link/wasm/segments/build.zig index 8f7d9e0583a7b3ac0ed4c3a8da7890690501e930..76160e905f8d25ac9da74285b6ac8416226e05b3 100644 --- a/test/link/wasm/segments/build.zig +++ b/test/link/wasm/segments/build.zig @@ -1,7 +1,6 @@ const std = @import("std"); -const Builder = std.build.Builder; -pub fn build(b: *Builder) void { +pub fn build(b: *std.Build) void { const test_step = b.step("test", "Test"); test_step.dependOn(b.getInstallStep()); diff --git a/test/link/wasm/stack_pointer/build.zig b/test/link/wasm/stack_pointer/build.zig index 42971c607de734e1ac5eb1607c5a1522b3c3243b..95c764388005b5214c5d3bc5f6334bae5b437c1b 100644 --- a/test/link/wasm/stack_pointer/build.zig +++ b/test/link/wasm/stack_pointer/build.zig @@ -1,7 +1,6 @@ const std = @import("std"); -const Builder = std.build.Builder; -pub fn build(b: *Builder) void { +pub fn build(b: *std.Build) void { const test_step = b.step("test", "Test"); test_step.dependOn(b.getInstallStep()); diff --git a/test/link/wasm/type/build.zig b/test/link/wasm/type/build.zig index 7fa384908398841fcbba9a37d91d85f47bab9990..816b57ccabedba016b6ef27f69091a02ff6b279b 100644 --- a/test/link/wasm/type/build.zig +++ b/test/link/wasm/type/build.zig @@ -1,7 +1,6 @@ const std = @import("std"); -const Builder = std.build.Builder; -pub fn build(b: *Builder) void { +pub fn build(b: *std.Build) void { const test_step = b.step("test", "Test"); test_step.dependOn(b.getInstallStep()); diff --git a/test/src/compare_output.zig b/test/src/compare_output.zig index a885faaadffb58109274a14fdbd3807f7685500e..edd48321c911183745530af768adddfbf852b6e7 100644 --- a/test/src/compare_output.zig +++ b/test/src/compare_output.zig @@ -1,7 +1,6 @@ // This is the implementation of the test harness. // For the actual test cases, see test/compare_output.zig. const std = @import("std"); -const build = std.build; const ArrayList = std.ArrayList; const fmt = std.fmt; const mem = std.mem; @@ -9,8 +8,8 @@ const fs = std.fs; const OptimizeMode = std.builtin.OptimizeMode; pub const CompareOutputContext = struct { - b: *build.Builder, - step: *build.Step, + b: *std.Build, + step: *std.Build.Step, test_index: usize, test_filter: ?[]const u8, optimize_modes: []const OptimizeMode, diff --git a/test/src/run_translated_c.zig b/test/src/run_translated_c.zig index 0c54655b32bfe8695efd9af2644adc02c91ed5ae..2103172ed6885b2a854bfeea545d2156537300c7 100644 --- a/test/src/run_translated_c.zig +++ b/test/src/run_translated_c.zig @@ -1,15 +1,14 @@ // This is the implementation of the test harness for running translated // C code. For the actual test cases, see test/run_translated_c.zig. const std = @import("std"); -const build = std.build; const ArrayList = std.ArrayList; const fmt = std.fmt; const mem = std.mem; const fs = std.fs; pub const RunTranslatedCContext = struct { - b: *build.Builder, - step: *build.Step, + b: *std.Build, + step: *std.Build.Step, test_index: usize, test_filter: ?[]const u8, target: std.zig.CrossTarget, diff --git a/test/src/translate_c.zig b/test/src/translate_c.zig index ad5fbb709140afd5d455cfb0e2eb4a4f5e3b5d78..e275ee57ee1742f8b066eae15c3d2199325d4b58 100644 --- a/test/src/translate_c.zig +++ b/test/src/translate_c.zig @@ -1,7 +1,6 @@ // This is the implementation of the test harness. // For the actual test cases, see test/translate_c.zig. const std = @import("std"); -const build = std.build; const ArrayList = std.ArrayList; const fmt = std.fmt; const mem = std.mem; @@ -9,8 +8,8 @@ const fs = std.fs; const CrossTarget = std.zig.CrossTarget; pub const TranslateCContext = struct { - b: *build.Builder, - step: *build.Step, + b: *std.Build, + step: *std.Build.Step, test_index: usize, test_filter: ?[]const u8, diff --git a/test/standalone/brace_expansion/build.zig b/test/standalone/brace_expansion/build.zig index 89250ff96fe489da24d7b968c26d0b3cf9a938a5..7c32a09befcb7da92767d5e98d45d3240f354344 100644 --- a/test/standalone/brace_expansion/build.zig +++ b/test/standalone/brace_expansion/build.zig @@ -1,6 +1,6 @@ -const Builder = @import("std").build.Builder; +const std = @import("std"); -pub fn build(b: *Builder) void { +pub fn build(b: *std.Build) void { const main = b.addTest(.{ .root_source_file = .{ .path = "main.zig" }, .optimize = b.standardOptimizeOption(.{}), diff --git a/test/standalone/c_compiler/build.zig b/test/standalone/c_compiler/build.zig index 6959f810d63fbebe247cdea393206d8067a6a83d..dce999d4a22ec429e1a73ac99c30ac732c31f06d 100644 --- a/test/standalone/c_compiler/build.zig +++ b/test/standalone/c_compiler/build.zig @@ -1,9 +1,8 @@ const std = @import("std"); const builtin = @import("builtin"); -const Builder = std.build.Builder; const CrossTarget = std.zig.CrossTarget; -// TODO integrate this with the std.build executor API +// TODO integrate this with the std.Build executor API fn isRunnableTarget(t: CrossTarget) bool { if (t.isNative()) return true; @@ -11,7 +10,7 @@ fn isRunnableTarget(t: CrossTarget) bool { t.getCpuArch() == builtin.cpu.arch); } -pub fn build(b: *Builder) void { +pub fn build(b: *std.Build) void { const optimize = b.standardOptimizeOption(.{}); const target = b.standardTargetOptions(.{}); diff --git a/test/standalone/emit_asm_and_bin/build.zig b/test/standalone/emit_asm_and_bin/build.zig index b8cbd5fc176152616ef08f966c5da80cc79eb25b..5345f0f5387feb7f92c13d4c2b8adec59c710e1c 100644 --- a/test/standalone/emit_asm_and_bin/build.zig +++ b/test/standalone/emit_asm_and_bin/build.zig @@ -1,6 +1,6 @@ -const Builder = @import("std").build.Builder; +const std = @import("std"); -pub fn build(b: *Builder) void { +pub fn build(b: *std.Build) void { const main = b.addTest(.{ .root_source_file = .{ .path = "main.zig" }, .optimize = b.standardOptimizeOption(.{}), diff --git a/test/standalone/empty_env/build.zig b/test/standalone/empty_env/build.zig index ecdd74aa90c81227f5d007a7d5584f4aadbacde6..c4b48461410f26c461a6ea53ad9822d1ab9ed8f7 100644 --- a/test/standalone/empty_env/build.zig +++ b/test/standalone/empty_env/build.zig @@ -1,6 +1,6 @@ -const Builder = @import("std").build.Builder; +const std = @import("std"); -pub fn build(b: *Builder) void { +pub fn build(b: *std.Build) void { const main = b.addExecutable(.{ .name = "main", .root_source_file = .{ .path = "main.zig" }, diff --git a/test/standalone/global_linkage/build.zig b/test/standalone/global_linkage/build.zig index 3064c6cc084ef49d3c7e6867c243bcdb8b0b8086..9f79c80fcf60735078641c95e36eb0dda96995e6 100644 --- a/test/standalone/global_linkage/build.zig +++ b/test/standalone/global_linkage/build.zig @@ -1,6 +1,6 @@ -const Builder = @import("std").build.Builder; +const std = @import("std"); -pub fn build(b: *Builder) void { +pub fn build(b: *std.Build) void { const optimize = b.standardOptimizeOption(.{}); const obj1 = b.addStaticLibrary(.{ diff --git a/test/standalone/install_raw_hex/build.zig b/test/standalone/install_raw_hex/build.zig index 94016b1d747bddbfe14c0fe247337ca100e6d254..b0f938a34432affefd78e746448306f888806622 100644 --- a/test/standalone/install_raw_hex/build.zig +++ b/test/standalone/install_raw_hex/build.zig @@ -1,8 +1,8 @@ const builtin = @import("builtin"); const std = @import("std"); -const CheckFileStep = std.build.CheckFileStep; +const CheckFileStep = std.Build.CheckFileStep; -pub fn build(b: *std.build.Builder) void { +pub fn build(b: *std.Build) void { const target = .{ .cpu_arch = .thumb, .cpu_model = .{ .explicit = &std.Target.arm.cpu.cortex_m4 }, diff --git a/test/standalone/issue_11595/build.zig b/test/standalone/issue_11595/build.zig index b0310947f67394078fb4fac09696170ccafd8cea..c335fb73dafe4e8c47feeeb046f609c2de4e8b90 100644 --- a/test/standalone/issue_11595/build.zig +++ b/test/standalone/issue_11595/build.zig @@ -1,9 +1,8 @@ const std = @import("std"); const builtin = @import("builtin"); -const Builder = std.build.Builder; const CrossTarget = std.zig.CrossTarget; -// TODO integrate this with the std.build executor API +// TODO integrate this with the std.Build executor API fn isRunnableTarget(t: CrossTarget) bool { if (t.isNative()) return true; @@ -11,7 +10,7 @@ fn isRunnableTarget(t: CrossTarget) bool { t.getCpuArch() == builtin.cpu.arch); } -pub fn build(b: *Builder) void { +pub fn build(b: *std.Build) void { const optimize = b.standardOptimizeOption(.{}); const target = b.standardTargetOptions(.{}); diff --git a/test/standalone/issue_12588/build.zig b/test/standalone/issue_12588/build.zig index 27a23d5a76f1c6a5a0347dedcc02f5ca6b4dba59..9f14c53e38684c54c9dee896a13442ef44c02a35 100644 --- a/test/standalone/issue_12588/build.zig +++ b/test/standalone/issue_12588/build.zig @@ -1,7 +1,6 @@ const std = @import("std"); -const Builder = std.build.Builder; -pub fn build(b: *Builder) void { +pub fn build(b: *std.Build) void { const optimize = b.standardOptimizeOption(.{}); const target = b.standardTargetOptions(.{}); diff --git a/test/standalone/issue_12706/build.zig b/test/standalone/issue_12706/build.zig index e3c40d34c6c4ea8e30acfb6c3ebc39dd178dc590..9d616477a2c7d4c546cc3ae940b80991cf7415df 100644 --- a/test/standalone/issue_12706/build.zig +++ b/test/standalone/issue_12706/build.zig @@ -1,9 +1,8 @@ const std = @import("std"); const builtin = @import("builtin"); -const Builder = std.build.Builder; const CrossTarget = std.zig.CrossTarget; -// TODO integrate this with the std.build executor API +// TODO integrate this with the std.Build executor API fn isRunnableTarget(t: CrossTarget) bool { if (t.isNative()) return true; @@ -11,7 +10,7 @@ fn isRunnableTarget(t: CrossTarget) bool { t.getCpuArch() == builtin.cpu.arch); } -pub fn build(b: *Builder) void { +pub fn build(b: *std.Build) void { const optimize = b.standardOptimizeOption(.{}); const target = b.standardTargetOptions(.{}); diff --git a/test/standalone/issue_13030/build.zig b/test/standalone/issue_13030/build.zig index 510c7610d9c2c61e9847322c6732c84e65e016ae..258d9b7db8a3e564b9819487f6563a45c9755da5 100644 --- a/test/standalone/issue_13030/build.zig +++ b/test/standalone/issue_13030/build.zig @@ -1,9 +1,8 @@ const std = @import("std"); const builtin = @import("builtin"); -const Builder = std.build.Builder; const CrossTarget = std.zig.CrossTarget; -pub fn build(b: *Builder) void { +pub fn build(b: *std.Build) void { const optimize = b.standardOptimizeOption(.{}); const target = b.standardTargetOptions(.{}); diff --git a/test/standalone/issue_339/build.zig b/test/standalone/issue_339/build.zig index 34c555cfdbc91e8f786189efcb977dd36565b415..62ac128aabd748a0a8bd586c14f7b1bf159a441c 100644 --- a/test/standalone/issue_339/build.zig +++ b/test/standalone/issue_339/build.zig @@ -1,6 +1,6 @@ -const Builder = @import("std").build.Builder; +const std = @import("std"); -pub fn build(b: *Builder) void { +pub fn build(b: *std.Build) void { const obj = b.addObject(.{ .name = "test", .root_source_file = .{ .path = "test.zig" }, diff --git a/test/standalone/issue_5825/build.zig b/test/standalone/issue_5825/build.zig index 8d7acc3e9a7e30ef20cf904183cccfe86dd01408..89272280d4e46fc26334bc498f9a6234b8e8dc32 100644 --- a/test/standalone/issue_5825/build.zig +++ b/test/standalone/issue_5825/build.zig @@ -1,6 +1,6 @@ -const Builder = @import("std").build.Builder; +const std = @import("std"); -pub fn build(b: *Builder) void { +pub fn build(b: *std.Build) void { const target = .{ .cpu_arch = .x86_64, .os_tag = .windows, diff --git a/test/standalone/issue_7030/build.zig b/test/standalone/issue_7030/build.zig index 41a646abe8469870e4fe4a979c0a341c85a91bfd..dc535318ccb503bd59d2b62c36585a5d89d71a87 100644 --- a/test/standalone/issue_7030/build.zig +++ b/test/standalone/issue_7030/build.zig @@ -1,6 +1,6 @@ -const Builder = @import("std").build.Builder; +const std = @import("std"); -pub fn build(b: *Builder) void { +pub fn build(b: *std.Build) void { const exe = b.addExecutable(.{ .name = "issue_7030", .root_source_file = .{ .path = "main.zig" }, diff --git a/test/standalone/issue_794/build.zig b/test/standalone/issue_794/build.zig index 59ff7ea9abd73805af066b86741c1c6e5f29f687..3089a28fd012dabc88fb80c6bd36b4252a1ccc7c 100644 --- a/test/standalone/issue_794/build.zig +++ b/test/standalone/issue_794/build.zig @@ -1,6 +1,6 @@ -const Builder = @import("std").build.Builder; +const std = @import("std"); -pub fn build(b: *Builder) void { +pub fn build(b: *std.Build) void { const test_artifact = b.addTest(.{ .root_source_file = .{ .path = "main.zig" }, }); diff --git a/test/standalone/issue_8550/build.zig b/test/standalone/issue_8550/build.zig index 233f701661315fb30879c2dba25bb34b99095b39..c3303d55db5e21fa82bc387f80a1846e5bd5f109 100644 --- a/test/standalone/issue_8550/build.zig +++ b/test/standalone/issue_8550/build.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn build(b: *std.build.Builder) !void { +pub fn build(b: *std.Build) !void { const target = std.zig.CrossTarget{ .os_tag = .freestanding, .cpu_arch = .arm, diff --git a/test/standalone/issue_9812/build.zig b/test/standalone/issue_9812/build.zig index 50eefe846c52d4e3609d8e9b9d2149bf84aa2e67..4ca55ce999192242cb78205d066c3985017d2538 100644 --- a/test/standalone/issue_9812/build.zig +++ b/test/standalone/issue_9812/build.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn build(b: *std.build.Builder) !void { +pub fn build(b: *std.Build) !void { const optimize = b.standardOptimizeOption(.{}); const zip_add = b.addTest(.{ .root_source_file = .{ .path = "main.zig" }, diff --git a/test/standalone/load_dynamic_library/build.zig b/test/standalone/load_dynamic_library/build.zig index 1aca02bc715f5967b465f0d00968a436d5af918c..44fc37893cea873188fdc97232c9d6728aa20280 100644 --- a/test/standalone/load_dynamic_library/build.zig +++ b/test/standalone/load_dynamic_library/build.zig @@ -1,6 +1,6 @@ -const Builder = @import("std").build.Builder; +const std = @import("std"); -pub fn build(b: *Builder) void { +pub fn build(b: *std.Build) void { const target = b.standardTargetOptions(.{}); const optimize = b.standardOptimizeOption(.{}); diff --git a/test/standalone/main_pkg_path/build.zig b/test/standalone/main_pkg_path/build.zig index baee74052edde7ccd9a565d52bb5e2ef0f81dafe..f9919d5ab57af4c3d3356b50a51ec890d72df62d 100644 --- a/test/standalone/main_pkg_path/build.zig +++ b/test/standalone/main_pkg_path/build.zig @@ -1,6 +1,6 @@ -const Builder = @import("std").build.Builder; +const std = @import("std"); -pub fn build(b: *Builder) void { +pub fn build(b: *std.Build) void { const test_exe = b.addTest(.{ .root_source_file = .{ .path = "a/test.zig" }, }); diff --git a/test/standalone/mix_c_files/build.zig b/test/standalone/mix_c_files/build.zig index ad69f05ff65630eea871d26900454eb319cd5756..f2dfb2093f10ec0cab970a0a5198b98c179a8b34 100644 --- a/test/standalone/mix_c_files/build.zig +++ b/test/standalone/mix_c_files/build.zig @@ -1,9 +1,8 @@ const std = @import("std"); const builtin = @import("builtin"); -const Builder = std.build.Builder; const CrossTarget = std.zig.CrossTarget; -// TODO integrate this with the std.build executor API +// TODO integrate this with the std.Build executor API fn isRunnableTarget(t: CrossTarget) bool { if (t.isNative()) return true; @@ -11,7 +10,7 @@ fn isRunnableTarget(t: CrossTarget) bool { t.getCpuArch() == builtin.cpu.arch); } -pub fn build(b: *Builder) void { +pub fn build(b: *std.Build) void { const optimize = b.standardOptimizeOption(.{}); const target = b.standardTargetOptions(.{}); diff --git a/test/standalone/mix_o_files/build.zig b/test/standalone/mix_o_files/build.zig index de3726538825e2e19a3da5305dfbdce07c1444ca..2708343aa5a942274f7f929f223e58f0a5164f0e 100644 --- a/test/standalone/mix_o_files/build.zig +++ b/test/standalone/mix_o_files/build.zig @@ -1,6 +1,6 @@ -const Builder = @import("std").build.Builder; +const std = @import("std"); -pub fn build(b: *Builder) void { +pub fn build(b: *std.Build) void { const optimize = b.standardOptimizeOption(.{}); const obj = b.addObject(.{ diff --git a/test/standalone/options/build.zig b/test/standalone/options/build.zig index 87a584a8875e65be4171052edafe2a817a67b18f..3f1e823359b5b229ea09a6557628063477b1d786 100644 --- a/test/standalone/options/build.zig +++ b/test/standalone/options/build.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn build(b: *std.build.Builder) void { +pub fn build(b: *std.Build) void { const target = b.standardTargetOptions(.{}); const optimize = b.standardOptimizeOption(.{}); diff --git a/test/standalone/pie/build.zig b/test/standalone/pie/build.zig index 3f0b8b9f2f2287b319b0f5d9f50ebcbecaf86637..d51ea27328c9e183db4308daf8ddbe51fb03d32d 100644 --- a/test/standalone/pie/build.zig +++ b/test/standalone/pie/build.zig @@ -1,6 +1,6 @@ -const Builder = @import("std").build.Builder; +const std = @import("std"); -pub fn build(b: *Builder) void { +pub fn build(b: *std.Build) void { const main = b.addTest(.{ .root_source_file = .{ .path = "main.zig" }, .optimize = b.standardOptimizeOption(.{}), diff --git a/test/standalone/pkg_import/build.zig b/test/standalone/pkg_import/build.zig index 8dcfaeded00b10fd33e1d1c37f4479f7c868aa3e..5fbc8a67ae7834047ba6b0c636143d3827fd2c41 100644 --- a/test/standalone/pkg_import/build.zig +++ b/test/standalone/pkg_import/build.zig @@ -1,6 +1,6 @@ -const Builder = @import("std").build.Builder; +const std = @import("std"); -pub fn build(b: *Builder) void { +pub fn build(b: *std.Build) void { const optimize = b.standardOptimizeOption(.{}); const exe = b.addExecutable(.{ diff --git a/test/standalone/shared_library/build.zig b/test/standalone/shared_library/build.zig index 135be095bc36385a4223309730aca18499a45963..91f7c8a06a674c6ba1ac1f492428cab0ec3ca89f 100644 --- a/test/standalone/shared_library/build.zig +++ b/test/standalone/shared_library/build.zig @@ -1,6 +1,6 @@ -const Builder = @import("std").build.Builder; +const std = @import("std"); -pub fn build(b: *Builder) void { +pub fn build(b: *std.Build) void { const optimize = b.standardOptimizeOption(.{}); const target = b.standardTargetOptions(.{}); const lib = b.addSharedLibrary(.{ diff --git a/test/standalone/static_c_lib/build.zig b/test/standalone/static_c_lib/build.zig index 81b4349e20f731b8bca00068a52d0e9828463e31..99378888433e48a65b6783440a53e1a5502d3049 100644 --- a/test/standalone/static_c_lib/build.zig +++ b/test/standalone/static_c_lib/build.zig @@ -1,6 +1,6 @@ -const Builder = @import("std").build.Builder; +const std = @import("std"); -pub fn build(b: *Builder) void { +pub fn build(b: *std.Build) void { const optimize = b.standardOptimizeOption(.{}); const foo = b.addStaticLibrary(.{ diff --git a/test/standalone/test_runner_path/build.zig b/test/standalone/test_runner_path/build.zig index 9b02da50c1d87775d13b77a715a2f151b33f780f..f073c55d4a320b124d31f0a405ab6aa23bd9d692 100644 --- a/test/standalone/test_runner_path/build.zig +++ b/test/standalone/test_runner_path/build.zig @@ -1,6 +1,6 @@ -const Builder = @import("std").build.Builder; +const std = @import("std"); -pub fn build(b: *Builder) void { +pub fn build(b: *std.Build) void { const test_exe = b.addTest(.{ .root_source_file = .{ .path = "test.zig" }, .kind = .test_exe, diff --git a/test/standalone/use_alias/build.zig b/test/standalone/use_alias/build.zig index d2ca90f3abff15df958ca5cf27a056b9c085f037..89e07efb22ccea09181c7140aafa5346e61832b0 100644 --- a/test/standalone/use_alias/build.zig +++ b/test/standalone/use_alias/build.zig @@ -1,6 +1,6 @@ -const Builder = @import("std").build.Builder; +const std = @import("std"); -pub fn build(b: *Builder) void { +pub fn build(b: *std.Build) void { const main = b.addTest(.{ .root_source_file = .{ .path = "main.zig" }, .optimize = b.standardOptimizeOption(.{}), diff --git a/test/standalone/windows_spawn/build.zig b/test/standalone/windows_spawn/build.zig index de58a602c3e38516951495807d1a891674f6a835..3ebde5a50c825d91c6f6c93950e7f0f5cf658200 100644 --- a/test/standalone/windows_spawn/build.zig +++ b/test/standalone/windows_spawn/build.zig @@ -1,6 +1,6 @@ -const Builder = @import("std").build.Builder; +const std = @import("std"); -pub fn build(b: *Builder) void { +pub fn build(b: *std.Build) void { const optimize = b.standardOptimizeOption(.{}); const hello = b.addExecutable(.{ diff --git a/test/tests.zig b/test/tests.zig index 575550be0275fdb69f1b820a69d5899110b137c6..de25528dde06ed0bf7dad0701d1c1ae7203f06ec 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -1,7 +1,6 @@ const std = @import("std"); const builtin = @import("builtin"); const debug = std.debug; -const build = std.build; const CrossTarget = std.zig.CrossTarget; const io = std.io; const fs = std.fs; @@ -9,9 +8,10 @@ const mem = std.mem; const fmt = std.fmt; const ArrayList = std.ArrayList; const OptimizeMode = std.builtin.OptimizeMode; -const LibExeObjStep = build.LibExeObjStep; +const LibExeObjStep = std.Build.LibExeObjStep; const Allocator = mem.Allocator; -const ExecError = build.Builder.ExecError; +const ExecError = std.Build.ExecError; +const Step = std.Build.Step; // Cases const compare_output = @import("compare_output.zig"); @@ -462,7 +462,7 @@ const test_targets = blk: { const max_stdout_size = 1 * 1024 * 1024; // 1 MB -pub fn addCompareOutputTests(b: *build.Builder, test_filter: ?[]const u8, optimize_modes: []const OptimizeMode) *build.Step { +pub fn addCompareOutputTests(b: *std.Build, test_filter: ?[]const u8, optimize_modes: []const OptimizeMode) *Step { const cases = b.allocator.create(CompareOutputContext) catch unreachable; cases.* = CompareOutputContext{ .b = b, @@ -477,7 +477,7 @@ pub fn addCompareOutputTests(b: *build.Builder, test_filter: ?[]const u8, optimi return cases.step; } -pub fn addStackTraceTests(b: *build.Builder, test_filter: ?[]const u8, optimize_modes: []const OptimizeMode) *build.Step { +pub fn addStackTraceTests(b: *std.Build, test_filter: ?[]const u8, optimize_modes: []const OptimizeMode) *Step { const cases = b.allocator.create(StackTracesContext) catch unreachable; cases.* = StackTracesContext{ .b = b, @@ -493,7 +493,7 @@ pub fn addStackTraceTests(b: *build.Builder, test_filter: ?[]const u8, optimize_ } pub fn addStandaloneTests( - b: *build.Builder, + b: *std.Build, test_filter: ?[]const u8, optimize_modes: []const OptimizeMode, skip_non_native: bool, @@ -506,7 +506,7 @@ pub fn addStandaloneTests( enable_wasmtime: bool, enable_wine: bool, enable_symlinks_windows: bool, -) *build.Step { +) *Step { const cases = b.allocator.create(StandaloneContext) catch unreachable; cases.* = StandaloneContext{ .b = b, @@ -532,13 +532,13 @@ pub fn addStandaloneTests( } pub fn addLinkTests( - b: *build.Builder, + b: *std.Build, test_filter: ?[]const u8, optimize_modes: []const OptimizeMode, enable_macos_sdk: bool, omit_stage2: bool, enable_symlinks_windows: bool, -) *build.Step { +) *Step { const cases = b.allocator.create(StandaloneContext) catch unreachable; cases.* = StandaloneContext{ .b = b, @@ -556,7 +556,7 @@ pub fn addLinkTests( return cases.step; } -pub fn addCliTests(b: *build.Builder, test_filter: ?[]const u8, optimize_modes: []const OptimizeMode) *build.Step { +pub fn addCliTests(b: *std.Build, test_filter: ?[]const u8, optimize_modes: []const OptimizeMode) *Step { _ = test_filter; _ = optimize_modes; const step = b.step("test-cli", "Test the command line interface"); @@ -577,7 +577,7 @@ pub fn addCliTests(b: *build.Builder, test_filter: ?[]const u8, optimize_modes: return step; } -pub fn addAssembleAndLinkTests(b: *build.Builder, test_filter: ?[]const u8, optimize_modes: []const OptimizeMode) *build.Step { +pub fn addAssembleAndLinkTests(b: *std.Build, test_filter: ?[]const u8, optimize_modes: []const OptimizeMode) *Step { const cases = b.allocator.create(CompareOutputContext) catch unreachable; cases.* = CompareOutputContext{ .b = b, @@ -592,7 +592,7 @@ pub fn addAssembleAndLinkTests(b: *build.Builder, test_filter: ?[]const u8, opti return cases.step; } -pub fn addTranslateCTests(b: *build.Builder, test_filter: ?[]const u8) *build.Step { +pub fn addTranslateCTests(b: *std.Build, test_filter: ?[]const u8) *Step { const cases = b.allocator.create(TranslateCContext) catch unreachable; cases.* = TranslateCContext{ .b = b, @@ -607,10 +607,10 @@ pub fn addTranslateCTests(b: *build.Builder, test_filter: ?[]const u8) *build.St } pub fn addRunTranslatedCTests( - b: *build.Builder, + b: *std.Build, test_filter: ?[]const u8, target: std.zig.CrossTarget, -) *build.Step { +) *Step { const cases = b.allocator.create(RunTranslatedCContext) catch unreachable; cases.* = .{ .b = b, @@ -625,7 +625,7 @@ pub fn addRunTranslatedCTests( return cases.step; } -pub fn addGenHTests(b: *build.Builder, test_filter: ?[]const u8) *build.Step { +pub fn addGenHTests(b: *std.Build, test_filter: ?[]const u8) *Step { const cases = b.allocator.create(GenHContext) catch unreachable; cases.* = GenHContext{ .b = b, @@ -640,7 +640,7 @@ pub fn addGenHTests(b: *build.Builder, test_filter: ?[]const u8) *build.Step { } pub fn addPkgTests( - b: *build.Builder, + b: *std.Build, test_filter: ?[]const u8, root_src: []const u8, name: []const u8, @@ -651,7 +651,7 @@ pub fn addPkgTests( skip_libc: bool, skip_stage1: bool, skip_stage2: bool, -) *build.Step { +) *Step { const step = b.step(b.fmt("test-{s}", .{name}), desc); for (test_targets) |test_target| { @@ -742,8 +742,8 @@ pub fn addPkgTests( } pub const StackTracesContext = struct { - b: *build.Builder, - step: *build.Step, + b: *std.Build, + step: *Step, test_index: usize, test_filter: ?[]const u8, optimize_modes: []const OptimizeMode, @@ -840,7 +840,7 @@ pub const StackTracesContext = struct { const RunAndCompareStep = struct { pub const base_id = .custom; - step: build.Step, + step: Step, context: *StackTracesContext, exe: *LibExeObjStep, name: []const u8, @@ -858,7 +858,7 @@ pub const StackTracesContext = struct { const allocator = context.b.allocator; const ptr = allocator.create(RunAndCompareStep) catch unreachable; ptr.* = RunAndCompareStep{ - .step = build.Step.init(.custom, "StackTraceCompareOutputStep", allocator, make), + .step = Step.init(.custom, "StackTraceCompareOutputStep", allocator, make), .context = context, .exe = exe, .name = name, @@ -871,7 +871,7 @@ pub const StackTracesContext = struct { return ptr; } - fn make(step: *build.Step) !void { + fn make(step: *Step) !void { const self = @fieldParentPtr(RunAndCompareStep, "step", step); const b = self.context.b; @@ -1014,8 +1014,8 @@ pub const StackTracesContext = struct { }; pub const StandaloneContext = struct { - b: *build.Builder, - step: *build.Step, + b: *std.Build, + step: *Step, test_index: usize, test_filter: ?[]const u8, optimize_modes: []const OptimizeMode, @@ -1150,8 +1150,8 @@ pub const StandaloneContext = struct { }; pub const GenHContext = struct { - b: *build.Builder, - step: *build.Step, + b: *std.Build, + step: *Step, test_index: usize, test_filter: ?[]const u8, @@ -1178,7 +1178,7 @@ pub const GenHContext = struct { }; const GenHCmpOutputStep = struct { - step: build.Step, + step: Step, context: *GenHContext, obj: *LibExeObjStep, name: []const u8, @@ -1194,7 +1194,7 @@ pub const GenHContext = struct { const allocator = context.b.allocator; const ptr = allocator.create(GenHCmpOutputStep) catch unreachable; ptr.* = GenHCmpOutputStep{ - .step = build.Step.init(.Custom, "ParseCCmpOutput", allocator, make), + .step = Step.init(.Custom, "ParseCCmpOutput", allocator, make), .context = context, .obj = obj, .name = name, @@ -1206,7 +1206,7 @@ pub const GenHContext = struct { return ptr; } - fn make(step: *build.Step) !void { + fn make(step: *Step) !void { const self = @fieldParentPtr(GenHCmpOutputStep, "step", step); const b = self.context.b; @@ -1348,7 +1348,7 @@ const c_abi_targets = [_]CrossTarget{ }, }; -pub fn addCAbiTests(b: *build.Builder, skip_non_native: bool, skip_release: bool) *build.Step { +pub fn addCAbiTests(b: *std.Build, skip_non_native: bool, skip_release: bool) *Step { const step = b.step("test-c-abi", "Run the C ABI tests"); const optimize_modes: [2]OptimizeMode = .{ .Debug, .ReleaseFast }; -- 2.54.0 From 60c4befad39a1e1689872bc78dd1b8f8d5c34887 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 31 Jan 2023 00:20:37 -0700 Subject: [PATCH 48/84] build.zig: remove dead list of unused source files --- build.zig | 160 ------------------------------------------------------ 1 file changed, 160 deletions(-) diff --git a/build.zig b/build.zig index 6b6c384fc4b81d1cb60a9bb44b2004871bc4bf5f..713eac6517e6a3571e51dc33ee1f480ccee66eac 100644 --- a/build.zig +++ b/build.zig @@ -870,166 +870,6 @@ fn toNativePathSep(b: *std.Build, s: []const u8) []u8 { return duplicated; } -const softfloat_sources = [_][]const u8{ - "deps/SoftFloat-3e/source/8086/f128M_isSignalingNaN.c", - "deps/SoftFloat-3e/source/8086/extF80M_isSignalingNaN.c", - "deps/SoftFloat-3e/source/8086/s_commonNaNToF128M.c", - "deps/SoftFloat-3e/source/8086/s_commonNaNToExtF80M.c", - "deps/SoftFloat-3e/source/8086/s_commonNaNToF16UI.c", - "deps/SoftFloat-3e/source/8086/s_commonNaNToF32UI.c", - "deps/SoftFloat-3e/source/8086/s_commonNaNToF64UI.c", - "deps/SoftFloat-3e/source/8086/s_f128MToCommonNaN.c", - "deps/SoftFloat-3e/source/8086/s_extF80MToCommonNaN.c", - "deps/SoftFloat-3e/source/8086/s_f16UIToCommonNaN.c", - "deps/SoftFloat-3e/source/8086/s_f32UIToCommonNaN.c", - "deps/SoftFloat-3e/source/8086/s_f64UIToCommonNaN.c", - "deps/SoftFloat-3e/source/8086/s_propagateNaNF128M.c", - "deps/SoftFloat-3e/source/8086/s_propagateNaNExtF80M.c", - "deps/SoftFloat-3e/source/8086/s_propagateNaNF16UI.c", - "deps/SoftFloat-3e/source/8086/softfloat_raiseFlags.c", - "deps/SoftFloat-3e/source/f128M_add.c", - "deps/SoftFloat-3e/source/f128M_div.c", - "deps/SoftFloat-3e/source/f128M_eq.c", - "deps/SoftFloat-3e/source/f128M_eq_signaling.c", - "deps/SoftFloat-3e/source/f128M_le.c", - "deps/SoftFloat-3e/source/f128M_le_quiet.c", - "deps/SoftFloat-3e/source/f128M_lt.c", - "deps/SoftFloat-3e/source/f128M_lt_quiet.c", - "deps/SoftFloat-3e/source/f128M_mul.c", - "deps/SoftFloat-3e/source/f128M_mulAdd.c", - "deps/SoftFloat-3e/source/f128M_rem.c", - "deps/SoftFloat-3e/source/f128M_roundToInt.c", - "deps/SoftFloat-3e/source/f128M_sqrt.c", - "deps/SoftFloat-3e/source/f128M_sub.c", - "deps/SoftFloat-3e/source/f128M_to_f16.c", - "deps/SoftFloat-3e/source/f128M_to_f32.c", - "deps/SoftFloat-3e/source/f128M_to_f64.c", - "deps/SoftFloat-3e/source/f128M_to_extF80M.c", - "deps/SoftFloat-3e/source/f128M_to_i32.c", - "deps/SoftFloat-3e/source/f128M_to_i32_r_minMag.c", - "deps/SoftFloat-3e/source/f128M_to_i64.c", - "deps/SoftFloat-3e/source/f128M_to_i64_r_minMag.c", - "deps/SoftFloat-3e/source/f128M_to_ui32.c", - "deps/SoftFloat-3e/source/f128M_to_ui32_r_minMag.c", - "deps/SoftFloat-3e/source/f128M_to_ui64.c", - "deps/SoftFloat-3e/source/f128M_to_ui64_r_minMag.c", - "deps/SoftFloat-3e/source/extF80M_add.c", - "deps/SoftFloat-3e/source/extF80M_div.c", - "deps/SoftFloat-3e/source/extF80M_eq.c", - "deps/SoftFloat-3e/source/extF80M_le.c", - "deps/SoftFloat-3e/source/extF80M_lt.c", - "deps/SoftFloat-3e/source/extF80M_mul.c", - "deps/SoftFloat-3e/source/extF80M_rem.c", - "deps/SoftFloat-3e/source/extF80M_roundToInt.c", - "deps/SoftFloat-3e/source/extF80M_sqrt.c", - "deps/SoftFloat-3e/source/extF80M_sub.c", - "deps/SoftFloat-3e/source/extF80M_to_f16.c", - "deps/SoftFloat-3e/source/extF80M_to_f32.c", - "deps/SoftFloat-3e/source/extF80M_to_f64.c", - "deps/SoftFloat-3e/source/extF80M_to_f128M.c", - "deps/SoftFloat-3e/source/f16_add.c", - "deps/SoftFloat-3e/source/f16_div.c", - "deps/SoftFloat-3e/source/f16_eq.c", - "deps/SoftFloat-3e/source/f16_isSignalingNaN.c", - "deps/SoftFloat-3e/source/f16_lt.c", - "deps/SoftFloat-3e/source/f16_mul.c", - "deps/SoftFloat-3e/source/f16_mulAdd.c", - "deps/SoftFloat-3e/source/f16_rem.c", - "deps/SoftFloat-3e/source/f16_roundToInt.c", - "deps/SoftFloat-3e/source/f16_sqrt.c", - "deps/SoftFloat-3e/source/f16_sub.c", - "deps/SoftFloat-3e/source/f16_to_extF80M.c", - "deps/SoftFloat-3e/source/f16_to_f128M.c", - "deps/SoftFloat-3e/source/f16_to_f64.c", - "deps/SoftFloat-3e/source/f32_to_extF80M.c", - "deps/SoftFloat-3e/source/f32_to_f128M.c", - "deps/SoftFloat-3e/source/f64_to_extF80M.c", - "deps/SoftFloat-3e/source/f64_to_f128M.c", - "deps/SoftFloat-3e/source/f64_to_f16.c", - "deps/SoftFloat-3e/source/i32_to_f128M.c", - "deps/SoftFloat-3e/source/s_add256M.c", - "deps/SoftFloat-3e/source/s_addCarryM.c", - "deps/SoftFloat-3e/source/s_addComplCarryM.c", - "deps/SoftFloat-3e/source/s_addF128M.c", - "deps/SoftFloat-3e/source/s_addExtF80M.c", - "deps/SoftFloat-3e/source/s_addM.c", - "deps/SoftFloat-3e/source/s_addMagsF16.c", - "deps/SoftFloat-3e/source/s_addMagsF32.c", - "deps/SoftFloat-3e/source/s_addMagsF64.c", - "deps/SoftFloat-3e/source/s_approxRecip32_1.c", - "deps/SoftFloat-3e/source/s_approxRecipSqrt32_1.c", - "deps/SoftFloat-3e/source/s_approxRecipSqrt_1Ks.c", - "deps/SoftFloat-3e/source/s_approxRecip_1Ks.c", - "deps/SoftFloat-3e/source/s_compare128M.c", - "deps/SoftFloat-3e/source/s_compare96M.c", - "deps/SoftFloat-3e/source/s_compareNonnormExtF80M.c", - "deps/SoftFloat-3e/source/s_countLeadingZeros16.c", - "deps/SoftFloat-3e/source/s_countLeadingZeros32.c", - "deps/SoftFloat-3e/source/s_countLeadingZeros64.c", - "deps/SoftFloat-3e/source/s_countLeadingZeros8.c", - "deps/SoftFloat-3e/source/s_eq128.c", - "deps/SoftFloat-3e/source/s_invalidF128M.c", - "deps/SoftFloat-3e/source/s_invalidExtF80M.c", - "deps/SoftFloat-3e/source/s_isNaNF128M.c", - "deps/SoftFloat-3e/source/s_le128.c", - "deps/SoftFloat-3e/source/s_lt128.c", - "deps/SoftFloat-3e/source/s_mul128MTo256M.c", - "deps/SoftFloat-3e/source/s_mul64To128M.c", - "deps/SoftFloat-3e/source/s_mulAddF128M.c", - "deps/SoftFloat-3e/source/s_mulAddF16.c", - "deps/SoftFloat-3e/source/s_mulAddF32.c", - "deps/SoftFloat-3e/source/s_mulAddF64.c", - "deps/SoftFloat-3e/source/s_negXM.c", - "deps/SoftFloat-3e/source/s_normExtF80SigM.c", - "deps/SoftFloat-3e/source/s_normRoundPackMToF128M.c", - "deps/SoftFloat-3e/source/s_normRoundPackMToExtF80M.c", - "deps/SoftFloat-3e/source/s_normRoundPackToF16.c", - "deps/SoftFloat-3e/source/s_normRoundPackToF32.c", - "deps/SoftFloat-3e/source/s_normRoundPackToF64.c", - "deps/SoftFloat-3e/source/s_normSubnormalF128SigM.c", - "deps/SoftFloat-3e/source/s_normSubnormalF16Sig.c", - "deps/SoftFloat-3e/source/s_normSubnormalF32Sig.c", - "deps/SoftFloat-3e/source/s_normSubnormalF64Sig.c", - "deps/SoftFloat-3e/source/s_remStepMBy32.c", - "deps/SoftFloat-3e/source/s_roundMToI64.c", - "deps/SoftFloat-3e/source/s_roundMToUI64.c", - "deps/SoftFloat-3e/source/s_roundPackMToExtF80M.c", - "deps/SoftFloat-3e/source/s_roundPackMToF128M.c", - "deps/SoftFloat-3e/source/s_roundPackToF16.c", - "deps/SoftFloat-3e/source/s_roundPackToF32.c", - "deps/SoftFloat-3e/source/s_roundPackToF64.c", - "deps/SoftFloat-3e/source/s_roundToI32.c", - "deps/SoftFloat-3e/source/s_roundToI64.c", - "deps/SoftFloat-3e/source/s_roundToUI32.c", - "deps/SoftFloat-3e/source/s_roundToUI64.c", - "deps/SoftFloat-3e/source/s_shiftLeftM.c", - "deps/SoftFloat-3e/source/s_shiftNormSigF128M.c", - "deps/SoftFloat-3e/source/s_shiftRightJam256M.c", - "deps/SoftFloat-3e/source/s_shiftRightJam32.c", - "deps/SoftFloat-3e/source/s_shiftRightJam64.c", - "deps/SoftFloat-3e/source/s_shiftRightJamM.c", - "deps/SoftFloat-3e/source/s_shiftRightM.c", - "deps/SoftFloat-3e/source/s_shortShiftLeft64To96M.c", - "deps/SoftFloat-3e/source/s_shortShiftLeftM.c", - "deps/SoftFloat-3e/source/s_shortShiftRightExtendM.c", - "deps/SoftFloat-3e/source/s_shortShiftRightJam64.c", - "deps/SoftFloat-3e/source/s_shortShiftRightJamM.c", - "deps/SoftFloat-3e/source/s_shortShiftRightM.c", - "deps/SoftFloat-3e/source/s_sub1XM.c", - "deps/SoftFloat-3e/source/s_sub256M.c", - "deps/SoftFloat-3e/source/s_subM.c", - "deps/SoftFloat-3e/source/s_subMagsF16.c", - "deps/SoftFloat-3e/source/s_subMagsF32.c", - "deps/SoftFloat-3e/source/s_subMagsF64.c", - "deps/SoftFloat-3e/source/s_tryPropagateNaNF128M.c", - "deps/SoftFloat-3e/source/s_tryPropagateNaNExtF80M.c", - "deps/SoftFloat-3e/source/softfloat_state.c", - "deps/SoftFloat-3e/source/ui32_to_f128M.c", - "deps/SoftFloat-3e/source/ui64_to_f128M.c", - "deps/SoftFloat-3e/source/ui32_to_extF80M.c", - "deps/SoftFloat-3e/source/ui64_to_extF80M.c", -}; - const zig_cpp_sources = [_][]const u8{ // These are planned to stay even when we are self-hosted. "src/zig_llvm.cpp", -- 2.54.0 From 5129fae4e8fdb68db1efdff20679b13487501691 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 31 Jan 2023 00:33:45 -0700 Subject: [PATCH 49/84] std.Build: accept host Target in create() And only detect native target in LibExeObjStep once, in create(). --- lib/build_runner.zig | 3 +++ lib/std/Build.zig | 10 ++++++++-- lib/std/Build/LibExeObjStep.zig | 8 ++++---- lib/std/Build/OptionsStep.zig | 4 ++++ 4 files changed, 19 insertions(+), 6 deletions(-) diff --git a/lib/build_runner.zig b/lib/build_runner.zig index 189b1187874242c17a22800dca579ca482ca88fc..f2b2eba9504efa347f83cba9de11c05ff936d51f 100644 --- a/lib/build_runner.zig +++ b/lib/build_runner.zig @@ -41,12 +41,15 @@ pub fn main() !void { return error.InvalidArgs; }; + const host = try std.zig.system.NativeTargetInfo.detect(.{}); + const builder = try std.Build.create( allocator, zig_exe, build_root, cache_root, global_cache_root, + host, ); defer builder.destroy(); diff --git a/lib/std/Build.zig b/lib/std/Build.zig index a3c579c743867396c8194b9e55f52a11ae438d4a..c0152ef6f1f8c788668371e3589425dbd722a9e3 100644 --- a/lib/std/Build.zig +++ b/lib/std/Build.zig @@ -179,12 +179,11 @@ pub fn create( build_root: []const u8, cache_root: []const u8, global_cache_root: []const u8, + host: NativeTargetInfo, ) !*Build { const env_map = try allocator.create(EnvMap); env_map.* = try process.getEnvMap(allocator); - const host = try NativeTargetInfo.detect(.{}); - const self = try allocator.create(Build); self.* = Build{ .zig_exe = zig_exe, @@ -1529,12 +1528,15 @@ test "builder.findProgram compiles" { var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); defer arena.deinit(); + const host = try NativeTargetInfo.detect(.{}); + const builder = try Build.create( arena.allocator(), "zig", "zig-cache", "zig-cache", "zig-cache", + host, ); defer builder.destroy(); _ = builder.findProgram(&[_][]const u8{}, &[_][]const u8{}) catch null; @@ -1713,12 +1715,16 @@ test "dupePkg()" { var arena = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena.deinit(); + + const host = try NativeTargetInfo.detect(.{}); + var builder = try Build.create( arena.allocator(), "test", "test", "test", "test", + host, ); defer builder.destroy(); diff --git a/lib/std/Build/LibExeObjStep.zig b/lib/std/Build/LibExeObjStep.zig index af9d34440da0b1517e4115f73510d5a56cf63a02..67f42c1783f079222a749ac6f34eedc8abc09b61 100644 --- a/lib/std/Build/LibExeObjStep.zig +++ b/lib/std/Build/LibExeObjStep.zig @@ -364,7 +364,7 @@ pub fn create(builder: *std.Build, options: Options) *LibExeObjStep { .output_h_path_source = GeneratedFile{ .step = &self.step }, .output_pdb_path_source = GeneratedFile{ .step = &self.step }, - .target_info = undefined, // populated in computeOutFileNames + .target_info = NativeTargetInfo.detect(self.target) catch unreachable, }; self.computeOutFileNames(); if (root_src) |rs| rs.addStepDependencies(&self.step); @@ -372,9 +372,6 @@ pub fn create(builder: *std.Build, options: Options) *LibExeObjStep { } fn computeOutFileNames(self: *LibExeObjStep) void { - self.target_info = NativeTargetInfo.detect(self.target) catch - unreachable; - const target = self.target_info.target; self.out_filename = std.zig.binNameAlloc(self.builder.allocator, .{ @@ -1946,12 +1943,15 @@ test "addPackage" { var arena = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena.deinit(); + const host = try NativeTargetInfo.detect(.{}); + var builder = try std.Build.create( arena.allocator(), "test", "test", "test", "test", + host, ); defer builder.destroy(); diff --git a/lib/std/Build/OptionsStep.zig b/lib/std/Build/OptionsStep.zig index 3d26807411e649f5a5767367379f738705e89ca3..8e1a7ef2fcf089ac7bd9d2b30370e4ccda2dc20c 100644 --- a/lib/std/Build/OptionsStep.zig +++ b/lib/std/Build/OptionsStep.zig @@ -279,12 +279,16 @@ test "OptionsStep" { var arena = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena.deinit(); + + const host = try std.zig.system.NativeTargetInfo.detect(.{}); + var builder = try std.Build.create( arena.allocator(), "test", "test", "test", "test", + host, ); defer builder.destroy(); -- 2.54.0 From 9a29f4e0387f0480273ca4347ee43e4917cad8e2 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 31 Jan 2023 12:48:46 -0700 Subject: [PATCH 50/84] langref updates for new std.Build API --- doc/langref.html.in | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/doc/langref.html.in b/doc/langref.html.in index 1163ad0200db89ec1645e414912d6b5684a2d940..00a263bae2b2509004dbe2c8a87c9290f208b649 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -10560,8 +10560,9 @@ pub fn build(b: *std.Build) void { // for restricting supported target set are available. const target = b.standardTargetOptions(.{}); - // Standard release options allow the person running `zig build` to select - // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. + // Standard optimization options allow the person running `zig build` to select + // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not + // set a preferred release mode, allowing the user to decide how to optimize. const optimize = b.standardOptimizeOption(.{}); const exe = b.addExecutable(.{ @@ -10964,8 +10965,11 @@ int main(int argc, char **argv) { const std = @import("std"); pub fn build(b: *std.Build) void { - const lib = b.addSharedLibrary("mathtest", "mathtest.zig", b.version(1, 0, 0)); - + const lib = b.addSharedLibrary(.{ + .name = "mathtest", + .root_source_file = .{ .path = "mathtest.zig" }, + .version = .{ .major = 1, .minor = 0, .patch = 0 }, + }); const exe = b.addExecutable(.{ .name = "test", }); @@ -11028,7 +11032,10 @@ int main(int argc, char **argv) { const std = @import("std"); pub fn build(b: *std.Build) void { - const obj = b.addObject("base64", "base64.zig"); + const obj = b.addObject(.{ + .name = "base64", + .root_source_file = .{ .path = "base64.zig" }, + }); const exe = b.addExecutable(.{ .name = "test", -- 2.54.0 From 34b314509919d85a6b6ff9de3bbdad2fec6b2b78 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 31 Jan 2023 13:05:00 -0700 Subject: [PATCH 51/84] update test case for new std.builtin.OptimizeMode API --- test/cases/compile_errors/invalid_member_of_builtin_enum.zig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/cases/compile_errors/invalid_member_of_builtin_enum.zig b/test/cases/compile_errors/invalid_member_of_builtin_enum.zig index 3edb17ffbffbcc953e446f4986a785a904682216..b0a176d792ba4f86c29cd67fb43f8f93a7137644 100644 --- a/test/cases/compile_errors/invalid_member_of_builtin_enum.zig +++ b/test/cases/compile_errors/invalid_member_of_builtin_enum.zig @@ -1,6 +1,6 @@ const builtin = @import("std").builtin; export fn entry() void { - const foo = builtin.Mode.x86; + const foo = builtin.OptimizeMode.x86; _ = foo; } @@ -8,5 +8,5 @@ export fn entry() void { // backend=stage2 // target=native // -// :3:30: error: enum 'builtin.Mode' has no member named 'x86' +// :3:38: error: enum 'builtin.OptimizeMode' has no member named 'x86' // :?:18: note: enum declared here -- 2.54.0 From 77544683ddd5f4d577ecc9c92a2b52a276aed2a6 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 31 Jan 2023 13:38:03 -0700 Subject: [PATCH 52/84] fix init-exe, init-lib templates --- lib/init-exe/build.zig | 2 +- lib/init-lib/build.zig | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/init-exe/build.zig b/lib/init-exe/build.zig index b88515b403500780437fb6af08e2b5d2dd5ba155..2ef5b21fe94aa9431fd91bb4dd799433345f17df 100644 --- a/lib/init-exe/build.zig +++ b/lib/init-exe/build.zig @@ -13,7 +13,7 @@ pub fn build(b: *std.Build) void { // Standard optimization options allow the person running `zig build` to select // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not // set a preferred release mode, allowing the user to decide how to optimize. - const optimize = b.standardOptimizeOption(); + const optimize = b.standardOptimizeOption(.{}); const exe = b.addExecutable(.{ .name = "$", diff --git a/lib/init-lib/build.zig b/lib/init-lib/build.zig index 5ebb55373f86e28b5fa4751050e11f318ad18ebc..2887c170e65b067e2638228c88d6da186d725279 100644 --- a/lib/init-lib/build.zig +++ b/lib/init-lib/build.zig @@ -13,7 +13,7 @@ pub fn build(b: *std.Build) void { // Standard optimization options allow the person running `zig build` to select // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not // set a preferred release mode, allowing the user to decide how to optimize. - const optimize = b.standardOptimizeOption(); + const optimize = b.standardOptimizeOption(.{}); const lib = b.addStaticLibrary(.{ .name = "$", -- 2.54.0 From 16cdd1297ebfac534615eaeb8439a4e1de71837c Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 31 Jan 2023 13:44:06 -0700 Subject: [PATCH 53/84] rename std.Build.LibExeObjStep to std.Build.CompileStep This matches the nomenclature internally: a Compilation is the main type that represents a single invokation of the compiler. --- build.zig | 12 +- lib/std/Build.zig | 49 +++--- lib/std/Build/CheckObjectStep.zig | 2 +- .../{LibExeObjStep.zig => CompileStep.zig} | 154 +++++++++--------- lib/std/Build/EmulatableRunStep.zig | 6 +- lib/std/Build/InstallArtifactStep.zig | 8 +- lib/std/Build/InstallRawStep.zig | 6 +- lib/std/Build/OptionsStep.zig | 6 +- lib/std/Build/RunStep.zig | 10 +- lib/std/Build/Step.zig | 4 +- lib/std/Build/TranslateCStep.zig | 6 +- lib/std/std.zig | 2 + test/link/macho/bugs/13457/build.zig | 1 - test/link/macho/dead_strip/build.zig | 7 +- test/link/macho/dead_strip_dylibs/build.zig | 3 +- test/link/macho/headerpad/build.zig | 3 +- test/link/macho/needed_framework/build.zig | 1 - test/link/macho/needed_library/build.zig | 1 - test/link/macho/search_strategy/build.zig | 7 +- test/link/macho/strict_validation/build.zig | 1 - test/link/macho/unwind_info/build.zig | 7 +- test/link/macho/uuid/build.zig | 7 +- test/link/macho/weak_framework/build.zig | 1 - test/link/macho/weak_library/build.zig | 1 - test/tests.zig | 10 +- 25 files changed, 162 insertions(+), 153 deletions(-) rename lib/std/Build/{LibExeObjStep.zig => CompileStep.zig} (93%) diff --git a/build.zig b/build.zig index 713eac6517e6a3571e51dc33ee1f480ccee66eac..ecf51fe31613fc7e42ccd637f546db7f657f4ead 100644 --- a/build.zig +++ b/build.zig @@ -516,7 +516,7 @@ fn addCompilerStep( b: *std.Build, optimize: std.builtin.OptimizeMode, target: std.zig.CrossTarget, -) *std.Build.LibExeObjStep { +) *std.Build.CompileStep { const exe = b.addExecutable(.{ .name = "zig", .root_source_file = .{ .path = "src/main.zig" }, @@ -544,7 +544,7 @@ const exe_cflags = [_][]const u8{ fn addCmakeCfgOptionsToExe( b: *std.Build, cfg: CMakeConfig, - exe: *std.Build.LibExeObjStep, + exe: *std.Build.CompileStep, use_zig_libcxx: bool, ) !void { if (exe.target.isDarwin()) { @@ -623,7 +623,7 @@ fn addCmakeCfgOptionsToExe( } } -fn addStaticLlvmOptionsToExe(exe: *std.Build.LibExeObjStep) !void { +fn addStaticLlvmOptionsToExe(exe: *std.Build.CompileStep) !void { // Adds the Zig C++ sources which both stage1 and stage2 need. // // We need this because otherwise zig_clang_cc1_main.cpp ends up pulling @@ -662,7 +662,7 @@ fn addStaticLlvmOptionsToExe(exe: *std.Build.LibExeObjStep) !void { fn addCxxKnownPath( b: *std.Build, ctx: CMakeConfig, - exe: *std.Build.LibExeObjStep, + exe: *std.Build.CompileStep, objname: []const u8, errtxt: ?[]const u8, need_cpp_includes: bool, @@ -695,7 +695,7 @@ fn addCxxKnownPath( } } -fn addCMakeLibraryList(exe: *std.Build.LibExeObjStep, list: []const u8) void { +fn addCMakeLibraryList(exe: *std.Build.CompileStep, list: []const u8) void { var it = mem.tokenize(u8, list, ";"); while (it.next()) |lib| { if (mem.startsWith(u8, lib, "-l")) { @@ -709,7 +709,7 @@ fn addCMakeLibraryList(exe: *std.Build.LibExeObjStep, list: []const u8) void { } const CMakeConfig = struct { - llvm_linkage: std.Build.LibExeObjStep.Linkage, + llvm_linkage: std.Build.CompileStep.Linkage, cmake_binary_dir: []const u8, cmake_prefix_path: []const u8, cmake_static_library_prefix: []const u8, diff --git a/lib/std/Build.zig b/lib/std/Build.zig index c0152ef6f1f8c788668371e3589425dbd722a9e3..4647baa3981784ba4ee54ce47458cab18e94b17f 100644 --- a/lib/std/Build.zig +++ b/lib/std/Build.zig @@ -19,6 +19,9 @@ const NativeTargetInfo = std.zig.system.NativeTargetInfo; const Sha256 = std.crypto.hash.sha2.Sha256; const Build = @This(); +///// deprecated: use `CompileStep` instead. +//pub const LibExeObjStep = CompileStep; + pub const Step = @import("Build/Step.zig"); pub const CheckFileStep = @import("Build/CheckFileStep.zig"); pub const CheckObjectStep = @import("Build/CheckObjectStep.zig"); @@ -29,7 +32,7 @@ pub const InstallArtifactStep = @import("Build/InstallArtifactStep.zig"); pub const InstallDirStep = @import("Build/InstallDirStep.zig"); pub const InstallFileStep = @import("Build/InstallFileStep.zig"); pub const InstallRawStep = @import("Build/InstallRawStep.zig"); -pub const LibExeObjStep = @import("Build/LibExeObjStep.zig"); +pub const CompileStep = @import("Build/CompileStep.zig"); pub const LogStep = @import("Build/LogStep.zig"); pub const OptionsStep = @import("Build/OptionsStep.zig"); pub const RemoveDirStep = @import("Build/RemoveDirStep.zig"); @@ -423,11 +426,11 @@ pub const ExecutableOptions = struct { version: ?std.builtin.Version = null, target: CrossTarget = .{}, optimize: std.builtin.Mode = .Debug, - linkage: ?LibExeObjStep.Linkage = null, + linkage: ?CompileStep.Linkage = null, }; -pub fn addExecutable(b: *Build, options: ExecutableOptions) *LibExeObjStep { - return LibExeObjStep.create(b, .{ +pub fn addExecutable(b: *Build, options: ExecutableOptions) *CompileStep { + return CompileStep.create(b, .{ .name = options.name, .root_source_file = options.root_source_file, .version = options.version, @@ -445,8 +448,8 @@ pub const ObjectOptions = struct { optimize: std.builtin.Mode, }; -pub fn addObject(b: *Build, options: ObjectOptions) *LibExeObjStep { - return LibExeObjStep.create(b, .{ +pub fn addObject(b: *Build, options: ObjectOptions) *CompileStep { + return CompileStep.create(b, .{ .name = options.name, .root_source_file = options.root_source_file, .target = options.target, @@ -463,8 +466,8 @@ pub const SharedLibraryOptions = struct { optimize: std.builtin.Mode, }; -pub fn addSharedLibrary(b: *Build, options: SharedLibraryOptions) *LibExeObjStep { - return LibExeObjStep.create(b, .{ +pub fn addSharedLibrary(b: *Build, options: SharedLibraryOptions) *CompileStep { + return CompileStep.create(b, .{ .name = options.name, .root_source_file = options.root_source_file, .kind = .lib, @@ -483,8 +486,8 @@ pub const StaticLibraryOptions = struct { version: ?std.builtin.Version = null, }; -pub fn addStaticLibrary(b: *Build, options: StaticLibraryOptions) *LibExeObjStep { - return LibExeObjStep.create(b, .{ +pub fn addStaticLibrary(b: *Build, options: StaticLibraryOptions) *CompileStep { + return CompileStep.create(b, .{ .name = options.name, .root_source_file = options.root_source_file, .kind = .lib, @@ -497,15 +500,15 @@ pub fn addStaticLibrary(b: *Build, options: StaticLibraryOptions) *LibExeObjStep pub const TestOptions = struct { name: []const u8 = "test", - kind: LibExeObjStep.Kind = .@"test", + kind: CompileStep.Kind = .@"test", root_source_file: FileSource, target: CrossTarget = .{}, optimize: std.builtin.Mode = .Debug, version: ?std.builtin.Version = null, }; -pub fn addTest(b: *Build, options: TestOptions) *LibExeObjStep { - return LibExeObjStep.create(b, .{ +pub fn addTest(b: *Build, options: TestOptions) *CompileStep { + return CompileStep.create(b, .{ .name = options.name, .kind = options.kind, .root_source_file = options.root_source_file, @@ -521,8 +524,8 @@ pub const AssemblyOptions = struct { optimize: std.builtin.Mode, }; -pub fn addAssembly(b: *Build, options: AssemblyOptions) *LibExeObjStep { - const obj_step = LibExeObjStep.create(b, .{ +pub fn addAssembly(b: *Build, options: AssemblyOptions) *CompileStep { + const obj_step = CompileStep.create(b, .{ .name = options.name, .root_source_file = null, .target = options.target, @@ -536,7 +539,7 @@ pub fn addAssembly(b: *Build, options: AssemblyOptions) *LibExeObjStep { /// executable. More command line arguments can be added with `addArg`, /// `addArgs`, and `addArtifactArg`. /// Be careful using this function, as it introduces a system dependency. -/// To run an executable built with zig build, see `LibExeObjStep.run`. +/// To run an executable built with zig build, see `CompileStep.run`. pub fn addSystemCommand(self: *Build, argv: []const []const u8) *RunStep { assert(argv.len >= 1); const run_step = RunStep.create(self, self.fmt("run {s}", .{argv[0]})); @@ -1167,11 +1170,11 @@ pub fn makePath(self: *Build, path: []const u8) !void { }; } -pub fn installArtifact(self: *Build, artifact: *LibExeObjStep) void { +pub fn installArtifact(self: *Build, artifact: *CompileStep) void { self.getInstallStep().dependOn(&self.addInstallArtifact(artifact).step); } -pub fn addInstallArtifact(self: *Build, artifact: *LibExeObjStep) *InstallArtifactStep { +pub fn addInstallArtifact(self: *Build, artifact: *CompileStep) *InstallArtifactStep { return InstallArtifactStep.create(self, artifact); } @@ -1195,7 +1198,7 @@ pub fn installLibFile(self: *Build, src_path: []const u8, dest_rel_path: []const } /// Output format (BIN vs Intel HEX) determined by filename -pub fn installRaw(self: *Build, artifact: *LibExeObjStep, dest_filename: []const u8, options: InstallRawStep.CreateOptions) *InstallRawStep { +pub fn installRaw(self: *Build, artifact: *CompileStep, dest_filename: []const u8, options: InstallRawStep.CreateOptions) *InstallRawStep { const raw = self.addInstallRaw(artifact, dest_filename, options); self.getInstallStep().dependOn(&raw.step); return raw; @@ -1220,7 +1223,7 @@ pub fn addInstallHeaderFile(b: *Build, src_path: []const u8, dest_rel_path: []co return b.addInstallFileWithDir(.{ .path = src_path }, .header, dest_rel_path); } -pub fn addInstallRaw(self: *Build, artifact: *LibExeObjStep, dest_filename: []const u8, options: InstallRawStep.CreateOptions) *InstallRawStep { +pub fn addInstallRaw(self: *Build, artifact: *CompileStep, dest_filename: []const u8, options: InstallRawStep.CreateOptions) *InstallRawStep { return InstallRawStep.create(self, artifact, dest_filename, options); } @@ -1456,8 +1459,8 @@ pub fn getInstallPath(self: *Build, dir: InstallDir, dest_rel_path: []const u8) pub const Dependency = struct { builder: *Build, - pub fn artifact(d: *Dependency, name: []const u8) *LibExeObjStep { - var found: ?*LibExeObjStep = null; + pub fn artifact(d: *Dependency, name: []const u8) *CompileStep { + var found: ?*CompileStep = null; for (d.builder.install_tls.step.dependencies.items) |dep_step| { const inst = dep_step.cast(InstallArtifactStep) orelse continue; if (mem.eql(u8, inst.artifact.name, name)) { @@ -1767,7 +1770,7 @@ test { _ = InstallDirStep; _ = InstallFileStep; _ = InstallRawStep; - _ = LibExeObjStep; + _ = CompileStep; _ = LogStep; _ = OptionsStep; _ = RemoveDirStep; diff --git a/lib/std/Build/CheckObjectStep.zig b/lib/std/Build/CheckObjectStep.zig index 7907be1787e3e358364d90efafc9449dbadea5c6..bfa533892781396f5efd8ba19a8fad2a5c0a903d 100644 --- a/lib/std/Build/CheckObjectStep.zig +++ b/lib/std/Build/CheckObjectStep.zig @@ -42,7 +42,7 @@ pub fn runAndCompare(self: *CheckObjectStep) *EmulatableRunStep { const dependencies_len = self.step.dependencies.items.len; assert(dependencies_len > 0); const exe_step = self.step.dependencies.items[dependencies_len - 1]; - const exe = exe_step.cast(std.Build.LibExeObjStep).?; + const exe = exe_step.cast(std.Build.CompileStep).?; const emulatable_step = EmulatableRunStep.create(self.builder, "EmulatableRun", exe); emulatable_step.step.dependOn(&self.step); return emulatable_step; diff --git a/lib/std/Build/LibExeObjStep.zig b/lib/std/Build/CompileStep.zig similarity index 93% rename from lib/std/Build/LibExeObjStep.zig rename to lib/std/Build/CompileStep.zig index 67f42c1783f079222a749ac6f34eedc8abc09b61..5257c85a5cbca4e4f36935eedcc2668644779151 100644 --- a/lib/std/Build/LibExeObjStep.zig +++ b/lib/std/Build/CompileStep.zig @@ -27,9 +27,9 @@ const CheckObjectStep = std.Build.CheckObjectStep; const RunStep = std.Build.RunStep; const OptionsStep = std.Build.OptionsStep; const ConfigHeaderStep = std.Build.ConfigHeaderStep; -const LibExeObjStep = @This(); +const CompileStep = @This(); -pub const base_id = .lib_exe_obj; +pub const base_id: Step.Id = .compile; step: Step, builder: *std.Build, @@ -234,7 +234,7 @@ pub const CSourceFile = struct { pub const LinkObject = union(enum) { static_path: FileSource, - other_step: *LibExeObjStep, + other_step: *CompileStep, system_lib: SystemLib, assembly_file: FileSource, c_source_file: *CSourceFile, @@ -265,7 +265,7 @@ const FrameworkLinkInfo = struct { pub const IncludeDir = union(enum) { raw_path: []const u8, raw_path_system: []const u8, - other_step: *LibExeObjStep, + other_step: *CompileStep, config_header_step: *ConfigHeaderStep, }; @@ -305,15 +305,15 @@ pub const EmitOption = union(enum) { } }; -pub fn create(builder: *std.Build, options: Options) *LibExeObjStep { +pub fn create(builder: *std.Build, options: Options) *CompileStep { const name = builder.dupe(options.name); const root_src: ?FileSource = if (options.root_source_file) |rsrc| rsrc.dupe(builder) else null; if (mem.indexOf(u8, name, "/") != null or mem.indexOf(u8, name, "\\") != null) { panic("invalid name: '{s}'. It looks like a file path, but it is supposed to be the library or application name.", .{name}); } - const self = builder.allocator.create(LibExeObjStep) catch unreachable; - self.* = LibExeObjStep{ + const self = builder.allocator.create(CompileStep) catch unreachable; + self.* = CompileStep{ .strip = null, .unwind_tables = null, .builder = builder, @@ -371,7 +371,7 @@ pub fn create(builder: *std.Build, options: Options) *LibExeObjStep { return self; } -fn computeOutFileNames(self: *LibExeObjStep) void { +fn computeOutFileNames(self: *CompileStep) void { const target = self.target_info.target; self.out_filename = std.zig.binNameAlloc(self.builder.allocator, .{ @@ -424,26 +424,26 @@ fn computeOutFileNames(self: *LibExeObjStep) void { } } -pub fn setOutputDir(self: *LibExeObjStep, dir: []const u8) void { +pub fn setOutputDir(self: *CompileStep, dir: []const u8) void { self.output_dir = self.builder.dupePath(dir); } -pub fn install(self: *LibExeObjStep) void { +pub fn install(self: *CompileStep) void { self.builder.installArtifact(self); } -pub fn installRaw(self: *LibExeObjStep, dest_filename: []const u8, options: InstallRawStep.CreateOptions) *InstallRawStep { +pub fn installRaw(self: *CompileStep, dest_filename: []const u8, options: InstallRawStep.CreateOptions) *InstallRawStep { return self.builder.installRaw(self, dest_filename, options); } -pub fn installHeader(a: *LibExeObjStep, src_path: []const u8, dest_rel_path: []const u8) void { +pub fn installHeader(a: *CompileStep, src_path: []const u8, dest_rel_path: []const u8) void { const install_file = a.builder.addInstallHeaderFile(src_path, dest_rel_path); a.builder.getInstallStep().dependOn(&install_file.step); a.installed_headers.append(&install_file.step) catch unreachable; } pub fn installHeadersDirectory( - a: *LibExeObjStep, + a: *CompileStep, src_dir_path: []const u8, dest_rel_path: []const u8, ) void { @@ -455,7 +455,7 @@ pub fn installHeadersDirectory( } pub fn installHeadersDirectoryOptions( - a: *LibExeObjStep, + a: *CompileStep, options: std.Build.InstallDirStep.Options, ) void { const install_dir = a.builder.addInstallDirectory(options); @@ -463,7 +463,7 @@ pub fn installHeadersDirectoryOptions( a.installed_headers.append(&install_dir.step) catch unreachable; } -pub fn installLibraryHeaders(a: *LibExeObjStep, l: *LibExeObjStep) void { +pub fn installLibraryHeaders(a: *CompileStep, l: *CompileStep) void { assert(l.kind == .lib); const install_step = a.builder.getInstallStep(); // Copy each element from installed_headers, modifying the builder @@ -488,7 +488,7 @@ pub fn installLibraryHeaders(a: *LibExeObjStep, l: *LibExeObjStep) void { /// Creates a `RunStep` with an executable built with `addExecutable`. /// Add command line arguments with `addArg`. -pub fn run(exe: *LibExeObjStep) *RunStep { +pub fn run(exe: *CompileStep) *RunStep { assert(exe.kind == .exe or exe.kind == .test_exe); // It doesn't have to be native. We catch that if you actually try to run it. @@ -512,7 +512,7 @@ pub fn run(exe: *LibExeObjStep) *RunStep { /// Allows running foreign binaries through emulation platforms such as Qemu or Rosetta. /// When a binary cannot be ran through emulation or the option is disabled, a warning /// will be printed and the binary will *NOT* be ran. -pub fn runEmulatable(exe: *LibExeObjStep) *EmulatableRunStep { +pub fn runEmulatable(exe: *CompileStep) *EmulatableRunStep { assert(exe.kind == .exe or exe.kind == .test_exe); const run_step = EmulatableRunStep.create(exe.builder, exe.builder.fmt("run {s}", .{exe.step.name}), exe); @@ -522,33 +522,33 @@ pub fn runEmulatable(exe: *LibExeObjStep) *EmulatableRunStep { return run_step; } -pub fn checkObject(self: *LibExeObjStep, obj_format: std.Target.ObjectFormat) *CheckObjectStep { +pub fn checkObject(self: *CompileStep, obj_format: std.Target.ObjectFormat) *CheckObjectStep { return CheckObjectStep.create(self.builder, self.getOutputSource(), obj_format); } -pub fn setLinkerScriptPath(self: *LibExeObjStep, source: FileSource) void { +pub fn setLinkerScriptPath(self: *CompileStep, source: FileSource) void { self.linker_script = source.dupe(self.builder); source.addStepDependencies(&self.step); } -pub fn linkFramework(self: *LibExeObjStep, framework_name: []const u8) void { +pub fn linkFramework(self: *CompileStep, framework_name: []const u8) void { self.frameworks.put(self.builder.dupe(framework_name), .{}) catch unreachable; } -pub fn linkFrameworkNeeded(self: *LibExeObjStep, framework_name: []const u8) void { +pub fn linkFrameworkNeeded(self: *CompileStep, framework_name: []const u8) void { self.frameworks.put(self.builder.dupe(framework_name), .{ .needed = true, }) catch unreachable; } -pub fn linkFrameworkWeak(self: *LibExeObjStep, framework_name: []const u8) void { +pub fn linkFrameworkWeak(self: *CompileStep, framework_name: []const u8) void { self.frameworks.put(self.builder.dupe(framework_name), .{ .weak = true, }) catch unreachable; } /// Returns whether the library, executable, or object depends on a particular system library. -pub fn dependsOnSystemLibrary(self: LibExeObjStep, name: []const u8) bool { +pub fn dependsOnSystemLibrary(self: CompileStep, name: []const u8) bool { if (isLibCLibrary(name)) { return self.is_linking_libc; } @@ -564,49 +564,49 @@ pub fn dependsOnSystemLibrary(self: LibExeObjStep, name: []const u8) bool { return false; } -pub fn linkLibrary(self: *LibExeObjStep, lib: *LibExeObjStep) void { +pub fn linkLibrary(self: *CompileStep, lib: *CompileStep) void { assert(lib.kind == .lib); self.linkLibraryOrObject(lib); } -pub fn isDynamicLibrary(self: *LibExeObjStep) bool { +pub fn isDynamicLibrary(self: *CompileStep) bool { return self.kind == .lib and self.linkage == Linkage.dynamic; } -pub fn isStaticLibrary(self: *LibExeObjStep) bool { +pub fn isStaticLibrary(self: *CompileStep) bool { return self.kind == .lib and self.linkage != Linkage.dynamic; } -pub fn producesPdbFile(self: *LibExeObjStep) bool { +pub fn producesPdbFile(self: *CompileStep) bool { if (!self.target.isWindows() and !self.target.isUefi()) return false; if (self.target.getObjectFormat() == .c) return false; if (self.strip == true) return false; return self.isDynamicLibrary() or self.kind == .exe or self.kind == .test_exe; } -pub fn linkLibC(self: *LibExeObjStep) void { +pub fn linkLibC(self: *CompileStep) void { self.is_linking_libc = true; } -pub fn linkLibCpp(self: *LibExeObjStep) void { +pub fn linkLibCpp(self: *CompileStep) void { self.is_linking_libcpp = true; } /// If the value is omitted, it is set to 1. /// `name` and `value` need not live longer than the function call. -pub fn defineCMacro(self: *LibExeObjStep, name: []const u8, value: ?[]const u8) void { +pub fn defineCMacro(self: *CompileStep, name: []const u8, value: ?[]const u8) void { const macro = std.Build.constructCMacro(self.builder.allocator, name, value); self.c_macros.append(macro) catch unreachable; } /// name_and_value looks like [name]=[value]. If the value is omitted, it is set to 1. -pub fn defineCMacroRaw(self: *LibExeObjStep, name_and_value: []const u8) void { +pub fn defineCMacroRaw(self: *CompileStep, name_and_value: []const u8) void { self.c_macros.append(self.builder.dupe(name_and_value)) catch unreachable; } /// This one has no integration with anything, it just puts -lname on the command line. /// Prefer to use `linkSystemLibrary` instead. -pub fn linkSystemLibraryName(self: *LibExeObjStep, name: []const u8) void { +pub fn linkSystemLibraryName(self: *CompileStep, name: []const u8) void { self.link_objects.append(.{ .system_lib = .{ .name = self.builder.dupe(name), @@ -619,7 +619,7 @@ pub fn linkSystemLibraryName(self: *LibExeObjStep, name: []const u8) void { /// This one has no integration with anything, it just puts -needed-lname on the command line. /// Prefer to use `linkSystemLibraryNeeded` instead. -pub fn linkSystemLibraryNeededName(self: *LibExeObjStep, name: []const u8) void { +pub fn linkSystemLibraryNeededName(self: *CompileStep, name: []const u8) void { self.link_objects.append(.{ .system_lib = .{ .name = self.builder.dupe(name), @@ -632,7 +632,7 @@ pub fn linkSystemLibraryNeededName(self: *LibExeObjStep, name: []const u8) void /// Darwin-only. This one has no integration with anything, it just puts -weak-lname on the /// command line. Prefer to use `linkSystemLibraryWeak` instead. -pub fn linkSystemLibraryWeakName(self: *LibExeObjStep, name: []const u8) void { +pub fn linkSystemLibraryWeakName(self: *CompileStep, name: []const u8) void { self.link_objects.append(.{ .system_lib = .{ .name = self.builder.dupe(name), @@ -645,7 +645,7 @@ pub fn linkSystemLibraryWeakName(self: *LibExeObjStep, name: []const u8) void { /// This links against a system library, exclusively using pkg-config to find the library. /// Prefer to use `linkSystemLibrary` instead. -pub fn linkSystemLibraryPkgConfigOnly(self: *LibExeObjStep, lib_name: []const u8) void { +pub fn linkSystemLibraryPkgConfigOnly(self: *CompileStep, lib_name: []const u8) void { self.link_objects.append(.{ .system_lib = .{ .name = self.builder.dupe(lib_name), @@ -658,7 +658,7 @@ pub fn linkSystemLibraryPkgConfigOnly(self: *LibExeObjStep, lib_name: []const u8 /// This links against a system library, exclusively using pkg-config to find the library. /// Prefer to use `linkSystemLibraryNeeded` instead. -pub fn linkSystemLibraryNeededPkgConfigOnly(self: *LibExeObjStep, lib_name: []const u8) void { +pub fn linkSystemLibraryNeededPkgConfigOnly(self: *CompileStep, lib_name: []const u8) void { self.link_objects.append(.{ .system_lib = .{ .name = self.builder.dupe(lib_name), @@ -671,7 +671,7 @@ pub fn linkSystemLibraryNeededPkgConfigOnly(self: *LibExeObjStep, lib_name: []co /// Run pkg-config for the given library name and parse the output, returning the arguments /// that should be passed to zig to link the given library. -pub fn runPkgConfig(self: *LibExeObjStep, lib_name: []const u8) ![]const []const u8 { +pub fn runPkgConfig(self: *CompileStep, lib_name: []const u8) ![]const []const u8 { const pkg_name = match: { // First we have to map the library name to pkg config name. Unfortunately, // there are several examples where this is not straightforward: @@ -765,19 +765,19 @@ pub fn runPkgConfig(self: *LibExeObjStep, lib_name: []const u8) ![]const []const return zig_args.toOwnedSlice(); } -pub fn linkSystemLibrary(self: *LibExeObjStep, name: []const u8) void { +pub fn linkSystemLibrary(self: *CompileStep, name: []const u8) void { self.linkSystemLibraryInner(name, .{}); } -pub fn linkSystemLibraryNeeded(self: *LibExeObjStep, name: []const u8) void { +pub fn linkSystemLibraryNeeded(self: *CompileStep, name: []const u8) void { self.linkSystemLibraryInner(name, .{ .needed = true }); } -pub fn linkSystemLibraryWeak(self: *LibExeObjStep, name: []const u8) void { +pub fn linkSystemLibraryWeak(self: *CompileStep, name: []const u8) void { self.linkSystemLibraryInner(name, .{ .weak = true }); } -fn linkSystemLibraryInner(self: *LibExeObjStep, name: []const u8, opts: struct { +fn linkSystemLibraryInner(self: *CompileStep, name: []const u8, opts: struct { needed: bool = false, weak: bool = false, }) void { @@ -800,23 +800,23 @@ fn linkSystemLibraryInner(self: *LibExeObjStep, name: []const u8, opts: struct { }) catch unreachable; } -pub fn setNamePrefix(self: *LibExeObjStep, text: []const u8) void { +pub fn setNamePrefix(self: *CompileStep, text: []const u8) void { assert(self.kind == .@"test" or self.kind == .test_exe); self.name_prefix = self.builder.dupe(text); } -pub fn setFilter(self: *LibExeObjStep, text: ?[]const u8) void { +pub fn setFilter(self: *CompileStep, text: ?[]const u8) void { assert(self.kind == .@"test" or self.kind == .test_exe); self.filter = if (text) |t| self.builder.dupe(t) else null; } -pub fn setTestRunner(self: *LibExeObjStep, path: ?[]const u8) void { +pub fn setTestRunner(self: *CompileStep, path: ?[]const u8) void { assert(self.kind == .@"test" or self.kind == .test_exe); self.test_runner = if (path) |p| self.builder.dupePath(p) else null; } /// Handy when you have many C/C++ source files and want them all to have the same flags. -pub fn addCSourceFiles(self: *LibExeObjStep, files: []const []const u8, flags: []const []const u8) void { +pub fn addCSourceFiles(self: *CompileStep, files: []const []const u8, flags: []const []const u8) void { const c_source_files = self.builder.allocator.create(CSourceFiles) catch unreachable; const files_copy = self.builder.dupeStrings(files); @@ -829,89 +829,89 @@ pub fn addCSourceFiles(self: *LibExeObjStep, files: []const []const u8, flags: [ self.link_objects.append(.{ .c_source_files = c_source_files }) catch unreachable; } -pub fn addCSourceFile(self: *LibExeObjStep, file: []const u8, flags: []const []const u8) void { +pub fn addCSourceFile(self: *CompileStep, file: []const u8, flags: []const []const u8) void { self.addCSourceFileSource(.{ .args = flags, .source = .{ .path = file }, }); } -pub fn addCSourceFileSource(self: *LibExeObjStep, source: CSourceFile) void { +pub fn addCSourceFileSource(self: *CompileStep, source: CSourceFile) void { const c_source_file = self.builder.allocator.create(CSourceFile) catch unreachable; c_source_file.* = source.dupe(self.builder); self.link_objects.append(.{ .c_source_file = c_source_file }) catch unreachable; source.source.addStepDependencies(&self.step); } -pub fn setVerboseLink(self: *LibExeObjStep, value: bool) void { +pub fn setVerboseLink(self: *CompileStep, value: bool) void { self.verbose_link = value; } -pub fn setVerboseCC(self: *LibExeObjStep, value: bool) void { +pub fn setVerboseCC(self: *CompileStep, value: bool) void { self.verbose_cc = value; } -pub fn overrideZigLibDir(self: *LibExeObjStep, dir_path: []const u8) void { +pub fn overrideZigLibDir(self: *CompileStep, dir_path: []const u8) void { self.override_lib_dir = self.builder.dupePath(dir_path); } -pub fn setMainPkgPath(self: *LibExeObjStep, dir_path: []const u8) void { +pub fn setMainPkgPath(self: *CompileStep, dir_path: []const u8) void { self.main_pkg_path = self.builder.dupePath(dir_path); } -pub fn setLibCFile(self: *LibExeObjStep, libc_file: ?FileSource) void { +pub fn setLibCFile(self: *CompileStep, libc_file: ?FileSource) void { self.libc_file = if (libc_file) |f| f.dupe(self.builder) else null; } /// Returns the generated executable, library or object file. /// To run an executable built with zig build, use `run`, or create an install step and invoke it. -pub fn getOutputSource(self: *LibExeObjStep) FileSource { +pub fn getOutputSource(self: *CompileStep) FileSource { return FileSource{ .generated = &self.output_path_source }; } /// Returns the generated import library. This function can only be called for libraries. -pub fn getOutputLibSource(self: *LibExeObjStep) FileSource { +pub fn getOutputLibSource(self: *CompileStep) FileSource { assert(self.kind == .lib); return FileSource{ .generated = &self.output_lib_path_source }; } /// Returns the generated header file. /// This function can only be called for libraries or object files which have `emit_h` set. -pub fn getOutputHSource(self: *LibExeObjStep) FileSource { +pub fn getOutputHSource(self: *CompileStep) FileSource { assert(self.kind != .exe and self.kind != .test_exe and self.kind != .@"test"); assert(self.emit_h); return FileSource{ .generated = &self.output_h_path_source }; } /// Returns the generated PDB file. This function can only be called for Windows and UEFI. -pub fn getOutputPdbSource(self: *LibExeObjStep) FileSource { +pub fn getOutputPdbSource(self: *CompileStep) FileSource { // TODO: Is this right? Isn't PDB for *any* PE/COFF file? assert(self.target.isWindows() or self.target.isUefi()); return FileSource{ .generated = &self.output_pdb_path_source }; } -pub fn addAssemblyFile(self: *LibExeObjStep, path: []const u8) void { +pub fn addAssemblyFile(self: *CompileStep, path: []const u8) void { self.link_objects.append(.{ .assembly_file = .{ .path = self.builder.dupe(path) }, }) catch unreachable; } -pub fn addAssemblyFileSource(self: *LibExeObjStep, source: FileSource) void { +pub fn addAssemblyFileSource(self: *CompileStep, source: FileSource) void { const source_duped = source.dupe(self.builder); self.link_objects.append(.{ .assembly_file = source_duped }) catch unreachable; source_duped.addStepDependencies(&self.step); } -pub fn addObjectFile(self: *LibExeObjStep, source_file: []const u8) void { +pub fn addObjectFile(self: *CompileStep, source_file: []const u8) void { self.addObjectFileSource(.{ .path = source_file }); } -pub fn addObjectFileSource(self: *LibExeObjStep, source: FileSource) void { +pub fn addObjectFileSource(self: *CompileStep, source: FileSource) void { self.link_objects.append(.{ .static_path = source.dupe(self.builder) }) catch unreachable; source.addStepDependencies(&self.step); } -pub fn addObject(self: *LibExeObjStep, obj: *LibExeObjStep) void { +pub fn addObject(self: *CompileStep, obj: *CompileStep) void { assert(obj.kind == .obj); self.linkLibraryOrObject(obj); } @@ -921,41 +921,41 @@ pub const addIncludeDir = @compileError("deprecated; use addIncludePath"); pub const addLibPath = @compileError("deprecated, use addLibraryPath"); pub const addFrameworkDir = @compileError("deprecated, use addFrameworkPath"); -pub fn addSystemIncludePath(self: *LibExeObjStep, path: []const u8) void { +pub fn addSystemIncludePath(self: *CompileStep, path: []const u8) void { self.include_dirs.append(IncludeDir{ .raw_path_system = self.builder.dupe(path) }) catch unreachable; } -pub fn addIncludePath(self: *LibExeObjStep, path: []const u8) void { +pub fn addIncludePath(self: *CompileStep, path: []const u8) void { self.include_dirs.append(IncludeDir{ .raw_path = self.builder.dupe(path) }) catch unreachable; } -pub fn addConfigHeader(self: *LibExeObjStep, config_header: *ConfigHeaderStep) void { +pub fn addConfigHeader(self: *CompileStep, config_header: *ConfigHeaderStep) void { self.step.dependOn(&config_header.step); self.include_dirs.append(.{ .config_header_step = config_header }) catch @panic("OOM"); } -pub fn addLibraryPath(self: *LibExeObjStep, path: []const u8) void { +pub fn addLibraryPath(self: *CompileStep, path: []const u8) void { self.lib_paths.append(self.builder.dupe(path)) catch unreachable; } -pub fn addRPath(self: *LibExeObjStep, path: []const u8) void { +pub fn addRPath(self: *CompileStep, path: []const u8) void { self.rpaths.append(self.builder.dupe(path)) catch unreachable; } -pub fn addFrameworkPath(self: *LibExeObjStep, dir_path: []const u8) void { +pub fn addFrameworkPath(self: *CompileStep, dir_path: []const u8) void { self.framework_dirs.append(self.builder.dupe(dir_path)) catch unreachable; } -pub fn addPackage(self: *LibExeObjStep, package: Pkg) void { +pub fn addPackage(self: *CompileStep, package: Pkg) void { self.packages.append(self.builder.dupePkg(package)) catch unreachable; self.addRecursiveBuildDeps(package); } -pub fn addOptions(self: *LibExeObjStep, package_name: []const u8, options: *OptionsStep) void { +pub fn addOptions(self: *CompileStep, package_name: []const u8, options: *OptionsStep) void { self.addPackage(options.getPackage(package_name)); } -fn addRecursiveBuildDeps(self: *LibExeObjStep, package: Pkg) void { +fn addRecursiveBuildDeps(self: *CompileStep, package: Pkg) void { package.source.addStepDependencies(&self.step); if (package.dependencies) |deps| { for (deps) |dep| { @@ -964,7 +964,7 @@ fn addRecursiveBuildDeps(self: *LibExeObjStep, package: Pkg) void { } } -pub fn addPackagePath(self: *LibExeObjStep, name: []const u8, pkg_index_path: []const u8) void { +pub fn addPackagePath(self: *CompileStep, name: []const u8, pkg_index_path: []const u8) void { self.addPackage(Pkg{ .name = self.builder.dupe(name), .source = .{ .path = self.builder.dupe(pkg_index_path) }, @@ -973,7 +973,7 @@ pub fn addPackagePath(self: *LibExeObjStep, name: []const u8, pkg_index_path: [] /// If Vcpkg was found on the system, it will be added to include and lib /// paths for the specified target. -pub fn addVcpkgPaths(self: *LibExeObjStep, linkage: LibExeObjStep.Linkage) !void { +pub fn addVcpkgPaths(self: *CompileStep, linkage: CompileStep.Linkage) !void { // Ideally in the Unattempted case we would call the function recursively // after findVcpkgRoot and have only one switch statement, but the compiler // cannot resolve the error set. @@ -1008,7 +1008,7 @@ pub fn addVcpkgPaths(self: *LibExeObjStep, linkage: LibExeObjStep.Linkage) !void } } -pub fn setExecCmd(self: *LibExeObjStep, args: []const ?[]const u8) void { +pub fn setExecCmd(self: *CompileStep, args: []const ?[]const u8) void { assert(self.kind == .@"test"); const duped_args = self.builder.allocator.alloc(?[]u8, args.len) catch unreachable; for (args) |arg, i| { @@ -1017,13 +1017,13 @@ pub fn setExecCmd(self: *LibExeObjStep, args: []const ?[]const u8) void { self.exec_cmd_args = duped_args; } -fn linkLibraryOrObject(self: *LibExeObjStep, other: *LibExeObjStep) void { +fn linkLibraryOrObject(self: *CompileStep, other: *CompileStep) void { self.step.dependOn(&other.step); self.link_objects.append(.{ .other_step = other }) catch unreachable; self.include_dirs.append(.{ .other_step = other }) catch unreachable; } -fn makePackageCmd(self: *LibExeObjStep, pkg: Pkg, zig_args: *ArrayList([]const u8)) error{OutOfMemory}!void { +fn makePackageCmd(self: *CompileStep, pkg: Pkg, zig_args: *ArrayList([]const u8)) error{OutOfMemory}!void { const builder = self.builder; try zig_args.append("--pkg-begin"); @@ -1040,7 +1040,7 @@ fn makePackageCmd(self: *LibExeObjStep, pkg: Pkg, zig_args: *ArrayList([]const u } fn make(step: *Step) !void { - const self = @fieldParentPtr(LibExeObjStep, "step", step); + const self = @fieldParentPtr(CompileStep, "step", step); const builder = self.builder; if (self.root_src == null and self.link_objects.items.len == 0) { @@ -2004,7 +2004,7 @@ const TransitiveDeps = struct { } } - fn addInner(td: *TransitiveDeps, other: *LibExeObjStep, dyn: bool) !void { + fn addInner(td: *TransitiveDeps, other: *CompileStep, dyn: bool) !void { // Inherit dependency on libc and libc++ td.is_linking_libcpp = td.is_linking_libcpp or other.is_linking_libcpp; td.is_linking_libc = td.is_linking_libc or other.is_linking_libc; diff --git a/lib/std/Build/EmulatableRunStep.zig b/lib/std/Build/EmulatableRunStep.zig index b7b12d791f7c2a612484a6208319b9a582c5cd3b..26804b2fc8a6a10196fe0d6d4e9d8d5e14c79377 100644 --- a/lib/std/Build/EmulatableRunStep.zig +++ b/lib/std/Build/EmulatableRunStep.zig @@ -6,7 +6,7 @@ const std = @import("../std.zig"); const Step = std.Build.Step; -const LibExeObjStep = std.Build.LibExeObjStep; +const CompileStep = std.Build.CompileStep; const RunStep = std.Build.RunStep; const fs = std.fs; @@ -23,7 +23,7 @@ step: Step, builder: *std.Build, /// The artifact (executable) to be run by this step -exe: *LibExeObjStep, +exe: *CompileStep, /// Set this to `null` to ignore the exit code for the purpose of determining a successful execution expected_exit_code: ?u8 = 0, @@ -45,7 +45,7 @@ hide_foreign_binaries_warning: bool, /// binary through emulation when any of the emulation options such as `enable_rosetta` are set to true. /// When set to false, and the binary is foreign, running the executable is skipped. /// Asserts given artifact is an executable. -pub fn create(builder: *std.Build, name: []const u8, artifact: *LibExeObjStep) *EmulatableRunStep { +pub fn create(builder: *std.Build, name: []const u8, artifact: *CompileStep) *EmulatableRunStep { std.debug.assert(artifact.kind == .exe or artifact.kind == .test_exe); const self = builder.allocator.create(EmulatableRunStep) catch unreachable; diff --git a/lib/std/Build/InstallArtifactStep.zig b/lib/std/Build/InstallArtifactStep.zig index 929b30e935fdd45893c5ce6ca77bf95fedac1b97..898b9e85e78da6ad62a289378c7f0e7d2afa2af1 100644 --- a/lib/std/Build/InstallArtifactStep.zig +++ b/lib/std/Build/InstallArtifactStep.zig @@ -1,6 +1,6 @@ const std = @import("../std.zig"); const Step = std.Build.Step; -const LibExeObjStep = std.Build.LibExeObjStep; +const CompileStep = std.Build.CompileStep; const InstallDir = std.Build.InstallDir; const InstallArtifactStep = @This(); @@ -8,12 +8,12 @@ pub const base_id = .install_artifact; step: Step, builder: *std.Build, -artifact: *LibExeObjStep, +artifact: *CompileStep, dest_dir: InstallDir, pdb_dir: ?InstallDir, h_dir: ?InstallDir, -pub fn create(builder: *std.Build, artifact: *LibExeObjStep) *InstallArtifactStep { +pub fn create(builder: *std.Build, artifact: *CompileStep) *InstallArtifactStep { if (artifact.install_step) |s| return s; const self = builder.allocator.create(InstallArtifactStep) catch unreachable; @@ -67,7 +67,7 @@ fn make(step: *Step) !void { const full_dest_path = builder.getInstallPath(self.dest_dir, self.artifact.out_filename); try builder.updateFile(self.artifact.getOutputSource().getPath(builder), full_dest_path); if (self.artifact.isDynamicLibrary() and self.artifact.version != null and self.artifact.target.wantSharedLibSymLinks()) { - try LibExeObjStep.doAtomicSymLinks(builder.allocator, full_dest_path, self.artifact.major_only_filename.?, self.artifact.name_only_filename.?); + try CompileStep.doAtomicSymLinks(builder.allocator, full_dest_path, self.artifact.major_only_filename.?, self.artifact.name_only_filename.?); } if (self.artifact.isDynamicLibrary() and self.artifact.target.isWindows() and self.artifact.emit_implib != .no_emit) { const full_implib_path = builder.getInstallPath(self.dest_dir, self.artifact.out_lib_filename); diff --git a/lib/std/Build/InstallRawStep.zig b/lib/std/Build/InstallRawStep.zig index 08d646ff88b79c7a59ee03d43223136ee88db683..e7ffe788786fe5fa38dd4f7bf026882f4d0e9ef5 100644 --- a/lib/std/Build/InstallRawStep.zig +++ b/lib/std/Build/InstallRawStep.zig @@ -9,7 +9,7 @@ const ArenaAllocator = std.heap.ArenaAllocator; const ArrayListUnmanaged = std.ArrayListUnmanaged; const File = std.fs.File; const InstallDir = std.Build.InstallDir; -const LibExeObjStep = std.Build.LibExeObjStep; +const CompileStep = std.Build.CompileStep; const Step = std.Build.Step; const elf = std.elf; const fs = std.fs; @@ -25,7 +25,7 @@ pub const RawFormat = enum { step: Step, builder: *std.Build, -artifact: *LibExeObjStep, +artifact: *CompileStep, dest_dir: InstallDir, dest_filename: []const u8, options: CreateOptions, @@ -40,7 +40,7 @@ pub const CreateOptions = struct { pub fn create( builder: *std.Build, - artifact: *LibExeObjStep, + artifact: *CompileStep, dest_filename: []const u8, options: CreateOptions, ) *InstallRawStep { diff --git a/lib/std/Build/OptionsStep.zig b/lib/std/Build/OptionsStep.zig index 8e1a7ef2fcf089ac7bd9d2b30370e4ccda2dc20c..94c41ce9e67623fb2aa0e15a79d6fc6b99aed500 100644 --- a/lib/std/Build/OptionsStep.zig +++ b/lib/std/Build/OptionsStep.zig @@ -3,7 +3,7 @@ const builtin = @import("builtin"); const fs = std.fs; const Step = std.Build.Step; const GeneratedFile = std.Build.GeneratedFile; -const LibExeObjStep = std.Build.LibExeObjStep; +const CompileStep = std.Build.CompileStep; const FileSource = std.Build.FileSource; const OptionsStep = @This(); @@ -195,7 +195,7 @@ pub fn addOptionFileSource( /// The value is the path in the cache dir. /// Adds a dependency automatically. -pub fn addOptionArtifact(self: *OptionsStep, name: []const u8, artifact: *LibExeObjStep) void { +pub fn addOptionArtifact(self: *OptionsStep, name: []const u8, artifact: *CompileStep) void { self.artifact_args.append(.{ .name = self.builder.dupe(name), .artifact = artifact }) catch unreachable; self.step.dependOn(&artifact.step); } @@ -266,7 +266,7 @@ fn hashContentsToFileName(self: *OptionsStep) [64]u8 { const OptionArtifactArg = struct { name: []const u8, - artifact: *LibExeObjStep, + artifact: *CompileStep, }; const OptionFileSourceArg = struct { diff --git a/lib/std/Build/RunStep.zig b/lib/std/Build/RunStep.zig index 83e4f7f66c706ba0f7de6297e2f0602c3b8dced8..9ab9ea6335224247ae234b401b3bbb07d6e18782 100644 --- a/lib/std/Build/RunStep.zig +++ b/lib/std/Build/RunStep.zig @@ -1,7 +1,7 @@ const std = @import("../std.zig"); const builtin = @import("builtin"); const Step = std.Build.Step; -const LibExeObjStep = std.Build.LibExeObjStep; +const CompileStep = std.Build.CompileStep; const WriteFileStep = std.Build.WriteFileStep; const fs = std.fs; const mem = std.mem; @@ -48,7 +48,7 @@ pub const StdIoAction = union(enum) { }; pub const Arg = union(enum) { - artifact: *LibExeObjStep, + artifact: *CompileStep, file_source: std.Build.FileSource, bytes: []u8, }; @@ -66,7 +66,7 @@ pub fn create(builder: *std.Build, name: []const u8) *RunStep { return self; } -pub fn addArtifactArg(self: *RunStep, artifact: *LibExeObjStep) void { +pub fn addArtifactArg(self: *RunStep, artifact: *CompileStep) void { self.argv.append(Arg{ .artifact = artifact }) catch unreachable; self.step.dependOn(&artifact.step); } @@ -355,13 +355,13 @@ fn printCmd(cwd: ?[]const u8, argv: []const []const u8) void { std.debug.print("\n", .{}); } -fn addPathForDynLibs(self: *RunStep, artifact: *LibExeObjStep) void { +fn addPathForDynLibs(self: *RunStep, artifact: *CompileStep) void { addPathForDynLibsInternal(&self.step, self.builder, artifact); } /// This should only be used for internal usage, this is called automatically /// for the user. -pub fn addPathForDynLibsInternal(step: *Step, builder: *std.Build, artifact: *LibExeObjStep) void { +pub fn addPathForDynLibsInternal(step: *Step, builder: *std.Build, artifact: *CompileStep) void { for (artifact.link_objects.items) |link_object| { switch (link_object) { .other_step => |other| { diff --git a/lib/std/Build/Step.zig b/lib/std/Build/Step.zig index 86d6645c293278999cedd34eaaecdf07a97cbcab..aff8a49161cdbddac29bc48e42a70ea6c6a013ae 100644 --- a/lib/std/Build/Step.zig +++ b/lib/std/Build/Step.zig @@ -7,7 +7,7 @@ done_flag: bool, pub const Id = enum { top_level, - lib_exe_obj, + compile, install_artifact, install_file, install_dir, @@ -28,7 +28,7 @@ pub const Id = enum { pub fn Type(comptime id: Id) type { return switch (id) { .top_level => Build.TopLevelStep, - .lib_exe_obj => Build.LibExeObjStep, + .compile => Build.CompileStep, .install_artifact => Build.InstallArtifactStep, .install_file => Build.InstallFileStep, .install_dir => Build.InstallDirStep, diff --git a/lib/std/Build/TranslateCStep.zig b/lib/std/Build/TranslateCStep.zig index 5404747846c70f91f9f6da5f3782c16439029121..c59362aeeec43442a720fa063551db4bef8e4f47 100644 --- a/lib/std/Build/TranslateCStep.zig +++ b/lib/std/Build/TranslateCStep.zig @@ -1,6 +1,6 @@ const std = @import("../std.zig"); const Step = std.Build.Step; -const LibExeObjStep = std.Build.LibExeObjStep; +const CompileStep = std.Build.CompileStep; const CheckFileStep = std.Build.CheckFileStep; const fs = std.fs; const mem = std.mem; @@ -51,11 +51,11 @@ pub const AddExecutableOptions = struct { version: ?std.builtin.Version = null, target: ?CrossTarget = null, optimize: ?std.builtin.Mode = null, - linkage: ?LibExeObjStep.Linkage = null, + linkage: ?CompileStep.Linkage = null, }; /// Creates a step to build an executable from the translated source. -pub fn addExecutable(self: *TranslateCStep, options: AddExecutableOptions) *LibExeObjStep { +pub fn addExecutable(self: *TranslateCStep, options: AddExecutableOptions) *CompileStep { return self.builder.addExecutable(.{ .root_source_file = .{ .generated = &self.output_file }, .name = options.name orelse "translated_c", diff --git a/lib/std/std.zig b/lib/std/std.zig index e0318ceb438b4062f45af3a8a16a58af4ebdc514..7440b4966250e476947c22060af9445c8964570f 100644 --- a/lib/std/std.zig +++ b/lib/std/std.zig @@ -97,8 +97,10 @@ pub const zig = @import("zig.zig"); pub const start = @import("start.zig"); ///// Deprecated. Use `std.Build` instead. +///// TODO: remove this after releasing 0.11.0 //pub const build = struct { // /// Deprecated. Use `std.Build` instead. +// /// TODO: remove this after releasing 0.11.0 // pub const Builder = Build; //}; diff --git a/test/link/macho/bugs/13457/build.zig b/test/link/macho/bugs/13457/build.zig index 6ca1f31b86b1cf1314e06ed244627e37a73e2ef4..3560b4a168c944b439485b3229186bae39c1ed75 100644 --- a/test/link/macho/bugs/13457/build.zig +++ b/test/link/macho/bugs/13457/build.zig @@ -1,5 +1,4 @@ const std = @import("std"); -const LibExeObjectStep = std.Build.LibExeObjStep; pub fn build(b: *std.Build) void { const optimize = b.standardOptimizeOption(.{}); diff --git a/test/link/macho/dead_strip/build.zig b/test/link/macho/dead_strip/build.zig index b6c30024929db544fd5f3218f29b83aca01e59ce..d82c81edca42c46e8edcf67272269c88df475fd8 100644 --- a/test/link/macho/dead_strip/build.zig +++ b/test/link/macho/dead_strip/build.zig @@ -1,5 +1,4 @@ const std = @import("std"); -const LibExeObjectStep = std.Build.LibExeObjStep; pub fn build(b: *std.Build) void { const optimize = b.standardOptimizeOption(.{}); @@ -36,7 +35,11 @@ pub fn build(b: *std.Build) void { } } -fn createScenario(b: *std.Build, optimize: std.builtin.OptimizeMode, target: std.zig.CrossTarget) *LibExeObjectStep { +fn createScenario( + b: *std.Build, + optimize: std.builtin.OptimizeMode, + target: std.zig.CrossTarget, +) *std.Build.CompileStep { const exe = b.addExecutable(.{ .name = "test", .optimize = optimize, diff --git a/test/link/macho/dead_strip_dylibs/build.zig b/test/link/macho/dead_strip_dylibs/build.zig index f61b30ca4af62069cca42cdb8f62250a0e029b84..8b62cec6e696267563cf025ce0a63215d9c879be 100644 --- a/test/link/macho/dead_strip_dylibs/build.zig +++ b/test/link/macho/dead_strip_dylibs/build.zig @@ -1,5 +1,4 @@ const std = @import("std"); -const LibExeObjectStep = std.Build.LibExeObjStep; pub fn build(b: *std.Build) void { const optimize = b.standardOptimizeOption(.{}); @@ -35,7 +34,7 @@ pub fn build(b: *std.Build) void { } } -fn createScenario(b: *std.Build, optimize: std.builtin.OptimizeMode) *LibExeObjectStep { +fn createScenario(b: *std.Build, optimize: std.builtin.OptimizeMode) *std.Build.CompileStep { const exe = b.addExecutable(.{ .name = "test", .optimize = optimize, diff --git a/test/link/macho/headerpad/build.zig b/test/link/macho/headerpad/build.zig index 2b3c6abb8a92a9558b3f8bf71057854179e4bde1..3ef17573f881a9e1c0ffcda65268373bbffa67e3 100644 --- a/test/link/macho/headerpad/build.zig +++ b/test/link/macho/headerpad/build.zig @@ -1,6 +1,5 @@ const std = @import("std"); const builtin = @import("builtin"); -const LibExeObjectStep = std.Build.LibExeObjStep; pub fn build(b: *std.Build) void { const optimize = b.standardOptimizeOption(.{}); @@ -93,7 +92,7 @@ pub fn build(b: *std.Build) void { } } -fn simpleExe(b: *std.Build, optimize: std.builtin.OptimizeMode) *LibExeObjectStep { +fn simpleExe(b: *std.Build, optimize: std.builtin.OptimizeMode) *std.Build.CompileStep { const exe = b.addExecutable(.{ .name = "main", .optimize = optimize, diff --git a/test/link/macho/needed_framework/build.zig b/test/link/macho/needed_framework/build.zig index 62b70b21f195dc995b371ed0dd3582ac419060fe..8b6e3dd87f6f31f5e75bbfc42fad86d603c2ceb0 100644 --- a/test/link/macho/needed_framework/build.zig +++ b/test/link/macho/needed_framework/build.zig @@ -1,5 +1,4 @@ const std = @import("std"); -const LibExeObjectStep = std.Build.LibExeObjStep; pub fn build(b: *std.Build) void { const optimize = b.standardOptimizeOption(.{}); diff --git a/test/link/macho/needed_library/build.zig b/test/link/macho/needed_library/build.zig index cdad94357bc53af113c5381cea16fe58cf5351c1..92a73d22b795cdebfe0f4aeeeccb2ab581bba6a3 100644 --- a/test/link/macho/needed_library/build.zig +++ b/test/link/macho/needed_library/build.zig @@ -1,5 +1,4 @@ const std = @import("std"); -const LibExeObjectStep = std.Build.LibExeObjStep; pub fn build(b: *std.Build) void { const optimize = b.standardOptimizeOption(.{}); diff --git a/test/link/macho/search_strategy/build.zig b/test/link/macho/search_strategy/build.zig index eeda89446bc5a7b92a5545b6fd31b82ed9f8b1d0..62757f885bd14d6a65633acf38383c13247b0fcc 100644 --- a/test/link/macho/search_strategy/build.zig +++ b/test/link/macho/search_strategy/build.zig @@ -1,5 +1,4 @@ const std = @import("std"); -const LibExeObjectStep = std.Build.LibExeObjStep; pub fn build(b: *std.Build) void { const optimize = b.standardOptimizeOption(.{}); @@ -35,7 +34,11 @@ pub fn build(b: *std.Build) void { } } -fn createScenario(b: *std.Build, optimize: std.builtin.OptimizeMode, target: std.zig.CrossTarget) *LibExeObjectStep { +fn createScenario( + b: *std.Build, + optimize: std.builtin.OptimizeMode, + target: std.zig.CrossTarget, +) *std.Build.CompileStep { const static = b.addStaticLibrary(.{ .name = "a", .optimize = optimize, diff --git a/test/link/macho/strict_validation/build.zig b/test/link/macho/strict_validation/build.zig index 6eabc02b5f8553b74da699aedc373b041d7b0e91..408076657b13f30f69b9a60cd75a21e69c2eaca8 100644 --- a/test/link/macho/strict_validation/build.zig +++ b/test/link/macho/strict_validation/build.zig @@ -1,6 +1,5 @@ const std = @import("std"); const builtin = @import("builtin"); -const LibExeObjectStep = std.Build.LibExeObjStep; pub fn build(b: *std.Build) void { const optimize = b.standardOptimizeOption(.{}); diff --git a/test/link/macho/unwind_info/build.zig b/test/link/macho/unwind_info/build.zig index e43c002e2ea89c725137153b3f09edbca9bed90c..408f762f5db2c4238c4d0bc645d38713813bff49 100644 --- a/test/link/macho/unwind_info/build.zig +++ b/test/link/macho/unwind_info/build.zig @@ -1,6 +1,5 @@ const std = @import("std"); const builtin = @import("builtin"); -const LibExeObjectStep = std.Build.LibExeObjStep; pub fn build(b: *std.Build) void { const optimize = b.standardOptimizeOption(.{}); @@ -51,7 +50,11 @@ fn testUnwindInfo( test_step.dependOn(&run_cmd.step); } -fn createScenario(b: *std.Build, optimize: std.builtin.OptimizeMode, target: std.zig.CrossTarget) *LibExeObjectStep { +fn createScenario( + b: *std.Build, + optimize: std.builtin.OptimizeMode, + target: std.zig.CrossTarget, +) *std.Build.CompileStep { const exe = b.addExecutable(.{ .name = "test", .optimize = optimize, diff --git a/test/link/macho/uuid/build.zig b/test/link/macho/uuid/build.zig index 62c288f1a034476e5f0d867dbd3f014e5208b522..6a68263fbf0cff4f0726580866b2e6e37455914f 100644 --- a/test/link/macho/uuid/build.zig +++ b/test/link/macho/uuid/build.zig @@ -1,5 +1,4 @@ const std = @import("std"); -const LibExeObjectStep = std.Build.LibExeObjStep; pub fn build(b: *std.Build) void { const test_step = b.step("test", "Test"); @@ -51,7 +50,11 @@ fn testUuid( } } -fn simpleDylib(b: *std.Build, optimize: std.builtin.OptimizeMode, target: std.zig.CrossTarget) *LibExeObjectStep { +fn simpleDylib( + b: *std.Build, + optimize: std.builtin.OptimizeMode, + target: std.zig.CrossTarget, +) *std.Build.CompileStep { const dylib = b.addSharedLibrary(.{ .name = "test", .version = .{ .major = 1, .minor = 0 }, diff --git a/test/link/macho/weak_framework/build.zig b/test/link/macho/weak_framework/build.zig index 5be66991dde676d2ccf2292023ca122a9432abb0..ca28458d7754445041bec28aeb1465b1b57854db 100644 --- a/test/link/macho/weak_framework/build.zig +++ b/test/link/macho/weak_framework/build.zig @@ -1,5 +1,4 @@ const std = @import("std"); -const LibExeObjectStep = std.Build.LibExeObjStep; pub fn build(b: *std.Build) void { const optimize = b.standardOptimizeOption(.{}); diff --git a/test/link/macho/weak_library/build.zig b/test/link/macho/weak_library/build.zig index 505ab5ae965ac921c6e8113a735631a0d0cd0c61..de5aa45e30deada80ecac9a5783dbef3ca216d84 100644 --- a/test/link/macho/weak_library/build.zig +++ b/test/link/macho/weak_library/build.zig @@ -1,5 +1,4 @@ const std = @import("std"); -const LibExeObjectStep = std.Build.LibExeObjStep; pub fn build(b: *std.Build) void { const optimize = b.standardOptimizeOption(.{}); diff --git a/test/tests.zig b/test/tests.zig index de25528dde06ed0bf7dad0701d1c1ae7203f06ec..0f36c8eb94002f9de1b8d101c4161220a447d6d4 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -8,7 +8,7 @@ const mem = std.mem; const fmt = std.fmt; const ArrayList = std.ArrayList; const OptimizeMode = std.builtin.OptimizeMode; -const LibExeObjStep = std.Build.LibExeObjStep; +const CompileStep = std.Build.CompileStep; const Allocator = mem.Allocator; const ExecError = std.Build.ExecError; const Step = std.Build.Step; @@ -842,7 +842,7 @@ pub const StackTracesContext = struct { step: Step, context: *StackTracesContext, - exe: *LibExeObjStep, + exe: *CompileStep, name: []const u8, optimize_mode: OptimizeMode, expect_output: []const u8, @@ -850,7 +850,7 @@ pub const StackTracesContext = struct { pub fn create( context: *StackTracesContext, - exe: *LibExeObjStep, + exe: *CompileStep, name: []const u8, optimize_mode: OptimizeMode, expect_output: []const u8, @@ -1180,14 +1180,14 @@ pub const GenHContext = struct { const GenHCmpOutputStep = struct { step: Step, context: *GenHContext, - obj: *LibExeObjStep, + obj: *CompileStep, name: []const u8, test_index: usize, case: *const TestCase, pub fn create( context: *GenHContext, - obj: *LibExeObjStep, + obj: *CompileStep, name: []const u8, case: *const TestCase, ) *GenHCmpOutputStep { -- 2.54.0 From 13a96165405af33fa6ef43a3ce2c1d8aea846287 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 31 Jan 2023 13:48:24 -0700 Subject: [PATCH 54/84] std.Build: add deprecated declarations These declarations are now aliases of their new APIs and marked as deprecated via doc comments: * std.build.Builder * std.build * std.Build.LibExeObjStep --- lib/std/Build.zig | 11 ++++++----- lib/std/std.zig | 9 ++------- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/lib/std/Build.zig b/lib/std/Build.zig index 4647baa3981784ba4ee54ce47458cab18e94b17f..008ae5f4d74db8d62dc6b872ffd2a2ac67af9067 100644 --- a/lib/std/Build.zig +++ b/lib/std/Build.zig @@ -19,8 +19,12 @@ const NativeTargetInfo = std.zig.system.NativeTargetInfo; const Sha256 = std.crypto.hash.sha2.Sha256; const Build = @This(); -///// deprecated: use `CompileStep` instead. -//pub const LibExeObjStep = CompileStep; +/// deprecated: use `CompileStep`. +pub const LibExeObjStep = CompileStep; +/// deprecated: use `Build`. +pub const Builder = Build; +/// deprecated: use `InstallDirStep.Options` +pub const InstallDirectoryOptions = InstallDirStep.Options; pub const Step = @import("Build/Step.zig"); pub const CheckFileStep = @import("Build/CheckFileStep.zig"); @@ -1637,9 +1641,6 @@ pub fn constructCMacro(allocator: Allocator, name: []const u8, value: ?[]const u return macro; } -/// deprecated: use `InstallDirStep.Options` -pub const InstallDirectoryOptions = InstallDirStep.Options; - pub const VcpkgRoot = union(VcpkgRootStatus) { unattempted: void, not_found: void, diff --git a/lib/std/std.zig b/lib/std/std.zig index 7440b4966250e476947c22060af9445c8964570f..40ba8965697e3d56d3e22106772ba002ab6f9ef9 100644 --- a/lib/std/std.zig +++ b/lib/std/std.zig @@ -96,13 +96,8 @@ pub const wasm = @import("wasm.zig"); pub const zig = @import("zig.zig"); pub const start = @import("start.zig"); -///// Deprecated. Use `std.Build` instead. -///// TODO: remove this after releasing 0.11.0 -//pub const build = struct { -// /// Deprecated. Use `std.Build` instead. -// /// TODO: remove this after releasing 0.11.0 -// pub const Builder = Build; -//}; +/// deprecated: use `Build`. +pub const build = Build; const root = @import("root"); const options_override = if (@hasDecl(root, "std_options")) root.std_options else struct {}; -- 2.54.0 From 90e48d4b3469fb4f8dd2f3b52e05453029d45fdc Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 31 Jan 2023 14:02:32 -0700 Subject: [PATCH 55/84] std.Build: avoid use of catch unreachable Usage of `catch unreachable` in build scripts is completely harmless because build scripts are always run in Debug mode, however, it sets a poor example for beginners to learn from. --- lib/std/Build.zig | 69 ++++++++------- lib/std/Build/CheckFileStep.zig | 2 +- lib/std/Build/CheckObjectStep.zig | 12 +-- lib/std/Build/CompileStep.zig | 121 ++++++++++++++------------ lib/std/Build/EmulatableRunStep.zig | 8 +- lib/std/Build/FmtStep.zig | 4 +- lib/std/Build/InstallArtifactStep.zig | 2 +- lib/std/Build/InstallRawStep.zig | 4 +- lib/std/Build/OptionsStep.zig | 62 +++++++------ lib/std/Build/RunStep.zig | 24 ++--- lib/std/Build/Step.zig | 4 +- lib/std/Build/TranslateCStep.zig | 12 +-- lib/std/Build/WriteFileStep.zig | 6 +- 13 files changed, 169 insertions(+), 161 deletions(-) diff --git a/lib/std/Build.zig b/lib/std/Build.zig index 008ae5f4d74db8d62dc6b872ffd2a2ac67af9067..d695637fc336414b606425734eb12a0974f2a0e0 100644 --- a/lib/std/Build.zig +++ b/lib/std/Build.zig @@ -564,12 +564,12 @@ pub fn addConfigHeader( /// Allocator.dupe without the need to handle out of memory. pub fn dupe(self: *Build, bytes: []const u8) []u8 { - return self.allocator.dupe(u8, bytes) catch unreachable; + return self.allocator.dupe(u8, bytes) catch @panic("OOM"); } /// Duplicates an array of strings without the need to handle out of memory. pub fn dupeStrings(self: *Build, strings: []const []const u8) [][]u8 { - const array = self.allocator.alloc([]u8, strings.len) catch unreachable; + const array = self.allocator.alloc([]u8, strings.len) catch @panic("OOM"); for (strings) |s, i| { array[i] = self.dupe(s); } @@ -596,7 +596,7 @@ pub fn dupePkg(self: *Build, package: Pkg) Pkg { }; if (package.dependencies) |dependencies| { - const new_dependencies = self.allocator.alloc(Pkg, dependencies.len) catch unreachable; + const new_dependencies = self.allocator.alloc(Pkg, dependencies.len) catch @panic("OOM"); the_copy.dependencies = new_dependencies; for (dependencies) |dep_package, i| { @@ -613,20 +613,20 @@ pub fn addWriteFile(self: *Build, file_path: []const u8, data: []const u8) *Writ } pub fn addWriteFiles(self: *Build) *WriteFileStep { - const write_file_step = self.allocator.create(WriteFileStep) catch unreachable; + const write_file_step = self.allocator.create(WriteFileStep) catch @panic("OOM"); write_file_step.* = WriteFileStep.init(self); return write_file_step; } pub fn addLog(self: *Build, comptime format: []const u8, args: anytype) *LogStep { const data = self.fmt(format, args); - const log_step = self.allocator.create(LogStep) catch unreachable; + const log_step = self.allocator.create(LogStep) catch @panic("OOM"); log_step.* = LogStep.init(self, data); return log_step; } pub fn addRemoveDirTree(self: *Build, dir_path: []const u8) *RemoveDirStep { - const remove_dir_step = self.allocator.create(RemoveDirStep) catch unreachable; + const remove_dir_step = self.allocator.create(RemoveDirStep) catch @panic("OOM"); remove_dir_step.* = RemoveDirStep.init(self, dir_path); return remove_dir_step; } @@ -719,13 +719,13 @@ pub fn option(self: *Build, comptime T: type, name_raw: []const u8, description_ const type_id = comptime typeToEnum(T); const enum_options = if (type_id == .@"enum") blk: { const fields = comptime std.meta.fields(T); - var options = ArrayList([]const u8).initCapacity(self.allocator, fields.len) catch unreachable; + var options = ArrayList([]const u8).initCapacity(self.allocator, fields.len) catch @panic("OOM"); inline for (fields) |field| { options.appendAssumeCapacity(field.name); } - break :blk options.toOwnedSlice() catch unreachable; + break :blk options.toOwnedSlice() catch @panic("OOM"); } else null; const available_option = AvailableOption{ .name = name, @@ -733,10 +733,10 @@ pub fn option(self: *Build, comptime T: type, name_raw: []const u8, description_ .description = description, .enum_options = enum_options, }; - if ((self.available_options_map.fetchPut(name, available_option) catch unreachable) != null) { + if ((self.available_options_map.fetchPut(name, available_option) catch @panic("OOM")) != null) { panic("Option '{s}' declared twice", .{name}); } - self.available_options_list.append(available_option) catch unreachable; + self.available_options_list.append(available_option) catch @panic("OOM"); const option_ptr = self.user_input_options.getPtr(name) orelse return null; option_ptr.used = true; @@ -840,7 +840,7 @@ pub fn option(self: *Build, comptime T: type, name_raw: []const u8, description_ return null; }, .scalar => |s| { - return self.allocator.dupe([]const u8, &[_][]const u8{s}) catch unreachable; + return self.allocator.dupe([]const u8, &[_][]const u8{s}) catch @panic("OOM"); }, .list => |lst| return lst.items, }, @@ -848,12 +848,12 @@ pub fn option(self: *Build, comptime T: type, name_raw: []const u8, description_ } pub fn step(self: *Build, name: []const u8, description: []const u8) *Step { - const step_info = self.allocator.create(TopLevelStep) catch unreachable; + const step_info = self.allocator.create(TopLevelStep) catch @panic("OOM"); step_info.* = TopLevelStep{ .step = Step.initNoOp(.top_level, name, self.allocator), .description = self.dupe(description), }; - self.top_level_steps.append(step_info) catch unreachable; + self.top_level_steps.append(step_info) catch @panic("OOM"); return &step_info.step; } @@ -949,7 +949,7 @@ pub fn standardTargetOptions(self: *Build, args: StandardTargetOptionsArgs) Cros }, }; - const selected_canonicalized_triple = selected_target.zigTriple(self.allocator) catch unreachable; + const selected_canonicalized_triple = selected_target.zigTriple(self.allocator) catch @panic("OOM"); if (args.whitelist) |list| whitelist_check: { // Make sure it's a match of one of the list. @@ -960,7 +960,7 @@ pub fn standardTargetOptions(self: *Build, args: StandardTargetOptionsArgs) Cros mismatch_cpu_features = true; mismatch_triple = true; - const t_triple = t.zigTriple(self.allocator) catch unreachable; + const t_triple = t.zigTriple(self.allocator) catch @panic("OOM"); if (mem.eql(u8, t_triple, selected_canonicalized_triple)) { mismatch_triple = false; whitelist_item = t; @@ -977,7 +977,7 @@ pub fn standardTargetOptions(self: *Build, args: StandardTargetOptionsArgs) Cros selected_canonicalized_triple, }); for (list) |t| { - const t_triple = t.zigTriple(self.allocator) catch unreachable; + const t_triple = t.zigTriple(self.allocator) catch @panic("OOM"); log.err(" {s}", .{t_triple}); } } else { @@ -1033,22 +1033,22 @@ pub fn addUserInputOption(self: *Build, name_raw: []const u8, value_raw: []const .scalar => |s| { // turn it into a list var list = ArrayList([]const u8).init(self.allocator); - list.append(s) catch unreachable; - list.append(value) catch unreachable; - self.user_input_options.put(name, .{ + try list.append(s); + try list.append(value); + try self.user_input_options.put(name, .{ .name = name, .value = .{ .list = list }, .used = false, - }) catch unreachable; + }); }, .list => |*list| { // append to the list - list.append(value) catch unreachable; - self.user_input_options.put(name, .{ + try list.append(value); + try self.user_input_options.put(name, .{ .name = name, .value = .{ .list = list.* }, .used = false, - }) catch unreachable; + }); }, .flag => { log.warn("Option '-D{s}={s}' conflicts with flag '-D{s}'.", .{ name, value, name }); @@ -1240,13 +1240,13 @@ pub fn addInstallFileWithDir( if (dest_rel_path.len == 0) { panic("dest_rel_path must be non-empty", .{}); } - const install_step = self.allocator.create(InstallFileStep) catch unreachable; + const install_step = self.allocator.create(InstallFileStep) catch @panic("OOM"); install_step.* = InstallFileStep.init(self, source.dupe(self), install_dir, dest_rel_path); return install_step; } pub fn addInstallDirectory(self: *Build, options: InstallDirectoryOptions) *InstallDirStep { - const install_step = self.allocator.create(InstallDirStep) catch unreachable; + const install_step = self.allocator.create(InstallDirStep) catch @panic("OOM"); install_step.* = InstallDirStep.init(self, options); return install_step; } @@ -1256,7 +1256,7 @@ pub fn pushInstalledFile(self: *Build, dir: InstallDir, dest_rel_path: []const u .dir = dir, .path = dest_rel_path, }; - self.installed_files.append(file.dupe(self)) catch unreachable; + self.installed_files.append(file.dupe(self)) catch @panic("OOM"); } pub fn updateFile(self: *Build, source_path: []const u8, dest_path: []const u8) !void { @@ -1289,16 +1289,15 @@ pub fn truncateFile(self: *Build, dest_path: []const u8) !void { } pub fn pathFromRoot(self: *Build, rel_path: []const u8) []u8 { - return fs.path.resolve(self.allocator, &[_][]const u8{ self.build_root, rel_path }) catch unreachable; + return fs.path.resolve(self.allocator, &[_][]const u8{ self.build_root, rel_path }) catch @panic("OOM"); } -/// Shorthand for `std.fs.path.join(Build.allocator, paths) catch unreachable` pub fn pathJoin(self: *Build, paths: []const []const u8) []u8 { - return fs.path.join(self.allocator, paths) catch unreachable; + return fs.path.join(self.allocator, paths) catch @panic("OOM"); } pub fn fmt(self: *Build, comptime format: []const u8, args: anytype) []u8 { - return fmt_lib.allocPrint(self.allocator, format, args) catch unreachable; + return fmt_lib.allocPrint(self.allocator, format, args) catch @panic("OOM"); } pub fn findProgram(self: *Build, names: []const []const u8, paths: []const []const u8) ![]const u8 { @@ -1442,7 +1441,7 @@ pub fn exec(self: *Build, argv: []const []const u8) ![]u8 { } pub fn addSearchPrefix(self: *Build, search_prefix: []const u8) void { - self.search_prefixes.append(self.dupePath(search_prefix)) catch unreachable; + self.search_prefixes.append(self.dupePath(search_prefix)) catch @panic("OOM"); } pub fn getInstallPath(self: *Build, dir: InstallDir, dest_rel_path: []const u8) []const u8 { @@ -1457,7 +1456,7 @@ pub fn getInstallPath(self: *Build, dir: InstallDir, dest_rel_path: []const u8) return fs.path.resolve( self.allocator, &[_][]const u8{ base_dir, dest_rel_path }, - ) catch unreachable; + ) catch @panic("OOM"); } pub const Dependency = struct { @@ -1509,14 +1508,14 @@ fn dependencyInner( comptime build_zig: type, args: anytype, ) *Dependency { - const sub_builder = b.createChild(name, build_root, args) catch unreachable; - sub_builder.runBuild(build_zig) catch unreachable; + const sub_builder = b.createChild(name, build_root, args) catch @panic("unhandled error"); + sub_builder.runBuild(build_zig) catch @panic("unhandled error"); if (sub_builder.validateUserInputDidItFail()) { std.debug.dumpCurrentStackTrace(@returnAddress()); } - const dep = b.allocator.create(Dependency) catch unreachable; + const dep = b.allocator.create(Dependency) catch @panic("OOM"); dep.* = .{ .builder = sub_builder }; return dep; } diff --git a/lib/std/Build/CheckFileStep.zig b/lib/std/Build/CheckFileStep.zig index 3b8cfe5263ae53b14e53ced20a4b1306a60b23da..b08a797e841343d926acc619c740f74bc4c3d5be 100644 --- a/lib/std/Build/CheckFileStep.zig +++ b/lib/std/Build/CheckFileStep.zig @@ -18,7 +18,7 @@ pub fn create( source: std.Build.FileSource, expected_matches: []const []const u8, ) *CheckFileStep { - const self = builder.allocator.create(CheckFileStep) catch unreachable; + const self = builder.allocator.create(CheckFileStep) catch @panic("OOM"); self.* = CheckFileStep{ .builder = builder, .step = Step.init(.check_file, "CheckFile", builder.allocator, make), diff --git a/lib/std/Build/CheckObjectStep.zig b/lib/std/Build/CheckObjectStep.zig index bfa533892781396f5efd8ba19a8fad2a5c0a903d..5cb096581f99d29142bf13e6a79a6b79a69904e8 100644 --- a/lib/std/Build/CheckObjectStep.zig +++ b/lib/std/Build/CheckObjectStep.zig @@ -24,7 +24,7 @@ obj_format: std.Target.ObjectFormat, pub fn create(builder: *std.Build, source: std.Build.FileSource, obj_format: std.Target.ObjectFormat) *CheckObjectStep { const gpa = builder.allocator; - const self = gpa.create(CheckObjectStep) catch unreachable; + const self = gpa.create(CheckObjectStep) catch @panic("OOM"); self.* = .{ .builder = builder, .step = Step.init(.check_file, "CheckObject", gpa, make), @@ -228,14 +228,14 @@ const Check = struct { self.actions.append(.{ .tag = .match, .phrase = self.builder.dupe(phrase), - }) catch unreachable; + }) catch @panic("OOM"); } fn notPresent(self: *Check, phrase: []const u8) void { self.actions.append(.{ .tag = .not_present, .phrase = self.builder.dupe(phrase), - }) catch unreachable; + }) catch @panic("OOM"); } fn computeCmp(self: *Check, phrase: []const u8, expected: ComputeCompareExpected) void { @@ -243,7 +243,7 @@ const Check = struct { .tag = .compute_cmp, .phrase = self.builder.dupe(phrase), .expected = expected, - }) catch unreachable; + }) catch @panic("OOM"); } }; @@ -251,7 +251,7 @@ const Check = struct { pub fn checkStart(self: *CheckObjectStep, phrase: []const u8) void { var new_check = Check.create(self.builder); new_check.match(phrase); - self.checks.append(new_check) catch unreachable; + self.checks.append(new_check) catch @panic("OOM"); } /// Adds another searched phrase to the latest created Check with `CheckObjectStep.checkStart(...)`. @@ -293,7 +293,7 @@ pub fn checkComputeCompare( ) void { var new_check = Check.create(self.builder); new_check.computeCmp(program, expected); - self.checks.append(new_check) catch unreachable; + self.checks.append(new_check) catch @panic("OOM"); } fn make(step: *Step) !void { diff --git a/lib/std/Build/CompileStep.zig b/lib/std/Build/CompileStep.zig index 5257c85a5cbca4e4f36935eedcc2668644779151..7396a5ce66bfd447fdedda348011397cf21f9d87 100644 --- a/lib/std/Build/CompileStep.zig +++ b/lib/std/Build/CompileStep.zig @@ -312,7 +312,7 @@ pub fn create(builder: *std.Build, options: Options) *CompileStep { panic("invalid name: '{s}'. It looks like a file path, but it is supposed to be the library or application name.", .{name}); } - const self = builder.allocator.create(CompileStep) catch unreachable; + const self = builder.allocator.create(CompileStep) catch @panic("OOM"); self.* = CompileStep{ .strip = null, .unwind_tables = null, @@ -364,7 +364,7 @@ pub fn create(builder: *std.Build, options: Options) *CompileStep { .output_h_path_source = GeneratedFile{ .step = &self.step }, .output_pdb_path_source = GeneratedFile{ .step = &self.step }, - .target_info = NativeTargetInfo.detect(self.target) catch unreachable, + .target_info = NativeTargetInfo.detect(self.target) catch @panic("unhandled error"), }; self.computeOutFileNames(); if (root_src) |rs| rs.addStepDependencies(&self.step); @@ -387,7 +387,7 @@ fn computeOutFileNames(self: *CompileStep) void { .static => .Static, }) else null, .version = self.version, - }) catch unreachable; + }) catch @panic("OOM"); if (self.kind == .lib) { if (self.linkage != null and self.linkage.? == .static) { @@ -439,7 +439,7 @@ pub fn installRaw(self: *CompileStep, dest_filename: []const u8, options: Instal pub fn installHeader(a: *CompileStep, src_path: []const u8, dest_rel_path: []const u8) void { const install_file = a.builder.addInstallHeaderFile(src_path, dest_rel_path); a.builder.getInstallStep().dependOn(&install_file.step); - a.installed_headers.append(&install_file.step) catch unreachable; + a.installed_headers.append(&install_file.step) catch @panic("OOM"); } pub fn installHeadersDirectory( @@ -460,7 +460,7 @@ pub fn installHeadersDirectoryOptions( ) void { const install_dir = a.builder.addInstallDirectory(options); a.builder.getInstallStep().dependOn(&install_dir.step); - a.installed_headers.append(&install_dir.step) catch unreachable; + a.installed_headers.append(&install_dir.step) catch @panic("OOM"); } pub fn installLibraryHeaders(a: *CompileStep, l: *CompileStep) void { @@ -472,7 +472,7 @@ pub fn installLibraryHeaders(a: *CompileStep, l: *CompileStep) void { const step_copy = switch (step.id) { inline .install_file, .install_dir => |id| blk: { const T = id.Type(); - const ptr = a.builder.allocator.create(T) catch unreachable; + const ptr = a.builder.allocator.create(T) catch @panic("OOM"); ptr.* = step.cast(T).?.*; ptr.override_source_builder = ptr.builder; ptr.builder = a.builder; @@ -480,10 +480,10 @@ pub fn installLibraryHeaders(a: *CompileStep, l: *CompileStep) void { }, else => unreachable, }; - a.installed_headers.append(step_copy) catch unreachable; + a.installed_headers.append(step_copy) catch @panic("OOM"); install_step.dependOn(step_copy); } - a.installed_headers.appendSlice(l.installed_headers.items) catch unreachable; + a.installed_headers.appendSlice(l.installed_headers.items) catch @panic("OOM"); } /// Creates a `RunStep` with an executable built with `addExecutable`. @@ -532,19 +532,19 @@ pub fn setLinkerScriptPath(self: *CompileStep, source: FileSource) void { } pub fn linkFramework(self: *CompileStep, framework_name: []const u8) void { - self.frameworks.put(self.builder.dupe(framework_name), .{}) catch unreachable; + self.frameworks.put(self.builder.dupe(framework_name), .{}) catch @panic("OOM"); } pub fn linkFrameworkNeeded(self: *CompileStep, framework_name: []const u8) void { self.frameworks.put(self.builder.dupe(framework_name), .{ .needed = true, - }) catch unreachable; + }) catch @panic("OOM"); } pub fn linkFrameworkWeak(self: *CompileStep, framework_name: []const u8) void { self.frameworks.put(self.builder.dupe(framework_name), .{ .weak = true, - }) catch unreachable; + }) catch @panic("OOM"); } /// Returns whether the library, executable, or object depends on a particular system library. @@ -596,12 +596,12 @@ pub fn linkLibCpp(self: *CompileStep) void { /// `name` and `value` need not live longer than the function call. pub fn defineCMacro(self: *CompileStep, name: []const u8, value: ?[]const u8) void { const macro = std.Build.constructCMacro(self.builder.allocator, name, value); - self.c_macros.append(macro) catch unreachable; + self.c_macros.append(macro) catch @panic("OOM"); } /// name_and_value looks like [name]=[value]. If the value is omitted, it is set to 1. pub fn defineCMacroRaw(self: *CompileStep, name_and_value: []const u8) void { - self.c_macros.append(self.builder.dupe(name_and_value)) catch unreachable; + self.c_macros.append(self.builder.dupe(name_and_value)) catch @panic("OOM"); } /// This one has no integration with anything, it just puts -lname on the command line. @@ -614,7 +614,7 @@ pub fn linkSystemLibraryName(self: *CompileStep, name: []const u8) void { .weak = false, .use_pkg_config = .no, }, - }) catch unreachable; + }) catch @panic("OOM"); } /// This one has no integration with anything, it just puts -needed-lname on the command line. @@ -627,7 +627,7 @@ pub fn linkSystemLibraryNeededName(self: *CompileStep, name: []const u8) void { .weak = false, .use_pkg_config = .no, }, - }) catch unreachable; + }) catch @panic("OOM"); } /// Darwin-only. This one has no integration with anything, it just puts -weak-lname on the @@ -640,7 +640,7 @@ pub fn linkSystemLibraryWeakName(self: *CompileStep, name: []const u8) void { .weak = true, .use_pkg_config = .no, }, - }) catch unreachable; + }) catch @panic("OOM"); } /// This links against a system library, exclusively using pkg-config to find the library. @@ -653,7 +653,7 @@ pub fn linkSystemLibraryPkgConfigOnly(self: *CompileStep, lib_name: []const u8) .weak = false, .use_pkg_config = .force, }, - }) catch unreachable; + }) catch @panic("OOM"); } /// This links against a system library, exclusively using pkg-config to find the library. @@ -666,7 +666,7 @@ pub fn linkSystemLibraryNeededPkgConfigOnly(self: *CompileStep, lib_name: []cons .weak = false, .use_pkg_config = .force, }, - }) catch unreachable; + }) catch @panic("OOM"); } /// Run pkg-config for the given library name and parse the output, returning the arguments @@ -797,7 +797,7 @@ fn linkSystemLibraryInner(self: *CompileStep, name: []const u8, opts: struct { .weak = opts.weak, .use_pkg_config = .yes, }, - }) catch unreachable; + }) catch @panic("OOM"); } pub fn setNamePrefix(self: *CompileStep, text: []const u8) void { @@ -817,7 +817,7 @@ pub fn setTestRunner(self: *CompileStep, path: ?[]const u8) void { /// Handy when you have many C/C++ source files and want them all to have the same flags. pub fn addCSourceFiles(self: *CompileStep, files: []const []const u8, flags: []const []const u8) void { - const c_source_files = self.builder.allocator.create(CSourceFiles) catch unreachable; + const c_source_files = self.builder.allocator.create(CSourceFiles) catch @panic("OOM"); const files_copy = self.builder.dupeStrings(files); const flags_copy = self.builder.dupeStrings(flags); @@ -826,7 +826,7 @@ pub fn addCSourceFiles(self: *CompileStep, files: []const []const u8, flags: []c .files = files_copy, .flags = flags_copy, }; - self.link_objects.append(.{ .c_source_files = c_source_files }) catch unreachable; + self.link_objects.append(.{ .c_source_files = c_source_files }) catch @panic("OOM"); } pub fn addCSourceFile(self: *CompileStep, file: []const u8, flags: []const []const u8) void { @@ -837,9 +837,9 @@ pub fn addCSourceFile(self: *CompileStep, file: []const u8, flags: []const []con } pub fn addCSourceFileSource(self: *CompileStep, source: CSourceFile) void { - const c_source_file = self.builder.allocator.create(CSourceFile) catch unreachable; + const c_source_file = self.builder.allocator.create(CSourceFile) catch @panic("OOM"); c_source_file.* = source.dupe(self.builder); - self.link_objects.append(.{ .c_source_file = c_source_file }) catch unreachable; + self.link_objects.append(.{ .c_source_file = c_source_file }) catch @panic("OOM"); source.source.addStepDependencies(&self.step); } @@ -893,12 +893,12 @@ pub fn getOutputPdbSource(self: *CompileStep) FileSource { pub fn addAssemblyFile(self: *CompileStep, path: []const u8) void { self.link_objects.append(.{ .assembly_file = .{ .path = self.builder.dupe(path) }, - }) catch unreachable; + }) catch @panic("OOM"); } pub fn addAssemblyFileSource(self: *CompileStep, source: FileSource) void { const source_duped = source.dupe(self.builder); - self.link_objects.append(.{ .assembly_file = source_duped }) catch unreachable; + self.link_objects.append(.{ .assembly_file = source_duped }) catch @panic("OOM"); source_duped.addStepDependencies(&self.step); } @@ -907,7 +907,7 @@ pub fn addObjectFile(self: *CompileStep, source_file: []const u8) void { } pub fn addObjectFileSource(self: *CompileStep, source: FileSource) void { - self.link_objects.append(.{ .static_path = source.dupe(self.builder) }) catch unreachable; + self.link_objects.append(.{ .static_path = source.dupe(self.builder) }) catch @panic("OOM"); source.addStepDependencies(&self.step); } @@ -922,11 +922,11 @@ pub const addLibPath = @compileError("deprecated, use addLibraryPath"); pub const addFrameworkDir = @compileError("deprecated, use addFrameworkPath"); pub fn addSystemIncludePath(self: *CompileStep, path: []const u8) void { - self.include_dirs.append(IncludeDir{ .raw_path_system = self.builder.dupe(path) }) catch unreachable; + self.include_dirs.append(IncludeDir{ .raw_path_system = self.builder.dupe(path) }) catch @panic("OOM"); } pub fn addIncludePath(self: *CompileStep, path: []const u8) void { - self.include_dirs.append(IncludeDir{ .raw_path = self.builder.dupe(path) }) catch unreachable; + self.include_dirs.append(IncludeDir{ .raw_path = self.builder.dupe(path) }) catch @panic("OOM"); } pub fn addConfigHeader(self: *CompileStep, config_header: *ConfigHeaderStep) void { @@ -935,19 +935,19 @@ pub fn addConfigHeader(self: *CompileStep, config_header: *ConfigHeaderStep) voi } pub fn addLibraryPath(self: *CompileStep, path: []const u8) void { - self.lib_paths.append(self.builder.dupe(path)) catch unreachable; + self.lib_paths.append(self.builder.dupe(path)) catch @panic("OOM"); } pub fn addRPath(self: *CompileStep, path: []const u8) void { - self.rpaths.append(self.builder.dupe(path)) catch unreachable; + self.rpaths.append(self.builder.dupe(path)) catch @panic("OOM"); } pub fn addFrameworkPath(self: *CompileStep, dir_path: []const u8) void { - self.framework_dirs.append(self.builder.dupe(dir_path)) catch unreachable; + self.framework_dirs.append(self.builder.dupe(dir_path)) catch @panic("OOM"); } pub fn addPackage(self: *CompileStep, package: Pkg) void { - self.packages.append(self.builder.dupePkg(package)) catch unreachable; + self.packages.append(self.builder.dupePkg(package)) catch @panic("OOM"); self.addRecursiveBuildDeps(package); } @@ -1010,7 +1010,7 @@ pub fn addVcpkgPaths(self: *CompileStep, linkage: CompileStep.Linkage) !void { pub fn setExecCmd(self: *CompileStep, args: []const ?[]const u8) void { assert(self.kind == .@"test"); - const duped_args = self.builder.allocator.alloc(?[]u8, args.len) catch unreachable; + const duped_args = self.builder.allocator.alloc(?[]u8, args.len) catch @panic("OOM"); for (args) |arg, i| { duped_args[i] = if (arg) |a| self.builder.dupe(a) else null; } @@ -1019,8 +1019,8 @@ pub fn setExecCmd(self: *CompileStep, args: []const ?[]const u8) void { fn linkLibraryOrObject(self: *CompileStep, other: *CompileStep) void { self.step.dependOn(&other.step); - self.link_objects.append(.{ .other_step = other }) catch unreachable; - self.include_dirs.append(.{ .other_step = other }) catch unreachable; + self.link_objects.append(.{ .other_step = other }) catch @panic("OOM"); + self.include_dirs.append(.{ .other_step = other }) catch @panic("OOM"); } fn makePackageCmd(self: *CompileStep, pkg: Pkg, zig_args: *ArrayList([]const u8)) error{OutOfMemory}!void { @@ -1051,7 +1051,7 @@ fn make(step: *Step) !void { var zig_args = ArrayList([]const u8).init(builder.allocator); defer zig_args.deinit(); - zig_args.append(builder.zig_exe) catch unreachable; + try zig_args.append(builder.zig_exe); const cmd = switch (self.kind) { .lib => "build-lib", @@ -1060,7 +1060,7 @@ fn make(step: *Step) !void { .@"test" => "test", .test_exe => "test", }; - zig_args.append(cmd) catch unreachable; + try zig_args.append(cmd); if (builder.color != .auto) { try zig_args.append("--color"); @@ -1265,12 +1265,12 @@ fn make(step: *Step) !void { try zig_args.append("--debug-compile-errors"); } - if (builder.verbose_cimport) zig_args.append("--verbose-cimport") catch unreachable; - if (builder.verbose_air) zig_args.append("--verbose-air") catch unreachable; - if (builder.verbose_llvm_ir) zig_args.append("--verbose-llvm-ir") catch unreachable; - if (builder.verbose_link or self.verbose_link) zig_args.append("--verbose-link") catch unreachable; - if (builder.verbose_cc or self.verbose_cc) zig_args.append("--verbose-cc") catch unreachable; - if (builder.verbose_llvm_cpu_features) zig_args.append("--verbose-llvm-cpu-features") catch unreachable; + if (builder.verbose_cimport) try zig_args.append("--verbose-cimport"); + if (builder.verbose_air) try zig_args.append("--verbose-air"); + if (builder.verbose_llvm_ir) try zig_args.append("--verbose-llvm-ir"); + if (builder.verbose_link or self.verbose_link) try zig_args.append("--verbose-link"); + if (builder.verbose_cc or self.verbose_cc) try zig_args.append("--verbose-cc"); + if (builder.verbose_llvm_cpu_features) try zig_args.append("--verbose-llvm-cpu-features"); if (self.emit_analysis.getArg(builder, "emit-analysis")) |arg| try zig_args.append(arg); if (self.emit_asm.getArg(builder, "emit-asm")) |arg| try zig_args.append(arg); @@ -1336,7 +1336,7 @@ fn make(step: *Step) !void { switch (self.optimize) { .Debug => {}, // Skip since it's the default. - else => zig_args.append(builder.fmt("-O{s}", .{@tagName(self.optimize)})) catch unreachable, + else => try zig_args.append(builder.fmt("-O{s}", .{@tagName(self.optimize)})), } try zig_args.append("--cache-dir"); @@ -1345,8 +1345,8 @@ fn make(step: *Step) !void { try zig_args.append("--global-cache-dir"); try zig_args.append(builder.pathFromRoot(builder.global_cache_root)); - zig_args.append("--name") catch unreachable; - zig_args.append(self.name) catch unreachable; + try zig_args.append("--name"); + try zig_args.append(self.name); if (self.linkage) |some| switch (some) { .dynamic => try zig_args.append("-dynamic"), @@ -1354,8 +1354,8 @@ fn make(step: *Step) !void { }; if (self.kind == .lib and self.linkage != null and self.linkage.? == .dynamic) { if (self.version) |version| { - zig_args.append("--version") catch unreachable; - zig_args.append(builder.fmt("{}", .{version})) catch unreachable; + try zig_args.append("--version"); + try zig_args.append(builder.fmt("{}", .{version})); } if (self.target.isDarwin()) { @@ -1651,13 +1651,13 @@ fn make(step: *Step) !void { const name = entry.key_ptr.*; const info = entry.value_ptr.*; if (info.needed) { - zig_args.append("-needed_framework") catch unreachable; + try zig_args.append("-needed_framework"); } else if (info.weak) { - zig_args.append("-weak_framework") catch unreachable; + try zig_args.append("-weak_framework"); } else { - zig_args.append("-framework") catch unreachable; + try zig_args.append("-framework"); } - zig_args.append(name) catch unreachable; + try zig_args.append(name); } } else { if (self.framework_dirs.items.len > 0) { @@ -1748,7 +1748,7 @@ fn make(step: *Step) !void { // Slow path for arguments that need to be escaped. We'll need to allocate and copy var escaped = try ArrayList(u8).initCapacity(args_arena.allocator(), arg.len + 1); const writer = escaped.writer(); - writer.writeAll(arg[0..arg_idx]) catch unreachable; + try writer.writeAll(arg[0..arg_idx]); for (arg[arg_idx..]) |to_escape| { if (to_escape == '\\' or to_escape == '"') try writer.writeByte('\\'); try writer.writeByte(to_escape); @@ -1874,23 +1874,28 @@ fn findVcpkgRoot(allocator: Allocator) !?[]const u8 { return vcpkg_path; } -pub fn doAtomicSymLinks(allocator: Allocator, output_path: []const u8, filename_major_only: []const u8, filename_name_only: []const u8) !void { +pub fn doAtomicSymLinks( + allocator: Allocator, + output_path: []const u8, + filename_major_only: []const u8, + filename_name_only: []const u8, +) !void { const out_dir = fs.path.dirname(output_path) orelse "."; const out_basename = fs.path.basename(output_path); // sym link for libfoo.so.1 to libfoo.so.1.2.3 - const major_only_path = fs.path.join( + const major_only_path = try fs.path.join( allocator, &[_][]const u8{ out_dir, filename_major_only }, - ) catch unreachable; + ); fs.atomicSymLink(allocator, out_basename, major_only_path) catch |err| { log.err("Unable to symlink {s} -> {s}", .{ major_only_path, out_basename }); return err; }; // sym link for libfoo.so to libfoo.so.1 - const name_only_path = fs.path.join( + const name_only_path = try fs.path.join( allocator, &[_][]const u8{ out_dir, filename_name_only }, - ) catch unreachable; + ); fs.atomicSymLink(allocator, filename_major_only, name_only_path) catch |err| { log.err("Unable to symlink {s} -> {s}", .{ name_only_path, filename_major_only }); return err; diff --git a/lib/std/Build/EmulatableRunStep.zig b/lib/std/Build/EmulatableRunStep.zig index 26804b2fc8a6a10196fe0d6d4e9d8d5e14c79377..5517f7f9aa01e94665e30d54bbb9598c3d94c624 100644 --- a/lib/std/Build/EmulatableRunStep.zig +++ b/lib/std/Build/EmulatableRunStep.zig @@ -47,7 +47,7 @@ hide_foreign_binaries_warning: bool, /// Asserts given artifact is an executable. pub fn create(builder: *std.Build, name: []const u8, artifact: *CompileStep) *EmulatableRunStep { std.debug.assert(artifact.kind == .exe or artifact.kind == .test_exe); - const self = builder.allocator.create(EmulatableRunStep) catch unreachable; + const self = builder.allocator.create(EmulatableRunStep) catch @panic("OOM"); const option_name = "hide-foreign-warnings"; const hide_warnings = if (builder.available_options_map.get(option_name) == null) warn: { @@ -154,9 +154,9 @@ fn warnAboutForeignBinaries(step: *EmulatableRunStep) void { const builder = step.builder; const artifact = step.exe; - const host_name = builder.host.target.zigTriple(builder.allocator) catch unreachable; - const foreign_name = artifact.target.zigTriple(builder.allocator) catch unreachable; - const target_info = std.zig.system.NativeTargetInfo.detect(artifact.target) catch unreachable; + const host_name = builder.host.target.zigTriple(builder.allocator) catch @panic("unhandled error"); + const foreign_name = artifact.target.zigTriple(builder.allocator) catch @panic("unhandled error"); + const target_info = std.zig.system.NativeTargetInfo.detect(artifact.target) catch @panic("unhandled error"); const need_cross_glibc = artifact.target.isGnuLibC() and artifact.is_linking_libc; switch (builder.host.getExternalExecutor(target_info, .{ .qemu_fixes_dl = need_cross_glibc and builder.glibc_runtimes_dir != null, diff --git a/lib/std/Build/FmtStep.zig b/lib/std/Build/FmtStep.zig index 44a93dee66db7f756f1b10d2856f55214a2eb3cd..6404d22f13bd99f3cc5f2d154bef8bc4bbda3afb 100644 --- a/lib/std/Build/FmtStep.zig +++ b/lib/std/Build/FmtStep.zig @@ -9,12 +9,12 @@ builder: *std.Build, argv: [][]const u8, pub fn create(builder: *std.Build, paths: []const []const u8) *FmtStep { - const self = builder.allocator.create(FmtStep) catch unreachable; + const self = builder.allocator.create(FmtStep) catch @panic("OOM"); const name = "zig fmt"; self.* = FmtStep{ .step = Step.init(.fmt, name, builder.allocator, make), .builder = builder, - .argv = builder.allocator.alloc([]u8, paths.len + 2) catch unreachable, + .argv = builder.allocator.alloc([]u8, paths.len + 2) catch @panic("OOM"), }; self.argv[0] = builder.zig_exe; diff --git a/lib/std/Build/InstallArtifactStep.zig b/lib/std/Build/InstallArtifactStep.zig index 898b9e85e78da6ad62a289378c7f0e7d2afa2af1..8ee739a41c20bd761ec5bd95c1a5fa216d5d9710 100644 --- a/lib/std/Build/InstallArtifactStep.zig +++ b/lib/std/Build/InstallArtifactStep.zig @@ -16,7 +16,7 @@ h_dir: ?InstallDir, pub fn create(builder: *std.Build, artifact: *CompileStep) *InstallArtifactStep { if (artifact.install_step) |s| return s; - const self = builder.allocator.create(InstallArtifactStep) catch unreachable; + const self = builder.allocator.create(InstallArtifactStep) catch @panic("OOM"); self.* = InstallArtifactStep{ .builder = builder, .step = Step.init(.install_artifact, builder.fmt("install {s}", .{artifact.step.name}), builder.allocator, make), diff --git a/lib/std/Build/InstallRawStep.zig b/lib/std/Build/InstallRawStep.zig index e7ffe788786fe5fa38dd4f7bf026882f4d0e9ef5..014c44f28785135f0751adc28626570f69db8e4e 100644 --- a/lib/std/Build/InstallRawStep.zig +++ b/lib/std/Build/InstallRawStep.zig @@ -44,7 +44,7 @@ pub fn create( dest_filename: []const u8, options: CreateOptions, ) *InstallRawStep { - const self = builder.allocator.create(InstallRawStep) catch unreachable; + const self = builder.allocator.create(InstallRawStep) catch @panic("OOM"); self.* = InstallRawStep{ .step = Step.init(.install_raw, builder.fmt("install raw binary {s}", .{artifact.step.name}), builder.allocator, make), .builder = builder, @@ -82,7 +82,7 @@ fn make(step: *Step) !void { const full_dest_path = b.getInstallPath(self.dest_dir, self.dest_filename); self.output_file.path = full_dest_path; - fs.cwd().makePath(b.getInstallPath(self.dest_dir, "")) catch unreachable; + try fs.cwd().makePath(b.getInstallPath(self.dest_dir, "")); var argv_list = std.ArrayList([]const u8).init(b.allocator); try argv_list.appendSlice(&.{ b.zig_exe, "objcopy" }); diff --git a/lib/std/Build/OptionsStep.zig b/lib/std/Build/OptionsStep.zig index 94c41ce9e67623fb2aa0e15a79d6fc6b99aed500..a3537375128539652844346116fcc1ad28a23345 100644 --- a/lib/std/Build/OptionsStep.zig +++ b/lib/std/Build/OptionsStep.zig @@ -19,7 +19,7 @@ artifact_args: std.ArrayList(OptionArtifactArg), file_source_args: std.ArrayList(OptionFileSourceArg), pub fn create(builder: *std.Build) *OptionsStep { - const self = builder.allocator.create(OptionsStep) catch unreachable; + const self = builder.allocator.create(OptionsStep) catch @panic("OOM"); self.* = .{ .builder = builder, .step = Step.init(.options, "options", builder.allocator, make), @@ -34,44 +34,48 @@ pub fn create(builder: *std.Build) *OptionsStep { } pub fn addOption(self: *OptionsStep, comptime T: type, name: []const u8, value: T) void { + return addOptionFallible(self, T, name, value) catch @panic("unhandled error"); +} + +fn addOptionFallible(self: *OptionsStep, comptime T: type, name: []const u8, value: T) !void { const out = self.contents.writer(); switch (T) { []const []const u8 => { - out.print("pub const {}: []const []const u8 = &[_][]const u8{{\n", .{std.zig.fmtId(name)}) catch unreachable; + try out.print("pub const {}: []const []const u8 = &[_][]const u8{{\n", .{std.zig.fmtId(name)}); for (value) |slice| { - out.print(" \"{}\",\n", .{std.zig.fmtEscapes(slice)}) catch unreachable; + try out.print(" \"{}\",\n", .{std.zig.fmtEscapes(slice)}); } - out.writeAll("};\n") catch unreachable; + try out.writeAll("};\n"); return; }, [:0]const u8 => { - out.print("pub const {}: [:0]const u8 = \"{}\";\n", .{ std.zig.fmtId(name), std.zig.fmtEscapes(value) }) catch unreachable; + try out.print("pub const {}: [:0]const u8 = \"{}\";\n", .{ std.zig.fmtId(name), std.zig.fmtEscapes(value) }); return; }, []const u8 => { - out.print("pub const {}: []const u8 = \"{}\";\n", .{ std.zig.fmtId(name), std.zig.fmtEscapes(value) }) catch unreachable; + try out.print("pub const {}: []const u8 = \"{}\";\n", .{ std.zig.fmtId(name), std.zig.fmtEscapes(value) }); return; }, ?[:0]const u8 => { - out.print("pub const {}: ?[:0]const u8 = ", .{std.zig.fmtId(name)}) catch unreachable; + try out.print("pub const {}: ?[:0]const u8 = ", .{std.zig.fmtId(name)}); if (value) |payload| { - out.print("\"{}\";\n", .{std.zig.fmtEscapes(payload)}) catch unreachable; + try out.print("\"{}\";\n", .{std.zig.fmtEscapes(payload)}); } else { - out.writeAll("null;\n") catch unreachable; + try out.writeAll("null;\n"); } return; }, ?[]const u8 => { - out.print("pub const {}: ?[]const u8 = ", .{std.zig.fmtId(name)}) catch unreachable; + try out.print("pub const {}: ?[]const u8 = ", .{std.zig.fmtId(name)}); if (value) |payload| { - out.print("\"{}\";\n", .{std.zig.fmtEscapes(payload)}) catch unreachable; + try out.print("\"{}\";\n", .{std.zig.fmtEscapes(payload)}); } else { - out.writeAll("null;\n") catch unreachable; + try out.writeAll("null;\n"); } return; }, std.builtin.Version => { - out.print( + try out.print( \\pub const {}: @import("std").builtin.Version = .{{ \\ .major = {d}, \\ .minor = {d}, @@ -84,11 +88,11 @@ pub fn addOption(self: *OptionsStep, comptime T: type, name: []const u8, value: value.major, value.minor, value.patch, - }) catch unreachable; + }); return; }, std.SemanticVersion => { - out.print( + try out.print( \\pub const {}: @import("std").SemanticVersion = .{{ \\ .major = {d}, \\ .minor = {d}, @@ -100,38 +104,38 @@ pub fn addOption(self: *OptionsStep, comptime T: type, name: []const u8, value: value.major, value.minor, value.patch, - }) catch unreachable; + }); if (value.pre) |some| { - out.print(" .pre = \"{}\",\n", .{std.zig.fmtEscapes(some)}) catch unreachable; + try out.print(" .pre = \"{}\",\n", .{std.zig.fmtEscapes(some)}); } if (value.build) |some| { - out.print(" .build = \"{}\",\n", .{std.zig.fmtEscapes(some)}) catch unreachable; + try out.print(" .build = \"{}\",\n", .{std.zig.fmtEscapes(some)}); } - out.writeAll("};\n") catch unreachable; + try out.writeAll("};\n"); return; }, else => {}, } switch (@typeInfo(T)) { .Enum => |enum_info| { - out.print("pub const {} = enum {{\n", .{std.zig.fmtId(@typeName(T))}) catch unreachable; + try out.print("pub const {} = enum {{\n", .{std.zig.fmtId(@typeName(T))}); inline for (enum_info.fields) |field| { - out.print(" {},\n", .{std.zig.fmtId(field.name)}) catch unreachable; + try out.print(" {},\n", .{std.zig.fmtId(field.name)}); } - out.writeAll("};\n") catch unreachable; - out.print("pub const {}: {s} = {s}.{s};\n", .{ + try out.writeAll("};\n"); + try out.print("pub const {}: {s} = {s}.{s};\n", .{ std.zig.fmtId(name), std.zig.fmtId(@typeName(T)), std.zig.fmtId(@typeName(T)), std.zig.fmtId(@tagName(value)), - }) catch unreachable; + }); return; }, else => {}, } - out.print("pub const {}: {s} = ", .{ std.zig.fmtId(name), @typeName(T) }) catch unreachable; - printLiteral(out, value, 0) catch unreachable; - out.writeAll(";\n") catch unreachable; + try out.print("pub const {}: {s} = ", .{ std.zig.fmtId(name), @typeName(T) }); + try printLiteral(out, value, 0); + try out.writeAll(";\n"); } // TODO: non-recursive? @@ -189,14 +193,14 @@ pub fn addOptionFileSource( self.file_source_args.append(.{ .name = name, .source = source.dupe(self.builder), - }) catch unreachable; + }) catch @panic("OOM"); source.addStepDependencies(&self.step); } /// The value is the path in the cache dir. /// Adds a dependency automatically. pub fn addOptionArtifact(self: *OptionsStep, name: []const u8, artifact: *CompileStep) void { - self.artifact_args.append(.{ .name = self.builder.dupe(name), .artifact = artifact }) catch unreachable; + self.artifact_args.append(.{ .name = self.builder.dupe(name), .artifact = artifact }) catch @panic("OOM"); self.step.dependOn(&artifact.step); } diff --git a/lib/std/Build/RunStep.zig b/lib/std/Build/RunStep.zig index 9ab9ea6335224247ae234b401b3bbb07d6e18782..07f23636232392b07576dd43bcf4ce24fb9a87d5 100644 --- a/lib/std/Build/RunStep.zig +++ b/lib/std/Build/RunStep.zig @@ -54,7 +54,7 @@ pub const Arg = union(enum) { }; pub fn create(builder: *std.Build, name: []const u8) *RunStep { - const self = builder.allocator.create(RunStep) catch unreachable; + const self = builder.allocator.create(RunStep) catch @panic("OOM"); self.* = RunStep{ .builder = builder, .step = Step.init(base_id, name, builder.allocator, make), @@ -67,19 +67,19 @@ pub fn create(builder: *std.Build, name: []const u8) *RunStep { } pub fn addArtifactArg(self: *RunStep, artifact: *CompileStep) void { - self.argv.append(Arg{ .artifact = artifact }) catch unreachable; + self.argv.append(Arg{ .artifact = artifact }) catch @panic("OOM"); self.step.dependOn(&artifact.step); } pub fn addFileSourceArg(self: *RunStep, file_source: std.Build.FileSource) void { self.argv.append(Arg{ .file_source = file_source.dupe(self.builder), - }) catch unreachable; + }) catch @panic("OOM"); file_source.addStepDependencies(&self.step); } pub fn addArg(self: *RunStep, arg: []const u8) void { - self.argv.append(Arg{ .bytes = self.builder.dupe(arg) }) catch unreachable; + self.argv.append(Arg{ .bytes = self.builder.dupe(arg) }) catch @panic("OOM"); } pub fn addArgs(self: *RunStep, args: []const []const u8) void { @@ -89,7 +89,7 @@ pub fn addArgs(self: *RunStep, args: []const []const u8) void { } pub fn clearEnvironment(self: *RunStep) void { - const new_env_map = self.builder.allocator.create(EnvMap) catch unreachable; + const new_env_map = self.builder.allocator.create(EnvMap) catch @panic("OOM"); new_env_map.* = EnvMap.init(self.builder.allocator); self.env_map = new_env_map; } @@ -107,9 +107,9 @@ pub fn addPathDirInternal(step: *Step, builder: *std.Build, search_path: []const if (prev_path) |pp| { const new_path = builder.fmt("{s}" ++ [1]u8{fs.path.delimiter} ++ "{s}", .{ pp, search_path }); - env_map.put(key, new_path) catch unreachable; + env_map.put(key, new_path) catch @panic("OOM"); } else { - env_map.put(key, builder.dupePath(search_path)) catch unreachable; + env_map.put(key, builder.dupePath(search_path)) catch @panic("OOM"); } } @@ -124,8 +124,8 @@ fn getEnvMapInternal(step: *Step, allocator: Allocator) *EnvMap { else => unreachable, }; return maybe_env_map orelse { - const env_map = allocator.create(EnvMap) catch unreachable; - env_map.* = process.getEnvMap(allocator) catch unreachable; + const env_map = allocator.create(EnvMap) catch @panic("OOM"); + env_map.* = process.getEnvMap(allocator) catch @panic("unhandled error"); switch (step.id) { .run => step.cast(RunStep).?.env_map = env_map, .emulatable_run => step.cast(RunStep).?.env_map = env_map, @@ -140,7 +140,7 @@ pub fn setEnvironmentVariable(self: *RunStep, key: []const u8, value: []const u8 env_map.put( self.builder.dupe(key), self.builder.dupe(value), - ) catch unreachable; + ) catch @panic("unhandled error"); } pub fn expectStdErrEqual(self: *RunStep, bytes: []const u8) void { @@ -234,7 +234,7 @@ pub fn runCommand( switch (stdout_action) { .expect_exact, .expect_matches => { - stdout = child.stdout.?.reader().readAllAlloc(builder.allocator, max_stdout_size) catch unreachable; + stdout = try child.stdout.?.reader().readAllAlloc(builder.allocator, max_stdout_size); }, .inherit, .ignore => {}, } @@ -244,7 +244,7 @@ pub fn runCommand( switch (stderr_action) { .expect_exact, .expect_matches => { - stderr = child.stderr.?.reader().readAllAlloc(builder.allocator, max_stdout_size) catch unreachable; + stderr = try child.stderr.?.reader().readAllAlloc(builder.allocator, max_stdout_size); }, .inherit, .ignore => {}, } diff --git a/lib/std/Build/Step.zig b/lib/std/Build/Step.zig index aff8a49161cdbddac29bc48e42a70ea6c6a013ae..ff0ceb2a51deda5a0ed99bfee7b7dc4cb813b615 100644 --- a/lib/std/Build/Step.zig +++ b/lib/std/Build/Step.zig @@ -57,7 +57,7 @@ pub fn init( ) Step { return Step{ .id = id, - .name = allocator.dupe(u8, name) catch unreachable, + .name = allocator.dupe(u8, name) catch @panic("OOM"), .makeFn = makeFn, .dependencies = std.ArrayList(*Step).init(allocator), .loop_flag = false, @@ -77,7 +77,7 @@ pub fn make(self: *Step) !void { } pub fn dependOn(self: *Step, other: *Step) void { - self.dependencies.append(other) catch unreachable; + self.dependencies.append(other) catch @panic("OOM"); } fn makeNoOp(self: *Step) anyerror!void { diff --git a/lib/std/Build/TranslateCStep.zig b/lib/std/Build/TranslateCStep.zig index c59362aeeec43442a720fa063551db4bef8e4f47..d9874142d82f8d0e3d46168749abfa5a75e48e20 100644 --- a/lib/std/Build/TranslateCStep.zig +++ b/lib/std/Build/TranslateCStep.zig @@ -28,7 +28,7 @@ pub const Options = struct { }; pub fn create(builder: *std.Build, options: Options) *TranslateCStep { - const self = builder.allocator.create(TranslateCStep) catch unreachable; + const self = builder.allocator.create(TranslateCStep) catch @panic("OOM"); const source = options.source_file.dupe(builder); self.* = TranslateCStep{ .step = Step.init(.translate_c, "translate-c", builder.allocator, make), @@ -67,7 +67,7 @@ pub fn addExecutable(self: *TranslateCStep, options: AddExecutableOptions) *Comp } pub fn addIncludeDir(self: *TranslateCStep, include_dir: []const u8) void { - self.include_dirs.append(self.builder.dupePath(include_dir)) catch unreachable; + self.include_dirs.append(self.builder.dupePath(include_dir)) catch @panic("OOM"); } pub fn addCheckFile(self: *TranslateCStep, expected_matches: []const []const u8) *CheckFileStep { @@ -78,12 +78,12 @@ pub fn addCheckFile(self: *TranslateCStep, expected_matches: []const []const u8) /// `name` and `value` need not live longer than the function call. pub fn defineCMacro(self: *TranslateCStep, name: []const u8, value: ?[]const u8) void { const macro = std.Build.constructCMacro(self.builder.allocator, name, value); - self.c_macros.append(macro) catch unreachable; + self.c_macros.append(macro) catch @panic("OOM"); } /// name_and_value looks like [name]=[value]. If the value is omitted, it is set to 1. pub fn defineCMacroRaw(self: *TranslateCStep, name_and_value: []const u8) void { - self.c_macros.append(self.builder.dupe(name_and_value)) catch unreachable; + self.c_macros.append(self.builder.dupe(name_and_value)) catch @panic("OOM"); } fn make(step: *Step) !void { @@ -129,8 +129,8 @@ fn make(step: *Step) !void { self.output_dir = fs.path.dirname(output_path).?; } - self.output_file.path = fs.path.join( + self.output_file.path = try fs.path.join( self.builder.allocator, &[_][]const u8{ self.output_dir.?, self.out_basename }, - ) catch unreachable; + ); } diff --git a/lib/std/Build/WriteFileStep.zig b/lib/std/Build/WriteFileStep.zig index 59ac568221f52e0c36485fc1f8cec7dcb3993471..9e8fcdc203125ceb030ed9712064c6683728ab8a 100644 --- a/lib/std/Build/WriteFileStep.zig +++ b/lib/std/Build/WriteFileStep.zig @@ -28,7 +28,7 @@ pub fn init(builder: *std.Build) WriteFileStep { } pub fn add(self: *WriteFileStep, basename: []const u8, bytes: []const u8) void { - const node = self.builder.allocator.create(std.TailQueue(File).Node) catch unreachable; + const node = self.builder.allocator.create(std.TailQueue(File).Node) catch @panic("unhandled error"); node.* = .{ .data = .{ .source = std.Build.GeneratedFile{ .step = &self.step }, @@ -106,10 +106,10 @@ fn make(step: *Step) !void { }); return err; }; - node.data.source.path = fs.path.join( + node.data.source.path = try fs.path.join( self.builder.allocator, &[_][]const u8{ self.output_dir, node.data.basename }, - ) catch unreachable; + ); } } } -- 2.54.0 From 2f5892671e49850070064f689a7d8f93d6a7a0dd Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 31 Jan 2023 14:56:35 -0700 Subject: [PATCH 56/84] move compiler's CType logic to std.Target This API only depends on std.Target and is extremely useful in build scripts when populating configure files. --- lib/std/target.zig | 553 +++++++++++++++++++++++++++++++++++++ src/Sema.zig | 2 +- src/codegen/c.zig | 1 - src/codegen/llvm.zig | 5 +- src/type.zig | 630 ++++--------------------------------------- 5 files changed, 601 insertions(+), 590 deletions(-) diff --git a/lib/std/target.zig b/lib/std/target.zig index 8ae175aac8a338b544ac31cf7699ea0429e0d343..4429f8be2d9bade533cd58f150aa96109c0f3db0 100644 --- a/lib/std/target.zig +++ b/lib/std/target.zig @@ -1880,6 +1880,559 @@ pub const Target = struct { => 16, }; } + + pub const CType = enum { + short, + ushort, + int, + uint, + long, + ulong, + longlong, + ulonglong, + float, + double, + longdouble, + }; + + pub fn c_type_byte_size(t: Target, c_type: CType) u16 { + return switch (c_type) { + .short, + .ushort, + .int, + .uint, + .long, + .ulong, + .longlong, + .ulonglong, + => @divExact(c_type_bit_size(t, c_type), 8), + + .float => 4, + .double => 8, + + .longdouble => switch (c_type_bit_size(t, c_type)) { + 16 => 2, + 32 => 4, + 64 => 8, + 80 => @intCast(u16, mem.alignForward(10, c_type_alignment(t, .longdouble))), + 128 => 16, + else => unreachable, + }, + }; + } + + pub fn c_type_bit_size(target: Target, c_type: CType) u16 { + switch (target.os.tag) { + .freestanding, .other => switch (target.cpu.arch) { + .msp430 => switch (c_type) { + .short, .ushort, .int, .uint => return 16, + .float, .long, .ulong => return 32, + .longlong, .ulonglong, .double, .longdouble => return 64, + }, + .avr => switch (c_type) { + .short, .ushort, .int, .uint => return 16, + .long, .ulong, .float, .double, .longdouble => return 32, + .longlong, .ulonglong => return 64, + }, + .tce, .tcele => switch (c_type) { + .short, .ushort => return 16, + .int, .uint, .long, .ulong, .longlong, .ulonglong => return 32, + .float, .double, .longdouble => return 32, + }, + .mips64, .mips64el => switch (c_type) { + .short, .ushort => return 16, + .int, .uint, .float => return 32, + .long, .ulong => return if (target.abi != .gnuabin32) 64 else 32, + .longlong, .ulonglong, .double => return 64, + .longdouble => return 128, + }, + .x86_64 => switch (c_type) { + .short, .ushort => return 16, + .int, .uint, .float => return 32, + .long, .ulong => switch (target.abi) { + .gnux32, .muslx32 => return 32, + else => return 64, + }, + .longlong, .ulonglong, .double => return 64, + .longdouble => return 80, + }, + else => switch (c_type) { + .short, .ushort => return 16, + .int, .uint, .float => return 32, + .long, .ulong => return target.cpu.arch.ptrBitWidth(), + .longlong, .ulonglong, .double => return 64, + .longdouble => switch (target.cpu.arch) { + .x86 => switch (target.abi) { + .android => return 64, + else => return 80, + }, + + .powerpc, + .powerpcle, + .powerpc64, + .powerpc64le, + => switch (target.abi) { + .musl, + .musleabi, + .musleabihf, + .muslx32, + => return 64, + else => return 128, + }, + + .riscv32, + .riscv64, + .aarch64, + .aarch64_be, + .aarch64_32, + .s390x, + .sparc, + .sparc64, + .sparcel, + .wasm32, + .wasm64, + => return 128, + + else => return 64, + }, + }, + }, + + .linux, + .freebsd, + .netbsd, + .dragonfly, + .openbsd, + .wasi, + .emscripten, + .plan9, + .solaris, + .haiku, + .ananas, + .fuchsia, + .minix, + => switch (target.cpu.arch) { + .msp430 => switch (c_type) { + .short, .ushort, .int, .uint => return 16, + .long, .ulong, .float => return 32, + .longlong, .ulonglong, .double, .longdouble => return 64, + }, + .avr => switch (c_type) { + .short, .ushort, .int, .uint => return 16, + .long, .ulong, .float, .double, .longdouble => return 32, + .longlong, .ulonglong => return 64, + }, + .tce, .tcele => switch (c_type) { + .short, .ushort => return 16, + .int, .uint, .long, .ulong, .longlong, .ulonglong => return 32, + .float, .double, .longdouble => return 32, + }, + .mips64, .mips64el => switch (c_type) { + .short, .ushort => return 16, + .int, .uint, .float => return 32, + .long, .ulong => return if (target.abi != .gnuabin32) 64 else 32, + .longlong, .ulonglong, .double => return 64, + .longdouble => if (target.os.tag == .freebsd) return 64 else return 128, + }, + .x86_64 => switch (c_type) { + .short, .ushort => return 16, + .int, .uint, .float => return 32, + .long, .ulong => switch (target.abi) { + .gnux32, .muslx32 => return 32, + else => return 64, + }, + .longlong, .ulonglong, .double => return 64, + .longdouble => return 80, + }, + else => switch (c_type) { + .short, .ushort => return 16, + .int, .uint, .float => return 32, + .long, .ulong => return target.cpu.arch.ptrBitWidth(), + .longlong, .ulonglong, .double => return 64, + .longdouble => switch (target.cpu.arch) { + .x86 => switch (target.abi) { + .android => return 64, + else => return 80, + }, + + .powerpc, + .powerpcle, + => switch (target.abi) { + .musl, + .musleabi, + .musleabihf, + .muslx32, + => return 64, + else => switch (target.os.tag) { + .freebsd, .netbsd, .openbsd => return 64, + else => return 128, + }, + }, + + .powerpc64, + .powerpc64le, + => switch (target.abi) { + .musl, + .musleabi, + .musleabihf, + .muslx32, + => return 64, + else => switch (target.os.tag) { + .freebsd, .openbsd => return 64, + else => return 128, + }, + }, + + .riscv32, + .riscv64, + .aarch64, + .aarch64_be, + .aarch64_32, + .s390x, + .mips64, + .mips64el, + .sparc, + .sparc64, + .sparcel, + .wasm32, + .wasm64, + => return 128, + + else => return 64, + }, + }, + }, + + .windows, .uefi => switch (target.cpu.arch) { + .x86 => switch (c_type) { + .short, .ushort => return 16, + .int, .uint, .float => return 32, + .long, .ulong => return 32, + .longlong, .ulonglong, .double => return 64, + .longdouble => switch (target.abi) { + .gnu, .gnuilp32, .cygnus => return 80, + else => return 64, + }, + }, + .x86_64 => switch (c_type) { + .short, .ushort => return 16, + .int, .uint, .float => return 32, + .long, .ulong => switch (target.abi) { + .cygnus => return 64, + else => return 32, + }, + .longlong, .ulonglong, .double => return 64, + .longdouble => switch (target.abi) { + .gnu, .gnuilp32, .cygnus => return 80, + else => return 64, + }, + }, + else => switch (c_type) { + .short, .ushort => return 16, + .int, .uint, .float => return 32, + .long, .ulong => return 32, + .longlong, .ulonglong, .double => return 64, + .longdouble => return 64, + }, + }, + + .macos, .ios, .tvos, .watchos => switch (c_type) { + .short, .ushort => return 16, + .int, .uint, .float => return 32, + .long, .ulong => switch (target.cpu.arch) { + .x86, .arm, .aarch64_32 => return 32, + .x86_64 => switch (target.abi) { + .gnux32, .muslx32 => return 32, + else => return 64, + }, + else => return 64, + }, + .longlong, .ulonglong, .double => return 64, + .longdouble => switch (target.cpu.arch) { + .x86 => switch (target.abi) { + .android => return 64, + else => return 80, + }, + .x86_64 => return 80, + else => return 64, + }, + }, + + .nvcl, .cuda => switch (c_type) { + .short, .ushort => return 16, + .int, .uint, .float => return 32, + .long, .ulong => switch (target.cpu.arch) { + .nvptx => return 32, + .nvptx64 => return 64, + else => return 64, + }, + .longlong, .ulonglong, .double => return 64, + .longdouble => return 64, + }, + + .amdhsa, .amdpal => switch (c_type) { + .short, .ushort => return 16, + .int, .uint, .float => return 32, + .long, .ulong, .longlong, .ulonglong, .double => return 64, + .longdouble => return 128, + }, + + .cloudabi, + .kfreebsd, + .lv2, + .zos, + .rtems, + .nacl, + .aix, + .ps4, + .ps5, + .elfiamcu, + .mesa3d, + .contiki, + .hermit, + .hurd, + .opencl, + .glsl450, + .vulkan, + .driverkit, + .shadermodel, + => @panic("TODO specify the C integer and float type sizes for this OS"), + } + } + + pub fn c_type_alignment(target: Target, c_type: CType) u16 { + // Overrides for unusual alignments + switch (target.cpu.arch) { + .avr => switch (c_type) { + .short, .ushort => return 2, + else => return 1, + }, + .x86 => switch (target.os.tag) { + .windows, .uefi => switch (c_type) { + .longlong, .ulonglong, .double => return 8, + .longdouble => switch (target.abi) { + .gnu, .gnuilp32, .cygnus => return 4, + else => return 8, + }, + else => {}, + }, + else => {}, + }, + else => {}, + } + + // Next-power-of-two-aligned, up to a maximum. + return @min( + std.math.ceilPowerOfTwoAssert(u16, (c_type_bit_size(target, c_type) + 7) / 8), + switch (target.cpu.arch) { + .arm, .armeb, .thumb, .thumbeb => switch (target.os.tag) { + .netbsd => switch (target.abi) { + .gnueabi, + .gnueabihf, + .eabi, + .eabihf, + .android, + .musleabi, + .musleabihf, + => 8, + + else => @as(u16, 4), + }, + .ios, .tvos, .watchos => 4, + else => 8, + }, + + .msp430, + .avr, + => 2, + + .arc, + .csky, + .x86, + .xcore, + .dxil, + .loongarch32, + .tce, + .tcele, + .le32, + .amdil, + .hsail, + .spir, + .spirv32, + .kalimba, + .shave, + .renderscript32, + .ve, + .spu_2, + => 4, + + .aarch64_32, + .amdgcn, + .amdil64, + .bpfel, + .bpfeb, + .hexagon, + .hsail64, + .loongarch64, + .m68k, + .mips, + .mipsel, + .sparc, + .sparcel, + .sparc64, + .lanai, + .le64, + .nvptx, + .nvptx64, + .r600, + .s390x, + .spir64, + .spirv64, + .renderscript64, + => 8, + + .aarch64, + .aarch64_be, + .mips64, + .mips64el, + .powerpc, + .powerpcle, + .powerpc64, + .powerpc64le, + .riscv32, + .riscv64, + .x86_64, + .wasm32, + .wasm64, + => 16, + }, + ); + } + + pub fn c_type_preferred_alignment(target: Target, c_type: CType) u16 { + // Overrides for unusual alignments + switch (target.cpu.arch) { + .arm, .armeb, .thumb, .thumbeb => switch (target.os.tag) { + .netbsd => switch (target.abi) { + .gnueabi, + .gnueabihf, + .eabi, + .eabihf, + .android, + .musleabi, + .musleabihf, + => {}, + + else => switch (c_type) { + .longdouble => return 4, + else => {}, + }, + }, + .ios, .tvos, .watchos => switch (c_type) { + .longdouble => return 4, + else => {}, + }, + else => {}, + }, + .arc => switch (c_type) { + .longdouble => return 4, + else => {}, + }, + .avr => switch (c_type) { + .int, .uint, .long, .ulong, .float, .longdouble => return 1, + .short, .ushort => return 2, + .double => return 4, + .longlong, .ulonglong => return 8, + }, + .x86 => switch (target.os.tag) { + .windows, .uefi => switch (c_type) { + .longdouble => switch (target.abi) { + .gnu, .gnuilp32, .cygnus => return 4, + else => return 8, + }, + else => {}, + }, + else => switch (c_type) { + .longdouble => return 4, + else => {}, + }, + }, + else => {}, + } + + // Next-power-of-two-aligned, up to a maximum. + return @min( + std.math.ceilPowerOfTwoAssert(u16, (c_type_bit_size(target, c_type) + 7) / 8), + switch (target.cpu.arch) { + .msp430 => @as(u16, 2), + + .csky, + .xcore, + .dxil, + .loongarch32, + .tce, + .tcele, + .le32, + .amdil, + .hsail, + .spir, + .spirv32, + .kalimba, + .shave, + .renderscript32, + .ve, + .spu_2, + => 4, + + .arc, + .arm, + .armeb, + .avr, + .thumb, + .thumbeb, + .aarch64_32, + .amdgcn, + .amdil64, + .bpfel, + .bpfeb, + .hexagon, + .hsail64, + .x86, + .loongarch64, + .m68k, + .mips, + .mipsel, + .sparc, + .sparcel, + .sparc64, + .lanai, + .le64, + .nvptx, + .nvptx64, + .r600, + .s390x, + .spir64, + .spirv64, + .renderscript64, + => 8, + + .aarch64, + .aarch64_be, + .mips64, + .mips64el, + .powerpc, + .powerpcle, + .powerpc64, + .powerpc64le, + .riscv32, + .riscv64, + .x86_64, + .wasm32, + .wasm64, + => 16, + }, + ); + } }; test { diff --git a/src/Sema.zig b/src/Sema.zig index 7448fd149c1d25307cf4d231dd921978cdbec6b7..87be3de7bec86db837a3ac3a2a2497da099ea6b1 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -26076,7 +26076,7 @@ fn coerceVarArgParam( .Array => return sema.fail(block, inst_src, "arrays must be passed by reference to variadic function", .{}), .Float => float: { const target = sema.mod.getTarget(); - const double_bits = @import("type.zig").CType.sizeInBits(.double, target); + const double_bits = target.c_type_bit_size(.double); const inst_bits = uncasted_ty.floatBits(sema.mod.getTarget()); if (inst_bits >= double_bits) break :float inst; switch (double_bits) { diff --git a/src/codegen/c.zig b/src/codegen/c.zig index eb0ae1b1f6b12133a7c9023845f5e422563ac7d9..2f721e1b4b2eb52e8a4539f64b16c41f2e21dfdd 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -16,7 +16,6 @@ const trace = @import("../tracy.zig").trace; const LazySrcLoc = Module.LazySrcLoc; const Air = @import("../Air.zig"); const Liveness = @import("../Liveness.zig"); -const CType = @import("../type.zig").CType; const target_util = @import("../target.zig"); const libcFloatPrefix = target_util.libcFloatPrefix; diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index c528abdd7cf5ee5a690f3570513192a199b1e104..e19c70f322d67fe52dd1ae7bd76d4d7291a6a0a3 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -19,7 +19,6 @@ const Liveness = @import("../Liveness.zig"); const Value = @import("../value.zig").Value; const Type = @import("../type.zig").Type; const LazySrcLoc = Module.LazySrcLoc; -const CType = @import("../type.zig").CType; const x86_64_abi = @import("../arch/x86_64/abi.zig"); const wasm_c_abi = @import("../arch/wasm/abi.zig"); const aarch64_c_abi = @import("../arch/aarch64/abi.zig"); @@ -11043,8 +11042,8 @@ fn backendSupportsF128(target: std.Target) bool { fn intrinsicsAllowed(scalar_ty: Type, target: std.Target) bool { return switch (scalar_ty.tag()) { .f16 => backendSupportsF16(target), - .f80 => (CType.longdouble.sizeInBits(target) == 80) and backendSupportsF80(target), - .f128 => (CType.longdouble.sizeInBits(target) == 128) and backendSupportsF128(target), + .f80 => (target.c_type_bit_size(.longdouble) == 80) and backendSupportsF80(target), + .f128 => (target.c_type_bit_size(.longdouble) == 128) and backendSupportsF128(target), else => true, }; } diff --git a/src/type.zig b/src/type.zig index c675cd225db1aa7baa6663f1c8d670b17825d580..a13e30cb4c2994d9bdd4e1a5b489173277a979ec 100644 --- a/src/type.zig +++ b/src/type.zig @@ -2937,24 +2937,24 @@ pub const Type = extern union { .anyframe_T, => return AbiAlignmentAdvanced{ .scalar = @divExact(target.cpu.arch.ptrBitWidth(), 8) }, - .c_short => return AbiAlignmentAdvanced{ .scalar = CType.short.alignment(target) }, - .c_ushort => return AbiAlignmentAdvanced{ .scalar = CType.ushort.alignment(target) }, - .c_int => return AbiAlignmentAdvanced{ .scalar = CType.int.alignment(target) }, - .c_uint => return AbiAlignmentAdvanced{ .scalar = CType.uint.alignment(target) }, - .c_long => return AbiAlignmentAdvanced{ .scalar = CType.long.alignment(target) }, - .c_ulong => return AbiAlignmentAdvanced{ .scalar = CType.ulong.alignment(target) }, - .c_longlong => return AbiAlignmentAdvanced{ .scalar = CType.longlong.alignment(target) }, - .c_ulonglong => return AbiAlignmentAdvanced{ .scalar = CType.ulonglong.alignment(target) }, - .c_longdouble => return AbiAlignmentAdvanced{ .scalar = CType.longdouble.alignment(target) }, + .c_short => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.short) }, + .c_ushort => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.ushort) }, + .c_int => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.int) }, + .c_uint => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.uint) }, + .c_long => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.long) }, + .c_ulong => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.ulong) }, + .c_longlong => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.longlong) }, + .c_ulonglong => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.ulonglong) }, + .c_longdouble => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.longdouble) }, .f16 => return AbiAlignmentAdvanced{ .scalar = 2 }, - .f32 => return AbiAlignmentAdvanced{ .scalar = CType.float.alignment(target) }, - .f64 => switch (CType.double.sizeInBits(target)) { - 64 => return AbiAlignmentAdvanced{ .scalar = CType.double.alignment(target) }, + .f32 => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.float) }, + .f64 => switch (target.c_type_bit_size(.double)) { + 64 => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.double) }, else => return AbiAlignmentAdvanced{ .scalar = 8 }, }, - .f80 => switch (CType.longdouble.sizeInBits(target)) { - 80 => return AbiAlignmentAdvanced{ .scalar = CType.longdouble.alignment(target) }, + .f80 => switch (target.c_type_bit_size(.longdouble)) { + 80 => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.longdouble) }, else => { var payload: Payload.Bits = .{ .base = .{ .tag = .int_unsigned }, @@ -2964,8 +2964,8 @@ pub const Type = extern union { return AbiAlignmentAdvanced{ .scalar = abiAlignment(u80_ty, target) }; }, }, - .f128 => switch (CType.longdouble.sizeInBits(target)) { - 128 => return AbiAlignmentAdvanced{ .scalar = CType.longdouble.alignment(target) }, + .f128 => switch (target.c_type_bit_size(.longdouble)) { + 128 => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.longdouble) }, else => return AbiAlignmentAdvanced{ .scalar = 16 }, }, @@ -3434,21 +3434,22 @@ pub const Type = extern union { else => return AbiSizeAdvanced{ .scalar = @divExact(target.cpu.arch.ptrBitWidth(), 8) }, }, - .c_short => return AbiSizeAdvanced{ .scalar = @divExact(CType.short.sizeInBits(target), 8) }, - .c_ushort => return AbiSizeAdvanced{ .scalar = @divExact(CType.ushort.sizeInBits(target), 8) }, - .c_int => return AbiSizeAdvanced{ .scalar = @divExact(CType.int.sizeInBits(target), 8) }, - .c_uint => return AbiSizeAdvanced{ .scalar = @divExact(CType.uint.sizeInBits(target), 8) }, - .c_long => return AbiSizeAdvanced{ .scalar = @divExact(CType.long.sizeInBits(target), 8) }, - .c_ulong => return AbiSizeAdvanced{ .scalar = @divExact(CType.ulong.sizeInBits(target), 8) }, - .c_longlong => return AbiSizeAdvanced{ .scalar = @divExact(CType.longlong.sizeInBits(target), 8) }, - .c_ulonglong => return AbiSizeAdvanced{ .scalar = @divExact(CType.ulonglong.sizeInBits(target), 8) }, + .c_short => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.short) }, + .c_ushort => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.ushort) }, + .c_int => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.int) }, + .c_uint => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.uint) }, + .c_long => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.long) }, + .c_ulong => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.ulong) }, + .c_longlong => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.longlong) }, + .c_ulonglong => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.ulonglong) }, + .c_longdouble => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.longdouble) }, .f16 => return AbiSizeAdvanced{ .scalar = 2 }, .f32 => return AbiSizeAdvanced{ .scalar = 4 }, .f64 => return AbiSizeAdvanced{ .scalar = 8 }, .f128 => return AbiSizeAdvanced{ .scalar = 16 }, - .f80 => switch (CType.longdouble.sizeInBits(target)) { - 80 => return AbiSizeAdvanced{ .scalar = std.mem.alignForward(10, CType.longdouble.alignment(target)) }, + .f80 => switch (target.c_type_bit_size(.longdouble)) { + 80 => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.longdouble) }, else => { var payload: Payload.Bits = .{ .base = .{ .tag = .int_unsigned }, @@ -3458,14 +3459,6 @@ pub const Type = extern union { return AbiSizeAdvanced{ .scalar = abiSize(u80_ty, target) }; }, }, - .c_longdouble => switch (CType.longdouble.sizeInBits(target)) { - 16 => return AbiSizeAdvanced{ .scalar = abiSize(Type.f16, target) }, - 32 => return AbiSizeAdvanced{ .scalar = abiSize(Type.f32, target) }, - 64 => return AbiSizeAdvanced{ .scalar = abiSize(Type.f64, target) }, - 80 => return AbiSizeAdvanced{ .scalar = abiSize(Type.f80, target) }, - 128 => return AbiSizeAdvanced{ .scalar = abiSize(Type.f128, target) }, - else => unreachable, - }, // TODO revisit this when we have the concept of the error tag type .anyerror_void_error_union, @@ -3748,15 +3741,15 @@ pub const Type = extern union { .manyptr_const_u8_sentinel_0, => return target.cpu.arch.ptrBitWidth(), - .c_short => return CType.short.sizeInBits(target), - .c_ushort => return CType.ushort.sizeInBits(target), - .c_int => return CType.int.sizeInBits(target), - .c_uint => return CType.uint.sizeInBits(target), - .c_long => return CType.long.sizeInBits(target), - .c_ulong => return CType.ulong.sizeInBits(target), - .c_longlong => return CType.longlong.sizeInBits(target), - .c_ulonglong => return CType.ulonglong.sizeInBits(target), - .c_longdouble => return CType.longdouble.sizeInBits(target), + .c_short => return target.c_type_bit_size(.short), + .c_ushort => return target.c_type_bit_size(.ushort), + .c_int => return target.c_type_bit_size(.int), + .c_uint => return target.c_type_bit_size(.uint), + .c_long => return target.c_type_bit_size(.long), + .c_ulong => return target.c_type_bit_size(.ulong), + .c_longlong => return target.c_type_bit_size(.longlong), + .c_ulonglong => return target.c_type_bit_size(.ulonglong), + .c_longdouble => return target.c_type_bit_size(.longdouble), .error_set, .error_set_single, @@ -4631,14 +4624,14 @@ pub const Type = extern union { .i128 => return .{ .signedness = .signed, .bits = 128 }, .usize => return .{ .signedness = .unsigned, .bits = target.cpu.arch.ptrBitWidth() }, .isize => return .{ .signedness = .signed, .bits = target.cpu.arch.ptrBitWidth() }, - .c_short => return .{ .signedness = .signed, .bits = CType.short.sizeInBits(target) }, - .c_ushort => return .{ .signedness = .unsigned, .bits = CType.ushort.sizeInBits(target) }, - .c_int => return .{ .signedness = .signed, .bits = CType.int.sizeInBits(target) }, - .c_uint => return .{ .signedness = .unsigned, .bits = CType.uint.sizeInBits(target) }, - .c_long => return .{ .signedness = .signed, .bits = CType.long.sizeInBits(target) }, - .c_ulong => return .{ .signedness = .unsigned, .bits = CType.ulong.sizeInBits(target) }, - .c_longlong => return .{ .signedness = .signed, .bits = CType.longlong.sizeInBits(target) }, - .c_ulonglong => return .{ .signedness = .unsigned, .bits = CType.ulonglong.sizeInBits(target) }, + .c_short => return .{ .signedness = .signed, .bits = target.c_type_bit_size(.short) }, + .c_ushort => return .{ .signedness = .unsigned, .bits = target.c_type_bit_size(.ushort) }, + .c_int => return .{ .signedness = .signed, .bits = target.c_type_bit_size(.int) }, + .c_uint => return .{ .signedness = .unsigned, .bits = target.c_type_bit_size(.uint) }, + .c_long => return .{ .signedness = .signed, .bits = target.c_type_bit_size(.long) }, + .c_ulong => return .{ .signedness = .unsigned, .bits = target.c_type_bit_size(.ulong) }, + .c_longlong => return .{ .signedness = .signed, .bits = target.c_type_bit_size(.longlong) }, + .c_ulonglong => return .{ .signedness = .unsigned, .bits = target.c_type_bit_size(.ulonglong) }, .enum_full, .enum_nonexhaustive => ty = ty.cast(Payload.EnumFull).?.data.tag_ty, .enum_numbered => ty = ty.castTag(.enum_numbered).?.data.tag_ty, @@ -4724,7 +4717,7 @@ pub const Type = extern union { .f64 => 64, .f80 => 80, .f128, .comptime_float => 128, - .c_longdouble => CType.longdouble.sizeInBits(target), + .c_longdouble => target.c_type_bit_size(.longdouble), else => unreachable, }; @@ -6689,536 +6682,3 @@ pub const Type = extern union { /// to packed struct layout to find out all the places in the codebase you need to edit! pub const packed_struct_layout_version = 2; }; - -pub const CType = enum { - short, - ushort, - int, - uint, - long, - ulong, - longlong, - ulonglong, - longdouble, - - // We don't have a `c_float`/`c_double` type in Zig, but these - // are useful for querying target-correct alignment and checking - // whether C's double is f64 or f32 - float, - double, - - pub fn sizeInBits(self: CType, target: Target) u16 { - switch (target.os.tag) { - .freestanding, .other => switch (target.cpu.arch) { - .msp430 => switch (self) { - .short, .ushort, .int, .uint => return 16, - .float, .long, .ulong => return 32, - .longlong, .ulonglong, .double, .longdouble => return 64, - }, - .avr => switch (self) { - .short, .ushort, .int, .uint => return 16, - .long, .ulong, .float, .double, .longdouble => return 32, - .longlong, .ulonglong => return 64, - }, - .tce, .tcele => switch (self) { - .short, .ushort => return 16, - .int, .uint, .long, .ulong, .longlong, .ulonglong => return 32, - .float, .double, .longdouble => return 32, - }, - .mips64, .mips64el => switch (self) { - .short, .ushort => return 16, - .int, .uint, .float => return 32, - .long, .ulong => return if (target.abi != .gnuabin32) 64 else 32, - .longlong, .ulonglong, .double => return 64, - .longdouble => return 128, - }, - .x86_64 => switch (self) { - .short, .ushort => return 16, - .int, .uint, .float => return 32, - .long, .ulong => switch (target.abi) { - .gnux32, .muslx32 => return 32, - else => return 64, - }, - .longlong, .ulonglong, .double => return 64, - .longdouble => return 80, - }, - else => switch (self) { - .short, .ushort => return 16, - .int, .uint, .float => return 32, - .long, .ulong => return target.cpu.arch.ptrBitWidth(), - .longlong, .ulonglong, .double => return 64, - .longdouble => switch (target.cpu.arch) { - .x86 => switch (target.abi) { - .android => return 64, - else => return 80, - }, - - .powerpc, - .powerpcle, - .powerpc64, - .powerpc64le, - => switch (target.abi) { - .musl, - .musleabi, - .musleabihf, - .muslx32, - => return 64, - else => return 128, - }, - - .riscv32, - .riscv64, - .aarch64, - .aarch64_be, - .aarch64_32, - .s390x, - .sparc, - .sparc64, - .sparcel, - .wasm32, - .wasm64, - => return 128, - - else => return 64, - }, - }, - }, - - .linux, - .freebsd, - .netbsd, - .dragonfly, - .openbsd, - .wasi, - .emscripten, - .plan9, - .solaris, - .haiku, - .ananas, - .fuchsia, - .minix, - => switch (target.cpu.arch) { - .msp430 => switch (self) { - .short, .ushort, .int, .uint => return 16, - .long, .ulong, .float => return 32, - .longlong, .ulonglong, .double, .longdouble => return 64, - }, - .avr => switch (self) { - .short, .ushort, .int, .uint => return 16, - .long, .ulong, .float, .double, .longdouble => return 32, - .longlong, .ulonglong => return 64, - }, - .tce, .tcele => switch (self) { - .short, .ushort => return 16, - .int, .uint, .long, .ulong, .longlong, .ulonglong => return 32, - .float, .double, .longdouble => return 32, - }, - .mips64, .mips64el => switch (self) { - .short, .ushort => return 16, - .int, .uint, .float => return 32, - .long, .ulong => return if (target.abi != .gnuabin32) 64 else 32, - .longlong, .ulonglong, .double => return 64, - .longdouble => if (target.os.tag == .freebsd) return 64 else return 128, - }, - .x86_64 => switch (self) { - .short, .ushort => return 16, - .int, .uint, .float => return 32, - .long, .ulong => switch (target.abi) { - .gnux32, .muslx32 => return 32, - else => return 64, - }, - .longlong, .ulonglong, .double => return 64, - .longdouble => return 80, - }, - else => switch (self) { - .short, .ushort => return 16, - .int, .uint, .float => return 32, - .long, .ulong => return target.cpu.arch.ptrBitWidth(), - .longlong, .ulonglong, .double => return 64, - .longdouble => switch (target.cpu.arch) { - .x86 => switch (target.abi) { - .android => return 64, - else => return 80, - }, - - .powerpc, - .powerpcle, - => switch (target.abi) { - .musl, - .musleabi, - .musleabihf, - .muslx32, - => return 64, - else => switch (target.os.tag) { - .freebsd, .netbsd, .openbsd => return 64, - else => return 128, - }, - }, - - .powerpc64, - .powerpc64le, - => switch (target.abi) { - .musl, - .musleabi, - .musleabihf, - .muslx32, - => return 64, - else => switch (target.os.tag) { - .freebsd, .openbsd => return 64, - else => return 128, - }, - }, - - .riscv32, - .riscv64, - .aarch64, - .aarch64_be, - .aarch64_32, - .s390x, - .mips64, - .mips64el, - .sparc, - .sparc64, - .sparcel, - .wasm32, - .wasm64, - => return 128, - - else => return 64, - }, - }, - }, - - .windows, .uefi => switch (target.cpu.arch) { - .x86 => switch (self) { - .short, .ushort => return 16, - .int, .uint, .float => return 32, - .long, .ulong => return 32, - .longlong, .ulonglong, .double => return 64, - .longdouble => switch (target.abi) { - .gnu, .gnuilp32, .cygnus => return 80, - else => return 64, - }, - }, - .x86_64 => switch (self) { - .short, .ushort => return 16, - .int, .uint, .float => return 32, - .long, .ulong => switch (target.abi) { - .cygnus => return 64, - else => return 32, - }, - .longlong, .ulonglong, .double => return 64, - .longdouble => switch (target.abi) { - .gnu, .gnuilp32, .cygnus => return 80, - else => return 64, - }, - }, - else => switch (self) { - .short, .ushort => return 16, - .int, .uint, .float => return 32, - .long, .ulong => return 32, - .longlong, .ulonglong, .double => return 64, - .longdouble => return 64, - }, - }, - - .macos, .ios, .tvos, .watchos => switch (self) { - .short, .ushort => return 16, - .int, .uint, .float => return 32, - .long, .ulong => switch (target.cpu.arch) { - .x86, .arm, .aarch64_32 => return 32, - .x86_64 => switch (target.abi) { - .gnux32, .muslx32 => return 32, - else => return 64, - }, - else => return 64, - }, - .longlong, .ulonglong, .double => return 64, - .longdouble => switch (target.cpu.arch) { - .x86 => switch (target.abi) { - .android => return 64, - else => return 80, - }, - .x86_64 => return 80, - else => return 64, - }, - }, - - .nvcl, .cuda => switch (self) { - .short, .ushort => return 16, - .int, .uint, .float => return 32, - .long, .ulong => switch (target.cpu.arch) { - .nvptx => return 32, - .nvptx64 => return 64, - else => return 64, - }, - .longlong, .ulonglong, .double => return 64, - .longdouble => return 64, - }, - - .amdhsa, .amdpal => switch (self) { - .short, .ushort => return 16, - .int, .uint, .float => return 32, - .long, .ulong, .longlong, .ulonglong, .double => return 64, - .longdouble => return 128, - }, - - .cloudabi, - .kfreebsd, - .lv2, - .zos, - .rtems, - .nacl, - .aix, - .ps4, - .ps5, - .elfiamcu, - .mesa3d, - .contiki, - .hermit, - .hurd, - .opencl, - .glsl450, - .vulkan, - .driverkit, - .shadermodel, - => @panic("TODO specify the C integer and float type sizes for this OS"), - } - } - - pub fn alignment(self: CType, target: Target) u16 { - - // Overrides for unusual alignments - switch (target.cpu.arch) { - .avr => switch (self) { - .short, .ushort => return 2, - else => return 1, - }, - .x86 => switch (target.os.tag) { - .windows, .uefi => switch (self) { - .longlong, .ulonglong, .double => return 8, - .longdouble => switch (target.abi) { - .gnu, .gnuilp32, .cygnus => return 4, - else => return 8, - }, - else => {}, - }, - else => {}, - }, - else => {}, - } - - // Next-power-of-two-aligned, up to a maximum. - return @min( - std.math.ceilPowerOfTwoAssert(u16, (self.sizeInBits(target) + 7) / 8), - switch (target.cpu.arch) { - .arm, .armeb, .thumb, .thumbeb => switch (target.os.tag) { - .netbsd => switch (target.abi) { - .gnueabi, - .gnueabihf, - .eabi, - .eabihf, - .android, - .musleabi, - .musleabihf, - => 8, - - else => @as(u16, 4), - }, - .ios, .tvos, .watchos => 4, - else => 8, - }, - - .msp430, - .avr, - => 2, - - .arc, - .csky, - .x86, - .xcore, - .dxil, - .loongarch32, - .tce, - .tcele, - .le32, - .amdil, - .hsail, - .spir, - .spirv32, - .kalimba, - .shave, - .renderscript32, - .ve, - .spu_2, - => 4, - - .aarch64_32, - .amdgcn, - .amdil64, - .bpfel, - .bpfeb, - .hexagon, - .hsail64, - .loongarch64, - .m68k, - .mips, - .mipsel, - .sparc, - .sparcel, - .sparc64, - .lanai, - .le64, - .nvptx, - .nvptx64, - .r600, - .s390x, - .spir64, - .spirv64, - .renderscript64, - => 8, - - .aarch64, - .aarch64_be, - .mips64, - .mips64el, - .powerpc, - .powerpcle, - .powerpc64, - .powerpc64le, - .riscv32, - .riscv64, - .x86_64, - .wasm32, - .wasm64, - => 16, - }, - ); - } - - pub fn preferredAlignment(self: CType, target: Target) u16 { - - // Overrides for unusual alignments - switch (target.cpu.arch) { - .arm, .armeb, .thumb, .thumbeb => switch (target.os.tag) { - .netbsd => switch (target.abi) { - .gnueabi, - .gnueabihf, - .eabi, - .eabihf, - .android, - .musleabi, - .musleabihf, - => {}, - - else => switch (self) { - .longdouble => return 4, - else => {}, - }, - }, - .ios, .tvos, .watchos => switch (self) { - .longdouble => return 4, - else => {}, - }, - else => {}, - }, - .arc => switch (self) { - .longdouble => return 4, - else => {}, - }, - .avr => switch (self) { - .int, .uint, .long, .ulong, .float, .longdouble => return 1, - .short, .ushort => return 2, - .double => return 4, - .longlong, .ulonglong => return 8, - }, - .x86 => switch (target.os.tag) { - .windows, .uefi => switch (self) { - .longdouble => switch (target.abi) { - .gnu, .gnuilp32, .cygnus => return 4, - else => return 8, - }, - else => {}, - }, - else => switch (self) { - .longdouble => return 4, - else => {}, - }, - }, - else => {}, - } - - // Next-power-of-two-aligned, up to a maximum. - return @min( - std.math.ceilPowerOfTwoAssert(u16, (self.sizeInBits(target) + 7) / 8), - switch (target.cpu.arch) { - .msp430 => @as(u16, 2), - - .csky, - .xcore, - .dxil, - .loongarch32, - .tce, - .tcele, - .le32, - .amdil, - .hsail, - .spir, - .spirv32, - .kalimba, - .shave, - .renderscript32, - .ve, - .spu_2, - => 4, - - .arc, - .arm, - .armeb, - .avr, - .thumb, - .thumbeb, - .aarch64_32, - .amdgcn, - .amdil64, - .bpfel, - .bpfeb, - .hexagon, - .hsail64, - .x86, - .loongarch64, - .m68k, - .mips, - .mipsel, - .sparc, - .sparcel, - .sparc64, - .lanai, - .le64, - .nvptx, - .nvptx64, - .r600, - .s390x, - .spir64, - .spirv64, - .renderscript64, - => 8, - - .aarch64, - .aarch64_be, - .mips64, - .mips64el, - .powerpc, - .powerpcle, - .powerpc64, - .powerpc64le, - .riscv32, - .riscv64, - .x86_64, - .wasm32, - .wasm64, - => 16, - }, - ); - } -}; -- 2.54.0 From 3c1fc3f566b4a0c4493187c7f07b5c401a3e3a1b Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 31 Jan 2023 14:57:20 -0700 Subject: [PATCH 57/84] std.Build.ConfigHeaderStep: support more types --- lib/std/Build/ConfigHeaderStep.zig | 76 +++++++++++++++++------------- 1 file changed, 44 insertions(+), 32 deletions(-) diff --git a/lib/std/Build/ConfigHeaderStep.zig b/lib/std/Build/ConfigHeaderStep.zig index b961227c9c6de0ea39c9b5f9aa67d6345d0d5497..58a78b939ddde62f3f063659e9741f5a22553af0 100644 --- a/lib/std/Build/ConfigHeaderStep.zig +++ b/lib/std/Build/ConfigHeaderStep.zig @@ -61,39 +61,51 @@ pub fn addValues(self: *ConfigHeaderStep, values: anytype) void { fn addValuesInner(self: *ConfigHeaderStep, values: anytype) !void { inline for (@typeInfo(@TypeOf(values)).Struct.fields) |field| { - switch (@typeInfo(field.type)) { - .Null => { - try self.values.put(field.name, .undef); - }, - .Void => { - try self.values.put(field.name, .defined); - }, - .Bool => { - try self.values.put(field.name, .{ .boolean = @field(values, field.name) }); - }, - .ComptimeInt => { - try self.values.put(field.name, .{ .int = @field(values, field.name) }); - }, - .EnumLiteral => { - try self.values.put(field.name, .{ .ident = @tagName(@field(values, field.name)) }); - }, - .Pointer => |ptr| { - switch (@typeInfo(ptr.child)) { - .Array => |array| { - if (ptr.size == .One and array.child == u8) { - try self.values.put(field.name, .{ .string = @field(values, field.name) }); - continue; - } - }, - else => {}, - } + try putValue(self, field.name, field.type, @field(values, field.name)); + } +} - @compileError("unsupported ConfigHeaderStep value type: " ++ - @typeName(field.type)); - }, - else => @compileError("unsupported ConfigHeaderStep value type: " ++ - @typeName(field.type)), - } +fn putValue(self: *ConfigHeaderStep, field_name: []const u8, comptime T: type, v: T) !void { + switch (@typeInfo(T)) { + .Null => { + try self.values.put(field_name, .undef); + }, + .Void => { + try self.values.put(field_name, .defined); + }, + .Bool => { + try self.values.put(field_name, .{ .boolean = v }); + }, + .Int => { + try self.values.put(field_name, .{ .int = v }); + }, + .ComptimeInt => { + try self.values.put(field_name, .{ .int = v }); + }, + .EnumLiteral => { + try self.values.put(field_name, .{ .ident = @tagName(v) }); + }, + .Optional => { + if (v) |x| { + return putValue(self, field_name, @TypeOf(x), x); + } else { + try self.values.put(field_name, .undef); + } + }, + .Pointer => |ptr| { + switch (@typeInfo(ptr.child)) { + .Array => |array| { + if (ptr.size == .One and array.child == u8) { + try self.values.put(field_name, .{ .string = v }); + return; + } + }, + else => {}, + } + + @compileError("unsupported ConfigHeaderStep value type: " ++ @typeName(T)); + }, + else => @compileError("unsupported ConfigHeaderStep value type: " ++ @typeName(T)), } } -- 2.54.0 From 7d14baec900efbbbae0ae25da79f976716241ec0 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 31 Jan 2023 15:00:26 -0700 Subject: [PATCH 58/84] tests: fix missing target for C ABI tests This regressed earlier in this branch. --- test/tests.zig | 1 + 1 file changed, 1 insertion(+) diff --git a/test/tests.zig b/test/tests.zig index 0f36c8eb94002f9de1b8d101c4161220a447d6d4..94030ce851418ad3bc016abb753402f84303d90e 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -1360,6 +1360,7 @@ pub fn addCAbiTests(b: *std.Build, skip_non_native: bool, skip_release: bool) *S const test_step = b.addTest(.{ .root_source_file = .{ .path = "test/c_abi/main.zig" }, .optimize = optimize_mode, + .target = c_abi_target, }); if (c_abi_target.abi != null and c_abi_target.abi.?.isMusl()) { // TODO NativeTargetInfo insists on dynamically linking musl -- 2.54.0 From 8d37c6f71c790faecdb6acdd2868823be2bd2496 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 31 Jan 2023 15:34:08 -0700 Subject: [PATCH 59/84] std.Build.CompileStep: fix API usage in unit test --- lib/std/Build/CompileStep.zig | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/std/Build/CompileStep.zig b/lib/std/Build/CompileStep.zig index 7396a5ce66bfd447fdedda348011397cf21f9d87..12c73bdba6b605bbbe7b0996231b44b6097f136b 100644 --- a/lib/std/Build/CompileStep.zig +++ b/lib/std/Build/CompileStep.zig @@ -1970,7 +1970,10 @@ test "addPackage" { .dependencies = &[_]Pkg{pkg_dep}, }; - var exe = builder.addExecutable("not_an_executable", "/not/an/executable.zig"); + var exe = builder.addExecutable(.{ + .name = "not_an_executable", + .root_source_file = .{ .path = "/not/an/executable.zig" }, + }); exe.addPackage(pkg_top); try std.testing.expectEqual(@as(usize, 1), exe.packages.items.len); -- 2.54.0 From 2ccff5115454bab4898bae3de88f5619310bc5c1 Mon Sep 17 00:00:00 2001 From: praschke Date: Tue, 31 Jan 2023 21:55:16 +0000 Subject: [PATCH 60/84] mingw: repair msvcrt-os build flags __LIBMSVCRT__ is still used and is distinct from __LIBMSVCRT_OS__ --- src/mingw.zig | 1 + 1 file changed, 1 insertion(+) diff --git a/src/mingw.zig b/src/mingw.zig index 1fee8e90a4160541895f170e2fca785e8080a3c8..06880743c6d777085a12ba2acecab4bc4a0d9498 100644 --- a/src/mingw.zig +++ b/src/mingw.zig @@ -106,6 +106,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void { .msvcrt_os_lib => { const extra_flags = try arena.dupe([]const u8, &[_][]const u8{ "-DHAVE_CONFIG_H", + "-D__LIBMSVCRT__", "-D__LIBMSVCRT_OS__", "-I", -- 2.54.0 From 9fdc32c96e3961ae2f5287483c9638051df34180 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Wed, 1 Feb 2023 09:13:49 +0100 Subject: [PATCH 61/84] link: clean up type resolution in Elf.Atom and MachO.Atom --- src/link/Coff/Atom.zig | 2 +- src/link/Elf/Atom.zig | 4 ++-- src/link/MachO/Atom.zig | 18 +++++++++--------- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/link/Coff/Atom.zig b/src/link/Coff/Atom.zig index 1ee31cccaadc03dcd1363cb348d3ae9892365755..80c04a8fa1e1e2b48625e2c36c9f753ac7c28e95 100644 --- a/src/link/Coff/Atom.zig +++ b/src/link/Coff/Atom.zig @@ -119,7 +119,7 @@ pub fn addBaseRelocation(coff_file: *Coff, atom_index: Index, offset: u32) !void try gop.value_ptr.append(gpa, offset); } -pub fn freeRelocations(coff_file: *Coff, atom_index: Atom.Index) void { +pub fn freeRelocations(coff_file: *Coff, atom_index: Index) void { const gpa = coff_file.base.allocator; var removed_relocs = coff_file.relocs.fetchRemove(atom_index); if (removed_relocs) |*relocs| relocs.value.deinit(gpa); diff --git a/src/link/Elf/Atom.zig b/src/link/Elf/Atom.zig index 79b699636fc3f532e14dba6946a1cf742e41c7cf..24cf19432ca40883da11a086e22209c1497bf3e3 100644 --- a/src/link/Elf/Atom.zig +++ b/src/link/Elf/Atom.zig @@ -20,8 +20,8 @@ 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_index: ?Atom.Index, -next_index: ?Atom.Index, +prev_index: ?Index, +next_index: ?Index, dbg_info_atom: Dwarf.Atom, diff --git a/src/link/MachO/Atom.zig b/src/link/MachO/Atom.zig index da0115d0698376724788ad72a2620735787f62b7..401d71813c7c853dab6ee2662c715d1a40b6c6d0 100644 --- a/src/link/MachO/Atom.zig +++ b/src/link/MachO/Atom.zig @@ -40,8 +40,8 @@ alignment: u32, /// Points to the previous and next neighbours /// TODO use the same trick as with symbols: reserve index 0 as null atom -next_index: ?Atom.Index, -prev_index: ?Atom.Index, +next_index: ?Index, +prev_index: ?Index, dbg_info_atom: Dwarf.Atom, @@ -119,13 +119,13 @@ pub fn freeListEligible(self: Atom, macho_file: *MachO) bool { return surplus >= MachO.min_text_capacity; } -pub fn addRelocation(macho_file: *MachO, atom_index: Atom.Index, reloc: Relocation) !void { +pub fn addRelocation(macho_file: *MachO, atom_index: Index, reloc: Relocation) !void { return addRelocations(macho_file, atom_index, 1, .{reloc}); } pub fn addRelocations( macho_file: *MachO, - atom_index: Atom.Index, + atom_index: Index, comptime count: comptime_int, relocs: [count]Relocation, ) !void { @@ -145,7 +145,7 @@ pub fn addRelocations( } } -pub fn addRebase(macho_file: *MachO, atom_index: Atom.Index, offset: u32) !void { +pub fn addRebase(macho_file: *MachO, atom_index: Index, offset: u32) !void { const gpa = macho_file.base.allocator; const atom = macho_file.getAtom(atom_index); log.debug(" (adding rebase at offset 0x{x} in %{?d})", .{ offset, atom.getSymbolIndex() }); @@ -156,7 +156,7 @@ pub fn addRebase(macho_file: *MachO, atom_index: Atom.Index, offset: u32) !void try gop.value_ptr.append(gpa, offset); } -pub fn addBinding(macho_file: *MachO, atom_index: Atom.Index, binding: Binding) !void { +pub fn addBinding(macho_file: *MachO, atom_index: Index, binding: Binding) !void { const gpa = macho_file.base.allocator; const atom = macho_file.getAtom(atom_index); log.debug(" (adding binding to symbol {s} at offset 0x{x} in %{?d})", .{ @@ -171,7 +171,7 @@ pub fn addBinding(macho_file: *MachO, atom_index: Atom.Index, binding: Binding) try gop.value_ptr.append(gpa, binding); } -pub fn addLazyBinding(macho_file: *MachO, atom_index: Atom.Index, binding: Binding) !void { +pub fn addLazyBinding(macho_file: *MachO, atom_index: Index, binding: Binding) !void { const gpa = macho_file.base.allocator; const atom = macho_file.getAtom(atom_index); log.debug(" (adding lazy binding to symbol {s} at offset 0x{x} in %{?d})", .{ @@ -186,7 +186,7 @@ pub fn addLazyBinding(macho_file: *MachO, atom_index: Atom.Index, binding: Bindi try gop.value_ptr.append(gpa, binding); } -pub fn resolveRelocations(macho_file: *MachO, atom_index: Atom.Index) !void { +pub fn resolveRelocations(macho_file: *MachO, atom_index: Index) !void { const atom = macho_file.getAtom(atom_index); const relocs = macho_file.relocs.get(atom_index) orelse return; const source_sym = atom.getSymbol(macho_file); @@ -203,7 +203,7 @@ pub fn resolveRelocations(macho_file: *MachO, atom_index: Atom.Index) !void { } } -pub fn freeRelocations(macho_file: *MachO, atom_index: Atom.Index) void { +pub fn freeRelocations(macho_file: *MachO, atom_index: Index) void { const gpa = macho_file.base.allocator; var removed_relocs = macho_file.relocs.fetchOrderedRemove(atom_index); if (removed_relocs) |*relocs| relocs.value.deinit(gpa); -- 2.54.0 From b3277c893691c462ec2e82577a78e7baafb42bf6 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Wed, 1 Feb 2023 11:12:53 +0100 Subject: [PATCH 62/84] link: make Plan9 atoms fully owned by the linker --- src/Module.zig | 4 +- src/Sema.zig | 2 +- src/arch/aarch64/CodeGen.zig | 11 +- src/arch/arm/CodeGen.zig | 5 +- src/arch/riscv64/CodeGen.zig | 5 +- src/arch/x86_64/CodeGen.zig | 11 +- src/link.zig | 4 +- src/link/Plan9.zig | 230 ++++++++++++++++++++++------------- 8 files changed, 171 insertions(+), 101 deletions(-) diff --git a/src/Module.zig b/src/Module.zig index b39fd2bab241a304819cd056a7ae5c51b1266ddf..a914dc90d81c86187318ed530cbb768becc52e40 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -5277,7 +5277,7 @@ pub fn clearDecl( .coff => .{ .coff = {} }, .elf => .{ .elf = {} }, .macho => .{ .macho = {} }, - .plan9 => .{ .plan9 = link.File.Plan9.DeclBlock.empty }, + .plan9 => .{ .plan9 = {} }, .c => .{ .c = {} }, .wasm => .{ .wasm = link.File.Wasm.DeclBlock.empty }, .spirv => .{ .spirv = {} }, @@ -5697,7 +5697,7 @@ pub fn allocateNewDecl( .coff => .{ .coff = {} }, .elf => .{ .elf = {} }, .macho => .{ .macho = {} }, - .plan9 => .{ .plan9 = link.File.Plan9.DeclBlock.empty }, + .plan9 => .{ .plan9 = {} }, .c => .{ .c = {} }, .wasm => .{ .wasm = link.File.Wasm.DeclBlock.empty }, .spirv => .{ .spirv = {} }, diff --git a/src/Sema.zig b/src/Sema.zig index 82321ef54565a72dd319b2862fa793560e9c89c3..e54bfc7bd9f67fc3c0b4dc93284735eac5dc6594 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -5568,7 +5568,7 @@ pub fn analyzeExport( .coff => .{ .coff = {} }, .elf => .{ .elf = {} }, .macho => .{ .macho = {} }, - .plan9 => .{ .plan9 = null }, + .plan9 => .{ .plan9 = {} }, .c => .{ .c = {} }, .wasm => .{ .wasm = .{} }, .spirv => .{ .spirv = {} }, diff --git a/src/arch/aarch64/CodeGen.zig b/src/arch/aarch64/CodeGen.zig index d0fba2fd0e737c6ca453fd743731c2ab30f64fc8..aab30b73dc13d8264cbe23d0e129e1bbf3b58285 100644 --- a/src/arch/aarch64/CodeGen.zig +++ b/src/arch/aarch64/CodeGen.zig @@ -4307,7 +4307,6 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier if (self.air.value(callee)) |func_value| { if (func_value.castTag(.function)) |func_payload| { const func = func_payload.data; - const fn_owner_decl = mod.declPtr(func.owner_decl); if (self.bin_file.cast(link.File.Elf)) |elf_file| { const atom_index = try elf_file.getOrCreateAtomForDecl(func.owner_decl); @@ -4333,11 +4332,12 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier }, }); } else if (self.bin_file.cast(link.File.Plan9)) |p9| { - try p9.seeDecl(func.owner_decl); + const decl_block_index = try p9.seeDecl(func.owner_decl); + const decl_block = p9.getDeclBlock(decl_block_index); const ptr_bits = self.target.cpu.arch.ptrBitWidth(); const ptr_bytes: u64 = @divExact(ptr_bits, 8); const got_addr = p9.bases.data; - const got_index = fn_owner_decl.link.plan9.got_index.?; + const got_index = decl_block.got_index.?; const fn_got_addr = got_addr + got_index * ptr_bytes; try self.genSetReg(Type.initTag(.usize), .x30, .{ .memory = fn_got_addr }); } else unreachable; @@ -6166,8 +6166,9 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne .sym_index = sym_index, } }; } else if (self.bin_file.cast(link.File.Plan9)) |p9| { - try p9.seeDecl(decl_index); - const got_addr = p9.bases.data + decl.link.plan9.got_index.? * ptr_bytes; + const decl_block_index = try p9.seeDecl(decl_index); + const decl_block = p9.getDeclBlock(decl_block_index); + const got_addr = p9.bases.data + decl_block.got_index.? * ptr_bytes; return MCValue{ .memory = got_addr }; } else { return self.fail("TODO codegen non-ELF const Decl pointer", .{}); diff --git a/src/arch/arm/CodeGen.zig b/src/arch/arm/CodeGen.zig index c6ee960e510163f433cb6d35bcc66cbae90497e5..6574501767d45bde89960633eca1ed05727f1605 100644 --- a/src/arch/arm/CodeGen.zig +++ b/src/arch/arm/CodeGen.zig @@ -6091,8 +6091,9 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne } else if (self.bin_file.cast(link.File.Coff)) |_| { return self.fail("TODO codegen COFF const Decl pointer", .{}); } else if (self.bin_file.cast(link.File.Plan9)) |p9| { - try p9.seeDecl(decl_index); - const got_addr = p9.bases.data + decl.link.plan9.got_index.? * ptr_bytes; + const decl_block_index = try p9.seeDecl(decl_index); + const decl_block = p9.getDeclBlock(decl_block_index); + const got_addr = p9.bases.data + decl_block.got_index.? * ptr_bytes; return MCValue{ .memory = got_addr }; } else { return self.fail("TODO codegen non-ELF const Decl pointer", .{}); diff --git a/src/arch/riscv64/CodeGen.zig b/src/arch/riscv64/CodeGen.zig index a0af1b3ccec40a4257898c67f8402cadff040c50..423816c0b17890fcc1d816ce351cb53011da3aa0 100644 --- a/src/arch/riscv64/CodeGen.zig +++ b/src/arch/riscv64/CodeGen.zig @@ -2558,8 +2558,9 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne } else if (self.bin_file.cast(link.File.Coff)) |_| { return self.fail("TODO codegen COFF const Decl pointer", .{}); } else if (self.bin_file.cast(link.File.Plan9)) |p9| { - try p9.seeDecl(decl_index); - const got_addr = p9.bases.data + decl.link.plan9.got_index.? * ptr_bytes; + const decl_block_index = try p9.seeDecl(decl_index); + const decl_block = p9.getDeclBlock(decl_block_index); + const got_addr = p9.bases.data + decl_block.got_index.? * ptr_bytes; return MCValue{ .memory = got_addr }; } else { return self.fail("TODO codegen non-ELF const Decl pointer", .{}); diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index b41973ea9742aa26815ed1e2bbfde2484753cefa..fcae7eaabc778821a24847cfe5a9014c2c451b37 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -3996,7 +3996,6 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier if (self.air.value(callee)) |func_value| { if (func_value.castTag(.function)) |func_payload| { const func = func_payload.data; - const fn_owner_decl = mod.declPtr(func.owner_decl); if (self.bin_file.cast(link.File.Elf)) |elf_file| { const atom_index = try elf_file.getOrCreateAtomForDecl(func.owner_decl); @@ -4042,11 +4041,12 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier .data = undefined, }); } else if (self.bin_file.cast(link.File.Plan9)) |p9| { - try p9.seeDecl(func.owner_decl); + const decl_block_index = try p9.seeDecl(func.owner_decl); + const decl_block = p9.getDeclBlock(decl_block_index); const ptr_bits = self.target.cpu.arch.ptrBitWidth(); const ptr_bytes: u64 = @divExact(ptr_bits, 8); const got_addr = p9.bases.data; - const got_index = fn_owner_decl.link.plan9.got_index.?; + const got_index = decl_block.got_index.?; const fn_got_addr = got_addr + got_index * ptr_bytes; _ = try self.addInst(.{ .tag = .call, @@ -6739,8 +6739,9 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne .sym_index = sym_index, } }; } else if (self.bin_file.cast(link.File.Plan9)) |p9| { - try p9.seeDecl(decl_index); - const got_addr = p9.bases.data + decl.link.plan9.got_index.? * ptr_bytes; + const decl_block_index = try p9.seeDecl(decl_index); + const decl_block = p9.getDeclBlock(decl_block_index); + const got_addr = p9.bases.data + decl_block.got_index.? * ptr_bytes; return MCValue{ .memory = got_addr }; } else { return self.fail("TODO codegen non-ELF const Decl pointer", .{}); diff --git a/src/link.zig b/src/link.zig index eb74615492f35ee96ea699287fbe97f24e5445ad..c0eacf88a0d6cab4627b169f8ca99ca578367b64 100644 --- a/src/link.zig +++ b/src/link.zig @@ -265,7 +265,7 @@ pub const File = struct { elf: void, coff: void, macho: void, - plan9: Plan9.DeclBlock, + plan9: void, c: void, wasm: Wasm.DeclBlock, spirv: void, @@ -287,7 +287,7 @@ pub const File = struct { elf: void, coff: void, macho: void, - plan9: Plan9.Export, + plan9: void, c: void, wasm: Wasm.Export, spirv: void, diff --git a/src/link/Plan9.zig b/src/link/Plan9.zig index a8b8caafab0f98ac72bf3009451b3c7e7e1b29d2..20f540022a00d9a1f62c3370aae4d72d31ce78e7 100644 --- a/src/link/Plan9.zig +++ b/src/link/Plan9.zig @@ -21,14 +21,7 @@ const Allocator = std.mem.Allocator; const log = std.log.scoped(.link); const assert = std.debug.assert; -const FnDeclOutput = struct { - /// this code is modified when relocated so it is mutable - code: []u8, - /// this might have to be modified in the linker, so thats why its mutable - lineinfo: []u8, - start_line: u32, - end_line: u32, -}; +pub const base_tag = .plan9; base: link.File, sixtyfour_bit: bool, @@ -101,6 +94,9 @@ got_index_free_list: std.ArrayListUnmanaged(usize) = .{}, syms_index_free_list: std.ArrayListUnmanaged(usize) = .{}, +decl_blocks: std.ArrayListUnmanaged(DeclBlock) = .{}, +decls: std.AutoHashMapUnmanaged(Module.Decl.Index, DeclMetadata) = .{}, + const Reloc = struct { target: Module.Decl.Index, offset: u64, @@ -115,17 +111,7 @@ const Bases = struct { const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(struct { info: DeclBlock, code: []const u8 })); -fn getAddr(self: Plan9, addr: u64, t: aout.Sym.Type) u64 { - return addr + switch (t) { - .T, .t, .l, .L => self.bases.text, - .D, .d, .B, .b => self.bases.data, - else => unreachable, - }; -} - -fn getSymAddr(self: Plan9, s: aout.Sym) u64 { - return self.getAddr(s.value, s.type); -} +pub const PtrWidth = enum { p32, p64 }; pub const DeclBlock = struct { type: aout.Sym.Type, @@ -135,13 +121,43 @@ pub const DeclBlock = struct { sym_index: ?usize, /// offset into got got_index: ?usize, - pub const empty = DeclBlock{ - .type = .t, - .offset = null, - .sym_index = null, - .got_index = null, + + pub const Index = u32; +}; + +const DeclMetadata = struct { + index: DeclBlock.Index, + exports: std.ArrayListUnmanaged(usize) = .{}, + + fn getExport(m: DeclMetadata, p9: *const Plan9, name: []const u8) ?usize { + for (m.exports.items) |exp| { + const sym = p9.syms.items[exp]; + if (mem.eql(u8, name, sym.name)) return exp; + } + return null; + } +}; + +const FnDeclOutput = struct { + /// this code is modified when relocated so it is mutable + code: []u8, + /// this might have to be modified in the linker, so thats why its mutable + lineinfo: []u8, + start_line: u32, + end_line: u32, +}; + +fn getAddr(self: Plan9, addr: u64, t: aout.Sym.Type) u64 { + return addr + switch (t) { + .T, .t, .l, .L => self.bases.text, + .D, .d, .B, .b => self.bases.data, + else => unreachable, }; -}; +} + +fn getSymAddr(self: Plan9, s: aout.Sym) u64 { + return self.getAddr(s.value, s.type); +} pub fn defaultBaseAddrs(arch: std.Target.Cpu.Arch) Bases { return switch (arch) { @@ -164,8 +180,6 @@ pub fn defaultBaseAddrs(arch: std.Target.Cpu.Arch) Bases { }; } -pub const PtrWidth = enum { p32, p64 }; - pub fn createEmpty(gpa: Allocator, options: link.Options) !*Plan9 { if (options.use_llvm) return error.LLVMBackendDoesNotSupportPlan9; @@ -271,7 +285,7 @@ pub fn updateFunc(self: *Plan9, module: *Module, func: *Module.Fn, air: Air, liv const decl = module.declPtr(decl_index); self.freeUnnamedConsts(decl_index); - try self.seeDecl(decl_index); + _ = try self.seeDecl(decl_index); log.debug("codegen decl {*} ({s})", .{ decl, decl.name }); var code_buffer = std.ArrayList(u8).init(self.base.allocator); @@ -313,11 +327,11 @@ pub fn updateFunc(self: *Plan9, module: *Module, func: *Module.Fn, air: Air, liv .end_line = end_line, }; try self.putFn(decl_index, out); - return self.updateFinish(decl); + return self.updateFinish(decl_index); } pub fn lowerUnnamedConst(self: *Plan9, tv: TypedValue, decl_index: Module.Decl.Index) !u32 { - try self.seeDecl(decl_index); + _ = try self.seeDecl(decl_index); var code_buffer = std.ArrayList(u8).init(self.base.allocator); defer code_buffer.deinit(); @@ -387,7 +401,7 @@ pub fn updateDecl(self: *Plan9, module: *Module, decl_index: Module.Decl.Index) } } - try self.seeDecl(decl_index); + _ = try self.seeDecl(decl_index); log.debug("codegen decl {*} ({s}) ({d})", .{ decl, decl.name, decl_index }); @@ -414,28 +428,31 @@ pub fn updateDecl(self: *Plan9, module: *Module, decl_index: Module.Decl.Index) if (self.data_decl_table.fetchPutAssumeCapacity(decl_index, duped_code)) |old_entry| { self.base.allocator.free(old_entry.value); } - return self.updateFinish(decl); + return self.updateFinish(decl_index); } /// called at the end of update{Decl,Func} -fn updateFinish(self: *Plan9, decl: *Module.Decl) !void { +fn updateFinish(self: *Plan9, decl_index: Module.Decl.Index) !void { + const decl = self.base.options.module.?.declPtr(decl_index); const is_fn = (decl.ty.zigTypeTag() == .Fn); log.debug("update the symbol table and got for decl {*} ({s})", .{ decl, decl.name }); const sym_t: aout.Sym.Type = if (is_fn) .t else .d; + + const decl_block = self.getDeclBlockPtr(self.decls.get(decl_index).?.index); // write the internal linker metadata - decl.link.plan9.type = sym_t; + decl_block.type = sym_t; // write the symbol // we already have the got index const sym: aout.Sym = .{ .value = undefined, // the value of stuff gets filled in in flushModule - .type = decl.link.plan9.type, + .type = decl_block.type, .name = mem.span(decl.name), }; - if (decl.link.plan9.sym_index) |s| { + if (decl_block.sym_index) |s| { self.syms.items[s] = sym; } else { const s = try self.allocateSymbolIndex(); - decl.link.plan9.sym_index = s; + decl_block.sym_index = s; self.syms.items[s] = sym; } } @@ -550,6 +567,7 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No while (it.next()) |entry| { const decl_index = entry.key_ptr.*; const decl = mod.declPtr(decl_index); + const decl_block = self.getDeclBlockPtr(self.decls.get(decl_index).?.index); const out = entry.value_ptr.*; log.debug("write text decl {*} ({s}), lines {d} to {d}", .{ decl, decl.name, out.start_line + 1, out.end_line }); { @@ -568,16 +586,16 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No iovecs_i += 1; const off = self.getAddr(text_i, .t); text_i += out.code.len; - decl.link.plan9.offset = off; + decl_block.offset = off; if (!self.sixtyfour_bit) { - mem.writeIntNative(u32, got_table[decl.link.plan9.got_index.? * 4 ..][0..4], @intCast(u32, off)); - mem.writeInt(u32, got_table[decl.link.plan9.got_index.? * 4 ..][0..4], @intCast(u32, off), self.base.options.target.cpu.arch.endian()); + mem.writeIntNative(u32, got_table[decl_block.got_index.? * 4 ..][0..4], @intCast(u32, off)); + mem.writeInt(u32, got_table[decl_block.got_index.? * 4 ..][0..4], @intCast(u32, off), self.base.options.target.cpu.arch.endian()); } else { - mem.writeInt(u64, got_table[decl.link.plan9.got_index.? * 8 ..][0..8], off, self.base.options.target.cpu.arch.endian()); + mem.writeInt(u64, got_table[decl_block.got_index.? * 8 ..][0..8], off, self.base.options.target.cpu.arch.endian()); } - self.syms.items[decl.link.plan9.sym_index.?].value = off; + self.syms.items[decl_block.sym_index.?].value = off; if (mod.decl_exports.get(decl_index)) |exports| { - try self.addDeclExports(mod, decl, exports.items); + try self.addDeclExports(mod, decl_index, exports.items); } } } @@ -598,6 +616,7 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No while (it.next()) |entry| { const decl_index = entry.key_ptr.*; const decl = mod.declPtr(decl_index); + const decl_block = self.getDeclBlockPtr(self.decls.get(decl_index).?.index); const code = entry.value_ptr.*; log.debug("write data decl {*} ({s})", .{ decl, decl.name }); @@ -606,15 +625,15 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No iovecs_i += 1; const off = self.getAddr(data_i, .d); data_i += code.len; - decl.link.plan9.offset = off; + decl_block.offset = off; if (!self.sixtyfour_bit) { - mem.writeInt(u32, got_table[decl.link.plan9.got_index.? * 4 ..][0..4], @intCast(u32, off), self.base.options.target.cpu.arch.endian()); + mem.writeInt(u32, got_table[decl_block.got_index.? * 4 ..][0..4], @intCast(u32, off), self.base.options.target.cpu.arch.endian()); } else { - mem.writeInt(u64, got_table[decl.link.plan9.got_index.? * 8 ..][0..8], off, self.base.options.target.cpu.arch.endian()); + mem.writeInt(u64, got_table[decl_block.got_index.? * 8 ..][0..8], off, self.base.options.target.cpu.arch.endian()); } - self.syms.items[decl.link.plan9.sym_index.?].value = off; + self.syms.items[decl_block.sym_index.?].value = off; if (mod.decl_exports.get(decl_index)) |exports| { - try self.addDeclExports(mod, decl, exports.items); + try self.addDeclExports(mod, decl_index, exports.items); } } // write the unnamed constants after the other data decls @@ -676,7 +695,8 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No for (kv.value_ptr.items) |reloc| { const target_decl_index = reloc.target; const target_decl = mod.declPtr(target_decl_index); - const target_decl_offset = target_decl.link.plan9.offset.?; + const target_decl_block = self.getDeclBlock(self.decls.get(target_decl_index).?.index); + const target_decl_offset = target_decl_block.offset.?; const offset = reloc.offset; const addend = reloc.addend; @@ -709,28 +729,36 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No fn addDeclExports( self: *Plan9, module: *Module, - decl: *Module.Decl, + decl_index: Module.Decl.Index, exports: []const *Module.Export, ) !void { + const metadata = self.decls.getPtr(decl_index).?; + const decl_block = self.getDeclBlock(metadata.index); + for (exports) |exp| { // plan9 does not support custom sections if (exp.options.section) |section_name| { if (!mem.eql(u8, section_name, ".text") or !mem.eql(u8, section_name, ".data")) { - try module.failed_exports.put(module.gpa, exp, try Module.ErrorMsg.create(self.base.allocator, decl.srcLoc(), "plan9 does not support extra sections", .{})); + try module.failed_exports.put(module.gpa, exp, try Module.ErrorMsg.create( + self.base.allocator, + module.declPtr(decl_index).srcLoc(), + "plan9 does not support extra sections", + .{}, + )); break; } } const sym = .{ - .value = decl.link.plan9.offset.?, - .type = decl.link.plan9.type.toGlobal(), + .value = decl_block.offset.?, + .type = decl_block.type.toGlobal(), .name = exp.options.name, }; - if (exp.link.plan9) |i| { + if (metadata.getExport(self, exp.options.name)) |i| { self.syms.items[i] = sym; } else { try self.syms.append(self.base.allocator, sym); - exp.link.plan9 = self.syms.items.len - 1; + try metadata.exports.append(self.base.allocator, self.syms.items.len - 1); } } } @@ -760,13 +788,18 @@ pub fn freeDecl(self: *Plan9, decl_index: Module.Decl.Index) void { self.base.allocator.free(removed_entry.value); } } - if (decl.link.plan9.got_index) |i| { - // TODO: if this catch {} is triggered, an assertion in flushModule will be triggered, because got_index_free_list will have the wrong length - self.got_index_free_list.append(self.base.allocator, i) catch {}; - } - if (decl.link.plan9.sym_index) |i| { - self.syms_index_free_list.append(self.base.allocator, i) catch {}; - self.syms.items[i] = aout.Sym.undefined_symbol; + if (self.decls.fetchRemove(decl_index)) |const_kv| { + var kv = const_kv; + const decl_block = self.getDeclBlock(kv.value.index); + if (decl_block.got_index) |i| { + // TODO: if this catch {} is triggered, an assertion in flushModule will be triggered, because got_index_free_list will have the wrong length + self.got_index_free_list.append(self.base.allocator, i) catch {}; + } + if (decl_block.sym_index) |i| { + self.syms_index_free_list.append(self.base.allocator, i) catch {}; + self.syms.items[i] = aout.Sym.undefined_symbol; + } + kv.value.exports.deinit(self.base.allocator); } self.freeUnnamedConsts(decl_index); { @@ -786,12 +819,30 @@ fn freeUnnamedConsts(self: *Plan9, decl_index: Module.Decl.Index) void { unnamed_consts.clearAndFree(self.base.allocator); } -pub fn seeDecl(self: *Plan9, decl_index: Module.Decl.Index) !void { - const mod = self.base.options.module.?; - const decl = mod.declPtr(decl_index); - if (decl.link.plan9.got_index == null) { - decl.link.plan9.got_index = self.allocateGotIndex(); +fn createDeclBlock(self: *Plan9) !DeclBlock.Index { + const gpa = self.base.allocator; + const index = @intCast(DeclBlock.Index, self.decl_blocks.items.len); + const decl_block = try self.decl_blocks.addOne(gpa); + decl_block.* = .{ + .type = .t, + .offset = null, + .sym_index = null, + .got_index = null, + }; + return index; +} + +pub fn seeDecl(self: *Plan9, decl_index: Module.Decl.Index) !DeclBlock.Index { + const gop = try self.decls.getOrPut(self.base.allocator, decl_index); + if (!gop.found_existing) { + const index = try self.createDeclBlock(); + self.getDeclBlockPtr(index).got_index = self.allocateGotIndex(); + gop.value_ptr.* = .{ + .index = index, + .exports = .{}, + }; } + return gop.value_ptr.index; } pub fn updateDeclExports( @@ -800,7 +851,7 @@ pub fn updateDeclExports( decl_index: Module.Decl.Index, exports: []const *Module.Export, ) !void { - try self.seeDecl(decl_index); + _ = try self.seeDecl(decl_index); // we do all the things in flush _ = module; _ = exports; @@ -842,10 +893,17 @@ pub fn deinit(self: *Plan9) void { self.syms_index_free_list.deinit(gpa); self.file_segments.deinit(gpa); self.path_arena.deinit(); + self.decl_blocks.deinit(gpa); + + { + var it = self.decls.iterator(); + while (it.next()) |entry| { + entry.value_ptr.exports.deinit(gpa); + } + self.decls.deinit(gpa); + } } -pub const Export = ?usize; -pub const base_tag = .plan9; pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*Plan9 { if (options.use_llvm) return error.LLVMBackendDoesNotSupportPlan9; @@ -911,20 +969,19 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void { } } - const mod = self.base.options.module.?; - // write the data symbols { var it = self.data_decl_table.iterator(); while (it.next()) |entry| { const decl_index = entry.key_ptr.*; - const decl = mod.declPtr(decl_index); - const sym = self.syms.items[decl.link.plan9.sym_index.?]; + const decl_metadata = self.decls.get(decl_index).?; + const decl_block = self.getDeclBlock(decl_metadata.index); + const sym = self.syms.items[decl_block.sym_index.?]; try self.writeSym(writer, sym); if (self.base.options.module.?.decl_exports.get(decl_index)) |exports| { - for (exports.items) |e| { - try self.writeSym(writer, self.syms.items[e.link.plan9.?]); - } + for (exports.items) |e| if (decl_metadata.getExport(self, e.options.name)) |exp_i| { + try self.writeSym(writer, self.syms.items[exp_i]); + }; } } } @@ -943,16 +1000,17 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void { var submap_it = symidx_and_submap.functions.iterator(); while (submap_it.next()) |entry| { const decl_index = entry.key_ptr.*; - const decl = mod.declPtr(decl_index); - const sym = self.syms.items[decl.link.plan9.sym_index.?]; + const decl_metadata = self.decls.get(decl_index).?; + const decl_block = self.getDeclBlock(decl_metadata.index); + const sym = self.syms.items[decl_block.sym_index.?]; try self.writeSym(writer, sym); if (self.base.options.module.?.decl_exports.get(decl_index)) |exports| { - for (exports.items) |e| { - const s = self.syms.items[e.link.plan9.?]; + for (exports.items) |e| if (decl_metadata.getExport(self, e.options.name)) |exp_i| { + const s = self.syms.items[exp_i]; if (mem.eql(u8, s.name, "_start")) self.entry_val = s.value; try self.writeSym(writer, s); - } + }; } } } @@ -1004,3 +1062,11 @@ pub fn getDeclVAddr( }); return undefined; } + +pub fn getDeclBlock(self: *const Plan9, index: DeclBlock.Index) DeclBlock { + return self.decl_blocks.items[index]; +} + +fn getDeclBlockPtr(self: *Plan9, index: DeclBlock.Index) *DeclBlock { + return &self.decl_blocks.items[index]; +} -- 2.54.0 From d98fc53b8fbe479f828114b0276d5290146cc2a3 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Wed, 1 Feb 2023 11:49:07 +0100 Subject: [PATCH 63/84] link: use strtab.StringTable in Dwarf --- src/link/Dwarf.zig | 20 ++++++-------------- src/link/Elf.zig | 10 +++++----- src/link/MachO/DebugSymbols.zig | 12 ++++++------ 3 files changed, 17 insertions(+), 25 deletions(-) diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig index 8278377095edfc5cd29a17aae7dc533fc4cbfd52..61ddda34943254fa7240e3148178202442296b0a 100644 --- a/src/link/Dwarf.zig +++ b/src/link/Dwarf.zig @@ -18,8 +18,9 @@ const LinkBlock = File.LinkBlock; const LinkFn = File.LinkFn; const LinkerLoad = @import("../codegen.zig").LinkerLoad; const Module = @import("../Module.zig"); -const Value = @import("../value.zig").Value; +const StringTable = @import("strtab.zig").StringTable; const Type = @import("../type.zig").Type; +const Value = @import("../value.zig").Value; allocator: Allocator, bin_file: *File, @@ -42,7 +43,7 @@ abbrev_table_offset: ?u64 = null, /// TODO replace with InternPool /// Table of debug symbol names. -strtab: std.ArrayListUnmanaged(u8) = .{}, +strtab: StringTable(.strtab) = .{}, /// Quick lookup array of all defined source files referenced by at least one Decl. /// They will end up in the DWARF debug_line header as two lists: @@ -1770,11 +1771,11 @@ pub fn writeDbgInfoHeader(self: *Dwarf, module: *Module, low_pc: u64, high_pc: u }, } // Write the form for the compile unit, which must match the abbrev table above. - const name_strp = try self.makeString(module.root_pkg.root_src_path); + const name_strp = try self.strtab.insert(self.allocator, module.root_pkg.root_src_path); var compile_unit_dir_buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined; const compile_unit_dir = resolveCompilationDir(module, &compile_unit_dir_buffer); - const comp_dir_strp = try self.makeString(compile_unit_dir); - const producer_strp = try self.makeString(link.producer_string); + const comp_dir_strp = try self.strtab.insert(self.allocator, compile_unit_dir); + const producer_strp = try self.strtab.insert(self.allocator, link.producer_string); di_buf.appendAssumeCapacity(@enumToInt(AbbrevKind.compile_unit)); if (self.bin_file.tag == .macho) { @@ -2435,15 +2436,6 @@ fn getRelocDbgInfoSubprogramHighPC(self: Dwarf) u32 { return dbg_info_low_pc_reloc_index + self.ptrWidthBytes(); } -/// TODO Improve this to use a table. -fn makeString(self: *Dwarf, bytes: []const u8) !u32 { - try self.strtab.ensureUnusedCapacity(self.allocator, bytes.len + 1); - const result = self.strtab.items.len; - self.strtab.appendSliceAssumeCapacity(bytes); - self.strtab.appendAssumeCapacity(0); - return @intCast(u32, result); -} - fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) { return actual_size +| (actual_size / ideal_factor); } diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 747120ac5d818ec53c3d0f201c09b0665022bedb..01326fb82eddccbafafd65f481cf5ec27f7940b2 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -688,8 +688,8 @@ pub fn populateMissingMetadata(self: *Elf) !void { // if (self.dwarf) |*dw| { // if (self.debug_str_section_index == null) { // self.debug_str_section_index = @intCast(u16, self.sections.slice().len); - // assert(dw.strtab.items.len == 0); - // try dw.strtab.append(gpa, 0); + // assert(dw.strtab.buffer.items.len == 0); + // try dw.strtab.buffer.append(gpa, 0); // try self.sections.append(gpa, .{ // .shdr = .{ // .sh_name = try self.shstrtab.insert(gpa, ".debug_str"), @@ -1164,10 +1164,10 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node // if (self.dwarf) |dwarf| { // const shdr_index = self.debug_str_section_index.?; - // if (self.debug_strtab_dirty or dwarf.strtab.items.len != self.sections.items(.shdr)[shdr_index].sh_size) { - // try self.growNonAllocSection(shdr_index, dwarf.strtab.items.len, 1, false); + // if (self.debug_strtab_dirty or dwarf.strtab.buffer.items.len != self.sections.items(.shdr)[shdr_index].sh_size) { + // try self.growNonAllocSection(shdr_index, dwarf.strtab.buffer.items.len, 1, false); // const debug_strtab_sect = self.sections.items(.shdr)[shdr_index]; - // try self.base.file.?.pwriteAll(dwarf.strtab.items, debug_strtab_sect.sh_offset); + // try self.base.file.?.pwriteAll(dwarf.strtab.buffer.items, debug_strtab_sect.sh_offset); // self.debug_strtab_dirty = false; // } // } diff --git a/src/link/MachO/DebugSymbols.zig b/src/link/MachO/DebugSymbols.zig index 7c22f441cd8ca509df12afdcfb358be8ea6e0ae6..0a5c8b03724ecc3284719fc1640071e27268f227 100644 --- a/src/link/MachO/DebugSymbols.zig +++ b/src/link/MachO/DebugSymbols.zig @@ -82,11 +82,11 @@ pub fn populateMissingMetadata(self: *DebugSymbols) !void { } if (self.debug_str_section_index == null) { - assert(self.dwarf.strtab.items.len == 0); - try self.dwarf.strtab.append(self.allocator, 0); + assert(self.dwarf.strtab.buffer.items.len == 0); + try self.dwarf.strtab.buffer.append(self.allocator, 0); self.debug_str_section_index = try self.allocateSection( "__debug_str", - @intCast(u32, self.dwarf.strtab.items.len), + @intCast(u32, self.dwarf.strtab.buffer.items.len), 0, ); self.debug_string_table_dirty = true; @@ -291,10 +291,10 @@ pub fn flushModule(self: *DebugSymbols, macho_file: *MachO) !void { { const sect_index = self.debug_str_section_index.?; - if (self.debug_string_table_dirty or self.dwarf.strtab.items.len != self.getSection(sect_index).size) { - const needed_size = @intCast(u32, self.dwarf.strtab.items.len); + if (self.debug_string_table_dirty or self.dwarf.strtab.buffer.items.len != self.getSection(sect_index).size) { + const needed_size = @intCast(u32, self.dwarf.strtab.buffer.items.len); try self.growSection(sect_index, needed_size, false); - try self.file.pwriteAll(self.dwarf.strtab.items, self.getSection(sect_index).offset); + try self.file.pwriteAll(self.dwarf.strtab.buffer.items, self.getSection(sect_index).offset); self.debug_string_table_dirty = false; } } -- 2.54.0 From 5de2aae63cd75322e58204a6be8df49754e4851a Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Wed, 1 Feb 2023 15:03:55 +0100 Subject: [PATCH 64/84] link: decouple DI atoms from linker atoms, and manage them in Dwarf linker --- src/Compilation.zig | 2 +- src/Module.zig | 12 +- src/arch/aarch64/CodeGen.zig | 17 +- src/arch/arm/CodeGen.zig | 17 +- src/arch/riscv64/CodeGen.zig | 10 +- src/arch/sparc64/CodeGen.zig | 10 +- src/arch/wasm/CodeGen.zig | 4 +- src/arch/x86_64/CodeGen.zig | 4 +- src/link.zig | 23 +- src/link/C.zig | 4 +- src/link/Coff.zig | 5 +- src/link/Dwarf.zig | 522 ++++++++++++++++++++--------------- src/link/Elf.zig | 520 +++++++++++++++++----------------- src/link/Elf/Atom.zig | 3 - src/link/MachO.zig | 130 ++++----- src/link/MachO/Atom.zig | 3 - src/link/Plan9.zig | 4 +- src/link/Wasm.zig | 17 +- src/link/Wasm/Atom.zig | 5 - 19 files changed, 655 insertions(+), 657 deletions(-) diff --git a/src/Compilation.zig b/src/Compilation.zig index 09c6e1c6867ad8d99ab1db20a5c115d4c9439fd4..7d42d3b610f2a5b8efc02d1b2f0dfc239c3be62a 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -3299,7 +3299,7 @@ fn processOneJob(comp: *Compilation, job: Job) !void { const gpa = comp.gpa; const module = comp.bin_file.options.module.?; const decl = module.declPtr(decl_index); - comp.bin_file.updateDeclLineNumber(module, decl) catch |err| { + comp.bin_file.updateDeclLineNumber(module, decl_index) catch |err| { try module.failed_decls.ensureUnusedCapacity(gpa, 1); module.failed_decls.putAssumeCapacityNoClobber(decl_index, try Module.ErrorMsg.create( gpa, diff --git a/src/Module.zig b/src/Module.zig index a914dc90d81c86187318ed530cbb768becc52e40..eb947a697795e60107e87e89c2f8776f0c1726ce 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -5186,12 +5186,12 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err .coff => { // TODO Implement for COFF }, - .elf => if (decl.fn_link.elf.len != 0) { + .elf => { // TODO Look into detecting when this would be unnecessary by storing enough state // in `Decl` to notice that the line number did not change. comp.work_queue.writeItemAssumeCapacity(.{ .update_line_number = decl_index }); }, - .macho => if (decl.fn_link.macho.len != 0) { + .macho => { // TODO Look into detecting when this would be unnecessary by storing enough state // in `Decl` to notice that the line number did not change. comp.work_queue.writeItemAssumeCapacity(.{ .update_line_number = decl_index }); @@ -5285,8 +5285,8 @@ pub fn clearDecl( }; decl.fn_link = switch (mod.comp.bin_file.tag) { .coff => .{ .coff = {} }, - .elf => .{ .elf = link.File.Dwarf.SrcFn.empty }, - .macho => .{ .macho = link.File.Dwarf.SrcFn.empty }, + .elf => .{ .elf = {} }, + .macho => .{ .macho = {} }, .plan9 => .{ .plan9 = {} }, .c => .{ .c = {} }, .wasm => .{ .wasm = link.File.Wasm.FnData.empty }, @@ -5705,8 +5705,8 @@ pub fn allocateNewDecl( }, .fn_link = switch (mod.comp.bin_file.tag) { .coff => .{ .coff = {} }, - .elf => .{ .elf = link.File.Dwarf.SrcFn.empty }, - .macho => .{ .macho = link.File.Dwarf.SrcFn.empty }, + .elf => .{ .elf = {} }, + .macho => .{ .macho = {} }, .plan9 => .{ .plan9 = {} }, .c => .{ .c = {} }, .wasm => .{ .wasm = link.File.Wasm.FnData.empty }, diff --git a/src/arch/aarch64/CodeGen.zig b/src/arch/aarch64/CodeGen.zig index aab30b73dc13d8264cbe23d0e129e1bbf3b58285..473a62fd83de249b197c866cae3b65d7e205ac07 100644 --- a/src/arch/aarch64/CodeGen.zig +++ b/src/arch/aarch64/CodeGen.zig @@ -203,13 +203,7 @@ const DbgInfoReloc = struct { else => unreachable, // not a possible argument }; - try dw.genArgDbgInfo( - reloc.name, - reloc.ty, - function.bin_file.tag, - function.mod_fn.owner_decl, - loc, - ); + try dw.genArgDbgInfo(reloc.name, reloc.ty, function.mod_fn.owner_decl, loc); }, .plan9 => {}, .none => {}, @@ -255,14 +249,7 @@ const DbgInfoReloc = struct { break :blk .nop; }, }; - try dw.genVarDbgInfo( - reloc.name, - reloc.ty, - function.bin_file.tag, - function.mod_fn.owner_decl, - is_ptr, - loc, - ); + try dw.genVarDbgInfo(reloc.name, reloc.ty, function.mod_fn.owner_decl, is_ptr, loc); }, .plan9 => {}, .none => {}, diff --git a/src/arch/arm/CodeGen.zig b/src/arch/arm/CodeGen.zig index 6574501767d45bde89960633eca1ed05727f1605..57a8aed69982285e7ba5b8c1ccf3e987af940ef0 100644 --- a/src/arch/arm/CodeGen.zig +++ b/src/arch/arm/CodeGen.zig @@ -282,13 +282,7 @@ const DbgInfoReloc = struct { else => unreachable, // not a possible argument }; - try dw.genArgDbgInfo( - reloc.name, - reloc.ty, - function.bin_file.tag, - function.mod_fn.owner_decl, - loc, - ); + try dw.genArgDbgInfo(reloc.name, reloc.ty, function.mod_fn.owner_decl, loc); }, .plan9 => {}, .none => {}, @@ -331,14 +325,7 @@ const DbgInfoReloc = struct { break :blk .nop; }, }; - try dw.genVarDbgInfo( - reloc.name, - reloc.ty, - function.bin_file.tag, - function.mod_fn.owner_decl, - is_ptr, - loc, - ); + try dw.genVarDbgInfo(reloc.name, reloc.ty, function.mod_fn.owner_decl, is_ptr, loc); }, .plan9 => {}, .none => {}, diff --git a/src/arch/riscv64/CodeGen.zig b/src/arch/riscv64/CodeGen.zig index 423816c0b17890fcc1d816ce351cb53011da3aa0..8b8fca48593af63593c0a9690bf5106c5da25d59 100644 --- a/src/arch/riscv64/CodeGen.zig +++ b/src/arch/riscv64/CodeGen.zig @@ -1615,13 +1615,9 @@ fn genArgDbgInfo(self: Self, inst: Air.Inst.Index, mcv: MCValue) !void { switch (self.debug_output) { .dwarf => |dw| switch (mcv) { - .register => |reg| try dw.genArgDbgInfo( - name, - ty, - self.bin_file.tag, - self.mod_fn.owner_decl, - .{ .register = reg.dwarfLocOp() }, - ), + .register => |reg| try dw.genArgDbgInfo(name, ty, self.mod_fn.owner_decl, .{ + .register = reg.dwarfLocOp(), + }), .stack_offset => {}, else => {}, }, diff --git a/src/arch/sparc64/CodeGen.zig b/src/arch/sparc64/CodeGen.zig index e67244167ef25351157c701e35add5749f7388b2..418c67c5807bfd253d03059f60b551c699c5caa7 100644 --- a/src/arch/sparc64/CodeGen.zig +++ b/src/arch/sparc64/CodeGen.zig @@ -3412,13 +3412,9 @@ fn genArgDbgInfo(self: Self, inst: Air.Inst.Index, mcv: MCValue) !void { switch (self.debug_output) { .dwarf => |dw| switch (mcv) { - .register => |reg| try dw.genArgDbgInfo( - name, - ty, - self.bin_file.tag, - self.mod_fn.owner_decl, - .{ .register = reg.dwarfLocOp() }, - ), + .register => |reg| try dw.genArgDbgInfo(name, ty, self.mod_fn.owner_decl, .{ + .register = reg.dwarfLocOp(), + }), else => {}, }, else => {}, diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index 342d6b70cc55ef3a8273729323010135a555a066..8212d281e57284fa1718e594784615af66dd38b6 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -2475,7 +2475,7 @@ fn airArg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { .dwarf => |dwarf| { const src_index = func.air.instructions.items(.data)[inst].arg.src_index; const name = func.mod_fn.getParamName(func.bin_file.base.options.module.?, src_index); - try dwarf.genArgDbgInfo(name, arg_ty, .wasm, func.mod_fn.owner_decl, .{ + try dwarf.genArgDbgInfo(name, arg_ty, func.mod_fn.owner_decl, .{ .wasm_local = arg.local.value, }); }, @@ -5539,7 +5539,7 @@ fn airDbgVar(func: *CodeGen, inst: Air.Inst.Index, is_ptr: bool) !void { break :blk .nop; }, }; - try func.debug_output.dwarf.genVarDbgInfo(name, ty, .wasm, func.mod_fn.owner_decl, is_ptr, loc); + try func.debug_output.dwarf.genVarDbgInfo(name, ty, func.mod_fn.owner_decl, is_ptr, loc); func.finishAir(inst, .none, &.{}); } diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index fcae7eaabc778821a24847cfe5a9014c2c451b37..c11ea4e63e2c5059d4dd051f8eac6b21c608f1c1 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -3836,7 +3836,7 @@ fn genArgDbgInfo(self: Self, ty: Type, name: [:0]const u8, mcv: MCValue) !void { }, else => unreachable, // not a valid function parameter }; - try dw.genArgDbgInfo(name, ty, self.bin_file.tag, self.mod_fn.owner_decl, loc); + try dw.genArgDbgInfo(name, ty, self.mod_fn.owner_decl, loc); }, .plan9 => {}, .none => {}, @@ -3876,7 +3876,7 @@ fn genVarDbgInfo( break :blk .nop; }, }; - try dw.genVarDbgInfo(name, ty, self.bin_file.tag, self.mod_fn.owner_decl, is_ptr, loc); + try dw.genVarDbgInfo(name, ty, self.mod_fn.owner_decl, is_ptr, loc); }, .plan9 => {}, .none => {}, diff --git a/src/link.zig b/src/link.zig index c0eacf88a0d6cab4627b169f8ca99ca578367b64..3dd182b586ae6f9d7ea73de7aff2d76a291d620d 100644 --- a/src/link.zig +++ b/src/link.zig @@ -273,9 +273,9 @@ pub const File = struct { }; pub const LinkFn = union { - elf: Dwarf.SrcFn, - coff: Coff.SrcFn, - macho: Dwarf.SrcFn, + elf: void, + coff: void, + macho: void, plan9: void, c: void, wasm: Wasm.FnData, @@ -580,22 +580,23 @@ pub const File = struct { } } - pub fn updateDeclLineNumber(base: *File, module: *Module, decl: *Module.Decl) UpdateDeclError!void { + pub fn updateDeclLineNumber(base: *File, module: *Module, decl_index: Module.Decl.Index) UpdateDeclError!void { + const decl = module.declPtr(decl_index); log.debug("updateDeclLineNumber {*} ({s}), line={}", .{ decl, decl.name, decl.src_line + 1, }); assert(decl.has_tv); if (build_options.only_c) { assert(base.tag == .c); - return @fieldParentPtr(C, "base", base).updateDeclLineNumber(module, decl); + return @fieldParentPtr(C, "base", base).updateDeclLineNumber(module, decl_index); } switch (base.tag) { - .coff => return @fieldParentPtr(Coff, "base", base).updateDeclLineNumber(module, decl), - .elf => return @fieldParentPtr(Elf, "base", base).updateDeclLineNumber(module, decl), - .macho => return @fieldParentPtr(MachO, "base", base).updateDeclLineNumber(module, decl), - .c => return @fieldParentPtr(C, "base", base).updateDeclLineNumber(module, decl), - .wasm => return @fieldParentPtr(Wasm, "base", base).updateDeclLineNumber(module, decl), - .plan9 => return @fieldParentPtr(Plan9, "base", base).updateDeclLineNumber(module, decl), + .coff => return @fieldParentPtr(Coff, "base", base).updateDeclLineNumber(module, decl_index), + .elf => return @fieldParentPtr(Elf, "base", base).updateDeclLineNumber(module, decl_index), + .macho => return @fieldParentPtr(MachO, "base", base).updateDeclLineNumber(module, decl_index), + .c => return @fieldParentPtr(C, "base", base).updateDeclLineNumber(module, decl_index), + .wasm => return @fieldParentPtr(Wasm, "base", base).updateDeclLineNumber(module, decl_index), + .plan9 => return @fieldParentPtr(Plan9, "base", base).updateDeclLineNumber(module, decl_index), .spirv, .nvptx => {}, } } diff --git a/src/link/C.zig b/src/link/C.zig index 8b05b8b22dac5fdce82aec74671719f34cf220e4..02e5cadfbc1186944817c5e1e4d35d0532aa1c0b 100644 --- a/src/link/C.zig +++ b/src/link/C.zig @@ -219,12 +219,12 @@ pub fn updateDecl(self: *C, module: *Module, decl_index: Module.Decl.Index) !voi code.shrinkAndFree(module.gpa, code.items.len); } -pub fn updateDeclLineNumber(self: *C, module: *Module, decl: *Module.Decl) !void { +pub fn updateDeclLineNumber(self: *C, module: *Module, decl_index: Module.Decl.Index) !void { // The C backend does not have the ability to fix line numbers without re-generating // the entire Decl. _ = self; _ = module; - _ = decl; + _ = decl_index; } pub fn flush(self: *C, comp: *Compilation, prog_node: *std.Progress.Node) !void { diff --git a/src/link/Coff.zig b/src/link/Coff.zig index c062276b73e5b3b997395085974bab07e13552cf..f563a617c78d07d493729c4f2c123bb442feb106 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -195,7 +195,6 @@ pub const PtrWidth = enum { }; } }; -pub const SrcFn = void; pub const SymbolWithLoc = struct { // Index into the respective symbol table. @@ -1545,10 +1544,10 @@ pub fn getGlobalSymbol(self: *Coff, name: []const u8) !u32 { return global_index; } -pub fn updateDeclLineNumber(self: *Coff, module: *Module, decl: *Module.Decl) !void { +pub fn updateDeclLineNumber(self: *Coff, module: *Module, decl_index: Module.Decl.Index) !void { _ = self; _ = module; - _ = decl; + _ = decl_index; log.debug("TODO implement updateDeclLineNumber", .{}); } diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig index 61ddda34943254fa7240e3148178202442296b0a..e90db2d0df74e4b01481a21e85ce563820238e42 100644 --- a/src/link/Dwarf.zig +++ b/src/link/Dwarf.zig @@ -27,17 +27,21 @@ bin_file: *File, ptr_width: PtrWidth, target: std.Target, -/// A list of `File.LinkFn` 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 `Atom`s whose Line Number Programs have surplus capacity. +/// This is the same concept as `Section.free_list` in Elf; see those doc comments. +src_fn_free_list: std.AutoHashMapUnmanaged(Atom.Index, void) = .{}, +src_fn_first_index: ?Atom.Index = null, +src_fn_last_index: ?Atom.Index = null, +src_fns: std.ArrayListUnmanaged(Atom) = .{}, +src_fn_decls: AtomTable = .{}, /// A list of `Atom`s whose corresponding .debug_info tags have surplus capacity. /// This is the same concept as `text_block_free_list`; see those doc comments. -atom_free_list: std.AutoHashMapUnmanaged(*Atom, void) = .{}, -atom_first: ?*Atom = null, -atom_last: ?*Atom = null, +di_atom_free_list: std.AutoHashMapUnmanaged(Atom.Index, void) = .{}, +di_atom_first_index: ?Atom.Index = null, +di_atom_last_index: ?Atom.Index = null, +di_atoms: std.ArrayListUnmanaged(Atom) = .{}, +di_atom_decls: AtomTable = .{}, abbrev_table_offset: ?u64 = null, @@ -51,22 +55,23 @@ strtab: StringTable(.strtab) = .{}, /// * []file_names di_files: std.AutoArrayHashMapUnmanaged(*const Module.File, void) = .{}, -/// List of atoms that are owned directly by the DWARF module. -/// TODO convert links in DebugInfoAtom into indices and make -/// sure every atom is owned by this module. -managed_atoms: std.ArrayListUnmanaged(*Atom) = .{}, - global_abbrev_relocs: std.ArrayListUnmanaged(AbbrevRelocation) = .{}, -pub const Atom = struct { - /// Previous/next linked list pointers. - /// This is the linked list node for this Decl's corresponding .debug_info tag. - prev: ?*Atom, - next: ?*Atom, - /// Offset into .debug_info pointing to the tag for this Decl. +const AtomTable = std.AutoHashMapUnmanaged(Module.Decl.Index, Atom.Index); + +const Atom = struct { + /// Offset into .debug_info pointing to the tag for this Decl, or + /// offset from the beginning of the Debug Line Program header that contains this function. off: u32, - /// Size of the .debug_info tag for this Decl, not including padding. + /// Size of the .debug_info tag for this Decl, not including padding, or + /// size of the line number program component belonging to this function, not + /// including padding. len: u32, + + prev_index: ?Index, + next_index: ?Index, + + pub const Index = u32; }; /// Represents state of the analysed Decl. @@ -76,6 +81,7 @@ pub const Atom = struct { pub const DeclState = struct { gpa: Allocator, mod: *Module, + di_atom_decls: *const AtomTable, dbg_line: std.ArrayList(u8), dbg_info: std.ArrayList(u8), abbrev_type_arena: std.heap.ArenaAllocator, @@ -89,10 +95,11 @@ pub const DeclState = struct { abbrev_relocs: std.ArrayListUnmanaged(AbbrevRelocation) = .{}, exprloc_relocs: std.ArrayListUnmanaged(ExprlocRelocation) = .{}, - fn init(gpa: Allocator, mod: *Module) DeclState { + fn init(gpa: Allocator, mod: *Module, di_atom_decls: *const AtomTable) DeclState { return .{ .gpa = gpa, .mod = mod, + .di_atom_decls = di_atom_decls, .dbg_line = std.ArrayList(u8).init(gpa), .dbg_info = std.ArrayList(u8).init(gpa), .abbrev_type_arena = std.heap.ArenaAllocator.init(gpa), @@ -120,11 +127,11 @@ pub const DeclState = struct { /// Adds local type relocation of the form: @offset => @this + addend /// @this signifies the offset within the .debug_abbrev section of the containing atom. - fn addTypeRelocLocal(self: *DeclState, atom: *const Atom, offset: u32, addend: u32) !void { + fn addTypeRelocLocal(self: *DeclState, atom_index: Atom.Index, offset: u32, addend: u32) !void { log.debug("{x}: @this + {x}", .{ offset, addend }); try self.abbrev_relocs.append(self.gpa, .{ .target = null, - .atom = atom, + .atom_index = atom_index, .offset = offset, .addend = addend, }); @@ -133,13 +140,13 @@ pub const DeclState = struct { /// Adds global type relocation of the form: @offset => @symbol + 0 /// @symbol signifies a type abbreviation posititioned somewhere in the .debug_abbrev section /// which we use as our target of the relocation. - fn addTypeRelocGlobal(self: *DeclState, atom: *const Atom, ty: Type, offset: u32) !void { + fn addTypeRelocGlobal(self: *DeclState, atom_index: Atom.Index, ty: Type, offset: u32) !void { const resolv = self.abbrev_resolver.getContext(ty, .{ .mod = self.mod, }) orelse blk: { const sym_index = @intCast(u32, self.abbrev_table.items.len); try self.abbrev_table.append(self.gpa, .{ - .atom = atom, + .atom_index = atom_index, .type = ty, .offset = undefined, }); @@ -154,7 +161,7 @@ pub const DeclState = struct { log.debug("{x}: %{d} + 0", .{ offset, resolv }); try self.abbrev_relocs.append(self.gpa, .{ .target = resolv, - .atom = atom, + .atom_index = atom_index, .offset = offset, .addend = 0, }); @@ -163,7 +170,7 @@ pub const DeclState = struct { fn addDbgInfoType( self: *DeclState, module: *Module, - atom: *Atom, + atom_index: Atom.Index, ty: Type, ) error{OutOfMemory}!void { const arena = self.abbrev_type_arena.allocator(); @@ -228,7 +235,7 @@ pub const DeclState = struct { // DW.AT.type, DW.FORM.ref4 var index = dbg_info_buffer.items.len; try dbg_info_buffer.resize(index + 4); - try self.addTypeRelocGlobal(atom, Type.bool, @intCast(u32, index)); + try self.addTypeRelocGlobal(atom_index, Type.bool, @intCast(u32, index)); // DW.AT.data_member_location, DW.FORM.sdata try dbg_info_buffer.ensureUnusedCapacity(6); dbg_info_buffer.appendAssumeCapacity(0); @@ -240,7 +247,7 @@ pub const DeclState = struct { // DW.AT.type, DW.FORM.ref4 index = dbg_info_buffer.items.len; try dbg_info_buffer.resize(index + 4); - try self.addTypeRelocGlobal(atom, payload_ty, @intCast(u32, index)); + try self.addTypeRelocGlobal(atom_index, payload_ty, @intCast(u32, index)); // DW.AT.data_member_location, DW.FORM.sdata const offset = abi_size - payload_ty.abiSize(target); try leb128.writeULEB128(dbg_info_buffer.writer(), offset); @@ -271,7 +278,7 @@ pub const DeclState = struct { try dbg_info_buffer.resize(index + 4); var buf = try arena.create(Type.SlicePtrFieldTypeBuffer); const ptr_ty = ty.slicePtrFieldType(buf); - try self.addTypeRelocGlobal(atom, ptr_ty, @intCast(u32, index)); + try self.addTypeRelocGlobal(atom_index, ptr_ty, @intCast(u32, index)); // DW.AT.data_member_location, DW.FORM.sdata try dbg_info_buffer.ensureUnusedCapacity(6); dbg_info_buffer.appendAssumeCapacity(0); @@ -283,7 +290,7 @@ pub const DeclState = struct { // DW.AT.type, DW.FORM.ref4 index = dbg_info_buffer.items.len; try dbg_info_buffer.resize(index + 4); - try self.addTypeRelocGlobal(atom, Type.usize, @intCast(u32, index)); + try self.addTypeRelocGlobal(atom_index, Type.usize, @intCast(u32, index)); // DW.AT.data_member_location, DW.FORM.sdata try dbg_info_buffer.ensureUnusedCapacity(2); dbg_info_buffer.appendAssumeCapacity(ptr_bytes); @@ -295,7 +302,7 @@ pub const DeclState = struct { // DW.AT.type, DW.FORM.ref4 const index = dbg_info_buffer.items.len; try dbg_info_buffer.resize(index + 4); - try self.addTypeRelocGlobal(atom, ty.childType(), @intCast(u32, index)); + try self.addTypeRelocGlobal(atom_index, ty.childType(), @intCast(u32, index)); } }, .Array => { @@ -306,13 +313,13 @@ pub const DeclState = struct { // DW.AT.type, DW.FORM.ref4 var index = dbg_info_buffer.items.len; try dbg_info_buffer.resize(index + 4); - try self.addTypeRelocGlobal(atom, ty.childType(), @intCast(u32, index)); + try self.addTypeRelocGlobal(atom_index, ty.childType(), @intCast(u32, index)); // DW.AT.subrange_type try dbg_info_buffer.append(@enumToInt(AbbrevKind.array_dim)); // DW.AT.type, DW.FORM.ref4 index = dbg_info_buffer.items.len; try dbg_info_buffer.resize(index + 4); - try self.addTypeRelocGlobal(atom, Type.usize, @intCast(u32, index)); + try self.addTypeRelocGlobal(atom_index, Type.usize, @intCast(u32, index)); // DW.AT.count, DW.FORM.udata const len = ty.arrayLenIncludingSentinel(); try leb128.writeULEB128(dbg_info_buffer.writer(), len); @@ -340,7 +347,7 @@ pub const DeclState = struct { // DW.AT.type, DW.FORM.ref4 var index = dbg_info_buffer.items.len; try dbg_info_buffer.resize(index + 4); - try self.addTypeRelocGlobal(atom, field, @intCast(u32, index)); + try self.addTypeRelocGlobal(atom_index, field, @intCast(u32, index)); // DW.AT.data_member_location, DW.FORM.sdata const field_off = ty.structFieldOffset(field_index, target); try leb128.writeULEB128(dbg_info_buffer.writer(), field_off); @@ -372,7 +379,7 @@ pub const DeclState = struct { // DW.AT.type, DW.FORM.ref4 var index = dbg_info_buffer.items.len; try dbg_info_buffer.resize(index + 4); - try self.addTypeRelocGlobal(atom, field.ty, @intCast(u32, index)); + try self.addTypeRelocGlobal(atom_index, field.ty, @intCast(u32, index)); // DW.AT.data_member_location, DW.FORM.sdata const field_off = ty.structFieldOffset(field_index, target); try leb128.writeULEB128(dbg_info_buffer.writer(), field_off); @@ -455,7 +462,7 @@ pub const DeclState = struct { // DW.AT.type, DW.FORM.ref4 const inner_union_index = dbg_info_buffer.items.len; try dbg_info_buffer.resize(inner_union_index + 4); - try self.addTypeRelocLocal(atom, @intCast(u32, inner_union_index), 5); + try self.addTypeRelocLocal(atom_index, @intCast(u32, inner_union_index), 5); // DW.AT.data_member_location, DW.FORM.sdata try leb128.writeULEB128(dbg_info_buffer.writer(), payload_offset); } @@ -482,7 +489,7 @@ pub const DeclState = struct { // DW.AT.type, DW.FORM.ref4 const index = dbg_info_buffer.items.len; try dbg_info_buffer.resize(index + 4); - try self.addTypeRelocGlobal(atom, field.ty, @intCast(u32, index)); + try self.addTypeRelocGlobal(atom_index, field.ty, @intCast(u32, index)); // DW.AT.data_member_location, DW.FORM.sdata try dbg_info_buffer.append(0); } @@ -499,7 +506,7 @@ pub const DeclState = struct { // DW.AT.type, DW.FORM.ref4 const index = dbg_info_buffer.items.len; try dbg_info_buffer.resize(index + 4); - try self.addTypeRelocGlobal(atom, union_obj.tag_ty, @intCast(u32, index)); + try self.addTypeRelocGlobal(atom_index, union_obj.tag_ty, @intCast(u32, index)); // DW.AT.data_member_location, DW.FORM.sdata try leb128.writeULEB128(dbg_info_buffer.writer(), tag_offset); @@ -542,7 +549,7 @@ pub const DeclState = struct { // DW.AT.type, DW.FORM.ref4 var index = dbg_info_buffer.items.len; try dbg_info_buffer.resize(index + 4); - try self.addTypeRelocGlobal(atom, payload_ty, @intCast(u32, index)); + try self.addTypeRelocGlobal(atom_index, payload_ty, @intCast(u32, index)); // DW.AT.data_member_location, DW.FORM.sdata try leb128.writeULEB128(dbg_info_buffer.writer(), payload_off); @@ -555,7 +562,7 @@ pub const DeclState = struct { // DW.AT.type, DW.FORM.ref4 index = dbg_info_buffer.items.len; try dbg_info_buffer.resize(index + 4); - try self.addTypeRelocGlobal(atom, error_ty, @intCast(u32, index)); + try self.addTypeRelocGlobal(atom_index, error_ty, @intCast(u32, index)); // DW.AT.data_member_location, DW.FORM.sdata try leb128.writeULEB128(dbg_info_buffer.writer(), error_off); @@ -588,12 +595,11 @@ pub const DeclState = struct { self: *DeclState, name: [:0]const u8, ty: Type, - tag: File.Tag, owner_decl: Module.Decl.Index, loc: DbgInfoLoc, ) error{OutOfMemory}!void { const dbg_info = &self.dbg_info; - const atom = getDbgInfoAtom(tag, self.mod, owner_decl); + const atom_index = self.di_atom_decls.get(owner_decl).?; const name_with_null = name.ptr[0 .. name.len + 1]; switch (loc) { @@ -638,7 +644,7 @@ pub const DeclState = struct { try dbg_info.ensureUnusedCapacity(5 + name_with_null.len); const index = dbg_info.items.len; try dbg_info.resize(index + 4); // dw.at.type, dw.form.ref4 - try self.addTypeRelocGlobal(atom, ty, @intCast(u32, index)); // DW.AT.type, DW.FORM.ref4 + try self.addTypeRelocGlobal(atom_index, ty, @intCast(u32, index)); // DW.AT.type, DW.FORM.ref4 dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string } @@ -646,13 +652,12 @@ pub const DeclState = struct { self: *DeclState, name: [:0]const u8, ty: Type, - tag: File.Tag, owner_decl: Module.Decl.Index, is_ptr: bool, loc: DbgInfoLoc, ) error{OutOfMemory}!void { const dbg_info = &self.dbg_info; - const atom = getDbgInfoAtom(tag, self.mod, owner_decl); + const atom_index = self.di_atom_decls.get(owner_decl).?; const name_with_null = name.ptr[0 .. name.len + 1]; try dbg_info.append(@enumToInt(AbbrevKind.variable)); const target = self.mod.getTarget(); @@ -782,7 +787,7 @@ pub const DeclState = struct { try dbg_info.ensureUnusedCapacity(5 + name_with_null.len); const index = dbg_info.items.len; try dbg_info.resize(index + 4); // dw.at.type, dw.form.ref4 - try self.addTypeRelocGlobal(atom, child_ty, @intCast(u32, index)); + try self.addTypeRelocGlobal(atom_index, child_ty, @intCast(u32, index)); dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string } @@ -815,7 +820,7 @@ pub const DeclState = struct { }; pub const AbbrevEntry = struct { - atom: *const Atom, + atom_index: Atom.Index, type: Type, offset: u32, }; @@ -824,7 +829,7 @@ pub const AbbrevRelocation = struct { /// If target is null, we deal with a local relocation that is based on simple offset + addend /// only. target: ?u32, - atom: *const Atom, + atom_index: Atom.Index, offset: u32, addend: u32, }; @@ -841,26 +846,6 @@ pub const ExprlocRelocation = struct { offset: u32, }; -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 const PtrWidth = enum { p32, p64 }; pub const AbbrevKind = enum(u8) { @@ -910,16 +895,18 @@ pub fn init(allocator: Allocator, bin_file: *File, target: std.Target) Dwarf { pub fn deinit(self: *Dwarf) void { const gpa = self.allocator; - self.dbg_line_fn_free_list.deinit(gpa); - self.atom_free_list.deinit(gpa); + + self.src_fn_free_list.deinit(gpa); + self.src_fns.deinit(gpa); + self.src_fn_decls.deinit(gpa); + + self.di_atom_free_list.deinit(gpa); + self.di_atoms.deinit(gpa); + self.di_atom_decls.deinit(gpa); + self.strtab.deinit(gpa); self.di_files.deinit(gpa); self.global_abbrev_relocs.deinit(gpa); - - for (self.managed_atoms.items) |atom| { - gpa.destroy(atom); - } - self.managed_atoms.deinit(gpa); } /// Initializes Decl's state and its matching output buffers. @@ -935,15 +922,19 @@ pub fn initDeclState(self: *Dwarf, mod: *Module, decl_index: Module.Decl.Index) log.debug("initDeclState {s}{*}", .{ decl_name, decl }); const gpa = self.allocator; - var decl_state = DeclState.init(gpa, mod); + var decl_state = DeclState.init(gpa, mod, &self.di_atom_decls); errdefer decl_state.deinit(); const dbg_line_buffer = &decl_state.dbg_line; const dbg_info_buffer = &decl_state.dbg_info; + const di_atom_index = try self.getOrCreateAtomForDecl(.di_atom, decl_index); + assert(decl.has_tv); switch (decl.ty.zigTypeTag()) { .Fn => { + _ = try self.getOrCreateAtomForDecl(.src_fn, decl_index); + // For functions we need to add a prologue to the debug line program. try dbg_line_buffer.ensureTotalCapacity(26); @@ -1003,8 +994,7 @@ pub fn initDeclState(self: *Dwarf, mod: *Module, decl_index: Module.Decl.Index) dbg_info_buffer.items.len += 4; // DW.AT.high_pc, DW.FORM.data4 // if (fn_ret_has_bits) { - const atom = getDbgInfoAtom(self.bin_file.tag, mod, decl_index); - try decl_state.addTypeRelocGlobal(atom, fn_ret_type, @intCast(u32, dbg_info_buffer.items.len)); + try decl_state.addTypeRelocGlobal(di_atom_index, fn_ret_type, @intCast(u32, dbg_info_buffer.items.len)); dbg_info_buffer.items.len += 4; // DW.AT.type, DW.FORM.ref4 } @@ -1076,26 +1066,23 @@ pub fn commitDeclState( // 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 src_fn = switch (self.bin_file.tag) { - .elf => &decl.fn_link.elf, - .macho => &decl.fn_link.macho, - .wasm => &decl.fn_link.wasm.src_fn, - else => unreachable, // TODO - }; + const src_fn_index = self.src_fn_decls.get(decl_index).?; + const src_fn = self.getAtomPtr(.src_fn, src_fn_index); src_fn.len = @intCast(u32, dbg_line_buffer.items.len); - if (self.dbg_line_fn_last) |last| blk: { - if (src_fn == last) break :blk; - if (src_fn.next) |next| { + if (self.src_fn_last_index) |last_index| blk: { + if (src_fn_index == last_index) break :blk; + if (src_fn.next_index) |next_index| { + const next = self.getAtomPtr(.src_fn, next_index); // 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(gpa, prev, {}) catch {}; - prev.next = src_fn.next; + if (src_fn.prev_index) |prev_index| { + self.src_fn_free_list.put(gpa, prev_index, {}) catch {}; + self.getAtomPtr(.src_fn, prev_index).next_index = src_fn.next_index; } - next.prev = src_fn.prev; - src_fn.next = null; + next.prev_index = src_fn.prev_index; + src_fn.next_index = null; // Populate where it used to be with NOPs. switch (self.bin_file.tag) { .elf => { @@ -1118,33 +1105,42 @@ pub fn commitDeclState( else => unreachable, } // 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.prev_index = last_index; + const last = self.getAtomPtr(.src_fn, last_index); + last.next_index = src_fn_index; + self.src_fn_last_index = src_fn_index; src_fn.off = last.off + padToIdeal(last.len); } - } else if (src_fn.prev == null) { + } else if (src_fn.prev_index == 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.prev_index = last_index; + const last = self.getAtomPtr(.src_fn, last_index); + last.next_index = src_fn_index; + self.src_fn_last_index = src_fn_index; src_fn.off = last.off + padToIdeal(last.len); } } 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; + self.src_fn_first_index = src_fn_index; + self.src_fn_last_index = src_fn_index; src_fn.off = padToIdeal(self.dbgLineNeededHeaderBytes(&[0][]u8{}, &[0][]u8{})); } - const last_src_fn = self.dbg_line_fn_last.?; + const last_src_fn_index = self.src_fn_last_index.?; + const last_src_fn = self.getAtom(.src_fn, last_src_fn_index); const needed_size = last_src_fn.off + last_src_fn.len; - 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; + const prev_padding_size: u32 = if (src_fn.prev_index) |prev_index| blk: { + const prev = self.getAtom(.src_fn, prev_index); + break :blk src_fn.off - (prev.off + prev.len); + } else 0; + const next_padding_size: u32 = if (src_fn.next_index) |next_index| blk: { + const next = self.getAtom(.src_fn, next_index); + break :blk 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. @@ -1213,7 +1209,7 @@ pub fn commitDeclState( if (dbg_info_buffer.items.len == 0) return; - const atom = getDbgInfoAtom(self.bin_file.tag, module, decl_index); + const di_atom_index = self.di_atom_decls.get(decl_index).?; if (decl_state.abbrev_table.items.len > 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 @@ -1235,12 +1231,12 @@ pub fn commitDeclState( if (deferred) continue; symbol.offset = @intCast(u32, dbg_info_buffer.items.len); - try decl_state.addDbgInfoType(module, atom, ty); + try decl_state.addDbgInfoType(module, di_atom_index, ty); } } log.debug("updateDeclDebugInfoAllocation for '{s}'", .{decl.name}); - try self.updateDeclDebugInfoAllocation(atom, @intCast(u32, dbg_info_buffer.items.len)); + try self.updateDeclDebugInfoAllocation(di_atom_index, @intCast(u32, dbg_info_buffer.items.len)); while (decl_state.abbrev_relocs.popOrNull()) |reloc| { if (reloc.target) |target| { @@ -1261,11 +1257,12 @@ pub fn commitDeclState( try self.global_abbrev_relocs.append(gpa, .{ .target = null, .offset = reloc.offset, - .atom = reloc.atom, + .atom_index = reloc.atom_index, .addend = reloc.addend, }); } else { - const value = symbol.atom.off + symbol.offset + reloc.addend; + const atom = self.getAtom(.di_atom, symbol.atom_index); + const value = atom.off + symbol.offset + reloc.addend; log.debug("{x}: [() => {x}] (%{d}, '{}')", .{ reloc.offset, value, target, ty.fmtDebug() }); mem.writeInt( u32, @@ -1275,10 +1272,11 @@ pub fn commitDeclState( ); } } else { + const atom = self.getAtom(.di_atom, reloc.atom_index); mem.writeInt( u32, dbg_info_buffer.items[reloc.offset..][0..@sizeOf(u32)], - reloc.atom.off + reloc.offset + reloc.addend, + atom.off + reloc.offset + reloc.addend, target_endian, ); } @@ -1294,7 +1292,7 @@ pub fn commitDeclState( .got_load => .got_load, }, .target = reloc.target, - .offset = reloc.offset + atom.off, + .offset = reloc.offset + self.getAtom(.di_atom, di_atom_index).off, .addend = 0, .prev_vaddr = 0, }); @@ -1304,10 +1302,10 @@ pub fn commitDeclState( } log.debug("writeDeclDebugInfo for '{s}", .{decl.name}); - try self.writeDeclDebugInfo(atom, dbg_info_buffer.items); + try self.writeDeclDebugInfo(di_atom_index, dbg_info_buffer.items); } -fn updateDeclDebugInfoAllocation(self: *Dwarf, atom: *Atom, len: u32) !void { +fn updateDeclDebugInfoAllocation(self: *Dwarf, atom_index: Atom.Index, len: u32) !void { const tracy = trace(@src()); defer tracy.end(); @@ -1316,19 +1314,21 @@ fn updateDeclDebugInfoAllocation(self: *Dwarf, atom: *Atom, len: u32) !void { // probably need to edit that logic too. const gpa = self.allocator; + const atom = self.getAtomPtr(.di_atom, atom_index); atom.len = len; - if (self.atom_last) |last| blk: { - if (atom == last) break :blk; - if (atom.next) |next| { + if (self.di_atom_last_index) |last_index| blk: { + if (atom_index == last_index) break :blk; + if (atom.next_index) |next_index| { + const next = self.getAtomPtr(.di_atom, next_index); // Update existing Decl - non-last item. if (atom.off + atom.len + min_nop_size > next.off) { // It grew too big, so we move it to a new location. - if (atom.prev) |prev| { - self.atom_free_list.put(gpa, prev, {}) catch {}; - prev.next = atom.next; + if (atom.prev_index) |prev_index| { + self.di_atom_free_list.put(gpa, prev_index, {}) catch {}; + self.getAtomPtr(.di_atom, prev_index).next_index = atom.next_index; } - next.prev = atom.prev; - atom.next = null; + next.prev_index = atom.prev_index; + atom.next_index = null; // Populate where it used to be with NOPs. switch (self.bin_file.tag) { .elf => { @@ -1351,31 +1351,33 @@ fn updateDeclDebugInfoAllocation(self: *Dwarf, atom: *Atom, len: u32) !void { else => unreachable, } // TODO Look at the free list before appending at the end. - atom.prev = last; - last.next = atom; - self.atom_last = atom; + atom.prev_index = last_index; + const last = self.getAtomPtr(.di_atom, last_index); + last.next_index = atom_index; + self.di_atom_last_index = atom_index; atom.off = last.off + padToIdeal(last.len); } - } else if (atom.prev == null) { + } else if (atom.prev_index == null) { // Append new Decl. // TODO Look at the free list before appending at the end. - atom.prev = last; - last.next = atom; - self.atom_last = atom; + atom.prev_index = last_index; + const last = self.getAtomPtr(.di_atom, last_index); + last.next_index = atom_index; + self.di_atom_last_index = atom_index; atom.off = last.off + padToIdeal(last.len); } } else { // This is the first Decl of the .debug_info - self.atom_first = atom; - self.atom_last = atom; + self.di_atom_first_index = atom_index; + self.di_atom_last_index = atom_index; atom.off = @intCast(u32, padToIdeal(self.dbgInfoHeaderBytes())); } } -fn writeDeclDebugInfo(self: *Dwarf, atom: *Atom, dbg_info_buf: []const u8) !void { +fn writeDeclDebugInfo(self: *Dwarf, atom_index: Atom.Index, dbg_info_buf: []const u8) !void { const tracy = trace(@src()); defer tracy.end(); @@ -1384,14 +1386,22 @@ fn writeDeclDebugInfo(self: *Dwarf, atom: *Atom, dbg_info_buf: []const u8) !void // probably need to edit that logic too. const gpa = self.allocator; - const last_decl = self.atom_last.?; + const atom = self.getAtom(.di_atom, atom_index); + const last_decl_index = self.di_atom_last_index.?; + const last_decl = self.getAtom(.di_atom, last_decl_index); // +1 for a trailing zero to end the children of the decl tag. const needed_size = last_decl.off + last_decl.len + 1; - const prev_padding_size: u32 = if (atom.prev) |prev| atom.off - (prev.off + prev.len) else 0; - const next_padding_size: u32 = if (atom.next) |next| next.off - (atom.off + atom.len) else 0; + const prev_padding_size: u32 = if (atom.prev_index) |prev_index| blk: { + const prev = self.getAtom(.di_atom, prev_index); + break :blk atom.off - (prev.off + prev.len); + } else 0; + const next_padding_size: u32 = if (atom.next_index) |next_index| blk: { + const next = self.getAtom(.di_atom, next_index); + break :blk next.off - (atom.off + atom.len); + } else 0; // To end the children of the decl tag. - const trailing_zero = atom.next == null; + const trailing_zero = atom.next_index == null; // We only have support for one compilation unit so far, so the offsets are directly // from the .debug_info section. @@ -1459,10 +1469,15 @@ fn writeDeclDebugInfo(self: *Dwarf, atom: *Atom, dbg_info_buf: []const u8) !void } } -pub fn updateDeclLineNumber(self: *Dwarf, decl: *const Module.Decl) !void { +pub fn updateDeclLineNumber(self: *Dwarf, module: *Module, decl_index: Module.Decl.Index) !void { const tracy = trace(@src()); defer tracy.end(); + const atom_index = try self.getOrCreateAtomForDecl(.src_fn, decl_index); + const atom = self.getAtom(.src_fn, atom_index); + if (atom.len == 0) return; + + const decl = module.declPtr(decl_index); const func = decl.val.castTag(.function).?.data; log.debug("decl.src_line={d}, func.lbrace_line={d}, func.rbrace_line={d}", .{ decl.src_line, @@ -1477,78 +1492,80 @@ pub fn updateDeclLineNumber(self: *Dwarf, decl: *const Module.Decl) !void { .elf => { const elf_file = self.bin_file.cast(File.Elf).?; const shdr = elf_file.sections.items(.shdr)[elf_file.debug_line_section_index.?]; - const file_pos = shdr.sh_offset + decl.fn_link.elf.off + self.getRelocDbgLineOff(); + const file_pos = shdr.sh_offset + atom.off + self.getRelocDbgLineOff(); try elf_file.base.file.?.pwriteAll(&data, file_pos); }, .macho => { const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?; const sect = d_sym.getSection(d_sym.debug_line_section_index.?); - const file_pos = sect.offset + decl.fn_link.macho.off + self.getRelocDbgLineOff(); + const file_pos = sect.offset + atom.off + self.getRelocDbgLineOff(); try d_sym.file.pwriteAll(&data, file_pos); }, .wasm => { const wasm_file = self.bin_file.cast(File.Wasm).?; - const offset = decl.fn_link.wasm.src_fn.off + self.getRelocDbgLineOff(); - const atom = wasm_file.debug_line_atom.?; - mem.copy(u8, atom.code.items[offset..], &data); + const offset = atom.off + self.getRelocDbgLineOff(); + const atom_ = wasm_file.debug_line_atom.?; + mem.copy(u8, atom_.code.items[offset..], &data); }, else => unreachable, } } -pub fn freeAtom(self: *Dwarf, atom: *Atom) void { - if (self.atom_first == atom) { - self.atom_first = atom.next; - } - if (self.atom_last == atom) { - // TODO shrink the .debug_info section size here - self.atom_last = atom.prev; - } - - if (atom.prev) |prev| { - prev.next = atom.next; - - // TODO the free list logic like we do for text blocks above - } else { - atom.prev = null; - } - - if (atom.next) |next| { - next.prev = atom.prev; - } else { - atom.next = null; - } -} - -pub fn freeDecl(self: *Dwarf, decl: *Module.Decl) void { - // TODO make this logic match freeTextBlock. Maybe abstract the logic out since the same thing - // is desired for both. +pub fn freeDecl(self: *Dwarf, decl_index: Module.Decl.Index) void { const gpa = self.allocator; - const fn_link = switch (self.bin_file.tag) { - .elf => &decl.fn_link.elf, - .macho => &decl.fn_link.macho, - .wasm => &decl.fn_link.wasm.src_fn, - else => unreachable, - }; - _ = self.dbg_line_fn_free_list.remove(fn_link); - if (fn_link.prev) |prev| { - self.dbg_line_fn_free_list.put(gpa, prev, {}) catch {}; - prev.next = fn_link.next; - if (fn_link.next) |next| { - next.prev = prev; - } else { - self.dbg_line_fn_last = prev; + // Free SrcFn atom + if (self.src_fn_decls.fetchRemove(decl_index)) |kv| { + const src_fn_index = kv.value; + const src_fn = self.getAtom(.src_fn, src_fn_index); + _ = self.src_fn_free_list.remove(src_fn_index); + + if (src_fn.prev_index) |prev_index| { + self.src_fn_free_list.put(gpa, prev_index, {}) catch {}; + const prev = self.getAtomPtr(.src_fn, prev_index); + prev.next_index = src_fn.next_index; + if (src_fn.next_index) |next_index| { + self.getAtomPtr(.src_fn, next_index).prev_index = prev_index; + } else { + self.src_fn_last_index = prev_index; + } + } else if (src_fn.next_index) |next_index| { + self.src_fn_first_index = next_index; + self.getAtomPtr(.src_fn, next_index).prev_index = null; + } + if (self.src_fn_first_index == src_fn_index) { + self.src_fn_first_index = src_fn.next_index; + } + if (self.src_fn_last_index == src_fn_index) { + self.src_fn_last_index = src_fn.prev_index; } - } else if (fn_link.next) |next| { - self.dbg_line_fn_first = next; - next.prev = null; - } - if (self.dbg_line_fn_first == fn_link) { - self.dbg_line_fn_first = fn_link.next; } - if (self.dbg_line_fn_last == fn_link) { - self.dbg_line_fn_last = fn_link.prev; + + // Free DI atom + if (self.di_atom_decls.fetchRemove(decl_index)) |kv| { + const di_atom_index = kv.value; + const di_atom = self.getAtomPtr(.di_atom, di_atom_index); + + if (self.di_atom_first_index == di_atom_index) { + self.di_atom_first_index = di_atom.next_index; + } + if (self.di_atom_last_index == di_atom_index) { + // TODO shrink the .debug_info section size here + self.di_atom_last_index = di_atom.prev_index; + } + + if (di_atom.prev_index) |prev_index| { + self.getAtomPtr(.di_atom, prev_index).next_index = di_atom.next_index; + // TODO the free list logic like we do for SrcFn above + } else { + di_atom.prev_index = null; + } + + if (di_atom.next_index) |next_index| { + self.getAtomPtr(.di_atom, next_index).prev_index = di_atom.prev_index; + } else { + di_atom.next_index = null; + } } } @@ -2276,10 +2293,14 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void { const needed_with_padding = padToIdeal(needed_bytes); const delta = needed_with_padding - dbg_line_prg_off; - var src_fn = self.dbg_line_fn_first.?; - const last_fn = self.dbg_line_fn_last.?; + const first_fn_index = self.src_fn_first_index.?; + const first_fn = self.getAtom(.src_fn, first_fn_index); + const last_fn_index = self.src_fn_last_index.?; + const last_fn = self.getAtom(.src_fn, last_fn_index); - var buffer = try gpa.alloc(u8, last_fn.off + last_fn.len - src_fn.off); + var src_fn_index = first_fn_index; + + var buffer = try gpa.alloc(u8, last_fn.off + last_fn.len - first_fn.off); defer gpa.free(buffer); switch (self.bin_file.tag) { @@ -2288,7 +2309,7 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void { const shdr_index = elf_file.debug_line_section_index.?; const needed_size = elf_file.sections.items(.shdr)[shdr_index].sh_size + delta; try elf_file.growNonAllocSection(shdr_index, needed_size, 1, true); - const file_pos = elf_file.sections.items(.shdr)[shdr_index].sh_offset + src_fn.off; + const file_pos = elf_file.sections.items(.shdr)[shdr_index].sh_offset + first_fn.off; const amt = try elf_file.base.file.?.preadAll(buffer, file_pos); if (amt != buffer.len) return error.InputOutput; @@ -2300,7 +2321,7 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void { const sect_index = d_sym.debug_line_section_index.?; const needed_size = @intCast(u32, d_sym.getSection(sect_index).size + delta); try d_sym.growSection(sect_index, needed_size, true); - const file_pos = d_sym.getSection(sect_index).offset + src_fn.off; + const file_pos = d_sym.getSection(sect_index).offset + first_fn.off; const amt = try d_sym.file.preadAll(buffer, file_pos); if (amt != buffer.len) return error.InputOutput; @@ -2310,18 +2331,19 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void { .wasm => { const wasm_file = self.bin_file.cast(File.Wasm).?; const debug_line = &wasm_file.debug_line_atom.?.code; - mem.copy(u8, buffer, debug_line.items[src_fn.off..]); + mem.copy(u8, buffer, debug_line.items[first_fn.off..]); try debug_line.resize(self.allocator, debug_line.items.len + delta); - mem.copy(u8, debug_line.items[src_fn.off + delta ..], buffer); + mem.copy(u8, debug_line.items[first_fn.off + delta ..], buffer); }, else => unreachable, } while (true) { + const src_fn = self.getAtomPtr(.src_fn, src_fn_index); src_fn.off += delta; - if (src_fn.next) |next| { - src_fn = next; + if (src_fn.next_index) |next_index| { + src_fn_index = next_index; } else break; } } @@ -2367,22 +2389,26 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void { } fn getDebugInfoOff(self: Dwarf) ?u32 { - const first = self.atom_first orelse return null; + const first_index = self.di_atom_first_index orelse return null; + const first = self.getAtom(.di_atom, first_index); return first.off; } fn getDebugInfoEnd(self: Dwarf) ?u32 { - const last = self.atom_last orelse return null; + const last_index = self.di_atom_last_index orelse return null; + const last = self.getAtom(.di_atom, last_index); return last.off + last.len; } fn getDebugLineProgramOff(self: Dwarf) ?u32 { - const first = self.dbg_line_fn_first orelse return null; + const first_index = self.src_fn_first_index orelse return null; + const first = self.getAtom(.src_fn, first_index); return first.off; } fn getDebugLineProgramEnd(self: Dwarf) ?u32 { - const last = self.dbg_line_fn_last orelse return null; + const last_index = self.src_fn_last_index orelse return null; + const last = self.getAtom(.src_fn, last_index); return last.off + last.len; } @@ -2457,23 +2483,14 @@ pub fn flushModule(self: *Dwarf, module: *Module) !void { } error_set.names = names; - const atom = try gpa.create(Atom); - errdefer gpa.destroy(atom); - atom.* = .{ - .prev = null, - .next = null, - .off = 0, - .len = 0, - }; - var dbg_info_buffer = std.ArrayList(u8).init(arena); try addDbgInfoErrorSet(arena, module, error_ty, self.target, &dbg_info_buffer); - try self.managed_atoms.append(gpa, atom); + const di_atom_index = try self.createAtom(.di_atom); log.debug("updateDeclDebugInfoAllocation in flushModule", .{}); - try self.updateDeclDebugInfoAllocation(atom, @intCast(u32, dbg_info_buffer.items.len)); + try self.updateDeclDebugInfoAllocation(di_atom_index, @intCast(u32, dbg_info_buffer.items.len)); log.debug("writeDeclDebugInfo in flushModule", .{}); - try self.writeDeclDebugInfo(atom, dbg_info_buffer.items); + try self.writeDeclDebugInfo(di_atom_index, dbg_info_buffer.items); const file_pos = blk: { switch (self.bin_file.tag) { @@ -2494,22 +2511,23 @@ pub fn flushModule(self: *Dwarf, module: *Module) !void { }; var buf: [@sizeOf(u32)]u8 = undefined; - mem.writeInt(u32, &buf, atom.off, self.target.cpu.arch.endian()); + mem.writeInt(u32, &buf, self.getAtom(.di_atom, di_atom_index).off, self.target.cpu.arch.endian()); while (self.global_abbrev_relocs.popOrNull()) |reloc| { + const atom = self.getAtom(.di_atom, reloc.atom_index); switch (self.bin_file.tag) { .elf => { const elf_file = self.bin_file.cast(File.Elf).?; - try elf_file.base.file.?.pwriteAll(&buf, file_pos + reloc.atom.off + reloc.offset); + try elf_file.base.file.?.pwriteAll(&buf, file_pos + atom.off + reloc.offset); }, .macho => { const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?; - try d_sym.file.pwriteAll(&buf, file_pos + reloc.atom.off + reloc.offset); + try d_sym.file.pwriteAll(&buf, file_pos + atom.off + reloc.offset); }, .wasm => { const wasm_file = self.bin_file.cast(File.Wasm).?; const debug_info = wasm_file.debug_info_atom.?.code; - mem.copy(u8, debug_info.items[reloc.atom.off + reloc.offset ..], &buf); + mem.copy(u8, debug_info.items[atom.off + reloc.offset ..], &buf); }, else => unreachable, } @@ -2627,12 +2645,62 @@ fn addDbgInfoErrorSet( try dbg_info_buffer.append(0); } -fn getDbgInfoAtom(tag: File.Tag, mod: *Module, decl_index: Module.Decl.Index) *Atom { - const decl = mod.declPtr(decl_index); - return switch (tag) { - .elf => unreachable, - .macho => unreachable, - .wasm => &decl.link.wasm.dbg_info_atom, - else => unreachable, +const Kind = enum { src_fn, di_atom }; + +fn createAtom(self: *Dwarf, comptime kind: Kind) !Atom.Index { + const index = blk: { + switch (kind) { + .src_fn => { + const index = @intCast(Atom.Index, self.src_fns.items.len); + _ = try self.src_fns.addOne(self.allocator); + break :blk index; + }, + .di_atom => { + const index = @intCast(Atom.Index, self.di_atoms.items.len); + _ = try self.di_atoms.addOne(self.allocator); + break :blk index; + }, + } + }; + const atom = self.getAtomPtr(kind, index); + atom.* = .{ + .off = 0, + .len = 0, + .prev_index = null, + .next_index = null, + }; + return index; +} + +fn getOrCreateAtomForDecl(self: *Dwarf, comptime kind: Kind, decl_index: Module.Decl.Index) !Atom.Index { + switch (kind) { + .src_fn => { + const gop = try self.src_fn_decls.getOrPut(self.allocator, decl_index); + if (!gop.found_existing) { + gop.value_ptr.* = try self.createAtom(kind); + } + return gop.value_ptr.*; + }, + .di_atom => { + const gop = try self.di_atom_decls.getOrPut(self.allocator, decl_index); + if (!gop.found_existing) { + gop.value_ptr.* = try self.createAtom(kind); + } + return gop.value_ptr.*; + }, + } +} + +fn getAtom(self: *const Dwarf, comptime kind: Kind, index: Atom.Index) Atom { + return switch (kind) { + .src_fn => self.src_fns.items[index], + .di_atom => self.di_atoms.items[index], + }; +} + +fn getAtomPtr(self: *Dwarf, comptime kind: Kind, index: Atom.Index) *Atom { + return switch (kind) { + .src_fn => &self.src_fns.items[index], + .di_atom => &self.di_atoms.items[index], }; } diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 01326fb82eddccbafafd65f481cf5ec27f7940b2..3e0c6d2b570334f4f4eca5671e7d30c82b0c8e51 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -344,9 +344,9 @@ pub fn deinit(self: *Elf) void { self.relocs.deinit(gpa); } - // if (self.dwarf) |*dw| { - // dw.deinit(); - // } + if (self.dwarf) |*dw| { + dw.deinit(); + } } pub fn getDeclVAddr(self: *Elf, decl_index: Module.Decl.Index, reloc_info: File.RelocInfo) !u64 { @@ -685,146 +685,146 @@ pub fn populateMissingMetadata(self: *Elf) !void { try self.writeSymbol(0); } - // if (self.dwarf) |*dw| { - // if (self.debug_str_section_index == null) { - // self.debug_str_section_index = @intCast(u16, self.sections.slice().len); - // assert(dw.strtab.buffer.items.len == 0); - // try dw.strtab.buffer.append(gpa, 0); - // try self.sections.append(gpa, .{ - // .shdr = .{ - // .sh_name = try self.shstrtab.insert(gpa, ".debug_str"), - // .sh_type = elf.SHT_PROGBITS, - // .sh_flags = elf.SHF_MERGE | elf.SHF_STRINGS, - // .sh_addr = 0, - // .sh_offset = 0, - // .sh_size = 0, - // .sh_link = 0, - // .sh_info = 0, - // .sh_addralign = 1, - // .sh_entsize = 1, - // }, - // .phdr_index = undefined, - // }); - // self.debug_strtab_dirty = true; - // self.shdr_table_dirty = true; - // } + if (self.dwarf) |*dw| { + if (self.debug_str_section_index == null) { + self.debug_str_section_index = @intCast(u16, self.sections.slice().len); + assert(dw.strtab.buffer.items.len == 0); + try dw.strtab.buffer.append(gpa, 0); + try self.sections.append(gpa, .{ + .shdr = .{ + .sh_name = try self.shstrtab.insert(gpa, ".debug_str"), + .sh_type = elf.SHT_PROGBITS, + .sh_flags = elf.SHF_MERGE | elf.SHF_STRINGS, + .sh_addr = 0, + .sh_offset = 0, + .sh_size = 0, + .sh_link = 0, + .sh_info = 0, + .sh_addralign = 1, + .sh_entsize = 1, + }, + .phdr_index = undefined, + }); + 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.slice().len); + if (self.debug_info_section_index == null) { + self.debug_info_section_index = @intCast(u16, self.sections.slice().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}", .{ - // off, - // off + file_size_hint, - // }); - // try self.sections.append(gpa, .{ - // .shdr = .{ - // .sh_name = try self.shstrtab.insert(gpa, ".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, - // }, - // .phdr_index = undefined, - // }); - // self.shdr_table_dirty = true; - // self.debug_info_header_dirty = true; - // } + 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}", .{ + off, + off + file_size_hint, + }); + try self.sections.append(gpa, .{ + .shdr = .{ + .sh_name = try self.shstrtab.insert(gpa, ".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, + }, + .phdr_index = undefined, + }); + 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.slice().len); + if (self.debug_abbrev_section_index == null) { + self.debug_abbrev_section_index = @intCast(u16, self.sections.slice().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}", .{ - // off, - // off + file_size_hint, - // }); - // try self.sections.append(gpa, .{ - // .shdr = .{ - // .sh_name = try self.shstrtab.insert(gpa, ".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, - // }, - // .phdr_index = undefined, - // }); - // self.shdr_table_dirty = true; - // self.debug_abbrev_section_dirty = true; - // } + 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}", .{ + off, + off + file_size_hint, + }); + try self.sections.append(gpa, .{ + .shdr = .{ + .sh_name = try self.shstrtab.insert(gpa, ".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, + }, + .phdr_index = undefined, + }); + 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.slice().len); + if (self.debug_aranges_section_index == null) { + self.debug_aranges_section_index = @intCast(u16, self.sections.slice().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}", .{ - // off, - // off + file_size_hint, - // }); - // try self.sections.append(gpa, .{ - // .shdr = .{ - // .sh_name = try self.shstrtab.insert(gpa, ".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, - // }, - // .phdr_index = undefined, - // }); - // self.shdr_table_dirty = true; - // self.debug_aranges_section_dirty = true; - // } + 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}", .{ + off, + off + file_size_hint, + }); + try self.sections.append(gpa, .{ + .shdr = .{ + .sh_name = try self.shstrtab.insert(gpa, ".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, + }, + .phdr_index = undefined, + }); + 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.slice().len); + if (self.debug_line_section_index == null) { + self.debug_line_section_index = @intCast(u16, self.sections.slice().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}", .{ - // off, - // off + file_size_hint, - // }); - // try self.sections.append(gpa, .{ - // .shdr = .{ - // .sh_name = try self.shstrtab.insert(gpa, ".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, - // }, - // .phdr_index = undefined, - // }); - // self.shdr_table_dirty = true; - // self.debug_line_header_dirty = true; - // } - // } + 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}", .{ + off, + off + file_size_hint, + }); + try self.sections.append(gpa, .{ + .shdr = .{ + .sh_name = try self.shstrtab.insert(gpa, ".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, + }, + .phdr_index = undefined, + }); + self.shdr_table_dirty = true; + self.debug_line_header_dirty = true; + } + } const shsize: u64 = switch (self.ptr_width) { .p32 => @sizeOf(elf.Elf32_Shdr), @@ -956,26 +956,25 @@ pub fn growNonAllocSection( } pub fn markDirty(self: *Elf, shdr_index: u16, phdr_index: ?u16) void { - _ = shdr_index; self.shdr_table_dirty = true; // TODO look into only writing one section if (phdr_index) |_| { self.phdr_table_dirty = true; // TODO look into making only the one program header dirty } - // if (self.dwarf) |_| { - // if (self.debug_info_section_index.? == shdr_index) { - // self.debug_info_header_dirty = true; - // } else if (self.debug_line_section_index.? == shdr_index) { - // self.debug_line_header_dirty = true; - // } else if (self.debug_abbrev_section_index.? == shdr_index) { - // self.debug_abbrev_section_dirty = true; - // } else if (self.debug_str_section_index.? == shdr_index) { - // self.debug_strtab_dirty = true; - // } else if (self.debug_aranges_section_index.? == shdr_index) { - // self.debug_aranges_section_dirty = true; - // } - // } + if (self.dwarf) |_| { + if (self.debug_info_section_index.? == shdr_index) { + self.debug_info_header_dirty = true; + } else if (self.debug_line_section_index.? == shdr_index) { + self.debug_line_header_dirty = true; + } else if (self.debug_abbrev_section_index.? == shdr_index) { + self.debug_abbrev_section_dirty = true; + } else if (self.debug_str_section_index.? == shdr_index) { + self.debug_strtab_dirty = true; + } else if (self.debug_aranges_section_index.? == shdr_index) { + self.debug_aranges_section_dirty = true; + } + } } pub fn flush(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void { @@ -1015,14 +1014,13 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node // TODO This linker code currently assumes there is only 1 compilation unit and it // corresponds to the Zig source code. const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented; - _ = module; const target_endian = self.base.options.target.cpu.arch.endian(); const foreign_endian = target_endian != builtin.cpu.arch.endian(); - // if (self.dwarf) |*dw| { - // try dw.flushModule(module); - // } + if (self.dwarf) |*dw| { + try dw.flushModule(module); + } { var it = self.relocs.iterator(); @@ -1068,43 +1066,43 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node self.logSymtab(); } - // if (self.dwarf) |*dw| { - // if (self.debug_abbrev_section_dirty) { - // try dw.writeDbgAbbrev(); - // 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.dwarf) |*dw| { + if (self.debug_abbrev_section_dirty) { + try dw.writeDbgAbbrev(); + 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) { - // // 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; - // try dw.writeDbgInfoHeader(module, low_pc, high_pc); - // self.debug_info_header_dirty = false; - // } + if (self.debug_info_header_dirty) { + // 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; + try dw.writeDbgInfoHeader(module, low_pc, high_pc); + self.debug_info_header_dirty = false; + } - // if (self.debug_aranges_section_dirty) { - // // 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.?]; - // try dw.writeDbgAranges(text_phdr.p_vaddr, text_phdr.p_memsz); - // 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_aranges_section_dirty) { + // 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.?]; + try dw.writeDbgAranges(text_phdr.p_vaddr, text_phdr.p_memsz); + 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) { - // try dw.writeDbgLineHeader(); - // self.debug_line_header_dirty = false; - // } - // } + if (self.debug_line_header_dirty) { + try dw.writeDbgLineHeader(); + self.debug_line_header_dirty = false; + } + } if (self.phdr_table_dirty) { const phsize: u64 = switch (self.ptr_width) { @@ -1162,15 +1160,15 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node } } - // if (self.dwarf) |dwarf| { - // const shdr_index = self.debug_str_section_index.?; - // if (self.debug_strtab_dirty or dwarf.strtab.buffer.items.len != self.sections.items(.shdr)[shdr_index].sh_size) { - // try self.growNonAllocSection(shdr_index, dwarf.strtab.buffer.items.len, 1, false); - // const debug_strtab_sect = self.sections.items(.shdr)[shdr_index]; - // try self.base.file.?.pwriteAll(dwarf.strtab.buffer.items, debug_strtab_sect.sh_offset); - // self.debug_strtab_dirty = false; - // } - // } + if (self.dwarf) |dwarf| { + const shdr_index = self.debug_str_section_index.?; + if (self.debug_strtab_dirty or dwarf.strtab.buffer.items.len != self.sections.items(.shdr)[shdr_index].sh_size) { + try self.growNonAllocSection(shdr_index, dwarf.strtab.buffer.items.len, 1, false); + const debug_strtab_sect = self.sections.items(.shdr)[shdr_index]; + try self.base.file.?.pwriteAll(dwarf.strtab.buffer.items, debug_strtab_sect.sh_offset); + self.debug_strtab_dirty = false; + } + } if (self.shdr_table_dirty) { const shsize: u64 = switch (self.ptr_width) { @@ -2100,10 +2098,6 @@ fn freeAtom(self: *Elf, atom_index: Atom.Index) void { self.getAtomPtr(atom_index).local_sym_index = 0; self.offset_table_free_list.append(self.base.allocator, atom.offset_table_index) catch {}; - - // if (self.dwarf) |*dw| { - // dw.freeAtom(&atom.dbg_info_atom); - // } } fn shrinkAtom(self: *Elf, atom_index: Atom.Index, new_block_size: u64) void { @@ -2133,7 +2127,6 @@ pub fn createAtom(self: *Elf) !Atom.Index { .offset_table_index = offset_table_index, .prev_index = null, .next_index = null, - .dbg_info_atom = undefined, }; log.debug("creating ATOM(%{d}) at index {d}", .{ local_sym_index, atom_index }); return atom_index; @@ -2219,16 +2212,16 @@ fn allocateAtom(self: *Elf, atom_index: Atom.Index, new_block_size: u64, alignme try self.growAllocSection(sym.st_shndx, needed_size); maybe_last_atom_index.* = atom_index; - // if (self.dwarf) |_| { - // // 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; - // } + if (self.dwarf) |_| { + // 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; + } } shdr.sh_addralign = math.max(shdr.sh_addralign, alignment); @@ -2333,9 +2326,9 @@ pub fn freeDecl(self: *Elf, decl_index: Module.Decl.Index) void { kv.value.exports.deinit(self.base.allocator); } - // if (self.dwarf) |*dw| { - // dw.freeDecl(decl); - // } + if (self.dwarf) |*dw| { + dw.freeDecl(decl_index); + } } pub fn getOrCreateAtomForDecl(self: *Elf, decl_index: Module.Decl.Index) !Atom.Index { @@ -2471,15 +2464,15 @@ pub fn updateFunc(self: *Elf, module: *Module, func: *Module.Fn, air: Air, liven var code_buffer = std.ArrayList(u8).init(self.base.allocator); defer code_buffer.deinit(); - // var decl_state: ?Dwarf.DeclState = if (self.dwarf) |*dw| try dw.initDeclState(module, decl_index) else null; - // defer if (decl_state) |*ds| ds.deinit(); + var decl_state: ?Dwarf.DeclState = if (self.dwarf) |*dw| try dw.initDeclState(module, decl_index) else null; + defer if (decl_state) |*ds| ds.deinit(); - // const res = if (decl_state) |*ds| - // try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .{ - // .dwarf = ds, - // }) - // else - const res = try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .none); + const res = if (decl_state) |*ds| + try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .{ + .dwarf = ds, + }) + else + try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .none); const code = switch (res) { .ok => code_buffer.items, @@ -2490,16 +2483,15 @@ pub fn updateFunc(self: *Elf, module: *Module, func: *Module.Fn, air: Air, liven }, }; const local_sym = try self.updateDeclCode(decl_index, code, elf.STT_FUNC); - _ = local_sym; - // if (decl_state) |*ds| { - // try self.dwarf.?.commitDeclState( - // module, - // decl_index, - // local_sym.st_value, - // local_sym.st_size, - // ds, - // ); - // } + if (decl_state) |*ds| { + try self.dwarf.?.commitDeclState( + module, + decl_index, + local_sym.st_value, + local_sym.st_size, + ds, + ); + } // Since we updated the vaddr and the size, each corresponding export // symbol also needs to be updated. @@ -2536,27 +2528,27 @@ pub fn updateDecl(self: *Elf, module: *Module, decl_index: Module.Decl.Index) !v var code_buffer = std.ArrayList(u8).init(self.base.allocator); defer code_buffer.deinit(); - // var decl_state: ?Dwarf.DeclState = if (self.dwarf) |*dw| try dw.initDeclState(module, decl_index) else null; - // defer if (decl_state) |*ds| ds.deinit(); + var decl_state: ?Dwarf.DeclState = if (self.dwarf) |*dw| try dw.initDeclState(module, decl_index) else null; + defer if (decl_state) |*ds| ds.deinit(); // TODO implement .debug_info for global variables const decl_val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val; - // const res = if (decl_state) |*ds| - // try codegen.generateSymbol(&self.base, decl.srcLoc(), .{ - // .ty = decl.ty, - // .val = decl_val, - // }, &code_buffer, .{ - // .dwarf = ds, - // }, .{ - // .parent_atom_index = atom.getSymbolIndex().?, - // }) - // else - const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), .{ - .ty = decl.ty, - .val = decl_val, - }, &code_buffer, .none, .{ - .parent_atom_index = atom.getSymbolIndex().?, - }); + const res = if (decl_state) |*ds| + try codegen.generateSymbol(&self.base, decl.srcLoc(), .{ + .ty = decl.ty, + .val = decl_val, + }, &code_buffer, .{ + .dwarf = ds, + }, .{ + .parent_atom_index = atom.getSymbolIndex().?, + }) + else + try codegen.generateSymbol(&self.base, decl.srcLoc(), .{ + .ty = decl.ty, + .val = decl_val, + }, &code_buffer, .none, .{ + .parent_atom_index = atom.getSymbolIndex().?, + }); const code = switch (res) { .ok => code_buffer.items, @@ -2568,16 +2560,15 @@ pub fn updateDecl(self: *Elf, module: *Module, decl_index: Module.Decl.Index) !v }; const local_sym = try self.updateDeclCode(decl_index, code, elf.STT_OBJECT); - _ = local_sym; - // if (decl_state) |*ds| { - // try self.dwarf.?.commitDeclState( - // module, - // decl_index, - // local_sym.st_value, - // local_sym.st_size, - // ds, - // ); - // } + if (decl_state) |*ds| { + try self.dwarf.?.commitDeclState( + module, + decl_index, + local_sym.st_value, + local_sym.st_size, + ds, + ); + } // Since we updated the vaddr and the size, each corresponding export // symbol also needs to be updated. @@ -2737,19 +2728,20 @@ pub fn updateDeclExports( } /// Must be called only after a successful call to `updateDecl`. -pub fn updateDeclLineNumber(self: *Elf, mod: *Module, decl: *const Module.Decl) !void { +pub fn updateDeclLineNumber(self: *Elf, mod: *Module, decl_index: Module.Decl.Index) !void { const tracy = trace(@src()); defer tracy.end(); + const decl = mod.declPtr(decl_index); const decl_name = try decl.getFullyQualifiedName(mod); defer self.base.allocator.free(decl_name); log.debug("updateDeclLineNumber {s}{*}", .{ decl_name, decl }); if (self.llvm_object) |_| return; - // if (self.dwarf) |*dw| { - // try dw.updateDeclLineNumber(decl); - // } + if (self.dwarf) |*dw| { + try dw.updateDeclLineNumber(mod, decl_index); + } } pub fn deleteDeclExport(self: *Elf, decl_index: Module.Decl.Index, name: []const u8) void { diff --git a/src/link/Elf/Atom.zig b/src/link/Elf/Atom.zig index 24cf19432ca40883da11a086e22209c1497bf3e3..4ab304ef714d38233fa96fd0bd035cebbef18096 100644 --- a/src/link/Elf/Atom.zig +++ b/src/link/Elf/Atom.zig @@ -4,7 +4,6 @@ const std = @import("std"); const assert = std.debug.assert; const elf = std.elf; -const Dwarf = @import("../Dwarf.zig"); const Elf = @import("../Elf.zig"); /// Each decl always gets a local symbol with the fully qualified name. @@ -23,8 +22,6 @@ offset_table_index: u32, prev_index: ?Index, next_index: ?Index, -dbg_info_atom: Dwarf.Atom, - pub const Index = u32; pub const Reloc = struct { diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 42aaa3a275810c02fdc1828ef726133679492099..22eb58775b9db861b0165c9377cabd8b8a628be5 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -472,9 +472,9 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented; - // if (self.d_sym) |*d_sym| { - // try d_sym.dwarf.flushModule(module); - // } + if (self.d_sym) |*d_sym| { + try d_sym.dwarf.flushModule(module); + } var libs = std.StringArrayHashMap(link.SystemLib).init(arena); try resolveLibSystem( @@ -664,10 +664,10 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No try self.writeCodeSignature(comp, csig); // code signing always comes last } - // if (self.d_sym) |*d_sym| { - // // Flush debug symbols bundle. - // try d_sym.flushModule(self); - // } + if (self.d_sym) |*d_sym| { + // Flush debug symbols bundle. + try d_sym.flushModule(self); + } // if (build_options.enable_link_snapshots) { // if (self.base.options.enable_link_snapshots) @@ -1089,7 +1089,6 @@ pub fn createAtom(self: *MachO) !Atom.Index { .alignment = 0, .prev_index = null, .next_index = null, - .dbg_info_atom = undefined, }; log.debug("creating ATOM(%{d}) at index {d}", .{ sym_index, atom_index }); return atom_index; @@ -1724,9 +1723,9 @@ pub fn deinit(self: *MachO) void { if (self.llvm_object) |llvm_object| llvm_object.destroy(gpa); } - // if (self.d_sym) |*d_sym| { - // d_sym.deinit(); - // } + if (self.d_sym) |*d_sym| { + d_sym.deinit(); + } self.got_entries.deinit(gpa); self.got_entries_free_list.deinit(gpa); @@ -1804,10 +1803,9 @@ pub fn deinit(self: *MachO) void { } fn freeAtom(self: *MachO, atom_index: Atom.Index) void { + const gpa = self.base.allocator; log.debug("freeAtom {d}", .{atom_index}); - const gpa = self.base.allocator; - // Remove any relocs and base relocs associated with this Atom Atom.freeRelocations(self, atom_index); @@ -1876,9 +1874,9 @@ fn freeAtom(self: *MachO, atom_index: Atom.Index) void { }; _ = self.got_entries_table.remove(got_target); - // if (self.d_sym) |*d_sym| { - // d_sym.swapRemoveRelocs(sym_index); - // } + if (self.d_sym) |*d_sym| { + d_sym.swapRemoveRelocs(sym_index); + } log.debug(" adding GOT index {d} to free list (target local@{d})", .{ got_index, sym_index }); } @@ -1887,10 +1885,6 @@ fn freeAtom(self: *MachO, atom_index: Atom.Index) void { _ = self.atom_by_index_table.remove(sym_index); log.debug(" adding local symbol index {d} to free list", .{sym_index}); self.getAtomPtr(atom_index).sym_index = 0; - - // if (self.d_sym) |*d_sym| { - // d_sym.dwarf.freeAtom(&atom.dbg_info_atom); - // } } fn shrinkAtom(self: *MachO, atom_index: Atom.Index, new_block_size: u64) void { @@ -2020,23 +2014,22 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv Atom.freeRelocations(self, atom_index); const atom = self.getAtom(atom_index); - _ = atom; var code_buffer = std.ArrayList(u8).init(self.base.allocator); defer code_buffer.deinit(); - // var decl_state = if (self.d_sym) |*d_sym| - // try d_sym.dwarf.initDeclState(module, decl_index) - // else - // null; - // defer if (decl_state) |*ds| ds.deinit(); + var decl_state = if (self.d_sym) |*d_sym| + try d_sym.dwarf.initDeclState(module, decl_index) + else + null; + defer if (decl_state) |*ds| ds.deinit(); - // const res = if (decl_state) |*ds| - // try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .{ - // .dwarf = ds, - // }) - // else - const res = try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .none); + const res = if (decl_state) |*ds| + try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .{ + .dwarf = ds, + }) + else + try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .none); const code = switch (res) { .ok => code_buffer.items, @@ -2048,11 +2041,10 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv }; const addr = try self.updateDeclCode(decl_index, code); - _ = addr; - // if (decl_state) |*ds| { - // try self.d_sym.?.dwarf.commitDeclState(module, decl_index, addr, atom.size, ds); - // } + if (decl_state) |*ds| { + try self.d_sym.?.dwarf.commitDeclState(module, decl_index, addr, atom.size, ds); + } // Since we updated the vaddr and the size, each corresponding export symbol also // needs to be updated. @@ -2154,29 +2146,29 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index) var code_buffer = std.ArrayList(u8).init(self.base.allocator); defer code_buffer.deinit(); - // var decl_state: ?Dwarf.DeclState = if (self.d_sym) |*d_sym| - // try d_sym.dwarf.initDeclState(module, decl_index) - // else - // null; - // defer if (decl_state) |*ds| ds.deinit(); + var decl_state: ?Dwarf.DeclState = if (self.d_sym) |*d_sym| + try d_sym.dwarf.initDeclState(module, decl_index) + else + null; + defer if (decl_state) |*ds| ds.deinit(); const decl_val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val; - // const res = if (decl_state) |*ds| - // try codegen.generateSymbol(&self.base, decl.srcLoc(), .{ - // .ty = decl.ty, - // .val = decl_val, - // }, &code_buffer, .{ - // .dwarf = ds, - // }, .{ - // .parent_atom_index = atom.getSymbolIndex().?, - // }) - // else - const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), .{ - .ty = decl.ty, - .val = decl_val, - }, &code_buffer, .none, .{ - .parent_atom_index = atom.getSymbolIndex().?, - }); + const res = if (decl_state) |*ds| + try codegen.generateSymbol(&self.base, decl.srcLoc(), .{ + .ty = decl.ty, + .val = decl_val, + }, &code_buffer, .{ + .dwarf = ds, + }, .{ + .parent_atom_index = atom.getSymbolIndex().?, + }) + else + try codegen.generateSymbol(&self.base, decl.srcLoc(), .{ + .ty = decl.ty, + .val = decl_val, + }, &code_buffer, .none, .{ + .parent_atom_index = atom.getSymbolIndex().?, + }); const code = switch (res) { .ok => code_buffer.items, @@ -2187,11 +2179,10 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index) }, }; const addr = try self.updateDeclCode(decl_index, code); - _ = addr; - // if (decl_state) |*ds| { - // try self.d_sym.?.dwarf.commitDeclState(module, decl_index, addr, atom.size, ds); - // } + if (decl_state) |*ds| { + try self.d_sym.?.dwarf.commitDeclState(module, decl_index, addr, atom.size, ds); + } // Since we updated the vaddr and the size, each corresponding export symbol also // needs to be updated. @@ -2432,13 +2423,10 @@ fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []const u8) return atom.getSymbol(self).n_value; } -pub fn updateDeclLineNumber(self: *MachO, module: *Module, decl: *const Module.Decl) !void { - _ = decl; - _ = self; - _ = module; - // if (self.d_sym) |*d_sym| { - // try d_sym.dwarf.updateDeclLineNumber(decl); - // } +pub fn updateDeclLineNumber(self: *MachO, module: *Module, decl_index: Module.Decl.Index) !void { + if (self.d_sym) |*d_sym| { + try d_sym.dwarf.updateDeclLineNumber(module, decl_index); + } } pub fn updateDeclExports( @@ -2611,9 +2599,9 @@ pub fn freeDecl(self: *MachO, decl_index: Module.Decl.Index) void { kv.value.exports.deinit(self.base.allocator); } - // if (self.d_sym) |*d_sym| { - // d_sym.dwarf.freeDecl(decl); - // } + if (self.d_sym) |*d_sym| { + d_sym.dwarf.freeDecl(decl_index); + } } pub fn getDeclVAddr(self: *MachO, decl_index: Module.Decl.Index, reloc_info: File.RelocInfo) !u64 { diff --git a/src/link/MachO/Atom.zig b/src/link/MachO/Atom.zig index 401d71813c7c853dab6ee2662c715d1a40b6c6d0..5fb94b7c1359c41cc7f1171f74e36c62263ebebd 100644 --- a/src/link/MachO/Atom.zig +++ b/src/link/MachO/Atom.zig @@ -13,7 +13,6 @@ const trace = @import("../../tracy.zig").trace; const Allocator = mem.Allocator; const Arch = std.Target.Cpu.Arch; -const Dwarf = @import("../Dwarf.zig"); const MachO = @import("../MachO.zig"); const Relocation = @import("Relocation.zig"); const SymbolWithLoc = MachO.SymbolWithLoc; @@ -43,8 +42,6 @@ alignment: u32, next_index: ?Index, prev_index: ?Index, -dbg_info_atom: Dwarf.Atom, - pub const Index = u32; pub const Binding = struct { diff --git a/src/link/Plan9.zig b/src/link/Plan9.zig index 20f540022a00d9a1f62c3370aae4d72d31ce78e7..87e3ca5c226aa1dd7a4f85eb97d53e5846ccc085 100644 --- a/src/link/Plan9.zig +++ b/src/link/Plan9.zig @@ -1018,10 +1018,10 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void { } /// Must be called only after a successful call to `updateDecl`. -pub fn updateDeclLineNumber(self: *Plan9, mod: *Module, decl: *const Module.Decl) !void { +pub fn updateDeclLineNumber(self: *Plan9, mod: *Module, decl_index: Module.Decl.Index) !void { _ = self; _ = mod; - _ = decl; + _ = decl_index; } pub fn getDeclVAddr( diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index 31dfb87659a113e2c202a42b32efc5ead1016652..ee4518796eb5776cf5b58cbb58b6c7eceb1e51ab 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -183,13 +183,9 @@ pub const Segment = struct { pub const FnData = struct { /// Reference to the wasm type that represents this function. type_index: u32, - /// Contains debug information related to this function. - /// For Wasm, the offset is relative to the code-section. - src_fn: Dwarf.SrcFn, pub const empty: FnData = .{ .type_index = undefined, - .src_fn = Dwarf.SrcFn.empty, }; }; @@ -1122,17 +1118,18 @@ pub fn updateDecl(wasm: *Wasm, mod: *Module, decl_index: Module.Decl.Index) !voi return wasm.finishUpdateDecl(decl, code); } -pub fn updateDeclLineNumber(wasm: *Wasm, mod: *Module, decl: *const Module.Decl) !void { +pub fn updateDeclLineNumber(wasm: *Wasm, mod: *Module, decl_index: Module.Decl.Index) !void { if (wasm.llvm_object) |_| return; if (wasm.dwarf) |*dw| { const tracy = trace(@src()); defer tracy.end(); + const decl = mod.declPtr(decl_index); const decl_name = try decl.getFullyQualifiedName(mod); defer wasm.base.allocator.free(decl_name); log.debug("updateDeclLineNumber {s}{*}", .{ decl_name, decl }); - try dw.updateDeclLineNumber(decl); + try dw.updateDeclLineNumber(mod, decl_index); } } @@ -1460,10 +1457,9 @@ pub fn freeDecl(wasm: *Wasm, decl_index: Module.Decl.Index) void { _ = wasm.resolved_symbols.swapRemove(atom.symbolLoc()); _ = wasm.symbol_atom.remove(atom.symbolLoc()); - if (wasm.dwarf) |*dwarf| { - dwarf.freeDecl(decl); - dwarf.freeAtom(&atom.dbg_info_atom); - } + // if (wasm.dwarf) |*dwarf| { + // dwarf.freeDecl(decl_index); + // } atom.deinit(wasm.base.allocator); } @@ -1882,7 +1878,6 @@ fn initializeCallCtorsFunction(wasm: *Wasm) !void { .next = null, .prev = null, .code = function_body.moveToUnmanaged(), - .dbg_info_atom = undefined, }; try wasm.managed_atoms.append(wasm.base.allocator, atom); try wasm.appendAtomAtIndex(wasm.code_section_index.?, atom); diff --git a/src/link/Wasm/Atom.zig b/src/link/Wasm/Atom.zig index 20f847e475359b3ac069664b4358e04080fca2f2..554f98b5ca9e1d8c68c158e63f5ef453c9033d62 100644 --- a/src/link/Wasm/Atom.zig +++ b/src/link/Wasm/Atom.zig @@ -4,7 +4,6 @@ const std = @import("std"); const types = @import("types.zig"); const Wasm = @import("../Wasm.zig"); const Symbol = @import("Symbol.zig"); -const Dwarf = @import("../Dwarf.zig"); const leb = std.leb; const log = std.log.scoped(.link); @@ -39,9 +38,6 @@ prev: ?*Atom, /// When the parent atom is being freed, it will also do so for all local atoms. locals: std.ArrayListUnmanaged(Atom) = .{}, -/// Represents the debug Atom that holds all debug information of this Atom. -dbg_info_atom: Dwarf.Atom, - /// Represents a default empty wasm `Atom` pub const empty: Atom = .{ .alignment = 0, @@ -51,7 +47,6 @@ pub const empty: Atom = .{ .prev = null, .size = 0, .sym_index = 0, - .dbg_info_atom = undefined, }; /// Frees all resources owned by this `Atom`. -- 2.54.0 From e0f3975fc8a7afd8a613802321fd46e64d8970d5 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Wed, 1 Feb 2023 16:01:43 +0100 Subject: [PATCH 65/84] link: make SpirV atoms fully owned by the linker --- src/Module.zig | 19 +++---------------- src/codegen/spirv.zig | 30 +++++++++++++++++++----------- src/link.zig | 2 +- src/link/SpirV.zig | 18 +++++++----------- 4 files changed, 30 insertions(+), 39 deletions(-) diff --git a/src/Module.zig b/src/Module.zig index eb947a697795e60107e87e89c2f8776f0c1726ce..bfeeea51e8b34e71a7bbe26af828c2fe2c8b1dd2 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -5183,20 +5183,7 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err decl.zir_decl_index = @intCast(u32, decl_sub_index); if (decl.getFunction()) |_| { switch (comp.bin_file.tag) { - .coff => { - // TODO Implement for COFF - }, - .elf => { - // TODO Look into detecting when this would be unnecessary by storing enough state - // in `Decl` to notice that the line number did not change. - comp.work_queue.writeItemAssumeCapacity(.{ .update_line_number = decl_index }); - }, - .macho => { - // TODO Look into detecting when this would be unnecessary by storing enough state - // in `Decl` to notice that the line number did not change. - comp.work_queue.writeItemAssumeCapacity(.{ .update_line_number = decl_index }); - }, - .plan9 => { + .coff, .elf, .macho, .plan9 => { // TODO Look into detecting when this would be unnecessary by storing enough state // in `Decl` to notice that the line number did not change. comp.work_queue.writeItemAssumeCapacity(.{ .update_line_number = decl_index }); @@ -5290,7 +5277,7 @@ pub fn clearDecl( .plan9 => .{ .plan9 = {} }, .c => .{ .c = {} }, .wasm => .{ .wasm = link.File.Wasm.FnData.empty }, - .spirv => .{ .spirv = .{} }, + .spirv => .{ .spirv = {} }, .nvptx => .{ .nvptx = {} }, }; } @@ -5710,7 +5697,7 @@ pub fn allocateNewDecl( .plan9 => .{ .plan9 = {} }, .c => .{ .c = {} }, .wasm => .{ .wasm = link.File.Wasm.FnData.empty }, - .spirv => .{ .spirv = .{} }, + .spirv => .{ .spirv = {} }, .nvptx => .{ .nvptx = {} }, }, .generation = 0, diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index e1af8c847f8a6c067643474d35e8b87dc21afcb9..c5a3d57d07343c6b6c1a4d2731123935f96c7e3d 100644 --- a/src/codegen/spirv.zig +++ b/src/codegen/spirv.zig @@ -49,7 +49,7 @@ pub const DeclGen = struct { spv: *SpvModule, /// The decl we are currently generating code for. - decl: *Decl, + decl_index: Decl.Index, /// The intermediate code of the declaration we are currently generating. Note: If /// the declaration is not a function, this value will be undefined! @@ -59,6 +59,8 @@ pub const DeclGen = struct { /// Note: If the declaration is not a function, this value will be undefined! liveness: Liveness, + ids: *const std.AutoHashMap(Decl.Index, IdResult), + /// An array of function argument result-ids. Each index corresponds with the /// function argument of the same index. args: std.ArrayListUnmanaged(IdRef) = .{}, @@ -133,14 +135,20 @@ pub const DeclGen = struct { /// Initialize the common resources of a DeclGen. Some fields are left uninitialized, /// only set when `gen` is called. - pub fn init(allocator: Allocator, module: *Module, spv: *SpvModule) DeclGen { + pub fn init( + allocator: Allocator, + module: *Module, + spv: *SpvModule, + ids: *const std.AutoHashMap(Decl.Index, IdResult), + ) DeclGen { return .{ .gpa = allocator, .module = module, .spv = spv, - .decl = undefined, + .decl_index = undefined, .air = undefined, .liveness = undefined, + .ids = ids, .next_arg_index = undefined, .current_block_label_id = undefined, .error_msg = undefined, @@ -150,9 +158,9 @@ pub const DeclGen = struct { /// Generate the code for `decl`. If a reportable error occurred during code generation, /// a message is returned by this function. Callee owns the memory. If this function /// returns such a reportable error, it is valid to be called again for a different decl. - pub fn gen(self: *DeclGen, decl: *Decl, air: Air, liveness: Liveness) !?*Module.ErrorMsg { + pub fn gen(self: *DeclGen, decl_index: Decl.Index, air: Air, liveness: Liveness) !?*Module.ErrorMsg { // Reset internal resources, we don't want to re-allocate these. - self.decl = decl; + self.decl_index = decl_index; self.air = air; self.liveness = liveness; self.args.items.len = 0; @@ -194,7 +202,7 @@ pub const DeclGen = struct { pub fn fail(self: *DeclGen, comptime format: []const u8, args: anytype) Error { @setCold(true); const src = LazySrcLoc.nodeOffset(0); - const src_loc = src.toSrcLoc(self.decl); + const src_loc = src.toSrcLoc(self.module.declPtr(self.decl_index)); assert(self.error_msg == null); self.error_msg = try Module.ErrorMsg.create(self.module.gpa, src_loc, format, args); return error.CodegenFail; @@ -332,7 +340,7 @@ pub const DeclGen = struct { }; const decl = self.module.declPtr(fn_decl_index); self.module.markDeclAlive(decl); - return decl.fn_link.spirv.id.toRef(); + return self.ids.get(fn_decl_index).?.toRef(); } const target = self.getTarget(); @@ -553,8 +561,8 @@ pub const DeclGen = struct { } fn genDecl(self: *DeclGen) !void { - const decl = self.decl; - const result_id = decl.fn_link.spirv.id; + const result_id = self.ids.get(self.decl_index).?; + const decl = self.module.declPtr(self.decl_index); if (decl.val.castTag(.function)) |_| { assert(decl.ty.zigTypeTag() == .Fn); @@ -945,7 +953,7 @@ pub const DeclGen = struct { fn airDbgStmt(self: *DeclGen, inst: Air.Inst.Index) !void { const dbg_stmt = self.air.instructions.items(.data)[inst].dbg_stmt; - const src_fname_id = try self.spv.resolveSourceFileName(self.decl); + const src_fname_id = try self.spv.resolveSourceFileName(self.module.declPtr(self.decl_index)); try self.func.body.emit(self.spv.gpa, .OpLine, .{ .file = src_fname_id, .line = dbg_stmt.line, @@ -1106,7 +1114,7 @@ pub const DeclGen = struct { assert(as.errors.items.len != 0); assert(self.error_msg == null); const loc = LazySrcLoc.nodeOffset(0); - const src_loc = loc.toSrcLoc(self.decl); + const src_loc = loc.toSrcLoc(self.module.declPtr(self.decl_index)); self.error_msg = try Module.ErrorMsg.create(self.module.gpa, src_loc, "failed to assemble SPIR-V inline assembly", .{}); const notes = try self.module.gpa.alloc(Module.ErrorMsg, as.errors.items.len); diff --git a/src/link.zig b/src/link.zig index 3dd182b586ae6f9d7ea73de7aff2d76a291d620d..450a008ceacd46e6d713710f09e4b8c8e2ab4fee 100644 --- a/src/link.zig +++ b/src/link.zig @@ -279,7 +279,7 @@ pub const File = struct { plan9: void, c: void, wasm: Wasm.FnData, - spirv: SpirV.FnData, + spirv: void, nvptx: void, }; diff --git a/src/link/SpirV.zig b/src/link/SpirV.zig index 7dbd3a42ce836fb515af2cb3f5b2ada905e2931f..14a29e4498673fb09df66cc35d01c9eb4cdf59c8 100644 --- a/src/link/SpirV.zig +++ b/src/link/SpirV.zig @@ -42,13 +42,6 @@ const SpvModule = @import("../codegen/spirv/Module.zig"); const spec = @import("../codegen/spirv/spec.zig"); const IdResult = spec.IdResult; -// TODO: Should this struct be used at all rather than just a hashmap of aux data for every decl? -pub const FnData = struct { - // We're going to fill these in flushModule, and we're going to fill them unconditionally, - // so just set it to undefined. - id: IdResult = undefined, -}; - base: link.File, /// This linker backend does not try to incrementally link output SPIR-V code. @@ -209,16 +202,19 @@ pub fn flushModule(self: *SpirV, comp: *Compilation, prog_node: *std.Progress.No // so that we can access them before processing them. // TODO: We're allocating an ID unconditionally now, are there // declarations which don't generate a result? - // TODO: fn_link is used here, but thats probably not the right field. It will work anyway though. + var ids = std.AutoHashMap(Module.Decl.Index, IdResult).init(self.base.allocator); + defer ids.deinit(); + try ids.ensureTotalCapacity(@intCast(u32, self.decl_table.count())); + for (self.decl_table.keys()) |decl_index| { const decl = module.declPtr(decl_index); if (decl.has_tv) { - decl.fn_link.spirv.id = spv.allocId(); + ids.putAssumeCapacityNoClobber(decl_index, spv.allocId()); } } // Now, actually generate the code for all declarations. - var decl_gen = codegen.DeclGen.init(self.base.allocator, module, &spv); + var decl_gen = codegen.DeclGen.init(self.base.allocator, module, &spv, &ids); defer decl_gen.deinit(); var it = self.decl_table.iterator(); @@ -231,7 +227,7 @@ pub fn flushModule(self: *SpirV, comp: *Compilation, prog_node: *std.Progress.No const liveness = entry.value_ptr.liveness; // Note, if `decl` is not a function, air/liveness may be undefined. - if (try decl_gen.gen(decl, air, liveness)) |msg| { + if (try decl_gen.gen(decl_index, air, liveness)) |msg| { try module.failed_decls.put(module.gpa, decl_index, msg); return; // TODO: Attempt to generate more decls? } -- 2.54.0 From 1aa0f8aa2f382fb56639ea6833a62c4b8b031247 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Wed, 1 Feb 2023 17:39:07 +0100 Subject: [PATCH 66/84] link: fix pointer invalidation issues in Elf, MachO and Coff --- src/link/Coff.zig | 12 ++++++++---- src/link/Elf.zig | 9 ++++----- src/link/MachO.zig | 4 ++-- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/link/Coff.zig b/src/link/Coff.zig index f563a617c78d07d493729c4f2c123bb442feb106..2922e783e1e3d690eb7516043522c5f20b806910 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -1035,7 +1035,6 @@ pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.In const unnamed_consts = gop.value_ptr; const atom_index = try self.createAtom(); - const atom = self.getAtomPtr(atom_index); const sym_name = blk: { const decl_name = try decl.getFullyQualifiedName(mod); @@ -1045,11 +1044,15 @@ pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.In break :blk try std.fmt.allocPrint(gpa, "__unnamed_{s}_{d}", .{ decl_name, index }); }; defer gpa.free(sym_name); - try self.setSymbolName(atom.getSymbolPtr(self), sym_name); - atom.getSymbolPtr(self).section_number = @intToEnum(coff.SectionNumber, self.rdata_section_index.? + 1); + { + const atom = self.getAtom(atom_index); + const sym = atom.getSymbolPtr(self); + try self.setSymbolName(sym, sym_name); + sym.section_number = @intToEnum(coff.SectionNumber, self.rdata_section_index.? + 1); + } const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), tv, &code_buffer, .none, .{ - .parent_atom_index = atom.getSymbolIndex().?, + .parent_atom_index = self.getAtom(atom_index).getSymbolIndex().?, }); const code = switch (res) { .ok => code_buffer.items, @@ -1062,6 +1065,7 @@ pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.In }; const required_alignment = tv.ty.abiAlignment(self.base.options.target); + const atom = self.getAtomPtr(atom_index); atom.alignment = required_alignment; atom.size = @intCast(u32, code.len); atom.getSymbolPtr(self).value = try self.allocateAtom(atom_index, atom.size, atom.alignment); diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 3e0c6d2b570334f4f4eca5671e7d30c82b0c8e51..45952da6c0f638e3a756438fd2f6727f57561211 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -2600,12 +2600,11 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module const name = self.shstrtab.get(name_str_index).?; const atom_index = try self.createAtom(); - const atom = self.getAtomPtr(atom_index); const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), typed_value, &code_buffer, .{ .none = {}, }, .{ - .parent_atom_index = atom.getSymbolIndex().?, + .parent_atom_index = self.getAtom(atom_index).getSymbolIndex().?, }); const code = switch (res) { .ok => code_buffer.items, @@ -2620,7 +2619,7 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module const required_alignment = typed_value.ty.abiAlignment(self.base.options.target); const shdr_index = self.rodata_section_index.?; const phdr_index = self.sections.items(.phdr_index)[shdr_index]; - const local_sym = atom.getSymbolPtr(self); + const local_sym = self.getAtom(atom_index).getSymbolPtr(self); local_sym.st_name = name_str_index; local_sym.st_info = (elf.STB_LOCAL << 4) | elf.STT_OBJECT; local_sym.st_other = 0; @@ -2631,14 +2630,14 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module log.debug("allocated text block for {s} at 0x{x}", .{ name, local_sym.st_value }); - try self.writeSymbol(atom.getSymbolIndex().?); + try self.writeSymbol(self.getAtom(atom_index).getSymbolIndex().?); try unnamed_consts.append(gpa, atom_index); const section_offset = local_sym.st_value - self.program_headers.items[phdr_index].p_vaddr; const file_offset = self.sections.items(.shdr)[shdr_index].sh_offset + section_offset; try self.base.file.?.pwriteAll(code, file_offset); - return atom.getSymbolIndex().?; + return self.getAtom(atom_index).getSymbolIndex().?; } pub fn updateDeclExports( diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 22eb58775b9db861b0165c9377cabd8b8a628be5..24ef275c5b0d5c9b7575d4d32721054261c71709 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -2079,10 +2079,9 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Modu log.debug("allocating symbol indexes for {?s}", .{name}); const atom_index = try self.createAtom(); - const atom = self.getAtomPtr(atom_index); const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), typed_value, &code_buffer, .none, .{ - .parent_atom_index = atom.getSymbolIndex().?, + .parent_atom_index = self.getAtom(atom_index).getSymbolIndex().?, }); const code = switch (res) { .ok => code_buffer.items, @@ -2095,6 +2094,7 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Modu }; const required_alignment = typed_value.ty.abiAlignment(self.base.options.target); + const atom = self.getAtomPtr(atom_index); atom.size = code.len; atom.alignment = required_alignment; // TODO: work out logic for disambiguating functions from function pointers -- 2.54.0 From 46f54b23ae604c3f99f51ca719d9085530f6b59c Mon Sep 17 00:00:00 2001 From: Luuk de Gram Date: Wed, 1 Feb 2023 18:55:35 +0100 Subject: [PATCH 67/84] link: make Wasm atoms fully owned by the linker --- src/Module.zig | 6 +- src/Sema.zig | 2 +- src/arch/wasm/CodeGen.zig | 30 +- src/arch/wasm/Emit.zig | 29 +- src/link.zig | 4 +- src/link/Dwarf.zig | 25 +- src/link/Wasm.zig | 520 ++++++++++++++------------- src/link/Wasm/Atom.zig | 44 ++- src/link/Wasm/Object.zig | 15 +- test/link/wasm/export-data/build.zig | 4 +- 10 files changed, 353 insertions(+), 326 deletions(-) diff --git a/src/Module.zig b/src/Module.zig index bfeeea51e8b34e71a7bbe26af828c2fe2c8b1dd2..f84d720d1f78c97f035a571434db6b598c4121be 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -5266,7 +5266,7 @@ pub fn clearDecl( .macho => .{ .macho = {} }, .plan9 => .{ .plan9 = {} }, .c => .{ .c = {} }, - .wasm => .{ .wasm = link.File.Wasm.DeclBlock.empty }, + .wasm => .{ .wasm = {} }, .spirv => .{ .spirv = {} }, .nvptx => .{ .nvptx = {} }, }; @@ -5374,7 +5374,7 @@ fn deleteDeclExports(mod: *Module, decl_index: Decl.Index) Allocator.Error!void try macho.deleteDeclExport(decl_index, exp.options.name); } if (mod.comp.bin_file.cast(link.File.Wasm)) |wasm| { - wasm.deleteExport(exp.link.wasm); + wasm.deleteDeclExport(decl_index); } if (mod.comp.bin_file.cast(link.File.Coff)) |coff| { coff.deleteDeclExport(decl_index, exp.options.name); @@ -5686,7 +5686,7 @@ pub fn allocateNewDecl( .macho => .{ .macho = {} }, .plan9 => .{ .plan9 = {} }, .c => .{ .c = {} }, - .wasm => .{ .wasm = link.File.Wasm.DeclBlock.empty }, + .wasm => .{ .wasm = {} }, .spirv => .{ .spirv = {} }, .nvptx => .{ .nvptx = {} }, }, diff --git a/src/Sema.zig b/src/Sema.zig index e54bfc7bd9f67fc3c0b4dc93284735eac5dc6594..4871961753453d34b8c0a681df0e07d2d8e756b0 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -5570,7 +5570,7 @@ pub fn analyzeExport( .macho => .{ .macho = {} }, .plan9 => .{ .plan9 = {} }, .c => .{ .c = {} }, - .wasm => .{ .wasm = .{} }, + .wasm => .{ .wasm = {} }, .spirv => .{ .spirv = {} }, .nvptx => .{ .nvptx = {} }, }, diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index 8212d281e57284fa1718e594784615af66dd38b6..8559a728e51894dcf9355848d534647faf53029e 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -1269,10 +1269,10 @@ fn genFunc(func: *CodeGen) InnerError!void { var emit: Emit = .{ .mir = mir, - .bin_file = &func.bin_file.base, + .bin_file = func.bin_file, .code = func.code, .locals = func.locals.items, - .decl = func.decl, + .decl_index = func.decl_index, .dbg_output = func.debug_output, .prev_di_line = 0, .prev_di_column = 0, @@ -2115,21 +2115,20 @@ fn airCall(func: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModif const fn_info = fn_ty.fnInfo(); const first_param_sret = firstParamSRet(fn_info.cc, fn_info.return_type, func.target); - const callee: ?*Decl = blk: { + const callee: ?Decl.Index = blk: { const func_val = func.air.value(pl_op.operand) orelse break :blk null; const module = func.bin_file.base.options.module.?; if (func_val.castTag(.function)) |function| { - const decl = module.declPtr(function.data.owner_decl); - try decl.link.wasm.ensureInitialized(func.bin_file); - break :blk decl; + _ = try func.bin_file.getOrCreateAtomForDecl(function.data.owner_decl); + break :blk function.data.owner_decl; } else if (func_val.castTag(.extern_fn)) |extern_fn| { const ext_decl = module.declPtr(extern_fn.data.owner_decl); const ext_info = ext_decl.ty.fnInfo(); var func_type = try genFunctype(func.gpa, ext_info.cc, ext_info.param_types, ext_info.return_type, func.target); defer func_type.deinit(func.gpa); - const atom = &ext_decl.link.wasm; - try atom.ensureInitialized(func.bin_file); + const atom_index = try func.bin_file.getOrCreateAtomForDecl(extern_fn.data.owner_decl); + const atom = func.bin_file.getAtomPtr(atom_index); ext_decl.fn_link.wasm.type_index = try func.bin_file.putOrGetFuncType(func_type); try func.bin_file.addOrUpdateImport( mem.sliceTo(ext_decl.name, 0), @@ -2137,11 +2136,10 @@ fn airCall(func: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModif ext_decl.getExternFn().?.lib_name, ext_decl.fn_link.wasm.type_index, ); - break :blk ext_decl; + break :blk extern_fn.data.owner_decl; } else if (func_val.castTag(.decl_ref)) |decl_ref| { - const decl = module.declPtr(decl_ref.data); - try decl.link.wasm.ensureInitialized(func.bin_file); - break :blk decl; + _ = try func.bin_file.getOrCreateAtomForDecl(decl_ref.data); + break :blk decl_ref.data; } return func.fail("Expected a function, but instead found type '{}'", .{func_val.tag()}); }; @@ -2162,7 +2160,8 @@ fn airCall(func: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModif } if (callee) |direct| { - try func.addLabel(.call, direct.link.wasm.sym_index); + const atom_index = func.bin_file.decls.get(direct).?; + try func.addLabel(.call, func.bin_file.getAtom(atom_index).sym_index); } else { // in this case we call a function pointer // so load its value onto the stack @@ -2758,9 +2757,10 @@ fn lowerDeclRefValue(func: *CodeGen, tv: TypedValue, decl_index: Module.Decl.Ind } module.markDeclAlive(decl); - try decl.link.wasm.ensureInitialized(func.bin_file); + const atom_index = try func.bin_file.getOrCreateAtomForDecl(decl_index); + const atom = func.bin_file.getAtom(atom_index); - const target_sym_index = decl.link.wasm.sym_index; + const target_sym_index = atom.sym_index; if (decl.ty.zigTypeTag() == .Fn) { try func.bin_file.addTableFunction(target_sym_index); return WValue{ .function_index = target_sym_index }; diff --git a/src/arch/wasm/Emit.zig b/src/arch/wasm/Emit.zig index 71d21d2797e7341c0d2cfe98f8d0513c717dc7c9..a340ac5da8b5837bb76850dea7b37aef32a84374 100644 --- a/src/arch/wasm/Emit.zig +++ b/src/arch/wasm/Emit.zig @@ -11,8 +11,8 @@ const leb128 = std.leb; /// Contains our list of instructions mir: Mir, -/// Reference to the file handler -bin_file: *link.File, +/// Reference to the Wasm module linker +bin_file: *link.File.Wasm, /// Possible error message. When set, the value is allocated and /// must be freed manually. error_msg: ?*Module.ErrorMsg = null, @@ -21,7 +21,7 @@ code: *std.ArrayList(u8), /// List of allocated locals. locals: []const u8, /// The declaration that code is being generated for. -decl: *Module.Decl, +decl_index: Module.Decl.Index, // Debug information /// Holds the debug information for this emission @@ -252,8 +252,8 @@ fn offset(self: Emit) u32 { fn fail(emit: *Emit, comptime format: []const u8, args: anytype) InnerError { @setCold(true); std.debug.assert(emit.error_msg == null); - // TODO: Determine the source location. - emit.error_msg = try Module.ErrorMsg.create(emit.bin_file.allocator, emit.decl.srcLoc(), format, args); + const mod = emit.bin_file.base.options.module.?; + emit.error_msg = try Module.ErrorMsg.create(emit.bin_file.base.allocator, mod.declPtr(emit.decl_index).srcLoc(), format, args); return error.EmitFail; } @@ -304,8 +304,9 @@ fn emitGlobal(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) !void { const global_offset = emit.offset(); try emit.code.appendSlice(&buf); - // globals can have index 0 as it represents the stack pointer - try emit.decl.link.wasm.relocs.append(emit.bin_file.allocator, .{ + const atom_index = emit.bin_file.decls.get(emit.decl_index).?; + const atom = emit.bin_file.getAtomPtr(atom_index); + try atom.relocs.append(emit.bin_file.base.allocator, .{ .index = label, .offset = global_offset, .relocation_type = .R_WASM_GLOBAL_INDEX_LEB, @@ -361,7 +362,9 @@ fn emitCall(emit: *Emit, inst: Mir.Inst.Index) !void { try emit.code.appendSlice(&buf); if (label != 0) { - try emit.decl.link.wasm.relocs.append(emit.bin_file.allocator, .{ + const atom_index = emit.bin_file.decls.get(emit.decl_index).?; + const atom = emit.bin_file.getAtomPtr(atom_index); + try atom.relocs.append(emit.bin_file.base.allocator, .{ .offset = call_offset, .index = label, .relocation_type = .R_WASM_FUNCTION_INDEX_LEB, @@ -387,7 +390,9 @@ fn emitFunctionIndex(emit: *Emit, inst: Mir.Inst.Index) !void { try emit.code.appendSlice(&buf); if (symbol_index != 0) { - try emit.decl.link.wasm.relocs.append(emit.bin_file.allocator, .{ + const atom_index = emit.bin_file.decls.get(emit.decl_index).?; + const atom = emit.bin_file.getAtomPtr(atom_index); + try atom.relocs.append(emit.bin_file.base.allocator, .{ .offset = index_offset, .index = symbol_index, .relocation_type = .R_WASM_TABLE_INDEX_SLEB, @@ -399,7 +404,7 @@ fn emitMemAddress(emit: *Emit, inst: Mir.Inst.Index) !void { const extra_index = emit.mir.instructions.items(.data)[inst].payload; const mem = emit.mir.extraData(Mir.Memory, extra_index).data; const mem_offset = emit.offset() + 1; - const is_wasm32 = emit.bin_file.options.target.cpu.arch == .wasm32; + const is_wasm32 = emit.bin_file.base.options.target.cpu.arch == .wasm32; if (is_wasm32) { try emit.code.append(std.wasm.opcode(.i32_const)); var buf: [5]u8 = undefined; @@ -413,7 +418,9 @@ fn emitMemAddress(emit: *Emit, inst: Mir.Inst.Index) !void { } if (mem.pointer != 0) { - try emit.decl.link.wasm.relocs.append(emit.bin_file.allocator, .{ + const atom_index = emit.bin_file.decls.get(emit.decl_index).?; + const atom = emit.bin_file.getAtomPtr(atom_index); + try atom.relocs.append(emit.bin_file.base.allocator, .{ .offset = mem_offset, .index = mem.pointer, .relocation_type = if (is_wasm32) .R_WASM_MEMORY_ADDR_LEB else .R_WASM_MEMORY_ADDR_LEB64, diff --git a/src/link.zig b/src/link.zig index 450a008ceacd46e6d713710f09e4b8c8e2ab4fee..0a3226f004a6d034f3f7befeba2cc1d9fccb9135 100644 --- a/src/link.zig +++ b/src/link.zig @@ -267,7 +267,7 @@ pub const File = struct { macho: void, plan9: void, c: void, - wasm: Wasm.DeclBlock, + wasm: void, spirv: void, nvptx: void, }; @@ -289,7 +289,7 @@ pub const File = struct { macho: void, plan9: void, c: void, - wasm: Wasm.Export, + wasm: void, spirv: void, nvptx: void, }; diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig index e90db2d0df74e4b01481a21e85ce563820238e42..a3d0aa8a5337e7a8a12536b211430ffeb5fd9ed5 100644 --- a/src/link/Dwarf.zig +++ b/src/link/Dwarf.zig @@ -1099,7 +1099,7 @@ pub fn commitDeclState( }, .wasm => { const wasm_file = self.bin_file.cast(File.Wasm).?; - const debug_line = wasm_file.debug_line_atom.?.code; + const debug_line = wasm_file.getAtomPtr(wasm_file.debug_line_atom.?).code; writeDbgLineNopsBuffered(debug_line.items, src_fn.off, 0, &.{}, src_fn.len); }, else => unreachable, @@ -1177,7 +1177,7 @@ pub fn commitDeclState( .wasm => { const wasm_file = self.bin_file.cast(File.Wasm).?; - const atom = wasm_file.debug_line_atom.?; + const atom = wasm_file.getAtomPtr(wasm_file.debug_line_atom.?); const debug_line = &atom.code; const segment_size = debug_line.items.len; if (needed_size != segment_size) { @@ -1345,7 +1345,8 @@ fn updateDeclDebugInfoAllocation(self: *Dwarf, atom_index: Atom.Index, len: u32) }, .wasm => { const wasm_file = self.bin_file.cast(File.Wasm).?; - const debug_info = &wasm_file.debug_info_atom.?.code; + const debug_info_index = wasm_file.debug_info_atom.?; + const debug_info = &wasm_file.getAtomPtr(debug_info_index).code; try writeDbgInfoNopsToArrayList(gpa, debug_info, atom.off, 0, &.{0}, atom.len, false); }, else => unreachable, @@ -1441,7 +1442,7 @@ fn writeDeclDebugInfo(self: *Dwarf, atom_index: Atom.Index, dbg_info_buf: []cons .wasm => { const wasm_file = self.bin_file.cast(File.Wasm).?; const info_atom = wasm_file.debug_info_atom.?; - const debug_info = &info_atom.code; + const debug_info = &wasm_file.getAtomPtr(info_atom).code; const segment_size = debug_info.items.len; if (needed_size != segment_size) { log.debug(" needed size does not equal allocated size: {d}", .{needed_size}); @@ -1504,8 +1505,8 @@ pub fn updateDeclLineNumber(self: *Dwarf, module: *Module, decl_index: Module.De .wasm => { const wasm_file = self.bin_file.cast(File.Wasm).?; const offset = atom.off + self.getRelocDbgLineOff(); - const atom_ = wasm_file.debug_line_atom.?; - mem.copy(u8, atom_.code.items[offset..], &data); + const line_atom_index = wasm_file.debug_line_atom.?; + mem.copy(u8, wasm_file.getAtomPtr(line_atom_index).code.items[offset..], &data); }, else => unreachable, } @@ -1722,7 +1723,7 @@ pub fn writeDbgAbbrev(self: *Dwarf) !void { }, .wasm => { const wasm_file = self.bin_file.cast(File.Wasm).?; - const debug_abbrev = &wasm_file.debug_abbrev_atom.?.code; + const debug_abbrev = &wasm_file.getAtomPtr(wasm_file.debug_abbrev_atom.?).code; try debug_abbrev.resize(wasm_file.base.allocator, needed_size); mem.copy(u8, debug_abbrev.items, &abbrev_buf); }, @@ -1835,7 +1836,7 @@ pub fn writeDbgInfoHeader(self: *Dwarf, module: *Module, low_pc: u64, high_pc: u }, .wasm => { const wasm_file = self.bin_file.cast(File.Wasm).?; - const debug_info = &wasm_file.debug_info_atom.?.code; + const debug_info = &wasm_file.getAtomPtr(wasm_file.debug_info_atom.?).code; try writeDbgInfoNopsToArrayList(self.allocator, debug_info, 0, 0, di_buf.items, jmp_amt, false); }, else => unreachable, @@ -2156,7 +2157,7 @@ pub fn writeDbgAranges(self: *Dwarf, addr: u64, size: u64) !void { }, .wasm => { const wasm_file = self.bin_file.cast(File.Wasm).?; - const debug_ranges = &wasm_file.debug_ranges_atom.?.code; + const debug_ranges = &wasm_file.getAtomPtr(wasm_file.debug_ranges_atom.?).code; try debug_ranges.resize(wasm_file.base.allocator, needed_size); mem.copy(u8, debug_ranges.items, di_buf.items); }, @@ -2330,7 +2331,7 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void { }, .wasm => { const wasm_file = self.bin_file.cast(File.Wasm).?; - const debug_line = &wasm_file.debug_line_atom.?.code; + const debug_line = &wasm_file.getAtomPtr(wasm_file.debug_line_atom.?).code; mem.copy(u8, buffer, debug_line.items[first_fn.off..]); try debug_line.resize(self.allocator, debug_line.items.len + delta); mem.copy(u8, debug_line.items[first_fn.off + delta ..], buffer); @@ -2381,7 +2382,7 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void { }, .wasm => { const wasm_file = self.bin_file.cast(File.Wasm).?; - const debug_line = wasm_file.debug_line_atom.?.code; + const debug_line = &wasm_file.getAtomPtr(wasm_file.debug_line_atom.?).code; writeDbgLineNopsBuffered(debug_line.items, 0, 0, di_buf.items, jmp_amt); }, else => unreachable, @@ -2526,7 +2527,7 @@ pub fn flushModule(self: *Dwarf, module: *Module) !void { }, .wasm => { const wasm_file = self.bin_file.cast(File.Wasm).?; - const debug_info = wasm_file.debug_info_atom.?.code; + const debug_info = wasm_file.getAtomPtr(wasm_file.debug_info_atom.?).code; mem.copy(u8, debug_info.items[atom.off + reloc.offset ..], &buf); }, else => unreachable, diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index ee4518796eb5776cf5b58cbb58b6c7eceb1e51ab..b06703ed6112e0150c51702928069b918d9d5132 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -9,7 +9,7 @@ const fs = std.fs; const leb = std.leb; const log = std.log.scoped(.link); -const Atom = @import("Wasm/Atom.zig"); +pub const Atom = @import("Wasm/Atom.zig"); const Dwarf = @import("Dwarf.zig"); const Module = @import("../Module.zig"); const Compilation = @import("../Compilation.zig"); @@ -31,10 +31,7 @@ const Object = @import("Wasm/Object.zig"); const Archive = @import("Wasm/Archive.zig"); const types = @import("Wasm/types.zig"); -pub const base_tag = link.File.Tag.wasm; - -/// deprecated: Use `@import("Wasm/Atom.zig");` -pub const DeclBlock = Atom; +pub const base_tag: link.File.Tag = .wasm; base: link.File, /// Output name of the file @@ -47,18 +44,16 @@ llvm_object: ?*LlvmObject = null, /// TODO: Allow setting this through a flag? host_name: []const u8 = "env", /// List of all `Decl` that are currently alive. -/// This is ment for bookkeeping so we can safely cleanup all codegen memory -/// when calling `deinit` -decls: std.AutoHashMapUnmanaged(Module.Decl.Index, void) = .{}, +/// Each index maps to the corresponding `Atom.Index`. +decls: std.AutoHashMapUnmanaged(Module.Decl.Index, Atom.Index) = .{}, /// List of all symbols generated by Zig code. symbols: std.ArrayListUnmanaged(Symbol) = .{}, /// List of symbol indexes which are free to be used. symbols_free_list: std.ArrayListUnmanaged(u32) = .{}, /// Maps atoms to their segment index -atoms: std.AutoHashMapUnmanaged(u32, *Atom) = .{}, -/// Atoms managed and created by the linker. This contains atoms -/// from object files, and not Atoms generated by a Decl. -managed_atoms: std.ArrayListUnmanaged(*Atom) = .{}, +atoms: std.AutoHashMapUnmanaged(u32, Atom.Index) = .{}, +/// List of all atoms. +managed_atoms: std.ArrayListUnmanaged(Atom) = .{}, /// Represents the index into `segments` where the 'code' section /// lives. code_section_index: ?u32 = null, @@ -148,7 +143,7 @@ undefs: std.StringArrayHashMapUnmanaged(SymbolLoc) = .{}, /// Maps a symbol's location to an atom. This can be used to find meta /// data of a symbol, such as its size, or its offset to perform a relocation. /// Undefined (and synthetic) symbols do not have an Atom and therefore cannot be mapped. -symbol_atom: std.AutoHashMapUnmanaged(SymbolLoc, *Atom) = .{}, +symbol_atom: std.AutoHashMapUnmanaged(SymbolLoc, Atom.Index) = .{}, /// Maps a symbol's location to its export name, which may differ from the decl's name /// which does the exporting. /// Note: The value represents the offset into the string table, rather than the actual string. @@ -165,14 +160,14 @@ error_table_symbol: ?u32 = null, // unit contains Zig code. The lifetime of these atoms are extended // until the end of the compiler's lifetime. Meaning they're not freed // during `flush()` in incremental-mode. -debug_info_atom: ?*Atom = null, -debug_line_atom: ?*Atom = null, -debug_loc_atom: ?*Atom = null, -debug_ranges_atom: ?*Atom = null, -debug_abbrev_atom: ?*Atom = null, -debug_str_atom: ?*Atom = null, -debug_pubnames_atom: ?*Atom = null, -debug_pubtypes_atom: ?*Atom = null, +debug_info_atom: ?Atom.Index = null, +debug_line_atom: ?Atom.Index = null, +debug_loc_atom: ?Atom.Index = null, +debug_ranges_atom: ?Atom.Index = null, +debug_abbrev_atom: ?Atom.Index = null, +debug_str_atom: ?Atom.Index = null, +debug_pubnames_atom: ?Atom.Index = null, +debug_pubtypes_atom: ?Atom.Index = null, pub const Segment = struct { alignment: u32, @@ -430,10 +425,10 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option // at the end during `initializeCallCtorsFunction`. } - if (!options.strip and options.module != null) { - wasm_bin.dwarf = Dwarf.init(allocator, &wasm_bin.base, options.target); - try wasm_bin.initDebugSections(); - } + // if (!options.strip and options.module != null) { + // wasm_bin.dwarf = Dwarf.init(allocator, &wasm_bin.base, options.target); + // try wasm_bin.initDebugSections(); + // } return wasm_bin; } @@ -474,6 +469,7 @@ fn createSyntheticSymbol(wasm: *Wasm, name: []const u8, tag: Symbol.Tag) !Symbol try wasm.globals.put(wasm.base.allocator, name_offset, loc); return loc; } + /// Initializes symbols and atoms for the debug sections /// Initialization is only done when compiling Zig code. /// When Zig is invoked as a linker instead, the atoms @@ -516,6 +512,36 @@ fn parseObjectFile(wasm: *Wasm, path: []const u8) !bool { return true; } +/// For a given `Module.Decl.Index` returns its corresponding `Atom.Index`. +/// When the index was not found, a new `Atom` will be created, and its index will be returned. +/// The newly created Atom is empty with default fields as specified by `Atom.empty`. +pub fn getOrCreateAtomForDecl(wasm: *Wasm, decl_index: Module.Decl.Index) !Atom.Index { + const gop = try wasm.decls.getOrPut(wasm.base.allocator, decl_index); + if (!gop.found_existing) { + gop.value_ptr.* = try wasm.createAtom(); + } + return gop.value_ptr.*; +} + +/// Creates a new empty `Atom` and returns its `Atom.Index` +fn createAtom(wasm: *Wasm) !Atom.Index { + const index = @intCast(Atom.Index, wasm.managed_atoms.items.len); + const atom = try wasm.managed_atoms.addOne(wasm.base.allocator); + atom.* = Atom.empty; + atom.sym_index = try wasm.allocateSymbol(); + try wasm.symbol_atom.putNoClobber(wasm.base.allocator, .{ .file = null, .index = atom.sym_index }, index); + + return index; +} + +pub inline fn getAtom(wasm: *const Wasm, index: Atom.Index) Atom { + return wasm.managed_atoms.items[index]; +} + +pub inline fn getAtomPtr(wasm: *Wasm, index: Atom.Index) *Atom { + return &wasm.managed_atoms.items[index]; +} + /// Parses an archive file and will then parse each object file /// that was found in the archive file. /// Returns false when the file is not an archive file. @@ -857,15 +883,16 @@ fn resolveLazySymbols(wasm: *Wasm) !void { try wasm.discarded.putNoClobber(wasm.base.allocator, kv.value, loc); _ = wasm.resolved_symbols.swapRemove(loc); // we don't want to emit this symbol, only use it for relocations. - const atom = try wasm.base.allocator.create(Atom); - errdefer wasm.base.allocator.destroy(atom); - try wasm.managed_atoms.append(wasm.base.allocator, atom); + // TODO: Can we use `createAtom` here while also re-using the symbol + // from `createSyntheticSymbol`. + const atom_index = @intCast(Atom.Index, wasm.managed_atoms.items.len); + const atom = try wasm.managed_atoms.addOne(wasm.base.allocator); atom.* = Atom.empty; atom.sym_index = loc.index; atom.alignment = 1; - try wasm.parseAtom(atom, .{ .data = .synthetic }); - try wasm.symbol_atom.putNoClobber(wasm.base.allocator, loc, atom); + try wasm.parseAtom(atom_index, .{ .data = .synthetic }); + try wasm.symbol_atom.putNoClobber(wasm.base.allocator, loc, atom_index); } if (wasm.undefs.fetchSwapRemove("__heap_end")) |kv| { @@ -873,15 +900,14 @@ fn resolveLazySymbols(wasm: *Wasm) !void { try wasm.discarded.putNoClobber(wasm.base.allocator, kv.value, loc); _ = wasm.resolved_symbols.swapRemove(loc); - const atom = try wasm.base.allocator.create(Atom); - errdefer wasm.base.allocator.destroy(atom); - try wasm.managed_atoms.append(wasm.base.allocator, atom); + const atom_index = @intCast(Atom.Index, wasm.managed_atoms.items.len); + const atom = try wasm.managed_atoms.addOne(wasm.base.allocator); atom.* = Atom.empty; atom.sym_index = loc.index; atom.alignment = 1; - try wasm.parseAtom(atom, .{ .data = .synthetic }); - try wasm.symbol_atom.putNoClobber(wasm.base.allocator, loc, atom); + try wasm.parseAtom(atom_index, .{ .data = .synthetic }); + try wasm.symbol_atom.putNoClobber(wasm.base.allocator, loc, atom_index); } } @@ -920,16 +946,6 @@ pub fn deinit(wasm: *Wasm) void { if (wasm.llvm_object) |llvm_object| llvm_object.destroy(gpa); } - if (wasm.base.options.module) |mod| { - var decl_it = wasm.decls.keyIterator(); - while (decl_it.next()) |decl_index_ptr| { - const decl = mod.declPtr(decl_index_ptr.*); - decl.link.wasm.deinit(gpa); - } - } else { - assert(wasm.decls.count() == 0); - } - for (wasm.func_types.items) |*func_type| { func_type.deinit(gpa); } @@ -954,9 +970,8 @@ pub fn deinit(wasm: *Wasm) void { wasm.symbol_atom.deinit(gpa); wasm.export_names.deinit(gpa); wasm.atoms.deinit(gpa); - for (wasm.managed_atoms.items) |managed_atom| { - managed_atom.deinit(gpa); - gpa.destroy(managed_atom); + for (wasm.managed_atoms.items) |*managed_atom| { + managed_atom.deinit(wasm); } wasm.managed_atoms.deinit(gpa); wasm.segments.deinit(gpa); @@ -1014,18 +1029,24 @@ pub fn updateFunc(wasm: *Wasm, mod: *Module, func: *Module.Fn, air: Air, livenes const decl_index = func.owner_decl; const decl = mod.declPtr(decl_index); - const atom = &decl.link.wasm; - try atom.ensureInitialized(wasm); - const gop = try wasm.decls.getOrPut(wasm.base.allocator, decl_index); - if (gop.found_existing) { - atom.clear(); - } else gop.value_ptr.* = {}; + const atom_index = try wasm.getOrCreateAtomForDecl(decl_index); + const atom = wasm.getAtomPtr(atom_index); + atom.clear(); - var decl_state: ?Dwarf.DeclState = if (wasm.dwarf) |*dwarf| try dwarf.initDeclState(mod, decl_index) else null; - defer if (decl_state) |*ds| ds.deinit(); + // var decl_state: ?Dwarf.DeclState = if (wasm.dwarf) |*dwarf| try dwarf.initDeclState(mod, decl_index) else null; + // defer if (decl_state) |*ds| ds.deinit(); var code_writer = std.ArrayList(u8).init(wasm.base.allocator); defer code_writer.deinit(); + // const result = try codegen.generateFunction( + // &wasm.base, + // decl.srcLoc(), + // func, + // air, + // liveness, + // &code_writer, + // if (decl_state) |*ds| .{ .dwarf = ds } else .none, + // ); const result = try codegen.generateFunction( &wasm.base, decl.srcLoc(), @@ -1033,7 +1054,7 @@ pub fn updateFunc(wasm: *Wasm, mod: *Module, func: *Module.Fn, air: Air, livenes air, liveness, &code_writer, - if (decl_state) |*ds| .{ .dwarf = ds } else .none, + .none, ); const code = switch (result) { @@ -1045,19 +1066,19 @@ pub fn updateFunc(wasm: *Wasm, mod: *Module, func: *Module.Fn, air: Air, livenes }, }; - if (wasm.dwarf) |*dwarf| { - try dwarf.commitDeclState( - mod, - decl_index, - // Actual value will be written after relocation. - // For Wasm, this is the offset relative to the code section - // which isn't known until flush(). - 0, - code.len, - &decl_state.?, - ); - } - return wasm.finishUpdateDecl(decl, code); + // if (wasm.dwarf) |*dwarf| { + // try dwarf.commitDeclState( + // mod, + // decl_index, + // // Actual value will be written after relocation. + // // For Wasm, this is the offset relative to the code section + // // which isn't known until flush(). + // 0, + // code.len, + // &decl_state.?, + // ); + // } + return wasm.finishUpdateDecl(decl_index, code); } // Generate code for the Decl, storing it in memory to be later written to @@ -1080,17 +1101,14 @@ pub fn updateDecl(wasm: *Wasm, mod: *Module, decl_index: Module.Decl.Index) !voi return; } - const atom = &decl.link.wasm; - try atom.ensureInitialized(wasm); - const gop = try wasm.decls.getOrPut(wasm.base.allocator, decl_index); - if (gop.found_existing) { - atom.clear(); - } else gop.value_ptr.* = {}; + const atom_index = try wasm.getOrCreateAtomForDecl(decl_index); + const atom = wasm.getAtomPtr(atom_index); + atom.clear(); if (decl.isExtern()) { const variable = decl.getVariable().?; const name = mem.sliceTo(decl.name, 0); - return wasm.addOrUpdateImport(name, decl.link.wasm.sym_index, variable.lib_name, null); + return wasm.addOrUpdateImport(name, atom.sym_index, variable.lib_name, null); } const val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val; @@ -1103,7 +1121,7 @@ pub fn updateDecl(wasm: *Wasm, mod: *Module, decl_index: Module.Decl.Index) !voi .{ .ty = decl.ty, .val = val }, &code_writer, .none, - .{ .parent_atom_index = decl.link.wasm.sym_index }, + .{ .parent_atom_index = atom.sym_index }, ); const code = switch (res) { @@ -1115,7 +1133,7 @@ pub fn updateDecl(wasm: *Wasm, mod: *Module, decl_index: Module.Decl.Index) !voi }, }; - return wasm.finishUpdateDecl(decl, code); + return wasm.finishUpdateDecl(decl_index, code); } pub fn updateDeclLineNumber(wasm: *Wasm, mod: *Module, decl_index: Module.Decl.Index) !void { @@ -1133,9 +1151,11 @@ pub fn updateDeclLineNumber(wasm: *Wasm, mod: *Module, decl_index: Module.Decl.I } } -fn finishUpdateDecl(wasm: *Wasm, decl: *Module.Decl, code: []const u8) !void { +fn finishUpdateDecl(wasm: *Wasm, decl_index: Module.Decl.Index, code: []const u8) !void { const mod = wasm.base.options.module.?; - const atom: *Atom = &decl.link.wasm; + const decl = mod.declPtr(decl_index); + const atom_index = wasm.decls.get(decl_index).?; + const atom = wasm.getAtomPtr(atom_index); const symbol = &wasm.symbols.items[atom.sym_index]; const full_name = try decl.getFullyQualifiedName(mod); defer wasm.base.allocator.free(full_name); @@ -1201,48 +1221,51 @@ pub fn lowerUnnamedConst(wasm: *Wasm, tv: TypedValue, decl_index: Module.Decl.In const decl = mod.declPtr(decl_index); // Create and initialize a new local symbol and atom - const local_index = decl.link.wasm.locals.items.len; + const atom_index = try wasm.createAtom(); + const parent_atom_index = try wasm.getOrCreateAtomForDecl(decl_index); + const parent_atom = wasm.getAtomPtr(parent_atom_index); + const local_index = parent_atom.locals.items.len; + try parent_atom.locals.append(wasm.base.allocator, atom_index); const fqdn = try decl.getFullyQualifiedName(mod); defer wasm.base.allocator.free(fqdn); const name = try std.fmt.allocPrintZ(wasm.base.allocator, "__unnamed_{s}_{d}", .{ fqdn, local_index }); defer wasm.base.allocator.free(name); - - const atom = try decl.link.wasm.locals.addOne(wasm.base.allocator); - atom.* = Atom.empty; - try atom.ensureInitialized(wasm); - atom.alignment = tv.ty.abiAlignment(wasm.base.options.target); - wasm.symbols.items[atom.sym_index] = .{ - .name = try wasm.string_table.put(wasm.base.allocator, name), - .flags = @enumToInt(Symbol.Flag.WASM_SYM_BINDING_LOCAL), - .tag = .data, - .index = undefined, - }; - - try wasm.resolved_symbols.putNoClobber(wasm.base.allocator, atom.symbolLoc(), {}); - var value_bytes = std.ArrayList(u8).init(wasm.base.allocator); defer value_bytes.deinit(); - const result = try codegen.generateSymbol( - &wasm.base, - decl.srcLoc(), - tv, - &value_bytes, - .none, - .{ - .parent_atom_index = atom.sym_index, - .addend = null, - }, - ); - const code = switch (result) { - .ok => value_bytes.items, - .fail => |em| { - decl.analysis = .codegen_failure; - try mod.failed_decls.put(mod.gpa, decl_index, em); - return error.AnalysisFail; - }, + const code = code: { + const atom = wasm.getAtomPtr(atom_index); + atom.alignment = tv.ty.abiAlignment(wasm.base.options.target); + wasm.symbols.items[atom.sym_index] = .{ + .name = try wasm.string_table.put(wasm.base.allocator, name), + .flags = @enumToInt(Symbol.Flag.WASM_SYM_BINDING_LOCAL), + .tag = .data, + .index = undefined, + }; + try wasm.resolved_symbols.putNoClobber(wasm.base.allocator, atom.symbolLoc(), {}); + + const result = try codegen.generateSymbol( + &wasm.base, + decl.srcLoc(), + tv, + &value_bytes, + .none, + .{ + .parent_atom_index = atom.sym_index, + .addend = null, + }, + ); + break :code switch (result) { + .ok => value_bytes.items, + .fail => |em| { + decl.analysis = .codegen_failure; + try mod.failed_decls.put(mod.gpa, decl_index, em); + return error.AnalysisFail; + }, + }; }; + const atom = wasm.getAtomPtr(atom_index); atom.size = @intCast(u32, code.len); try atom.code.appendSlice(wasm.base.allocator, code); return atom.sym_index; @@ -1290,10 +1313,13 @@ pub fn getDeclVAddr( ) !u64 { const mod = wasm.base.options.module.?; const decl = mod.declPtr(decl_index); - try decl.link.wasm.ensureInitialized(wasm); - const target_symbol_index = decl.link.wasm.sym_index; + + const target_atom_index = try wasm.getOrCreateAtomForDecl(decl_index); + const target_symbol_index = wasm.getAtom(target_atom_index).sym_index; + assert(reloc_info.parent_atom_index != 0); - const atom = wasm.symbol_atom.get(.{ .file = null, .index = reloc_info.parent_atom_index }).?; + const atom_index = wasm.symbol_atom.get(.{ .file = null, .index = reloc_info.parent_atom_index }).?; + const atom = wasm.getAtomPtr(atom_index); const is_wasm32 = wasm.base.options.target.cpu.arch == .wasm32; if (decl.ty.zigTypeTag() == .Fn) { assert(reloc_info.addend == 0); // addend not allowed for function relocations @@ -1321,9 +1347,10 @@ pub fn getDeclVAddr( return target_symbol_index; } -pub fn deleteExport(wasm: *Wasm, exp: Export) void { +pub fn deleteDeclExport(wasm: *Wasm, decl_index: Module.Decl.Index) void { if (wasm.llvm_object) |_| return; - const sym_index = exp.sym_index orelse return; + const atom_index = wasm.decls.get(decl_index) orelse return; + const sym_index = wasm.getAtom(atom_index).sym_index; const loc: SymbolLoc = .{ .file = null, .index = sym_index }; const symbol = loc.getSymbol(wasm); const symbol_name = wasm.string_table.get(symbol.name); @@ -1349,7 +1376,8 @@ pub fn updateDeclExports( } const decl = mod.declPtr(decl_index); - if (decl.link.wasm.getSymbolIndex() == null) return; // unititialized + const atom_index = try wasm.getOrCreateAtomForDecl(decl_index); + const atom = wasm.getAtom(atom_index); for (exports) |exp| { if (exp.options.section) |section| { @@ -1364,7 +1392,7 @@ pub fn updateDeclExports( const export_name = try wasm.string_table.put(wasm.base.allocator, exp.options.name); if (wasm.globals.getPtr(export_name)) |existing_loc| { - if (existing_loc.index == decl.link.wasm.sym_index) continue; + if (existing_loc.index == atom.sym_index) continue; const existing_sym: Symbol = existing_loc.getSymbol(wasm).*; const exp_is_weak = exp.options.linkage == .Internal or exp.options.linkage == .Weak; @@ -1385,15 +1413,16 @@ pub fn updateDeclExports( } else if (exp_is_weak) { continue; // to-be-exported symbol is weak, so we keep the existing symbol } else { - existing_loc.index = decl.link.wasm.sym_index; + // TODO: Revisit this, why was this needed? + existing_loc.index = atom.sym_index; existing_loc.file = null; - exp.link.wasm.sym_index = existing_loc.index; + // exp.link.wasm.sym_index = existing_loc.index; } } - const exported_decl = mod.declPtr(exp.exported_decl); - const sym_index = exported_decl.link.wasm.sym_index; - const sym_loc = exported_decl.link.wasm.symbolLoc(); + const exported_atom_index = try wasm.getOrCreateAtomForDecl(exp.exported_decl); + const exported_atom = wasm.getAtom(exported_atom_index); + const sym_loc = exported_atom.symbolLoc(); const symbol = sym_loc.getSymbol(wasm); switch (exp.options.linkage) { .Internal => { @@ -1429,7 +1458,6 @@ pub fn updateDeclExports( // if the symbol was previously undefined, remove it as an import _ = wasm.imports.remove(sym_loc); _ = wasm.undefs.swapRemove(exp.options.name); - exp.link.wasm.sym_index = sym_index; } } @@ -1439,11 +1467,13 @@ pub fn freeDecl(wasm: *Wasm, decl_index: Module.Decl.Index) void { } const mod = wasm.base.options.module.?; const decl = mod.declPtr(decl_index); - const atom = &decl.link.wasm; + const atom_index = wasm.decls.get(decl_index).?; + const atom = wasm.getAtomPtr(atom_index); wasm.symbols_free_list.append(wasm.base.allocator, atom.sym_index) catch {}; _ = wasm.decls.remove(decl_index); wasm.symbols.items[atom.sym_index].tag = .dead; - for (atom.locals.items) |local_atom| { + for (atom.locals.items) |local_atom_index| { + const local_atom = wasm.getAtom(local_atom_index); const local_symbol = &wasm.symbols.items[local_atom.sym_index]; local_symbol.tag = .dead; // also for any local symbol wasm.symbols_free_list.append(wasm.base.allocator, local_atom.sym_index) catch {}; @@ -1461,7 +1491,16 @@ pub fn freeDecl(wasm: *Wasm, decl_index: Module.Decl.Index) void { // dwarf.freeDecl(decl_index); // } - atom.deinit(wasm.base.allocator); + if (atom.next) |next_atom_index| { + const next_atom = wasm.getAtomPtr(next_atom_index); + next_atom.prev = atom.prev; + atom.next = null; + } + if (atom.prev) |prev_index| { + const prev_atom = wasm.getAtomPtr(prev_index); + prev_atom.next = atom.next; + atom.prev = null; + } } /// Appends a new entry to the indirect function table @@ -1583,7 +1622,8 @@ const Kind = union(enum) { }; /// Parses an Atom and inserts its metadata into the corresponding sections. -fn parseAtom(wasm: *Wasm, atom: *Atom, kind: Kind) !void { +fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void { + const atom = wasm.getAtomPtr(atom_index); const symbol = (SymbolLoc{ .file = null, .index = atom.sym_index }).getSymbol(wasm); const final_index: u32 = switch (kind) { .function => |fn_data| result: { @@ -1658,18 +1698,20 @@ fn parseAtom(wasm: *Wasm, atom: *Atom, kind: Kind) !void { const segment: *Segment = &wasm.segments.items[final_index]; segment.alignment = std.math.max(segment.alignment, atom.alignment); - try wasm.appendAtomAtIndex(final_index, atom); + try wasm.appendAtomAtIndex(final_index, atom_index); } /// From a given index, append the given `Atom` at the back of the linked list. /// Simply inserts it into the map of atoms when it doesn't exist yet. -pub fn appendAtomAtIndex(wasm: *Wasm, index: u32, atom: *Atom) !void { - if (wasm.atoms.getPtr(index)) |last| { - last.*.next = atom; - atom.prev = last.*; - last.* = atom; +pub fn appendAtomAtIndex(wasm: *Wasm, index: u32, atom_index: Atom.Index) !void { + const atom = wasm.getAtomPtr(atom_index); + if (wasm.atoms.getPtr(index)) |last_index_ptr| { + const last = wasm.getAtomPtr(last_index_ptr.*); + last.*.next = atom_index; + atom.prev = last_index_ptr.*; + last_index_ptr.* = atom_index; } else { - try wasm.atoms.putNoClobber(wasm.base.allocator, index, atom); + try wasm.atoms.putNoClobber(wasm.base.allocator, index, atom_index); } } @@ -1679,16 +1721,17 @@ fn allocateDebugAtoms(wasm: *Wasm) !void { if (wasm.dwarf == null) return; const allocAtom = struct { - fn f(bin: *Wasm, maybe_index: *?u32, atom: *Atom) !void { + fn f(bin: *Wasm, maybe_index: *?u32, atom_index: Atom.Index) !void { const index = maybe_index.* orelse idx: { const index = @intCast(u32, bin.segments.items.len); try bin.appendDummySegment(); maybe_index.* = index; break :idx index; }; + const atom = bin.getAtomPtr(atom_index); atom.size = @intCast(u32, atom.code.items.len); bin.symbols.items[atom.sym_index].index = index; - try bin.appendAtomAtIndex(index, atom); + try bin.appendAtomAtIndex(index, atom_index); } }.f; @@ -1710,15 +1753,16 @@ fn allocateAtoms(wasm: *Wasm) !void { var it = wasm.atoms.iterator(); while (it.next()) |entry| { const segment = &wasm.segments.items[entry.key_ptr.*]; - var atom: *Atom = entry.value_ptr.*.getFirst(); + var atom_index = entry.value_ptr.*; var offset: u32 = 0; while (true) { + const atom = wasm.getAtomPtr(atom_index); const symbol_loc = atom.symbolLoc(); if (wasm.code_section_index) |index| { if (index == entry.key_ptr.*) { if (!wasm.resolved_symbols.contains(symbol_loc)) { // only allocate resolved function body's. - atom = atom.next orelse break; + atom_index = atom.prev orelse break; continue; } } @@ -1732,8 +1776,7 @@ fn allocateAtoms(wasm: *Wasm) !void { atom.size, }); offset += atom.size; - try wasm.symbol_atom.put(wasm.base.allocator, symbol_loc, atom); // Update atom pointers - atom = atom.next orelse break; + atom_index = atom.prev orelse break; } segment.size = std.mem.alignForwardGeneric(u32, offset, segment.alignment); } @@ -1867,8 +1910,8 @@ fn initializeCallCtorsFunction(wasm: *Wasm) !void { symbol.index = func_index; // create the atom that will be output into the final binary - const atom = try wasm.base.allocator.create(Atom); - errdefer wasm.base.allocator.destroy(atom); + const atom_index = @intCast(Atom.Index, wasm.managed_atoms.items.len); + const atom = try wasm.managed_atoms.addOne(wasm.base.allocator); atom.* = .{ .size = @intCast(u32, function_body.items.len), .offset = 0, @@ -1879,13 +1922,13 @@ fn initializeCallCtorsFunction(wasm: *Wasm) !void { .prev = null, .code = function_body.moveToUnmanaged(), }; - try wasm.managed_atoms.append(wasm.base.allocator, atom); - try wasm.appendAtomAtIndex(wasm.code_section_index.?, atom); - try wasm.symbol_atom.putNoClobber(wasm.base.allocator, loc, atom); + try wasm.appendAtomAtIndex(wasm.code_section_index.?, atom_index); + try wasm.symbol_atom.putNoClobber(wasm.base.allocator, loc, atom_index); // `allocateAtoms` has already been called, set the atom's offset manually. // This is fine to do manually as we insert the atom at the very end. - atom.offset = atom.prev.?.offset + atom.prev.?.size; + const prev_atom = wasm.getAtom(atom.prev.?); + atom.offset = prev_atom.offset + prev_atom.size; } fn setupImports(wasm: *Wasm) !void { @@ -2088,7 +2131,8 @@ fn setupExports(wasm: *Wasm) !void { break :blk try wasm.string_table.put(wasm.base.allocator, sym_name); }; const exp: types.Export = if (symbol.tag == .data) exp: { - const atom = wasm.symbol_atom.get(sym_loc).?; + const atom_index = wasm.symbol_atom.get(sym_loc).?; + const atom = wasm.getAtom(atom_index); const va = atom.getVA(wasm, symbol); const global_index = @intCast(u32, wasm.imported_globals_count + wasm.wasm_globals.items.len); try wasm.wasm_globals.append(wasm.base.allocator, .{ @@ -2193,7 +2237,8 @@ fn setupMemory(wasm: *Wasm) !void { const segment_index = wasm.data_segments.get(".synthetic").?; const segment = &wasm.segments.items[segment_index]; segment.offset = 0; // for simplicity we store the entire VA into atom's offset. - const atom = wasm.symbol_atom.get(loc).?; + const atom_index = wasm.symbol_atom.get(loc).?; + const atom = wasm.getAtomPtr(atom_index); atom.offset = @intCast(u32, mem.alignForwardGeneric(u64, memory_ptr, heap_alignment)); } @@ -2226,7 +2271,8 @@ fn setupMemory(wasm: *Wasm) !void { const segment_index = wasm.data_segments.get(".synthetic").?; const segment = &wasm.segments.items[segment_index]; segment.offset = 0; - const atom = wasm.symbol_atom.get(loc).?; + const atom_index = wasm.symbol_atom.get(loc).?; + const atom = wasm.getAtomPtr(atom_index); atom.offset = @intCast(u32, memory_ptr); } @@ -2352,15 +2398,14 @@ pub fn getErrorTableSymbol(wasm: *Wasm) !u32 { // and then return said symbol's index. The final table will be populated // during `flush` when we know all possible error names. - // As sym_index '0' is reserved, we use it for our stack pointer symbol - const symbol_index = wasm.symbols_free_list.popOrNull() orelse blk: { - const index = @intCast(u32, wasm.symbols.items.len); - _ = try wasm.symbols.addOne(wasm.base.allocator); - break :blk index; - }; + const atom_index = try wasm.createAtom(); + const atom = wasm.getAtomPtr(atom_index); + const slice_ty = Type.initTag(.const_slice_u8_sentinel_0); + atom.alignment = slice_ty.abiAlignment(wasm.base.options.target); + const sym_index = atom.sym_index; const sym_name = try wasm.string_table.put(wasm.base.allocator, "__zig_err_name_table"); - const symbol = &wasm.symbols.items[symbol_index]; + const symbol = &wasm.symbols.items[sym_index]; symbol.* = .{ .name = sym_name, .tag = .data, @@ -2369,20 +2414,11 @@ pub fn getErrorTableSymbol(wasm: *Wasm) !u32 { }; symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); - const slice_ty = Type.initTag(.const_slice_u8_sentinel_0); + try wasm.resolved_symbols.put(wasm.base.allocator, atom.symbolLoc(), {}); - const atom = try wasm.base.allocator.create(Atom); - atom.* = Atom.empty; - atom.sym_index = symbol_index; - atom.alignment = slice_ty.abiAlignment(wasm.base.options.target); - try wasm.managed_atoms.append(wasm.base.allocator, atom); - const loc = atom.symbolLoc(); - try wasm.resolved_symbols.put(wasm.base.allocator, loc, {}); - try wasm.symbol_atom.put(wasm.base.allocator, loc, atom); - - log.debug("Error name table was created with symbol index: ({d})", .{symbol_index}); - wasm.error_table_symbol = symbol_index; - return symbol_index; + log.debug("Error name table was created with symbol index: ({d})", .{sym_index}); + wasm.error_table_symbol = sym_index; + return sym_index; } /// Populates the error name table, when `error_table_symbol` is not null. @@ -2391,22 +2427,17 @@ pub fn getErrorTableSymbol(wasm: *Wasm) !u32 { /// The table is what is being pointed to within the runtime bodies that are generated. fn populateErrorNameTable(wasm: *Wasm) !void { const symbol_index = wasm.error_table_symbol orelse return; - const atom: *Atom = wasm.symbol_atom.get(.{ .file = null, .index = symbol_index }).?; + const atom_index = wasm.symbol_atom.get(.{ .file = null, .index = symbol_index }).?; + const atom = wasm.getAtomPtr(atom_index); + // Rather than creating a symbol for each individual error name, // we create a symbol for the entire region of error names. We then calculate // the pointers into the list using addends which are appended to the relocation. - const names_atom = try wasm.base.allocator.create(Atom); - names_atom.* = Atom.empty; - try wasm.managed_atoms.append(wasm.base.allocator, names_atom); - const names_symbol_index = wasm.symbols_free_list.popOrNull() orelse blk: { - const index = @intCast(u32, wasm.symbols.items.len); - _ = try wasm.symbols.addOne(wasm.base.allocator); - break :blk index; - }; - names_atom.sym_index = names_symbol_index; + const names_atom_index = try wasm.createAtom(); + const names_atom = wasm.getAtomPtr(names_atom_index); names_atom.alignment = 1; const sym_name = try wasm.string_table.put(wasm.base.allocator, "__zig_err_names"); - const names_symbol = &wasm.symbols.items[names_symbol_index]; + const names_symbol = &wasm.symbols.items[names_atom.sym_index]; names_symbol.* = .{ .name = sym_name, .tag = .data, @@ -2430,7 +2461,7 @@ fn populateErrorNameTable(wasm: *Wasm) !void { try atom.code.writer(wasm.base.allocator).writeIntLittle(u32, len - 1); // create relocation to the error name try atom.relocs.append(wasm.base.allocator, .{ - .index = names_symbol_index, + .index = names_atom.sym_index, .relocation_type = .R_WASM_MEMORY_ADDR_I32, .offset = offset, .addend = @intCast(i32, addend), @@ -2449,61 +2480,53 @@ fn populateErrorNameTable(wasm: *Wasm) !void { const name_loc = names_atom.symbolLoc(); try wasm.resolved_symbols.put(wasm.base.allocator, name_loc, {}); - try wasm.symbol_atom.put(wasm.base.allocator, name_loc, names_atom); + try wasm.symbol_atom.put(wasm.base.allocator, name_loc, names_atom_index); // link the atoms with the rest of the binary so they can be allocated // and relocations will be performed. - try wasm.parseAtom(atom, .{ .data = .read_only }); - try wasm.parseAtom(names_atom, .{ .data = .read_only }); + try wasm.parseAtom(atom_index, .{ .data = .read_only }); + try wasm.parseAtom(names_atom_index, .{ .data = .read_only }); } /// From a given index variable, creates a new debug section. /// This initializes the index, appends a new segment, /// and finally, creates a managed `Atom`. -pub fn createDebugSectionForIndex(wasm: *Wasm, index: *?u32, name: []const u8) !*Atom { +pub fn createDebugSectionForIndex(wasm: *Wasm, index: *?u32, name: []const u8) !Atom.Index { const new_index = @intCast(u32, wasm.segments.items.len); index.* = new_index; try wasm.appendDummySegment(); - const sym_index = wasm.symbols_free_list.popOrNull() orelse idx: { - const tmp_index = @intCast(u32, wasm.symbols.items.len); - _ = try wasm.symbols.addOne(wasm.base.allocator); - break :idx tmp_index; - }; - wasm.symbols.items[sym_index] = .{ + const atom_index = try wasm.createAtom(); + const atom = wasm.getAtomPtr(atom_index); + wasm.symbols.items[atom.sym_index] = .{ .tag = .section, .name = try wasm.string_table.put(wasm.base.allocator, name), .index = 0, .flags = @enumToInt(Symbol.Flag.WASM_SYM_BINDING_LOCAL), }; - const atom = try wasm.base.allocator.create(Atom); - atom.* = Atom.empty; atom.alignment = 1; // debug sections are always 1-byte-aligned - atom.sym_index = sym_index; - try wasm.managed_atoms.append(wasm.base.allocator, atom); - try wasm.symbol_atom.put(wasm.base.allocator, atom.symbolLoc(), atom); - return atom; + return atom_index; } fn resetState(wasm: *Wasm) void { for (wasm.segment_info.values()) |segment_info| { wasm.base.allocator.free(segment_info.name); } - if (wasm.base.options.module) |mod| { - var decl_it = wasm.decls.keyIterator(); - while (decl_it.next()) |decl_index_ptr| { - const decl = mod.declPtr(decl_index_ptr.*); - const atom = &decl.link.wasm; - atom.next = null; - atom.prev = null; - for (atom.locals.items) |*local_atom| { - local_atom.next = null; - local_atom.prev = null; - } + var atom_it = wasm.decls.valueIterator(); + while (atom_it.next()) |atom_index| { + const atom = wasm.getAtomPtr(atom_index.*); + atom.next = null; + atom.prev = null; + + for (atom.locals.items) |local_atom_index| { + const local_atom = wasm.getAtomPtr(local_atom_index); + local_atom.next = null; + local_atom.prev = null; } } + wasm.functions.clearRetainingCapacity(); wasm.exports.clearRetainingCapacity(); wasm.segments.clearRetainingCapacity(); @@ -2800,28 +2823,29 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod try wasm.setupStart(); try wasm.setupImports(); if (wasm.base.options.module) |mod| { - var decl_it = wasm.decls.keyIterator(); - while (decl_it.next()) |decl_index_ptr| { - const decl = mod.declPtr(decl_index_ptr.*); + var decl_it = wasm.decls.iterator(); + while (decl_it.next()) |entry| { + const decl = mod.declPtr(entry.key_ptr.*); if (decl.isExtern()) continue; - const atom = &decl.*.link.wasm; + const atom_index = entry.value_ptr.*; if (decl.ty.zigTypeTag() == .Fn) { - try wasm.parseAtom(atom, .{ .function = decl.fn_link.wasm }); + try wasm.parseAtom(atom_index, .{ .function = decl.fn_link.wasm }); } else if (decl.getVariable()) |variable| { if (!variable.is_mutable) { - try wasm.parseAtom(atom, .{ .data = .read_only }); + try wasm.parseAtom(atom_index, .{ .data = .read_only }); } else if (variable.init.isUndefDeep()) { - try wasm.parseAtom(atom, .{ .data = .uninitialized }); + try wasm.parseAtom(atom_index, .{ .data = .uninitialized }); } else { - try wasm.parseAtom(atom, .{ .data = .initialized }); + try wasm.parseAtom(atom_index, .{ .data = .initialized }); } } else { - try wasm.parseAtom(atom, .{ .data = .read_only }); + try wasm.parseAtom(atom_index, .{ .data = .read_only }); } // also parse atoms for a decl's locals - for (atom.locals.items) |*local_atom| { - try wasm.parseAtom(local_atom, .{ .data = .read_only }); + const atom = wasm.getAtomPtr(atom_index); + for (atom.locals.items) |local_atom_index| { + try wasm.parseAtom(local_atom_index, .{ .data = .read_only }); } } @@ -3066,20 +3090,22 @@ fn writeToFile( var code_section_size: u32 = 0; if (wasm.code_section_index) |code_index| { const header_offset = try reserveVecSectionHeader(&binary_bytes); - var atom: *Atom = wasm.atoms.get(code_index).?.getFirst(); + var atom_index = wasm.atoms.get(code_index).?; // The code section must be sorted in line with the function order. var sorted_atoms = try std.ArrayList(*Atom).initCapacity(wasm.base.allocator, wasm.functions.count()); defer sorted_atoms.deinit(); while (true) { + var atom = wasm.getAtomPtr(atom_index); if (wasm.resolved_symbols.contains(atom.symbolLoc())) { if (!is_obj) { atom.resolveRelocs(wasm); } sorted_atoms.appendAssumeCapacity(atom); } - atom = atom.next orelse break; + // atom = if (atom.prev) |prev| wasm.getAtomPtr(prev) else break; + atom_index = atom.prev orelse break; } const atom_sort_fn = struct { @@ -3119,11 +3145,11 @@ fn writeToFile( // do not output 'bss' section unless we import memory and therefore // want to guarantee the data is zero initialized if (!import_memory and std.mem.eql(u8, entry.key_ptr.*, ".bss")) continue; - const atom_index = entry.value_ptr.*; - const segment = wasm.segments.items[atom_index]; + const segment_index = entry.value_ptr.*; + const segment = wasm.segments.items[segment_index]; if (segment.size == 0) continue; // do not emit empty segments segment_count += 1; - var atom: *Atom = wasm.atoms.getPtr(atom_index).?.*.getFirst(); + var atom_index = wasm.atoms.get(segment_index).?; // flag and index to memory section (currently, there can only be 1 memory section in wasm) try leb.writeULEB128(binary_writer, @as(u32, 0)); @@ -3134,6 +3160,7 @@ fn writeToFile( // fill in the offset table and the data segments var current_offset: u32 = 0; while (true) { + const atom = wasm.getAtomPtr(atom_index); if (!is_obj) { atom.resolveRelocs(wasm); } @@ -3149,8 +3176,8 @@ fn writeToFile( try binary_writer.writeAll(atom.code.items); current_offset += atom.size; - if (atom.next) |next| { - atom = next; + if (atom.prev) |prev| { + atom_index = prev; } else { // also pad with zeroes when last atom to ensure // segments are aligned. @@ -3192,15 +3219,15 @@ fn writeToFile( } if (!wasm.base.options.strip) { - if (wasm.dwarf) |*dwarf| { - const mod = wasm.base.options.module.?; - try dwarf.writeDbgAbbrev(); - // for debug info and ranges, the address is always 0, - // as locations are always offsets relative to 'code' section. - try dwarf.writeDbgInfoHeader(mod, 0, code_section_size); - try dwarf.writeDbgAranges(0, code_section_size); - try dwarf.writeDbgLineHeader(); - } + // if (wasm.dwarf) |*dwarf| { + // const mod = wasm.base.options.module.?; + // try dwarf.writeDbgAbbrev(); + // // for debug info and ranges, the address is always 0, + // // as locations are always offsets relative to 'code' section. + // try dwarf.writeDbgInfoHeader(mod, 0, code_section_size); + // try dwarf.writeDbgAranges(0, code_section_size); + // try dwarf.writeDbgLineHeader(); + // } var debug_bytes = std.ArrayList(u8).init(wasm.base.allocator); defer debug_bytes.deinit(); @@ -3223,11 +3250,11 @@ fn writeToFile( for (debug_sections) |item| { if (item.index) |index| { - var atom = wasm.atoms.get(index).?.getFirst(); + var atom = wasm.getAtomPtr(wasm.atoms.get(index).?); while (true) { atom.resolveRelocs(wasm); try debug_bytes.appendSlice(atom.code.items); - atom = atom.next orelse break; + atom = if (atom.prev) |prev| wasm.getAtomPtr(prev) else break; } try emitDebugSection(&binary_bytes, debug_bytes.items, item.name); debug_bytes.clearRetainingCapacity(); @@ -3959,7 +3986,8 @@ fn emitSymbolTable(wasm: *Wasm, binary_bytes: *std.ArrayList(u8), symbol_table: if (symbol.isDefined()) { try leb.writeULEB128(writer, symbol.index); - const atom = wasm.symbol_atom.get(sym_loc).?; + const atom_index = wasm.symbol_atom.get(sym_loc).?; + const atom = wasm.getAtom(atom_index); try leb.writeULEB128(writer, @as(u32, atom.offset)); try leb.writeULEB128(writer, @as(u32, atom.size)); } @@ -4037,7 +4065,7 @@ fn emitCodeRelocations( const reloc_start = binary_bytes.items.len; var count: u32 = 0; - var atom: *Atom = wasm.atoms.get(code_index).?.getFirst(); + var atom: *Atom = wasm.getAtomPtr(wasm.atoms.get(code_index).?); // for each atom, we calculate the uleb size and append that var size_offset: u32 = 5; // account for code section size leb128 while (true) { @@ -4055,7 +4083,7 @@ fn emitCodeRelocations( } log.debug("Emit relocation: {}", .{relocation}); } - atom = atom.next orelse break; + atom = if (atom.prev) |prev| wasm.getAtomPtr(prev) else break; } if (count == 0) return; var buf: [5]u8 = undefined; @@ -4086,7 +4114,7 @@ fn emitDataRelocations( // for each atom, we calculate the uleb size and append that var size_offset: u32 = 5; // account for code section size leb128 for (wasm.data_segments.values()) |segment_index| { - var atom: *Atom = wasm.atoms.get(segment_index).?.getFirst(); + var atom: *Atom = wasm.getAtomPtr(wasm.atoms.get(segment_index).?); while (true) { size_offset += getULEB128Size(atom.size); for (atom.relocs.items) |relocation| { @@ -4105,7 +4133,7 @@ fn emitDataRelocations( } log.debug("Emit relocation: {}", .{relocation}); } - atom = atom.next orelse break; + atom = if (atom.prev) |prev| wasm.getAtomPtr(prev) else break; } } if (count == 0) return; diff --git a/src/link/Wasm/Atom.zig b/src/link/Wasm/Atom.zig index 554f98b5ca9e1d8c68c158e63f5ef453c9033d62..e719f8dfcc48ad33be4933a4f535227dd572ec06 100644 --- a/src/link/Wasm/Atom.zig +++ b/src/link/Wasm/Atom.zig @@ -29,14 +29,17 @@ file: ?u16, /// Next atom in relation to this atom. /// When null, this atom is the last atom -next: ?*Atom, +next: ?Atom.Index, /// Previous atom in relation to this atom. /// is null when this atom is the first in its order -prev: ?*Atom, +prev: ?Atom.Index, /// Contains atoms local to a decl, all managed by this `Atom`. /// When the parent atom is being freed, it will also do so for all local atoms. -locals: std.ArrayListUnmanaged(Atom) = .{}, +locals: std.ArrayListUnmanaged(Atom.Index) = .{}, + +/// Alias to an unsigned 32-bit integer +pub const Index = u32; /// Represents a default empty wasm `Atom` pub const empty: Atom = .{ @@ -50,14 +53,12 @@ pub const empty: Atom = .{ }; /// Frees all resources owned by this `Atom`. -pub fn deinit(atom: *Atom, gpa: Allocator) void { +pub fn deinit(atom: *Atom, wasm: *Wasm) void { + const gpa = wasm.base.allocator; atom.relocs.deinit(gpa); atom.code.deinit(gpa); - - for (atom.locals.items) |*local| { - local.deinit(gpa); - } atom.locals.deinit(gpa); + atom.* = undefined; } /// Sets the length of relocations and code to '0', @@ -78,24 +79,11 @@ pub fn format(atom: Atom, comptime fmt: []const u8, options: std.fmt.FormatOptio }); } -/// Returns the first `Atom` from a given atom -pub fn getFirst(atom: *Atom) *Atom { - var tmp = atom; - while (tmp.prev) |prev| tmp = prev; - return tmp; -} - /// Returns the location of the symbol that represents this `Atom` pub fn symbolLoc(atom: Atom) Wasm.SymbolLoc { return .{ .file = atom.file, .index = atom.sym_index }; } -pub fn ensureInitialized(atom: *Atom, wasm_bin: *Wasm) !void { - if (atom.getSymbolIndex() != null) return; // already initialized - atom.sym_index = try wasm_bin.allocateSymbol(); - try wasm_bin.symbol_atom.putNoClobber(wasm_bin.base.allocator, atom.symbolLoc(), atom); -} - pub fn getSymbolIndex(atom: Atom) ?u32 { if (atom.sym_index == 0) return null; return atom.sym_index; @@ -198,20 +186,28 @@ fn relocationValue(atom: Atom, relocation: types.Relocation, wasm_bin: *const Wa if (symbol.isUndefined()) { return 0; } - const target_atom = wasm_bin.symbol_atom.get(target_loc).?; + const target_atom_index = wasm_bin.symbol_atom.get(target_loc) orelse { + // this can only occur during incremental-compilation when a relocation + // still points to a freed decl. It is fine to emit the value 0 here + // as no actual code will point towards it. + return 0; + }; + const target_atom = wasm_bin.getAtom(target_atom_index); const va = @intCast(i32, target_atom.getVA(wasm_bin, symbol)); return @intCast(u32, va + relocation.addend); }, .R_WASM_EVENT_INDEX_LEB => return symbol.index, .R_WASM_SECTION_OFFSET_I32 => { - const target_atom = wasm_bin.symbol_atom.get(target_loc).?; + const target_atom_index = wasm_bin.symbol_atom.get(target_loc).?; + const target_atom = wasm_bin.getAtom(target_atom_index); const rel_value = @intCast(i32, target_atom.offset) + relocation.addend; return @intCast(u32, rel_value); }, .R_WASM_FUNCTION_OFFSET_I32 => { - const target_atom = wasm_bin.symbol_atom.get(target_loc) orelse { + const target_atom_index = wasm_bin.symbol_atom.get(target_loc) orelse { return @bitCast(u32, @as(i32, -1)); }; + const target_atom = wasm_bin.getAtom(target_atom_index); const offset: u32 = 11 + Wasm.getULEB128Size(target_atom.size); // Header (11 bytes fixed-size) + body size (leb-encoded) const rel_value = @intCast(i32, target_atom.offset + offset) + relocation.addend; return @intCast(u32, rel_value); diff --git a/src/link/Wasm/Object.zig b/src/link/Wasm/Object.zig index 8f49d687125bb3397aeae947837aaf5b6dec454d..7d4f6a4e36f32b817be6127d88d6f7594c42c2d1 100644 --- a/src/link/Wasm/Object.zig +++ b/src/link/Wasm/Object.zig @@ -901,14 +901,9 @@ pub fn parseIntoAtoms(object: *Object, gpa: Allocator, object_index: u16, wasm_b continue; // found unknown section, so skip parsing into atom as we do not know how to handle it. }; - const atom = try gpa.create(Atom); + const atom_index = @intCast(Atom.Index, wasm_bin.managed_atoms.items.len); + const atom = try wasm_bin.managed_atoms.addOne(gpa); atom.* = Atom.empty; - errdefer { - atom.deinit(gpa); - gpa.destroy(atom); - } - - try wasm_bin.managed_atoms.append(gpa, atom); atom.file = object_index; atom.size = relocatable_data.size; atom.alignment = relocatable_data.getAlignment(object); @@ -938,12 +933,12 @@ pub fn parseIntoAtoms(object: *Object, gpa: Allocator, object_index: u16, wasm_b .index = relocatable_data.getIndex(), })) |symbols| { atom.sym_index = symbols.pop(); - try wasm_bin.symbol_atom.putNoClobber(gpa, atom.symbolLoc(), atom); + try wasm_bin.symbol_atom.putNoClobber(gpa, atom.symbolLoc(), atom_index); // symbols referencing the same atom will be added as alias // or as 'parent' when they are global. while (symbols.popOrNull()) |idx| { - try wasm_bin.symbol_atom.putNoClobber(gpa, .{ .file = atom.file, .index = idx }, atom); + try wasm_bin.symbol_atom.putNoClobber(gpa, .{ .file = atom.file, .index = idx }, atom_index); const alias_symbol = object.symtable[idx]; if (alias_symbol.isGlobal()) { atom.sym_index = idx; @@ -956,7 +951,7 @@ pub fn parseIntoAtoms(object: *Object, gpa: Allocator, object_index: u16, wasm_b segment.alignment = std.math.max(segment.alignment, atom.alignment); } - try wasm_bin.appendAtomAtIndex(final_index, atom); + try wasm_bin.appendAtomAtIndex(final_index, atom_index); log.debug("Parsed into atom: '{s}' at segment index {d}", .{ object.string_table.get(object.symtable[atom.sym_index].name), final_index }); } } diff --git a/test/link/wasm/export-data/build.zig b/test/link/wasm/export-data/build.zig index 283566dab3aaff0fbd33da647a9a38e7cf5450bf..db2ca804e8cde54773645cd22b96df54f6c3405c 100644 --- a/test/link/wasm/export-data/build.zig +++ b/test/link/wasm/export-data/build.zig @@ -23,8 +23,8 @@ pub fn build(b: *Builder) void { check_lib.checkNext("type i32"); check_lib.checkNext("mutable false"); check_lib.checkNext("i32.const {bar_address}"); - check_lib.checkComputeCompare("foo_address", .{ .op = .eq, .value = .{ .literal = 0 } }); - check_lib.checkComputeCompare("bar_address", .{ .op = .eq, .value = .{ .literal = 4 } }); + check_lib.checkComputeCompare("foo_address", .{ .op = .eq, .value = .{ .literal = 4 } }); + check_lib.checkComputeCompare("bar_address", .{ .op = .eq, .value = .{ .literal = 0 } }); check_lib.checkStart("Section export"); check_lib.checkNext("entries 3"); -- 2.54.0 From beb20d29db3fe945746581eba5d2f2cae1403cdb Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Wed, 1 Feb 2023 19:32:54 +0100 Subject: [PATCH 68/84] link: remove union types which are now internal to backends --- src/Module.zig | 56 +++++---------------------------------- src/Sema.zig | 10 ------- src/arch/wasm/CodeGen.zig | 6 ++--- src/link.zig | 33 ----------------------- src/link/Wasm.zig | 2 +- 5 files changed, 10 insertions(+), 97 deletions(-) diff --git a/src/Module.zig b/src/Module.zig index f84d720d1f78c97f035a571434db6b598c4121be..b395c0a9502392a562405223fd972d88b38cf4c3 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -328,8 +328,6 @@ pub const ErrorInt = u32; pub const Export = struct { options: std.builtin.ExportOptions, src: LazySrcLoc, - /// Represents the position of the export, if any, in the output file. - link: link.File.Export, /// The Decl that performs the export. Note that this is *not* the Decl being exported. owner_decl: Decl.Index, /// The Decl containing the export statement. Inline function calls @@ -533,16 +531,8 @@ pub const Decl = struct { /// What kind of a declaration is this. kind: Kind, - /// Represents the position of the code in the output file. - /// This is populated regardless of semantic analysis and code generation. - link: link.File.LinkBlock, - - /// Represents the function in the linked output file, if the `Decl` is a function. - /// This is stored here and not in `Fn` because `Decl` survives across updates but - /// `Fn` does not. - /// TODO Look into making `Fn` a longer lived structure and moving this field there - /// to save on memory usage. - fn_link: link.File.LinkFn, + /// TODO remove this once Wasm backend catches up + fn_link: ?link.File.Wasm.FnData = null, /// The shallow set of other decls whose typed_value could possibly change if this Decl's /// typed_value is modified. @@ -5258,27 +5248,9 @@ pub fn clearDecl( if (decl.ty.isFnOrHasRuntimeBits()) { mod.comp.bin_file.freeDecl(decl_index); - // TODO instead of a union, put this memory trailing Decl objects, - // and allow it to be variably sized. - decl.link = switch (mod.comp.bin_file.tag) { - .coff => .{ .coff = {} }, - .elf => .{ .elf = {} }, - .macho => .{ .macho = {} }, - .plan9 => .{ .plan9 = {} }, - .c => .{ .c = {} }, - .wasm => .{ .wasm = {} }, - .spirv => .{ .spirv = {} }, - .nvptx => .{ .nvptx = {} }, - }; decl.fn_link = switch (mod.comp.bin_file.tag) { - .coff => .{ .coff = {} }, - .elf => .{ .elf = {} }, - .macho => .{ .macho = {} }, - .plan9 => .{ .plan9 = {} }, - .c => .{ .c = {} }, - .wasm => .{ .wasm = link.File.Wasm.FnData.empty }, - .spirv => .{ .spirv = {} }, - .nvptx => .{ .nvptx = {} }, + .wasm => link.File.Wasm.FnData.empty, + else => null, }; } if (decl.getInnerNamespace()) |namespace| { @@ -5680,25 +5652,9 @@ pub fn allocateNewDecl( .deletion_flag = false, .zir_decl_index = 0, .src_scope = src_scope, - .link = switch (mod.comp.bin_file.tag) { - .coff => .{ .coff = {} }, - .elf => .{ .elf = {} }, - .macho => .{ .macho = {} }, - .plan9 => .{ .plan9 = {} }, - .c => .{ .c = {} }, - .wasm => .{ .wasm = {} }, - .spirv => .{ .spirv = {} }, - .nvptx => .{ .nvptx = {} }, - }, .fn_link = switch (mod.comp.bin_file.tag) { - .coff => .{ .coff = {} }, - .elf => .{ .elf = {} }, - .macho => .{ .macho = {} }, - .plan9 => .{ .plan9 = {} }, - .c => .{ .c = {} }, - .wasm => .{ .wasm = link.File.Wasm.FnData.empty }, - .spirv => .{ .spirv = {} }, - .nvptx => .{ .nvptx = {} }, + .wasm => link.File.Wasm.FnData.empty, + else => null, }, .generation = 0, .is_pub = false, diff --git a/src/Sema.zig b/src/Sema.zig index 4871961753453d34b8c0a681df0e07d2d8e756b0..54c3c6dc3886055b3c58d5c689350ca7cddd95bb 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -5564,16 +5564,6 @@ pub fn analyzeExport( .visibility = borrowed_options.visibility, }, .src = src, - .link = switch (mod.comp.bin_file.tag) { - .coff => .{ .coff = {} }, - .elf => .{ .elf = {} }, - .macho => .{ .macho = {} }, - .plan9 => .{ .plan9 = {} }, - .c => .{ .c = {} }, - .wasm => .{ .wasm = {} }, - .spirv => .{ .spirv = {} }, - .nvptx => .{ .nvptx = {} }, - }, .owner_decl = sema.owner_decl_index, .src_decl = block.src_decl, .exported_decl = exported_decl_index, diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index 8559a728e51894dcf9355848d534647faf53029e..cf9c741513de8b2a1a5f264ad9a5ffbc80723e59 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -1194,7 +1194,7 @@ fn genFunc(func: *CodeGen) InnerError!void { const fn_info = func.decl.ty.fnInfo(); var func_type = try genFunctype(func.gpa, fn_info.cc, fn_info.param_types, fn_info.return_type, func.target); defer func_type.deinit(func.gpa); - func.decl.fn_link.wasm.type_index = try func.bin_file.putOrGetFuncType(func_type); + func.decl.fn_link.?.type_index = try func.bin_file.putOrGetFuncType(func_type); var cc_result = try func.resolveCallingConventionValues(func.decl.ty); defer cc_result.deinit(func.gpa); @@ -2129,12 +2129,12 @@ fn airCall(func: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModif defer func_type.deinit(func.gpa); const atom_index = try func.bin_file.getOrCreateAtomForDecl(extern_fn.data.owner_decl); const atom = func.bin_file.getAtomPtr(atom_index); - ext_decl.fn_link.wasm.type_index = try func.bin_file.putOrGetFuncType(func_type); + ext_decl.fn_link.?.type_index = try func.bin_file.putOrGetFuncType(func_type); try func.bin_file.addOrUpdateImport( mem.sliceTo(ext_decl.name, 0), atom.getSymbolIndex().?, ext_decl.getExternFn().?.lib_name, - ext_decl.fn_link.wasm.type_index, + ext_decl.fn_link.?.type_index, ); break :blk extern_fn.data.owner_decl; } else if (func_val.castTag(.decl_ref)) |decl_ref| { diff --git a/src/link.zig b/src/link.zig index 0a3226f004a6d034f3f7befeba2cc1d9fccb9135..2b3ce5166738a364274f736b77f743a9907a245a 100644 --- a/src/link.zig +++ b/src/link.zig @@ -261,39 +261,6 @@ pub const File = struct { /// of this linking operation. lock: ?Cache.Lock = null, - pub const LinkBlock = union { - elf: void, - coff: void, - macho: void, - plan9: void, - c: void, - wasm: void, - spirv: void, - nvptx: void, - }; - - pub const LinkFn = union { - elf: void, - coff: void, - macho: void, - plan9: void, - c: void, - wasm: Wasm.FnData, - spirv: void, - nvptx: void, - }; - - pub const Export = union { - elf: void, - coff: void, - macho: void, - plan9: void, - c: void, - wasm: void, - spirv: void, - nvptx: void, - }; - /// 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 diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index b06703ed6112e0150c51702928069b918d9d5132..17391b017a0a2fab7e4ec1a77e71b73530a3beca 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -2829,7 +2829,7 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod if (decl.isExtern()) continue; const atom_index = entry.value_ptr.*; if (decl.ty.zigTypeTag() == .Fn) { - try wasm.parseAtom(atom_index, .{ .function = decl.fn_link.wasm }); + try wasm.parseAtom(atom_index, .{ .function = decl.fn_link.? }); } else if (decl.getVariable()) |variable| { if (!variable.is_mutable) { try wasm.parseAtom(atom_index, .{ .data = .read_only }); -- 2.54.0 From 490addde278001694d554a9a9fe2eb8235831143 Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Wed, 1 Feb 2023 20:50:43 +0200 Subject: [PATCH 69/84] Sema: fix error location on comptime arg to typed generic param Closes #14505 --- src/Sema.zig | 13 +++++++++++- ...omptime_arg_to_generic_fn_callee_error.zig | 21 +++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 test/cases/compile_errors/comptime_arg_to_generic_fn_callee_error.zig diff --git a/src/Sema.zig b/src/Sema.zig index d306c68e08570d6495a909eabd5169e985668c23..4615c5b16258d1ecc809716d35078546f57cfa11 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -9015,7 +9015,18 @@ fn zirParam( if (is_comptime and sema.preallocated_new_func != null) { // We have a comptime value for this parameter so it should be elided from the // function type of the function instruction in this block. - const coerced_arg = try sema.coerce(block, param_ty, arg, src); + const coerced_arg = sema.coerce(block, param_ty, arg, .unneeded) catch |err| switch (err) { + error.NeededSourceLocation => { + // We are instantiating a generic function and a comptime arg + // cannot be coerced to the param type, but since we don't + // have the callee source location return `GenericPoison` + // so that the instantiation is failed and the coercion + // is handled by comptime call logic instead. + assert(sema.is_generic_instantiation); + return error.GenericPoison; + }, + else => return err, + }; sema.inst_map.putAssumeCapacity(inst, coerced_arg); return; } diff --git a/test/cases/compile_errors/comptime_arg_to_generic_fn_callee_error.zig b/test/cases/compile_errors/comptime_arg_to_generic_fn_callee_error.zig new file mode 100644 index 0000000000000000000000000000000000000000..efc3f556a943022e89a649684d249beb77c68d61 --- /dev/null +++ b/test/cases/compile_errors/comptime_arg_to_generic_fn_callee_error.zig @@ -0,0 +1,21 @@ +const std = @import("std"); +const MyStruct = struct { + a: i32, + b: i32, + + pub fn getA(self: *List) i32 { + return self.items(.c); + } +}; +const List = std.MultiArrayList(MyStruct); +pub export fn entry() void { + var list = List{}; + _ = MyStruct.getA(&list); +} + +// error +// backend=stage2 +// target=native +// +// :7:28: error: no field named 'c' in enum 'meta.FieldEnum(tmp.MyStruct)' +// :?:?: note: enum declared here -- 2.54.0 From 3c8d9681946630a1d953cb2c37cad248c7445093 Mon Sep 17 00:00:00 2001 From: ominitay <37453713+ominitay@users.noreply.github.com> Date: Sun, 31 Jul 2022 22:58:04 +0100 Subject: [PATCH 70/84] fmt: Make default_max_depth configurable --- lib/std/fmt.zig | 11 ++++++----- lib/std/std.zig | 5 +++++ 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/lib/std/fmt.zig b/lib/std/fmt.zig index 94b25c79a1e6fef3da2b4b5dce2563e7b7899263..f2ee24a9e31dd6d7d52c515473d1c4be173dab7f 100644 --- a/lib/std/fmt.zig +++ b/lib/std/fmt.zig @@ -1,11 +1,12 @@ const std = @import("std.zig"); +const builtin = @import("builtin"); + const io = std.io; const math = std.math; const assert = std.debug.assert; const mem = std.mem; const unicode = std.unicode; const meta = std.meta; -const builtin = @import("builtin"); const errol = @import("fmt/errol.zig"); const lossyCast = std.math.lossyCast; const expectFmt = std.testing.expectFmt; @@ -190,7 +191,7 @@ pub fn format( .precision = precision, }, writer, - default_max_depth, + std.options.fmt_max_depth, ); } @@ -2140,15 +2141,15 @@ test "buffer" { { var buf1: [32]u8 = undefined; var fbs = std.io.fixedBufferStream(&buf1); - try formatType(1234, "", FormatOptions{}, fbs.writer(), default_max_depth); + try formatType(1234, "", FormatOptions{}, fbs.writer(), std.options.fmt_max_depth); try std.testing.expect(mem.eql(u8, fbs.getWritten(), "1234")); fbs.reset(); - try formatType('a', "c", FormatOptions{}, fbs.writer(), default_max_depth); + try formatType('a', "c", FormatOptions{}, fbs.writer(), std.options.fmt_max_depth); try std.testing.expect(mem.eql(u8, fbs.getWritten(), "a")); fbs.reset(); - try formatType(0b1100, "b", FormatOptions{}, fbs.writer(), default_max_depth); + try formatType(0b1100, "b", FormatOptions{}, fbs.writer(), std.options.fmt_max_depth); try std.testing.expect(mem.eql(u8, fbs.getWritten(), "1100")); } } diff --git a/lib/std/std.zig b/lib/std/std.zig index 40ba8965697e3d56d3e22106772ba002ab6f9ef9..e02be2ebafec9adf286cc457167706fdead30572 100644 --- a/lib/std/std.zig +++ b/lib/std/std.zig @@ -153,6 +153,11 @@ pub const options = struct { else log.defaultLog; + pub const fmt_max_depth = if (@hasDecl(options_override, "fmt_max_depth")) + options_override.fmt_max_depth + else + fmt.default_max_depth; + pub const cryptoRandomSeed: fn (buffer: []u8) void = if (@hasDecl(options_override, "cryptoRandomSeed")) options_override.cryptoRandomSeed else -- 2.54.0 From 86ec26b1f00ce9ee2a9d559a1ca0415d05a9b908 Mon Sep 17 00:00:00 2001 From: Evan Typanski Date: Sat, 28 Jan 2023 11:53:38 -0500 Subject: [PATCH 71/84] translate-c: Fix types on assign expression bool --- src/translate_c.zig | 5 ++++- test/translate_c.zig | 16 ++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/translate_c.zig b/src/translate_c.zig index 47a21f5b5ce029bebc04046b690899de4823c8a6..a6715d161c9b9b69c51fdff3352a39e50e71c4e0 100644 --- a/src/translate_c.zig +++ b/src/translate_c.zig @@ -4519,7 +4519,10 @@ fn transCreateNodeAssign( defer block_scope.deinit(); const tmp = try block_scope.makeMangledName(c, "tmp"); - const rhs_node = try transExpr(c, &block_scope.base, rhs, .used); + var rhs_node = try transExpr(c, &block_scope.base, rhs, .used); + if (!exprIsBooleanType(lhs) and isBoolRes(rhs_node)) { + rhs_node = try Tag.bool_to_int.create(c.arena, rhs_node); + } const tmp_decl = try Tag.var_simple.create(c.arena, .{ .name = tmp, .init = rhs_node }); try block_scope.statements.append(tmp_decl); diff --git a/test/translate_c.zig b/test/translate_c.zig index 4ecb6835f5a9b12d8780936148db4428164ea0ec..d2db895a5a24633bb8b2c0643e4569d9b67ea888 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -3900,4 +3900,20 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub const ZERO = @as(c_int, 0); \\pub const WORLD = @as(c_int, 0o0000123); }); + + cases.add("Assign expression from bool to int", + \\void foo(void) { + \\ int a; + \\ if (a = 1 > 0) {} + \\} + , &[_][]const u8{ + \\pub export fn foo() void { + \\ var a: c_int = undefined; + \\ if ((blk: { + \\ const tmp = @boolToInt(@as(c_int, 1) > @as(c_int, 0)); + \\ a = tmp; + \\ break :blk tmp; + \\ }) != 0) {} + \\} + }); } -- 2.54.0 From 1fba88450db12f184d76f0651f7ca933322c1fc0 Mon Sep 17 00:00:00 2001 From: Josh Holland Date: Fri, 27 Jan 2023 18:29:28 +0000 Subject: [PATCH 72/84] langref: add paragraph and examples about indexing non-ASCII strings PR #10610 addressed most of the points from #1854. This additional paragraph and examples covers the OMISSIONS section clarifying issues about indexing into non-ASCII strings (whether valid UTF-8 or not). I think this finally closes #1854. --- doc/langref.html.in | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/doc/langref.html.in b/doc/langref.html.in index 00a263bae2b2509004dbe2c8a87c9290f208b649..2e16c0c9e684e5e18a46ba2670fb88b3a2454790 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -871,6 +871,13 @@ pub fn main() void { However, it is possible to embed non-UTF-8 bytes into a string literal using \xNN notation.

+ Indexing into a string containing non-ASCII bytes will return individual bytes, whether valid + UTF-8 or not. + The {#link|Zig Standard Library#} provides routines for checking the validity of UTF-8 encoded + strings, accessing their code points and other encoding/decoding related tasks in + {#syntax#}std.unicode{#endsyntax#}. +

+

Unicode code point literals have type {#syntax#}comptime_int{#endsyntax#}, the same as {#link|Integer Literals#}. All {#link|Escape Sequences#} are valid in both string literals and Unicode code point literals. @@ -894,9 +901,12 @@ pub fn main() void { print("{}\n", .{'e' == '\x65'}); // true print("{d}\n", .{'\u{1f4a9}'}); // 128169 print("{d}\n", .{'💯'}); // 128175 - print("{}\n", .{mem.eql(u8, "hello", "h\x65llo")}); // true - print("0x{x}\n", .{"\xff"[0]}); // non-UTF-8 strings are possible with \xNN notation. print("{u}\n", .{'âš¡'}); + print("{}\n", .{mem.eql(u8, "hello", "h\x65llo")}); // true + print("{}\n", .{mem.eql(u8, "💯", "\xf0\x9f\x92\xaf")}); // also true + const invalid_utf8 = "\xff\xfe"; // non-UTF-8 strings are possible with \xNN notation. + print("0x{x}\n", .{invalid_utf8[1]}); // indexing them returns individual bytes... + print("0x{x}\n", .{"💯"[1]}); // ...as does indexing part-way through non-ASCII characters } {#code_end#} {#see_also|Arrays|Source Encoding#} -- 2.54.0 From 629c3108aa71f94bd26dba8d4f20c9f3a3945bd4 Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Wed, 1 Feb 2023 21:41:02 +0200 Subject: [PATCH 73/84] AstGen: fix orelse type coercion in call arguments Closes #14506 --- src/AstGen.zig | 8 +++++++- test/behavior/basic.zig | 18 ++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/AstGen.zig b/src/AstGen.zig index a5667ce9e8664e0f892429c22ee62a09b45fda40..10673a2b37e7fcd8c799e72a52ec3ffc79aba58b 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -8721,6 +8721,7 @@ fn callExpr( defer arg_block.unstack(); // `call_inst` is reused to provide the param type. + arg_block.rl_ty_inst = call_inst; const arg_ref = try expr(&arg_block, &arg_block.base, .{ .rl = .{ .coerced_ty = call_inst }, .ctx = .fn_arg }, param_node); _ = try arg_block.addBreak(.break_inline, call_index, arg_ref); @@ -10869,7 +10870,12 @@ const GenZir = struct { // we emit ZIR for the block break instructions to have the result values, // and then rvalue() on that to pass the value to the result location. switch (parent_ri.rl) { - .ty, .coerced_ty => |ty_inst| { + .coerced_ty => |ty_inst| { + // Type coercion needs to happend before breaks. + gz.rl_ty_inst = ty_inst; + gz.break_result_info = .{ .rl = .{ .ty = ty_inst } }; + }, + .ty => |ty_inst| { gz.rl_ty_inst = ty_inst; gz.break_result_info = parent_ri; }, diff --git a/test/behavior/basic.zig b/test/behavior/basic.zig index 8a97b3cbcd3e788ec6fc171bcfbb31753e3111d5..b82bfab99ed30a412007535eb908907661ae6f09 100644 --- a/test/behavior/basic.zig +++ b/test/behavior/basic.zig @@ -1125,3 +1125,21 @@ test "returning an opaque type from a function" { }; try expect(S.foo(123).b == 123); } + +test "orelse coercion as function argument" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + + const Loc = struct { start: i32 = -1 }; + const Container = struct { + a: ?Loc = null, + fn init(a: Loc) @This() { + return .{ + .a = a, + }; + } + }; + var optional: ?Loc = .{}; + var foo = Container.init(optional orelse .{}); + try expect(foo.a.?.start == -1); +} -- 2.54.0 From ea6e0e33a7630fb78550a5567a98420c3377350c Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 1 Feb 2023 18:42:29 -0700 Subject: [PATCH 74/84] zig build: add executable bit and file path to package hash Unfortunately, due to the Windows equivalent of executable permissions being a bit tricky, there is follow-up work to be done. What is done in this commit is the hash modifications. At the fetch layer, executable bits inside packages are ignored. In the hash computation layer, executable bit is implemented for POSIX but not yet for Windows. This means that the hash will not break again in the future for packages that do not have any executable files, but it will break for packages that do. This is a hash-breaking change. Closes #14308 --- lib/std/fs/file.zig | 3 ++- lib/std/tar.zig | 23 +++++++++++++++++++++++ src/Package.zig | 24 +++++++++++++++++++++++- 3 files changed, 48 insertions(+), 2 deletions(-) diff --git a/lib/std/fs/file.zig b/lib/std/fs/file.zig index a6ecc37d92146278bd72d3c18a277fc8547d8533..1ba4bc18fdc5a14b7b2a732cbe70d8672242934f 100644 --- a/lib/std/fs/file.zig +++ b/lib/std/fs/file.zig @@ -179,7 +179,7 @@ pub const File = struct { lock_nonblocking: bool = false, /// For POSIX systems this is the file system mode the file will - /// be created with. + /// be created with. On other systems this is always 0. mode: Mode = default_mode, /// Setting this to `.blocking` prevents `O.NONBLOCK` from being passed even @@ -307,6 +307,7 @@ pub const File = struct { /// is unique to each filesystem. inode: INode, size: u64, + /// This is available on POSIX systems and is always 0 otherwise. mode: Mode, kind: Kind, diff --git a/lib/std/tar.zig b/lib/std/tar.zig index 4f6a77c6ba45adefe1a969b2d8fe30070069f74a..91772d7319137ca74d8db0272520d5d649e405bf 100644 --- a/lib/std/tar.zig +++ b/lib/std/tar.zig @@ -1,6 +1,18 @@ pub const Options = struct { /// Number of directory levels to skip when extracting files. strip_components: u32 = 0, + /// How to handle the "mode" property of files from within the tar file. + mode_mode: ModeMode = .executable_bit_only, + + const ModeMode = enum { + /// The mode from the tar file is completely ignored. Files are created + /// with the default mode when creating files. + ignore, + /// The mode from the tar file is inspected for the owner executable bit + /// only. This bit is copied to the group and other executable bits. + /// Other bits of the mode are left as the default when creating files. + executable_bit_only, + }; }; pub const Header = struct { @@ -72,6 +84,17 @@ pub const Header = struct { }; pub fn pipeToFileSystem(dir: std.fs.Dir, reader: anytype, options: Options) !void { + switch (options.mode_mode) { + .ignore => {}, + .executable_bit_only => { + // This code does not look at the mode bits yet. To implement this feature, + // the implementation must be adjusted to look at the mode, and check the + // user executable bit, then call fchmod on newly created files when + // the executable bit is supposed to be set. + // It also needs to properly deal with ACLs on Windows. + @panic("TODO: unimplemented: tar ModeMode.executable_bit_only"); + }, + } var file_name_buffer: [255]u8 = undefined; var buffer: [512 * 8]u8 = undefined; var start: usize = 0; diff --git a/src/Package.zig b/src/Package.zig index ebe84b8444d33f40bc5fc8d10026c456fbd9af0a..0f036b9ef5b050478d154c82f5d4d1202fbe7edc 100644 --- a/src/Package.zig +++ b/src/Package.zig @@ -1,5 +1,6 @@ const Package = @This(); +const builtin = @import("builtin"); const std = @import("std"); const fs = std.fs; const mem = std.mem; @@ -440,6 +441,12 @@ fn unpackTarball( try std.tar.pipeToFileSystem(out_dir, decompress.reader(), .{ .strip_components = 1, + // TODO: we would like to set this to executable_bit_only, but two + // things need to happen before that: + // 1. the tar implementation needs to support it + // 2. the hashing algorithm here needs to support detecting the is_executable + // bit on Windows from the ACLs (see the isExecutable function). + .mode_mode = .ignore, }); } @@ -468,7 +475,7 @@ const HashedFile = struct { hash: [Hash.digest_length]u8, failure: Error!void, - const Error = fs.File.OpenError || fs.File.ReadError; + const Error = fs.File.OpenError || fs.File.ReadError || fs.File.StatError; fn lessThan(context: void, lhs: *const HashedFile, rhs: *const HashedFile) bool { _ = context; @@ -544,6 +551,8 @@ fn hashFileFallible(dir: fs.Dir, hashed_file: *HashedFile) HashedFile.Error!void var buf: [8000]u8 = undefined; var file = try dir.openFile(hashed_file.path, .{}); var hasher = Hash.init(.{}); + hasher.update(hashed_file.path); + hasher.update(&.{ 0, @boolToInt(try isExecutable(file)) }); while (true) { const bytes_read = try file.read(&buf); if (bytes_read == 0) break; @@ -552,6 +561,19 @@ fn hashFileFallible(dir: fs.Dir, hashed_file: *HashedFile) HashedFile.Error!void hasher.final(&hashed_file.hash); } +fn isExecutable(file: fs.File) !bool { + if (builtin.os.tag == .windows) { + // TODO check the ACL on Windows. + // Until this is implemented, this could be a false negative on + // Windows, which is why we do not yet set executable_bit_only above + // when unpacking the tarball. + return false; + } else { + const stat = try file.stat(); + return (stat.mode & std.os.S.IXUSR) != 0; + } +} + const hex_charset = "0123456789abcdef"; fn hex64(x: u64) [16]u8 { -- 2.54.0 From 24ff8a1a5fc00c405e5506251f11d23653d6c8b5 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 1 Feb 2023 20:02:35 -0700 Subject: [PATCH 75/84] zig build: use multihash for the hash field https://multiformats.io/multihash/ Still, only SHA2-256 is supported. This is only intended to future-proof the hash field of the manifest. closes #14284 --- src/Package.zig | 76 +++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 67 insertions(+), 9 deletions(-) diff --git a/src/Package.zig b/src/Package.zig index 0f036b9ef5b050478d154c82f5d4d1202fbe7edc..35b1ff505627803018051aef8b8351c4e299717b 100644 --- a/src/Package.zig +++ b/src/Package.zig @@ -299,16 +299,37 @@ fn fetchAndUnpack( // Check if the expected_hash is already present in the global package // cache, and thereby avoid both fetching and unpacking. if (expected_hash) |h| cached: { - if (h.len != 2 * Hash.digest_length) { + const hex_multihash_len = 2 * multihash_len; + if (h.len >= 2) { + const their_multihash_func = std.fmt.parseInt(u8, h[0..2], 16) catch |err| { + return reportError( + ini, + comp_directory, + h.ptr, + "invalid multihash value: unable to parse hash function: {s}", + .{@errorName(err)}, + ); + }; + if (@intToEnum(MultihashFunction, their_multihash_func) != multihash_function) { + return reportError( + ini, + comp_directory, + h.ptr, + "unsupported hash function: only sha2-256 is supported", + .{}, + ); + } + } + if (h.len != hex_multihash_len) { return reportError( ini, comp_directory, h.ptr, "wrong hash size. expected: {d}, found: {d}", - .{ Hash.digest_length, h.len }, + .{ hex_multihash_len, h.len }, ); } - const hex_digest = h[0 .. 2 * Hash.digest_length]; + const hex_digest = h[0..hex_multihash_len]; const pkg_dir_sub_path = "p" ++ s ++ hex_digest; var pkg_dir = global_cache_directory.handle.openDir(pkg_dir_sub_path, .{}) catch |err| switch (err) { error.FileNotFound => break :cached, @@ -397,8 +418,8 @@ fn fetchAndUnpack( const pkg_dir_sub_path = "p" ++ s ++ hexDigest(actual_hash); try renameTmpIntoCache(global_cache_directory.handle, tmp_dir_sub_path, pkg_dir_sub_path); + const actual_hex = hexDigest(actual_hash); if (expected_hash) |h| { - const actual_hex = hexDigest(actual_hash); if (!mem.eql(u8, h, &actual_hex)) { return reportError( ini, @@ -414,7 +435,7 @@ fn fetchAndUnpack( comp_directory, url.ptr, "url field is missing corresponding hash field: hash={s}", - .{std.fmt.fmtSliceHexLower(&actual_hash)}, + .{&actual_hex}, ); } @@ -592,11 +613,30 @@ test hex64 { try std.testing.expectEqualStrings("[00efcdab78563412]", s); } -fn hexDigest(digest: [Hash.digest_length]u8) [Hash.digest_length * 2]u8 { - var result: [Hash.digest_length * 2]u8 = undefined; +const multihash_function: MultihashFunction = switch (Hash) { + std.crypto.hash.sha2.Sha256 => .@"sha2-256", + else => @compileError("unreachable"), +}; +comptime { + // We avoid unnecessary uleb128 code in hexDigest by asserting here the + // values are small enough to be contained in the one-byte encoding. + assert(@enumToInt(multihash_function) < 127); + assert(Hash.digest_length < 127); +} +const multihash_len = 1 + 1 + Hash.digest_length; + +fn hexDigest(digest: [Hash.digest_length]u8) [multihash_len * 2]u8 { + var result: [multihash_len * 2]u8 = undefined; + + result[0] = hex_charset[@enumToInt(multihash_function) >> 4]; + result[1] = hex_charset[@enumToInt(multihash_function) & 15]; + + result[2] = hex_charset[Hash.digest_length >> 4]; + result[3] = hex_charset[Hash.digest_length & 15]; + for (digest) |byte, i| { - result[i * 2 + 0] = hex_charset[byte >> 4]; - result[i * 2 + 1] = hex_charset[byte & 15]; + result[4 + i * 2] = hex_charset[byte >> 4]; + result[5 + i * 2] = hex_charset[byte & 15]; } return result; } @@ -629,3 +669,21 @@ fn renameTmpIntoCache( break; } } + +const MultihashFunction = enum(u16) { + identity = 0x00, + sha1 = 0x11, + @"sha2-256" = 0x12, + @"sha2-512" = 0x13, + @"sha3-512" = 0x14, + @"sha3-384" = 0x15, + @"sha3-256" = 0x16, + @"sha3-224" = 0x17, + @"sha2-384" = 0x20, + @"sha2-256-trunc254-padded" = 0x1012, + @"sha2-224" = 0x1013, + @"sha2-512-224" = 0x1014, + @"sha2-512-256" = 0x1015, + @"blake2b-256" = 0xb220, + _, +}; -- 2.54.0 From 72a7e3dc5e3d2128f4d95b7ba9554ea2e6e35139 Mon Sep 17 00:00:00 2001 From: praschke Date: Wed, 1 Feb 2023 20:52:06 +0000 Subject: [PATCH 76/84] mingw: stop using K&R-style function definitions this patch is from upstream, to fix -Wdeprecated-non-prototypes issues. K&R-style has apparently been deprecated since even C89, and C2x will be repurposing the syntax space. this warning triggers when the change would affect the meaning of the code. --- lib/libc/mingw/misc/strtoimax.c | 5 +---- lib/libc/mingw/misc/strtoumax.c | 5 +---- lib/libc/mingw/misc/wcstoimax.c | 5 +---- lib/libc/mingw/misc/wcstoumax.c | 5 +---- 4 files changed, 4 insertions(+), 16 deletions(-) diff --git a/lib/libc/mingw/misc/strtoimax.c b/lib/libc/mingw/misc/strtoimax.c index eef5da97cc93d80e3b1b84c2800861e82607c776..9e75f8a2750307fc4cb6dbe537f5bbcbe030c6e7 100644 --- a/lib/libc/mingw/misc/strtoimax.c +++ b/lib/libc/mingw/misc/strtoimax.c @@ -31,10 +31,7 @@ #define valid(n, b) ((n) >= 0 && (n) < (b)) intmax_t -strtoimax(nptr, endptr, base) - register const char * __restrict__ nptr; - char ** __restrict__ endptr; - register int base; +strtoimax(const char * __restrict__ nptr, char ** __restrict__ endptr, int base) { register uintmax_t accum; /* accumulates converted value */ register int n; /* numeral from digit character */ diff --git a/lib/libc/mingw/misc/strtoumax.c b/lib/libc/mingw/misc/strtoumax.c index e86cd761328d6513608b2390e7f755ad1e9d1a3e..2c24db14d8296c711161c8a9ab146ecd30a42279 100644 --- a/lib/libc/mingw/misc/strtoumax.c +++ b/lib/libc/mingw/misc/strtoumax.c @@ -31,10 +31,7 @@ #define valid(n, b) ((n) >= 0 && (n) < (b)) uintmax_t -strtoumax(nptr, endptr, base) - register const char * __restrict__ nptr; - char ** __restrict__ endptr; - register int base; +strtoumax(const char * __restrict__ nptr, char ** __restrict__ endptr, int base) { register uintmax_t accum; /* accumulates converted value */ register uintmax_t next; /* for computing next value of accum */ diff --git a/lib/libc/mingw/misc/wcstoimax.c b/lib/libc/mingw/misc/wcstoimax.c index 9821cf07cc29d68561bb4914a2d7d4bcb07b766a..99e97b92144ca450ca878b3f3b0fd9993f3056c0 100644 --- a/lib/libc/mingw/misc/wcstoimax.c +++ b/lib/libc/mingw/misc/wcstoimax.c @@ -33,10 +33,7 @@ #define valid(n, b) ((n) >= 0 && (n) < (b)) intmax_t -wcstoimax(nptr, endptr, base) - register const wchar_t * __restrict__ nptr; - wchar_t ** __restrict__ endptr; - register int base; +wcstoimax(const wchar_t * __restrict__ nptr, wchar_t ** __restrict__ endptr, int base) { register uintmax_t accum; /* accumulates converted value */ register int n; /* numeral from digit character */ diff --git a/lib/libc/mingw/misc/wcstoumax.c b/lib/libc/mingw/misc/wcstoumax.c index 0f1ed540c2c17825b0a352bb2dff2515eb9b32fa..97f2c3083372ad83d5ce5744f8a047bfc781956f 100644 --- a/lib/libc/mingw/misc/wcstoumax.c +++ b/lib/libc/mingw/misc/wcstoumax.c @@ -33,10 +33,7 @@ #define valid(n, b) ((n) >= 0 && (n) < (b)) uintmax_t -wcstoumax(nptr, endptr, base) - register const wchar_t * __restrict__ nptr; - wchar_t ** __restrict__ endptr; - register int base; +wcstoumax(const wchar_t * __restrict__ nptr, wchar_t ** __restrict__ endptr, int base) { register uintmax_t accum; /* accumulates converted value */ register uintmax_t next; /* for computing next value of accum */ -- 2.54.0 From e712d5f03e6e3ddde6a4a6f7d2d82e786efd543a Mon Sep 17 00:00:00 2001 From: Kirk Scheibelhut Date: Wed, 1 Feb 2023 10:15:58 -0800 Subject: [PATCH 77/84] remove reference to removed addTestExe --- lib/std/Build/InstallArtifactStep.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/std/Build/InstallArtifactStep.zig b/lib/std/Build/InstallArtifactStep.zig index 8ee739a41c20bd761ec5bd95c1a5fa216d5d9710..c419c85fdf16640e8d8c26d3fa1a74936b626907 100644 --- a/lib/std/Build/InstallArtifactStep.zig +++ b/lib/std/Build/InstallArtifactStep.zig @@ -23,7 +23,7 @@ pub fn create(builder: *std.Build, artifact: *CompileStep) *InstallArtifactStep .artifact = artifact, .dest_dir = artifact.override_dest_dir orelse switch (artifact.kind) { .obj => @panic("Cannot install a .obj build artifact."), - .@"test" => @panic("Cannot install a test build artifact, use addTestExe instead."), + .@"test" => @panic("Cannot install a .test build artifact, use .test_exe instead."), .exe, .test_exe => InstallDir{ .bin = {} }, .lib => InstallDir{ .lib = {} }, }, -- 2.54.0 From c3abb63fe99eb7091e5841f8e65f197b77d868a8 Mon Sep 17 00:00:00 2001 From: Krzysztof Wolicki Der Teufel Date: Thu, 2 Feb 2023 14:46:42 +0100 Subject: [PATCH 78/84] autodoc: Added `@qualCast` builtin function handling --- lib/docs/main.js | 4 ++++ src/Autodoc.zig | 1 + 2 files changed, 5 insertions(+) diff --git a/lib/docs/main.js b/lib/docs/main.js index d488d018a66dbe4d5775e41a2481a4cc78306096..62af5866b64290b0985ec4bdad302718dfd1995b 100644 --- a/lib/docs/main.js +++ b/lib/docs/main.js @@ -1354,6 +1354,10 @@ const NAV_MODES = { payloadHtml += "ptrCast"; break; } + case "qual_cast": { + payloadHtml += "qualCast"; + break; + } case "truncate": { payloadHtml += "truncate"; break; diff --git a/src/Autodoc.zig b/src/Autodoc.zig index 8afc9c859b5a7aa8c2b2d0eaa94f884db411c3b8..0798ec198fe86d20623a6a8eacfd69910b3baf64 100644 --- a/src/Autodoc.zig +++ b/src/Autodoc.zig @@ -1400,6 +1400,7 @@ fn walkInstruction( .float_cast, .int_cast, .ptr_cast, + .qual_cast, .truncate, .align_cast, .has_decl, -- 2.54.0 From 03cdb4fb5853109e46bdc08d8a849a23780093ae Mon Sep 17 00:00:00 2001 From: Jan Philipp Hafer Date: Thu, 26 Jan 2023 22:44:39 +0100 Subject: [PATCH 79/84] compiler_rt: make README visually nice and improve explanations This commit makes the text more dense with sources, noes the outstanding audit and adds an explanation of the table before converting everything to markdown tables. For the status a checkmark or cross in utf8 encoding are used and the input and output sizes of all operations are given inclusive comments for understanding of the routines. This should document all compiler_rt integer and float routines, but does not include a documentation of existing ieee floating and math routines. --- lib/compiler_rt/README.md | 993 ++++++++++++++++++++------------------ 1 file changed, 528 insertions(+), 465 deletions(-) diff --git a/lib/compiler_rt/README.md b/lib/compiler_rt/README.md index b2c6a10695ab45b92feb1591242ed7006c983e8f..8e838dfcedfac8ffd1ba3a5f6d26c16ebdc98d70 100644 --- a/lib/compiler_rt/README.md +++ b/lib/compiler_rt/README.md @@ -27,482 +27,545 @@ then statically linked and therefore is a transparent dependency for the programmer. For details see `../compiler_rt.zig`. -The routines in this folder are listed below. -Routines are annotated as `type source routine // description`, with `routine` -being the name used in aforementioned `compiler_rt.zig`. -`dev` means deviating from compiler_rt, `port` ported, `source` is the -information source for the implementation, `none` means unimplemented. -Some examples for the naming convention are: -- dev source name_routine, name_routine2 various implementations for performance, simplicity etc -- port llvm compiler-rt library routines from [LLVM](http://compiler-rt.llvm.org/) - * LLVM emits library calls to compiler-rt, if the hardware lacks functionality -- port musl libc routines from [musl](https://musl.libc.org/) -If the library or information source is uncommon, use the entry `other` for `source`. -Please do not break the search by inserting entries in another format than `impl space source`. - Bugs should be solved by trying to duplicate the bug upstream, if possible. * If the bug exists upstream, get it fixed upstream and port the fix downstream to Zig. * If the bug only exists in Zig, use the corresponding C code and debug both implementations side by side to figure out what is wrong. -## Integer library routines +Routines with status are given below. Sources were besides +"The Art of Computer Programming" by Donald E. Knuth, "HackersDelight" by Henry S. Warren, +"Bit Twiddling Hacks" collected by Sean Eron Anderson, "Berkeley SoftFloat" by John R. Hauser, +LLVM "compiler-rt" as it was MIT-licensed, "musl libc" and thoughts + work of contributors. -#### Integer Bit operations +The compiler-rt routines have not yet been audited. +See https://github.com/ziglang/zig/issues/1504. -- dev HackersDelight __clzsi2 // count leading zeros -- dev HackersDelight __clzdi2 // count leading zeros -- dev HackersDelight __clzti2 // count leading zeros -- dev HackersDelight __ctzsi2 // count trailing zeros -- dev HackersDelight __ctzdi2 // count trailing zeros -- dev HackersDelight __ctzti2 // count trailing zeros -- dev __ctzsi2 __ffssi2 // find least significant 1 bit -- dev __ctzsi2 __ffsdi2 // find least significant 1 bit -- dev __ctzsi2 __ffsti2 // find least significant 1 bit -- dev BitTwiddlingHacks __paritysi2 // bit parity -- dev BitTwiddlingHacks __paritydi2 // bit parity -- dev BitTwiddlingHacks __parityti2 // bit parity -- dev TAOCP __popcountsi2 // bit population -- dev TAOCP __popcountdi2 // bit population -- dev TAOCP __popcountti2 // bit population -- dev other __bswapsi2 // a byteswapped -- dev other __bswapdi2 // a byteswapped -- dev other __bswapti2 // a byteswapped +From left to right the columns mean 1. if the routine is implemented (✗ or ✓), +2. the name, 3. input (`a`), 4. input (`b`), 5. return value, +6. an explanation of the functionality, .. to repeat the comment from the +column a row above and/or additional return values. +Some routines have more extensive comments supplemented with a reference text. -#### Integer Comparison +Integer and Float Operations -- port llvm __cmpsi2 // a,b: i32, (a 0, (a==b) -> 1, (a>b) -> 2 -- port llvm __cmpdi2 // a,b: i64 -- port llvm __cmpti2 // a,b: i128 -- port llvm __ucmpsi2 // a,b: u32, (a 0, (a==b) -> 1, (a>b) -> 2 -- port llvm __ucmpdi2 // a,b: u64 -- port llvm __ucmpti2 // a,b: u128 +| Done | Name | a | b | Out | Comment | +| ------ | ------------- | ---- | ---- | ---- | ------------------------------ | +| | | | | | **Integer Bit Operations** | +| ✓ | __clzsi2 | u32 | ∅ | i32 | count leading zeroes | +| ✓ | __clzdi2 | u64 | ∅ | i32 | count leading zeroes | +| ✓ | __clzti2 | u128 | ∅ | i32 | count trailing zeros | +| ✓ | __ctzsi2 | u32 | ∅ | i32 | count trailing zeros | +| ✓ | __ctzdi2 | u64 | ∅ | i32 | count trailing zeros | +| ✓ | __ctzti2 | u128 | ∅ | i32 | count leading zeroes | +| ✓ | __ffssi2 | u32 | ∅ | i32 | count leading zeroes | +| ✓ | __ffsdi2 | u64 | ∅ | i32 | count leading zeroes | +| ✓ | __ffsti2 | u128 | ∅ | i32 | count leading zeroes | +| ✓ | __paritysi2 | u32 | ∅ | i32 | find least significant 1 bit | +| ✓ | __paritydi2 | u64 | ∅ | i32 | find least significant 1 bit | +| ✓ | __parityti2 | u128 | ∅ | i32 | find least significant 1 bit | +| ✓ | __popcountsi2 | u32 | ∅ | i32 | bit population | +| ✓ | __popcountdi2 | u64 | ∅ | i32 | bit population | +| ✓ | __popcountti2 | u128 | ∅ | i32 | bit population | +| ✓ | __bswapsi2 | u32 | ∅ | i32 | bit parity | +| ✓ | __bswapdi2 | u64 | ∅ | i32 | bit parity | +| ✓ | __bswapti2 | u128 | ∅ | i32 | bit parity | +| | | | | | **Integer Comparison** | +| ✓ | __cmpsi2 | i32 | i32 | i32 | `(a 0, (a==b) -> 1, (a>b) -> 2` | +| ✓ | __cmpdi2 | i64 | i64 | i32 | .. | +| ✓ | __cmpti2 | i128 | i128 | i32 | .. | +| ✓ | __ucmpsi2 | i32 | i32 | i32 | `(a 0, (a==b) -> 1, (a>b) -> 2` | +| ✓ | __ucmpdi2 | i64 | i64 | i32 | .. | +| ✓ | __ucmpti2 | i128 | i128 | i32 | .. | +| | | | | | **Integer Arithmetic** | +| ✗ | __ashlsi3 | i32 | i32 | i32 | `a << b` [^unused_rl78] | +| ✓ | __ashldi3 | i64 | i32 | i64 | .. | +| ✓ | __ashlti3 | i128 | i32 | i128 | .. | +| ✓ | __aeabi_llsl | i32 | i32 | i32 | .. ARM | +| ✗ | __ashrsi3 | i32 | i32 | i32 | `a >> b` arithmetic (sign fill) [^unused_rl78] | +| ✓ | __ashrdi3 | i64 | i32 | i64 | .. | +| ✓ | __ashrti3 | i128 | i32 | i128 | .. | +| ✓ | __aeabi_lasr | i64 | i32 | i64 | .. ARM | +| ✗ | __lshrsi3 | i32 | i32 | i32 | `a >> b` logical (zero fill) [^unused_rl78] | +| ✓ | __lshrdi3 | i64 | i32 | i64 | .. | +| ✓ | __lshrti3 | i128 | i32 | i128 | .. | +| ✓ | __aeabi_llsr | i64 | i32 | i64 | .. ARM | +| ✓ | __negsi2 | i32 | i32 | i32 | `-a` [^libgcc_compat] | +| ✓ | __negdi2 | i64 | i64 | i64 | .. | +| ✓ | __negti2 | i128 | i128 | i128 | .. | +| ✓ | __mulsi3 | i32 | i32 | i32 | `a * b` | +| ✓ | __muldi3 | i64 | i64 | i64 | .. | +| ✓ | __multi3 | i128 | i128 | i128 | .. | +| ✓ | __divsi3 | i32 | i32 | i32 | `a / b` | +| ✓ | __divdi3 | i64 | i64 | i64 | .. | +| ✓ | __divti3 | i128 | i128 | i128 | .. | +| ✓ | __aeabi_idiv | i32 | i32 | i32 | .. ARM | +| ✓ | __udivsi3 | u32 | u32 | u32 | `a / b` | +| ✓ | __udivdi3 | u64 | u64 | u64 | .. | +| ✓ | __udivti3 | u128 | u128 | u128 | .. | +| ✓ | __aeabi_uidiv | i32 | i32 | i32 | .. ARM | +| ✓ | __modsi3 | i32 | i32 | i32 | `a % b` | +| ✓ | __moddi3 | i64 | i64 | i64 | .. | +| ✓ | __modti3 | i128 | i128 | i128 | .. | +| ✓ | __umodsi3 | u32 | u32 | u32 | `a % b` | +| ✓ | __umoddi3 | u64 | u64 | u64 | .. | +| ✓ | __umodti3 | u128 | u128 | u128 | .. | +| ✓ | __udivmodsi4 | u32 | u32 | u32 | `a / b, rem.* = a % b` | +| ✓ | __udivmoddi4 | u64 | u64 | u64 | .. | +| ✓ | __udivmodti4 | u128 | u128 | u128 | .. | +| ✓ | __divmodsi4 | i32 | i32 | i32 | `a / b, rem.* = a % b` | +| ✓ | __divmoddi4 | i64 | i64 | i64 | .. | +| ✗ | __divmodti4 | i128 | i128 | i128 | .. [^libgcc_compat] | +| | | | | | **Integer Arithmetic with Trapping Overflow**| +| ✓ | __absvsi2 | i32 | i32 | i32 | abs(a) | +| ✓ | __absvdi2 | i64 | i64 | i64 | .. | +| ✓ | __absvti2 | i128 | i128 | i128 | .. | +| ✓ | __negvsi2 | i32 | i32 | i32 | `-a` [^libgcc_compat] | +| ✓ | __negvdi2 | i64 | i64 | i64 | .. | +| ✓ | __negvti2 | i128 | i128 | i128 | .. | +| ✗ | __addvsi3 | i32 | i32 | i32 | `a + b` | +| ✗ | __addvdi3 | i64 | i64 | i64 | .. | +| ✗ | __addvti3 | i128 | i128 | i128 | .. | +| ✗ | __subvsi3 | i32 | i32 | i32 | `a - b` | +| ✗ | __subvdi3 | i64 | i64 | i64 | .. | +| ✗ | __subvti3 | i128 | i128 | i128 | .. | +| ✗ | __mulvsi3 | i32 | i32 | i32 | `a * b` | +| ✗ | __mulvdi3 | i64 | i64 | i64 | .. | +| ✗ | __mulvti3 | i128 | i128 | i128 | .. | +| | | | | | **Integer Arithmetic which Return on Overflow** [^noptr_faster] | +| ✓ | __addosi4 | i32 | i32 | i32 | `a + b`, overflow->ov.*=1 else 0 [^perf_addition] | +| ✓ | __addodi4 | i64 | i64 | i64 | .. | +| ✓ | __addoti4 | i128 | i128 | i128 | .. | +| ✓ | __subosi4 | i32 | i32 | i32 | `a - b`, overflow->ov.*=1 else 0 [^perf_addition] | +| ✓ | __subodi4 | i64 | i64 | i64 | .. | +| ✓ | __suboti4 | i128 | i128 | i128 | .. | +| ✓ | __mulosi4 | i32 | i32 | i32 | `a * b`, overflow->ov.*=1 else 0 | +| ✓ | __mulodi4 | i64 | i64 | i64 | .. | +| ✓ | __muloti4 | i128 | i128 | i128 | .. | +| | | | | | **Float Conversion** | +| ✓ | __extendsfdf2 | f32 | ∅ | f64 | .. | +| ✓ | __extendsftf2 | f32 | ∅ | f128 | .. | +| ✓ | __extendsfxf2 | f32 | ∅ | f80 | .. | +| ✓ | __extenddftf2 | f64 | ∅ | f128 | .. | +| ✓ | __extenddfxf2 | f64 | ∅ | f80 | .. | +| ✓ | __truncsfhf2 | f32 | ∅ | f16 | rounding towards zero | +| ✓ | __truncdfhf2 | f64 | ∅ | f16 | .. | +| ✓ | __truncdfsf2 | f64 | ∅ | f32 | .. | +| ✓ | __trunctfhf2 | f128 | ∅ | f16 | .. | +| ✓ | __trunctfsf2 | f128 | ∅ | f32 | .. | +| ✓ | __trunctfdf2 | f128 | ∅ | f64 | .. | +| ✓ | __trunctfxf2 | f128 | ∅ | f80 | .. | +| ✓ | __truncxfhf2 | f80 | ∅ | f16 | .. | +| ✓ | __truncxfsf2 | f80 | ∅ | f32 | .. | +| ✓ | __truncxfdf2 | f80 | ∅ | f64 | .. | +| ✓ | __aeabi_f2h | f32 | ∅ | f16 | .. ARM | +| ✓ | __gnu_f2h_ieee | f32 | ∅ | f16 | ..GNU naming convention | +| ✓ | __aeabi_d2h | f64 | ∅ | f16 | .. ARM | +| ✓ | __aeabi_d2f | f64 | ∅ | f32 | .. ARM | +| ✓ | __trunckfsf2 | f128 | ∅ | f32 | .. PPC | +| ✓ | _Qp_qtos |*f128 | ∅ | f32 | .. SPARC | +| ✓ | __trunckfdf2 | f128 | ∅ | f64 | .. PPC | +| ✓ | _Qp_qtod |*f128 | ∅ | f64 | .. SPARC | +| ✓ | __fixhfsi | f16 | ∅ | i32 | rounding towards zero | +| ✓ | __fixsfsi | f32 | ∅ | i32 | .. | +| ✓ | __fixdfsi | f64 | ∅ | i32 | .. | +| ✓ | __fixtfsi | f128 | ∅ | i32 | .. | +| ✓ | __fixxfsi | f80 | ∅ | i32 | .. | +| ✓ | __fixhfdi | f16 | ∅ | i64 | .. | +| ✓ | __fixsfdi | f32 | ∅ | i64 | .. | +| ✓ | __fixdfdi | f64 | ∅ | i64 | .. | +| ✓ | __fixtfdi | f128 | ∅ | i64 | .. | +| ✓ | __fixxfdi | f80 | ∅ | i64 | .. | +| ✓ | __fixhfti | f16 | ∅ | i128 | .. | +| ✓ | __fixsfti | f32 | ∅ | i128 | .. | +| ✓ | __fixdfti | f64 | ∅ | i128 | .. | +| ✓ | __fixtfti | f128 | ∅ | i128 | .. | +| ✓ | __fixxfti | f80 | ∅ | i128 | .. | +| ✓ | __fixunshfsi | f16 | ∅ | u32 | rounding towards zero. negative values become 0. | +| ✓ | __fixunssfsi | f32 | ∅ | u32 | .. | +| ✓ | __fixunsdfsi | f64 | ∅ | u32 | .. | +| ✓ | __fixunstfsi | f128 | ∅ | u32 | .. | +| ✓ | __fixunsxfsi | f80 | ∅ | u32 | .. | +| ✓ | __fixunshfdi | f16 | ∅ | u64 | .. | +| ✓ | __fixunssfdi | f32 | ∅ | u64 | .. | +| ✓ | __fixunsdfdi | f64 | ∅ | u64 | .. | +| ✓ | __fixunstfdi | f128 | ∅ | u64 | .. | +| ✓ | __fixunsxfdi | f80 | ∅ | u64 | .. | +| ✓ | __fixunshfti | f16 | ∅ | u128 | .. | +| ✓ | __fixunssfti | f32 | ∅ | u128 | .. | +| ✓ | __fixunsdfti | f64 | ∅ | u128 | .. | +| ✓ | __fixunstfti | f128 | ∅ | u128 | .. | +| ✓ | __fixunsxfti | f80 | ∅ | u128 | .. | +| ✓ | __floatsihf | i32 | ∅ | f16 | int_to_float conversions | +| ✓ | __floatsisf | i32 | ∅ | f32 | .. | +| ✓ | __floatsidf | i32 | ∅ | f64 | .. | +| ✓ | __floatsitf | i32 | ∅ | f128 | .. | +| ✓ | __floatsixf | i32 | ∅ | f80 | .. | +| ✓ | __floatdisf | i64 | ∅ | f32 | .. | +| ✓ | __floatdidf | i64 | ∅ | f64 | .. | +| ✓ | __floatditf | i64 | ∅ | f128 | .. | +| ✓ | __floatdixf | i64 | ∅ | f80 | .. | +| ✓ | __floattihf | i128 | ∅ | f16 | .. | +| ✓ | __floattisf | i128 | ∅ | f32 | .. | +| ✓ | __floattidf | i128 | ∅ | f64 | .. | +| ✓ | __floattitf | i128 | ∅ | f128 | .. | +| ✓ | __floattixf | i128 | ∅ | f80 | .. | +| ✓ | __floatunsihf | u32 | ∅ | f16 | uint_to_float conversions | +| ✓ | __floatunsisf | u32 | ∅ | f32 | .. | +| ✓ | __floatunsidf | u32 | ∅ | f64 | .. | +| ✓ | __floatunsitf | u32 | ∅ | f128 | .. | +| ✓ | __floatunsixf | u32 | ∅ | f80 | .. | +| ✓ | __floatundihf | u64 | ∅ | f16 | .. | +| ✓ | __floatundisf | u64 | ∅ | f32 | .. | +| ✓ | __floatundidf | u64 | ∅ | f64 | .. | +| ✓ | __floatunditf | u64 | ∅ | f128 | .. | +| ✓ | __floatundixf | u64 | ∅ | f80 | .. | +| ✓ | __floatuntihf | u128 | ∅ | f16 | .. | +| ✓ | __floatuntisf | u128 | ∅ | f32 | .. | +| ✓ | __floatuntidf | u128 | ∅ | f64 | .. | +| ✓ | __floatuntitf | u128 | ∅ | f128 | .. | +| ✓ | __floatuntixf | u128 | ∅ | f80 | .. | +| | | | | | **Float Comparison** | +| ✓ | __cmphf2 | f16 | f16 | i32 | `(a-1, (a==b)->0, (a>b)->1, Nan->1` | +| ✓ | __cmpsf2 | f32 | f32 | i32 | exported from __lesf2, __ledf2, __letf2 (below) | +| ✓ | __cmpdf2 | f64 | f64 | i32 | But: if NaN is a possibility, use another routine. | +| ✓ | __cmptf2 | f128 | f128 | i32 | .. | +| ✓ | __cmpxf2 | f80 | f80 | i32 | .. | +| ✓ | _Qp_cmp |*f128 |*f128 | i32 | .. SPARC | +| ✓ | __unordhf2 | f16 | f16 | i32 | `(a==+-NaN or b==+-NaN) -> !=0, else -> 0` | +| ✓ | __unordsf2 | f32 | f32 | i32 | .. | +| ✓ | __unorddf2 | f64 | f64 | i32 | Note: only reliable for (input!=NaN) | +| ✓ | __unordtf2 | f128 | f128 | i32 | .. | +| ✓ | __unordxf2 | f80 | f80 | i32 | .. | +| ✓ | __aeabi_fcmpun | f32 | f32 | i32 | .. ARM | +| ✓ | __aeabi_dcmpun | f32 | f32 | i32 | .. ARM | +| ✓ | __unordkf2 | f128 | f128 | i32 | .. PPC | +| ✓ | __eqhf2 | f16 | f16 | i32 | `(a!=NaN) and (b!=Nan) and (a==b) -> output=0` | +| ✓ | __eqsf2 | f32 | f32 | i32 | .. | +| ✓ | __eqdf2 | f64 | f64 | i32 | .. | +| ✓ | __eqtf2 | f128 | f128 | i32 | .. | +| ✓ | __eqxf2 | f80 | f80 | i32 | .. | +| ✓ | __aeabi_fcmpeq | f32 | f32 | i32 | .. ARM | +| ✓ | __aeabi_dcmpeq | f32 | f32 | i32 | .. ARM | +| ✓ | __eqkf2 | f128 | f128 | i32 | .. PPC | +| ✓ | _Qp_feq |*f128 |*f128 | bool | .. SPARC | +| ✓ | __nehf2 | f16 | f16 | i32 | `(a==NaN) or (b==Nan) or (a!=b) -> output!=0` | +| ✓ | __nesf2 | f32 | f32 | i32 | Note: __eqXf2 and __neXf2 have same return value | +| ✓ | __nedf2 | f64 | f64 | i32 | .. | +| ✓ | __netf2 | f128 | f128 | i32 | .. | +| ✓ | __nexf2 | f80 | f80 | i32 | .. | +| ✓ | __nekf2 | f128 | f128 | i32 | .. PPC | +| ✓ | _Qp_fne |*f128 |*f128 | bool | .. SPARC | +| ✓ | __gehf2 | f16 | f16 | i32 | `(a!=Nan) and (b!=Nan) and (a>=b) -> output>=0` | +| ✓ | __gesf2 | f32 | f32 | i32 | .. | +| ✓ | __gedf2 | f64 | f64 | i32 | .. | +| ✓ | __getf2 | f128 | f128 | i32 | .. | +| ✓ | __gexf2 | f80 | f80 | i32 | .. | +| ✓ | __gekf2 | f128 | f128 | i32 | .. PPC | +| ✓ | _Qp_fge |*f128 |*f128 | bool | .. SPARC | +| ✓ | __lthf2 | f16 | f16 | i32 | `(a!=Nan) and (b!=Nan) and (a output<0` | +| ✓ | __ltsf2 | f32 | f32 | i32 | .. | +| ✓ | __ltdf2 | f64 | f64 | i32 | .. | +| ✓ | __lttf2 | f128 | f128 | i32 | .. | +| ✓ | __ltxf2 | f80 | f80 | i32 | .. | +| ✓ | __ltkf2 | f128 | f128 | i32 | .. PPC | +| ✓ | __aeabi_fcmplt | f32 | f32 | i32 | .. ARM | +| ✓ | __aeabi_dcmplt | f32 | f32 | i32 | .. ARM | +| ✓ | _Qp_flt |*f128 |*f128 | bool | .. SPARC | +| ✓ | __lehf2 | f16 | f16 | i32 | `(a!=Nan) and (b!=Nan) and (a<=b) -> output<=0` | +| ✓ | __lesf2 | f32 | f32 | i32 | .. | +| ✓ | __ledf2 | f64 | f64 | i32 | .. | +| ✓ | __letf2 | f128 | f128 | i32 | .. | +| ✓ | __lexf2 | f80 | f80 | i32 | .. | +| ✓ | __aeabi_fcmple | f32 | f32 | i32 | .. ARM | +| ✓ | __aeabi_dcmple | f32 | f32 | i32 | .. ARM | +| ✓ | __lekf2 | f128 | f128 | i32 | .. PPC | +| ✓ | _Qp_fle |*f128 |*f128 | bool | .. SPARC | +| ✓ | __gthf2 | f16 | f16 | i32 | `(a!=Nan) and (b!=Nan) and (a>b) -> output>0` | +| ✓ | __gtsf2 | f32 | f32 | i32 | .. | +| ✓ | __gtdf2 | f64 | f64 | i32 | .. | +| ✓ | __gttf2 | f128 | f128 | i32 | .. | +| ✓ | __gtxf2 | f80 | f80 | i32 | .. | +| ✓ | __gtkf2 | f128 | f128 | i32 | .. PPC | +| ✓ | _Qp_fgt |*f128 |*f128 | bool | .. SPARC | +| | | | | | **Float Arithmetic** | +| ✓ | __addhf3 | f32 | f32 | f32 | `a + b` | +| ✓ | __addsf3 | f32 | f32 | f32 | .. | +| ✓ | __adddf3 | f64 | f64 | f64 | .. | +| ✓ | __addtf3 | f128 | f128 | f128 | .. | +| ✓ | __addxf3 | f80 | f80 | f80 | .. | +| ✓ | __aeabi_fadd | f32 | f32 | f32 | .. ARM | +| ✓ | __aeabi_dadd | f64 | f64 | f64 | .. ARM | +| ✓ | __addkf3 | f128 | f128 | f128 | .. PPC | +| ✓ | _Qp_add |*f128 |*f128 | void | .. SPARC args *c,*a,*b c=a+b | +| ✓ | __subhf3 | f32 | f32 | f32 | `a - b` | +| ✓ | __subsf3 | f32 | f32 | f32 | .. | +| ✓ | __subdf3 | f64 | f64 | f64 | .. | +| ✓ | __subtf3 | f128 | f128 | f128 | .. | +| ✓ | __subxf3 | f80 | f80 | f80 | .. | +| ✓ | __aeabi_fsub | f32 | f32 | f32 | .. ARM | +| ✓ | __aeabi_dsub | f64 | f64 | f64 | .. ARM | +| ✓ | __subkf3 | f128 | f128 | f128 | .. PPC | +| ✓ | _Qp_sub |*f128 |*f128 | void | .. SPARC args *c,*a,*b c=a-b | +| ✓ | __mulhf3 | f32 | f32 | f32 | `a * b` | +| ✓ | __mulsf3 | f32 | f32 | f32 | .. | +| ✓ | __muldf3 | f64 | f64 | f64 | .. | +| ✓ | __multf3 | f128 | f128 | f128 | .. | +| ✓ | __mulxf3 | f80 | f80 | f80 | .. | +| ✓ | __aeabi_fmul | f32 | f32 | f32 | .. ARM | +| ✓ | __aeabi_dmul | f64 | f64 | f64 | .. ARM | +| ✓ | __mulkf3 | f128 | f128 | f128 | .. PPC | +| ✓ | _Qp_mul |*f128 |*f128 | void | .. SPARC args *c,*a,*b c=a*b | +| ✓ | __divsf3 | f32 | f32 | f32 | `a / b` | +| ✓ | __divdf3 | f64 | f64 | f64 | .. | +| ✓ | __divtf3 | f128 | f128 | f128 | .. | +| ✓ | __divxf3 | f80 | f80 | f80 | .. | +| ✓ | __aeabi_fdiv | f32 | f32 | f32 | .. ARM | +| ✓ | __aeabi_ddiv | f64 | f64 | f64 | .. ARM | +| ✓ | __divkf3 | f128 | f128 | f128 | .. PPC | +| ✓ | _Qp_div |*f128 |*f128 | void | .. SPARC args *c,*a,*b c=a*b | +| ✓ | __negsf2 | f32 | ∅ | f32[^unused_rl78] | -a (can be lowered directly to a xor) | +| ✓ | __negdf2 | f64 | ∅ | f64 | .. | +| ✓ | __negtf2 | f128 | ∅ | f128 | .. | +| ✓ | __negxf2 | f80 | ∅ | f80 | .. | +| | | | | | **Floating point raised to integer power** | +| ✗ | __powihf2 | f16 | f16 | f16 | `a ^ b` | +| ✗ | __powisf2 | f32 | f32 | f32 | .. | +| ✗ | __powidf2 | f64 | f64 | f64 | .. | +| ✗ | __powitf2 | f128 | f128 | f128 | .. | +| ✗ | __powixf2 | f80 | f80 | f80 | .. | +| ✓ | __mulhc3 | all4 | f16 | f16 | `(a+ib) * (c+id)` | +| ✓ | __mulsc3 | all4 | f32 | f32 | .. | +| ✓ | __muldc3 | all4 | f64 | f64 | .. | +| ✓ | __multc3 | all4 | f128 | f128 | .. | +| ✓ | __mulxc3 | all4 | f80 | f80 | .. | +| ✓ | __divhc3 | all4 | f16 | f16 | `(a+ib) / (c+id)` | +| ✓ | __divsc3 | all4 | f32 | f32 | .. | +| ✓ | __divdc3 | all4 | f64 | f64 | .. | +| ✓ | __divtc3 | all4 | f128 | f128 | .. | +| ✓ | __divxc3 | all4 | f80 | f80 | .. | -#### Integer Arithmetic +[^unused_rl78]: Unused in LLVM, but used for example by rl78. +[^libgcc_compat]: Unused in backends and for symbol-level compatibility with libgcc. +[^noptr_faster]: Operations without pointer and without C struct semantics lead to better optimizations. +[^perf_addition]: Has better performance than standard method due to 2s complement semantics. +Not provided by LLVM and libgcc. -- none none __ashlsi3 // a,b: i32, a << b unused in llvm, TODO (e.g. used by rl78) -- port llvm __ashldi3 // a,b: u64 -- port llvm __ashlti3 // a,b: u128 -- none none __ashrsi3 // a,b: i32, a >> b arithmetic (sign fill) TODO (e.g. used by rl78) -- port llvm __ashrdi3 // .. -- port llvm __ashrti3 // -- none none __lshrsi3 // a,b: i32, a >> b logical (zero fill) TODO (e.g. used by rl78) -- port llvm __lshrdi3 // -- port llvm __lshrti3 // -- port llvm __negdi2 // a: i32, -a, symbol-level compatibility with libgcc -- port llvm __negti2 // unnecessary: unused in backends -- port llvm __mulsi3 // a,b: i32, a * b -- port llvm __muldi3 // -- port llvm __multi3 // -- port llvm __divsi3 // a,b: i32, a / b -- port llvm __divdi3 // -- port llvm __divti3 // -- port llvm __udivsi3 // a,b: u32, a / b -- port llvm __udivdi3 // -- port llvm __udivti3 // -- port llvm __modsi3 // a,b: i32, a % b -- port llvm __moddi3 // -- port llvm __modti3 // -- port llvm __umodsi3 // a,b: u32, a % b -- port llvm __umoddi3 // -- port llvm __umodti3 // -- port llvm __udivmoddi4 // a,b: u32, a / b, rem.* = a % b unsigned -- port llvm __udivmodti4 // -- port llvm __udivmodsi4 // -- port llvm __divmodsi4 // a,b: i32, a / b, rem.* = a % b signed, ARM -- port llvm __divmoddi4 // - -#### Integer Arithmetic with trapping overflow - -- dev BitTwiddlingHacks __absvsi2 // abs(a) -- dev BitTwiddlingHacks __absvdi2 // abs(a) -- dev BitTwiddlingHacks __absvti2 // abs(a) -- port llvm __negvsi2 // -a symbol-level compatibility: libgcc -- port llvm __negvdi2 // -a unnecessary: unused in backends -- port llvm __negvti2 // -a -- TODO upstreaming __addvsi3..__mulvti3 after testing panics works -- dev HackersDelight __addvsi3 // a + b -- dev HackersDelight __addvdi3 // -- dev HackersDelight __addvti3 // -- dev HackersDelight __subvsi3 // a - b -- dev HackersDelight __subvdi3 // -- dev HackersDelight __subvti3 // -- dev HackersDelight __mulvsi3 // a * b -- dev HackersDelight __mulvdi3 // -- dev HackersDelight __mulvti3 // - -#### Integer Arithmetic which returns if overflow (would be faster without pointer) - -- dev HackersDelight __addosi4 // a + b, overflow->ov.*=1 else 0 -- dev HackersDelight __addodi4 // (completeness + performance, llvm does not use them) -- dev HackersDelight __addoti4 // -- dev HackersDelight __subosi4 // a - b, overflow->ov.*=1 else 0 -- dev HackersDelight __subodi4 // (completeness + performance, llvm does not use them) -- dev HackersDelight __suboti4 // -- dev HackersDelight __mulosi4 // a * b, overflow->ov.*=1 else 0 -- dev HackersDelight __mulodi4 // (required by llvm) -- dev HackersDelight __muloti4 // - -## Float library routines - -TODO: review source of implementation - -#### Float Conversion - -- dev other __extendsfdf2 // a: f32 -> f64, TODO: missing tests -- dev other __extendsftf2 // a: f32 -> f128 -- dev llvm __extendsfxf2 // a: f32 -> f80, TODO: missing tests -- dev other __extenddftf2 // a: f64 -> f128 -- dev llvm __extenddfxf2 // a: f64 -> f80 -- dev other __truncdfsf2 // a: f64 -> f32, rounding towards zero -- dev other __trunctfdf2 // a: f128-> f64 -- dev other __trunctfsf2 // a: f128-> f32 -- dev llvm __truncxfsf2 // a: f80 -> f32, TODO: missing tests -- dev llvm __truncxfdf2 // a: f80 -> f64, TODO: missing tests - -- dev unclear __fixsfsi // a: f32 -> i32, rounding towards zero -- dev unclear __fixdfsi // a: f64 -> i32 -- dev unclear __fixtfsi // a: f128-> i32 -- dev unclear __fixxfsi // a: f80 -> i32, TODO: missing tests -- dev unclear __fixsfdi // a: f32 -> i64, rounding towards zero -- dev unclear __fixdfdi // .. -- dev unclear __fixtfdi // -- dev unclear __fixxfdi // TODO: missing tests -- dev unclear __fixsfti // a: f32 -> i128, rounding towards zero -- dev unclear __fixdfti // .. -- dev unclear __fixtfdi // -- dev unclear __fixxfti // TODO: missing tests - -- dev unclear __fixunssfsi // a: f32 -> u32, rounding towards zero. negative values become 0. -- dev unclear __fixunsdfsi // .. -- dev unclear __fixunstfsi // -- dev unclear __fixunsxfsi // TODO: missing tests -- dev unclear __fixunssfdi // a: f32 -> u64, rounding towards zero. negative values become 0. -- dev unclear __fixunsdfdi // -- dev unclear __fixunstfdi // -- dev unclear __fixunsxfdi // TODO: missing tests -- dev unclear __fixunssfti // a: f32 -> u128, rounding towards zero. negative values become 0. -- dev unclear __fixunsdfti // -- dev unclear __fixunstfdi // -- dev unclear __fixunsxfti // TODO: some more tests needed for base coverage - -- dev unclear __floatsisf // a: i32 -> f32 -- dev unclear __floatsidf // a: i32 -> f64, TODO: missing tests -- dev unclear __floatsitf // .. -- dev unclear __floatsixf // TODO: missing tests -- dev unclear __floatdisf // a: i64 -> f32 -- dev unclear __floatdidf // -- dev unclear __floatditf // -- dev unclear __floatdixf // TODO: missing tests -- dev unclear __floattisf // a: i128-> f32 -- dev unclear __floattidf // -- dev unclear __floattitf // -- dev unclear __floattixf // TODO: missing tests - -- dev unclear __floatunsisf // a: u32 -> f32 -- dev unclear __floatunsidf // TODO: missing tests -- dev unclear __floatunsitf // -- dev unclear __floatunsixf // TODO: missing tests -- dev unclear __floatundisf // a: u64 -> f32 -- dev unclear __floatundidf // -- dev unclear __floatunditf // -- dev unclear __floatundixf // TODO: missing tests -- dev unclear __floatuntisf // a: u128-> f32 -- dev unclear __floatuntidf // -- dev unclear __floatuntitf // -- dev unclear __floatuntixf // TODO: missing tests - -#### Float Comparison - -- dev other __cmpsf2 // a,b:f32, (a-1,(a==b)->0,(a>b)->1,Nan->1 -- dev other __cmpdf2 // exported from __lesf2, __ledf2, __letf2 (below) -- dev other __cmptf2 // But: if NaN is a possibility, use another routine. -- dev other __unordsf2 // a,b:f32, (a==+-NaN or b==+-NaN) -> !=0, else -> 0 -- dev other __unorddf2 // __only reliable for (input!=NaN)__ -- dev other __unordtf2 // TODO: missing tests -- dev other __eqsf2 // (a!=NaN) and (b!=Nan) and (a==b) -> output=0 -- dev other __eqdf2 // -- dev other __eqtf2 // -- dev other __nesf2 // (a==NaN) or (b==Nan) or (a!=b) -> output!=0 -- dev other __nedf2 // -- dev other __netf2 // __eqtf2 and __netf2 have same return value -> tested with __eqsf2 -- dev other __gesf2 // (a!=Nan) and (b!=Nan) and (a>=b) -> output>=0 -- dev other __gedf2 // -- dev other __getf2 // TODO: missing tests -- dev other __ltsf2 // (a!=Nan) and (b!=Nan) and (a output<0 -- dev other __ltdf2 // -- dev other __lttf2 // TODO: missing tests -- dev other __lesf2 // (a!=Nan) and (b!=Nan) and (a<=b) -> output<=0 -- dev other __ledf2 // -- dev other __letf2 // TODO: missing tests -- dev other __gtsf2 // (a!=Nan) and (b!=Nan) and (a>b) -> output>0 -- dev other __gtdf2 // -- dev other __gttf2 // TODO: missing tests - -#### Float Arithmetic - -- dev unclear __addsf3 // a + b f32, TODO: missing tests -- dev unclear __adddf3 // a + b f64, TODO: missing tests -- dev unclear __addtf3 // a + b f128 -- dev unclear __addxf3 // a + b f80 -- dev unclear __aeabi_fadd // a + b f64 ARM: AAPCS -- dev unclear __aeabi_dadd // a + b f64 ARM: AAPCS -- dev unclear __subsf3 // a - b, TODO: missing tests -- dev unclear __subdf3 // a - b, TODO: missing tests -- dev unclear __subtf3 // a - b -- dev unclear __subxf3 // a - b f80, TODO: missing tests -- dev unclear __aeabi_fsub // a - b f64 ARM: AAPCS -- dev unclear __aeabi_dsub // a - b f64 ARM: AAPCS -- dev unclear __mulsf3 // a * b, TODO: missing tests -- dev unclear __muldf3 // a * b, TODO: missing tests -- dev unclear __multf3 // a * b -- dev unclear __mulxf3 // a * b -- dev unclear __divsf3 // a / b, TODO: review tests -- dev unclear __divdf3 // a / b, TODO: review tests -- dev unclear __divtf3 // a / b -- dev unclear __divxf3 // a / b -- dev unclear __negsf2 // -a symbol-level compatibility: libgcc uses this for the rl78 -- dev unclear __negdf2 // -a unnecessary: can be lowered directly to a xor -- dev unclear __negtf2 // -a, TODO: missing tests -- dev unclear __negxf2 // -a, TODO: missing tests - -#### Floating point raised to integer power -- dev unclear __powisf2 // a ^ b, TODO -- dev unclear __powidf2 // -- dev unclear __powitf2 // -- dev unclear __powixf2 // -- dev unclear __mulsc3 // (a+ib) * (c+id) -- dev unclear __muldc3 // -- dev unclear __multc3 // -- dev unclear __mulxc3 // -- dev unclear __divsc3 // (a+ib) * / (c+id) -- dev unclear __divdc3 // -- dev unclear __divtc3 // -- dev unclear __divxc3 // - -## Decimal float library routines +Decimal float library routines BID means Binary Integer Decimal encoding, DPD means Densely Packed Decimal encoding. BID should be only chosen for binary data, DPD for decimal data (ASCII, Unicode etc). -If possible, use BCD instead of DPD to represent numbers not accurately representable -in binary like the number 0.2. - -All routines are TODO. - -#### Decimal float Conversion - -- __dpd_extendsddd2 // dec32->dec64 -- __bid_extendsddd2 // dec32->dec64 -- __dpd_extendsdtd2 // dec32->dec128 -- __bid_extendsdtd2 // dec32->dec128 -- __dpd_extendddtd2 // dec64->dec128 -- __bid_extendddtd2 // dec64->dec128 -- __dpd_truncddsd2 // dec64->dec32 -- __bid_truncddsd2 // dec64->dec32 -- __dpd_trunctdsd2 // dec128->dec32 -- __bid_trunctdsd2 // dec128->dec32 -- __dpd_trunctddd2 // dec128->dec64 -- __bid_trunctddd2 // dec128->dec64 - -- __dpd_extendsfdd // float->dec64 -- __bid_extendsfdd // float->dec64 -- __dpd_extendsftd // float->dec128 -- __bid_extendsftd // float->dec128 -- __dpd_extenddftd // double->dec128 -- __bid_extenddftd // double->dec128 -- __dpd_extendxftd // long double->dec128 -- __bid_extendxftd // long double->dec128 -- __dpd_truncdfsd // double->dec32 -- __bid_truncdfsd // double->dec32 -- __dpd_truncxfsd // long double->dec32 -- __bid_truncxfsd // long double->dec32 -- __dpd_trunctfsd // long double->dec32 -- __bid_trunctfsd // long double->dec32 -- __dpd_truncxfdd // long double->dec64 -- __bid_truncxfdd // long double->dec64 -- __dpd_trunctfdd // long double->dec64 -- __bid_trunctfdd // long double->dec64 - -- __dpd_truncddsf // dec64->float -- __bid_truncddsf // dec64->float -- __dpd_trunctdsf // dec128->float -- __bid_trunctdsf // dec128->float -- __dpd_extendsddf // dec32->double -- __bid_extendsddf // dec32->double -- __dpd_trunctddf // dec128->double -- __bid_trunctddf // dec128->double -- __dpd_extendsdxf // dec32->long double -- __bid_extendsdxf // dec32->long double -- __dpd_extendddxf // dec64->long double -- __bid_extendddxf // dec64->long double -- __dpd_trunctdxf // dec128->long double -- __bid_trunctdxf // dec128->long double -- __dpd_extendsdtf // dec32->long double -- __bid_extendsdtf // dec32->long double -- __dpd_extendddtf // dec64->long double -- __bid_extendddtf // dec64->long double - -Same size conversion: -- __dpd_extendsfsd // float->dec32 -- __bid_extendsfsd // float->dec32 -- __dpd_extenddfdd // double->dec64 -- __bid_extenddfdd // double->dec64 -- __dpd_extendtftd //long double->dec128 -- __bid_extendtftd //long double->dec128 -- __dpd_truncsdsf // dec32->float -- __bid_truncsdsf // dec32->float -- __dpd_truncdddf // dec64->float -- __bid_truncdddf // dec64->float -- __dpd_trunctdtf // dec128->long double -- __bid_trunctdtf // dec128->long double - -- __dpd_fixsdsi // dec32->int -- __bid_fixsdsi // dec32->int -- __dpd_fixddsi // dec64->int -- __bid_fixddsi // dec64->int -- __dpd_fixtdsi // dec128->int -- __bid_fixtdsi // dec128->int - -- __dpd_fixsddi // dec32->long -- __bid_fixsddi // dec32->long -- __dpd_fixdddi // dec64->long -- __bid_fixdddi // dec64->long -- __dpd_fixtddi // dec128->long -- __bid_fixtddi // dec128->long - -- __dpd_fixunssdsi // dec32->unsigned int, All negative values become zero. -- __bid_fixunssdsi // dec32->unsigned int -- __dpd_fixunsddsi // dec64->unsigned int -- __bid_fixunsddsi // dec64->unsigned int -- __dpd_fixunstdsi // dec128->unsigned int -- __bid_fixunstdsi // dec128->unsigned int - -- __dpd_fixunssddi // dec32->unsigned long, All negative values become zero. -- __bid_fixunssddi // dec32->unsigned long -- __dpd_fixunsdddi // dec64->unsigned long -- __bid_fixunsdddi // dec64->unsigned long -- __dpd_fixunstddi // dec128->unsigned long -- __bid_fixunstddi // dec128->unsigned long - -- __dpd_floatsisd // int->dec32 -- __bid_floatsisd // int->dec32 -- __dpd_floatsidd // int->dec64 -- __bid_floatsidd // int->dec64 -- __dpd_floatsitd // int->dec128 -- __bid_floatsitd // int->dec128 - -- __dpd_floatdisd // long->dec32 -- __bid_floatdisd // long->dec32 -- __dpd_floatdidd // long->dec64 -- __bid_floatdidd // long->dec64 -- __dpd_floatditd // long->dec128 -- __bid_floatditd // long->dec128 - -- __dpd_floatunssisd // unsigned int->dec32 -- __bid_floatunssisd // unsigned int->dec32 -- __dpd_floatunssidd // unsigned int->dec64 -- __bid_floatunssidd // unsigned int->dec64 -- __dpd_floatunssitd // unsigned int->dec128 -- __bid_floatunssitd // unsigned int->dec128 - -- __dpd_floatunsdisd // unsigned long->dec32 -- __bid_floatunsdisd // unsigned long->dec32 -- __dpd_floatunsdidd // unsigned long->dec64 -- __bid_floatunsdidd // unsigned long->dec64 -- __dpd_floatunsditd // unsigned long->dec128 -- __bid_floatunsditd // unsigned long->dec128 - -#### Decimal float Comparison - -All decimal float comparison routines return c_int. - -- __dpd_unordsd2 // a,b: dec32, a +-NaN or a +-NaN -> 1(nonzero), else -> 0 -- __bid_unordsd2 // a,b: dec32 -- __dpd_unorddd2 // a,b: dec64 -- __bid_unorddd2 // a,b: dec64 -- __dpd_unordtd2 // a,b: dec128 -- __bid_unordtd2 // a,b: dec128 - -- __dpd_eqsd2 // a,b: dec32, a!=+-NaN and b!=+-Nan and a==b -> 0, else -> 1(nonzero) -- __bid_eqsd2 // a,b: dec32 -- __dpd_eqdd2 // a,b: dec64 -- __bid_eqdd2 // a,b: dec64 -- __dpd_eqtd2 // a,b: dec128 -- __bid_eqtd2 // a,b: dec128 - -- __dpd_nesd2 // a,b: dec32, a==+-NaN or b==+-NaN or a!=b -> 1(nonzero), else -> 0 -- __bid_nesd2 // a,b: dec32 -- __dpd_nedd2 // a,b: dec64 -- __bid_nedd2 // a,b: dec64 -- __dpd_netd2 // a,b: dec128 -- __bid_netd2 // a,b: dec128 - -- __dpd_gesd2 // a,b: dec32, a!=+-NaN and b!=+-NaN and a>=b -> >=0, else -> <0 -- __bid_gesd2 // a,b: dec32 -- __dpd_gedd2 // a,b: dec64 -- __bid_gedd2 // a,b: dec64 -- __dpd_getd2 // a,b: dec128 -- __bid_getd2 // a,b: dec128 - -- __dpd_ltsd2 // a,b: dec32, a!=+-NaN and b!=+-NaN and a <0, else -> >=0 -- __bid_ltsd2 // a,b: dec32 -- __dpd_ltdd2 // a,b: dec64 -- __bid_ltdd2 // a,b: dec64 -- __dpd_lttd2 // a,b: dec128 -- __bid_lttd2 // a,b: dec128 - -- __dpd_lesd2 // a,b: dec32, a!=+-NaN and b!=+-NaN and a<=b -> <=0, else -> >=0 -- __bid_lesd2 // a,b: dec32 -- __dpd_ledd2 // a,b: dec64 -- __bid_ledd2 // a,b: dec64 -- __dpd_letd2 // a,b: dec128 -- __bid_letd2 // a,b: dec128 - -- __dpd_gtsd2 // a,b: dec32, a!=+-NaN and b!=+-NaN and a>b -> >0, else -> <=0 -- __bid_gtsd2 // a,b: dec32 -- __dpd_gtdd2 // a,b: dec64 -- __bid_gtdd2 // a,b: dec64 -- __dpd_gttd2 // a,b: dec128 -- __bid_gttd2 // a,b: dec128 - -#### Decimal float Arithmetic - -These numbers include options with routines for +-0 and +-Nan. - -- __dpd_addsd3 // a,b: dec32 -> dec32, a + b -- __bid_addsd3 // a,b: dec32 -> dec32 -- __dpd_adddd3 // a,b: dec64 -> dec64 -- __bid_adddd3 // a,b: dec64 -> dec64 -- __dpd_addtd3 // a,b: dec128-> dec128 -- __bid_addtd3 // a,b: dec128-> dec128 -- __dpd_subsd3 // a,b: dec32, a - b -- __bid_subsd3 // a,b: dec32 -> dec32 -- __dpd_subdd3 // a,b: dec64 .. -- __bid_subdd3 // a,b: dec64 -- __dpd_subtd3 // a,b: dec128 -- __bid_subtd3 // a,b: dec128 -- __dpd_mulsd3 // a,b: dec32, a * b -- __bid_mulsd3 // a,b: dec32 -> dec32 -- __dpd_muldd3 // a,b: dec64 .. -- __bid_muldd3 // a,b: dec64 -- __dpd_multd3 // a,b: dec128 -- __bid_multd3 // a,b: dec128 -- __dpd_divsd3 // a,b: dec32, a / b -- __bid_divsd3 // a,b: dec32 -> dec32 -- __dpd_divdd3 // a,b: dec64 .. -- __bid_divdd3 // a,b: dec64 -- __dpd_divtd3 // a,b: dec128 -- __bid_divtd3 // a,b: dec128 -- __dpd_negsd2 // a,b: dec32, -a -- __bid_negsd2 // a,b: dec32 -> dec32 -- __dpd_negdd2 // a,b: dec64 .. -- __bid_negdd2 // a,b: dec64 -- __dpd_negtd2 // a,b: dec128 -- __bid_negtd2 // a,b: dec128 - -## Fixed-point fractional library routines - -TODO - -Too unclear for work items: -- Miscellaneous routines => unclear, if supported (cache control and stack functions) -- Zig-specific language runtime features, for example "Arbitrary length integer library routines" +For example the number 0.2 is not accurately representable in binary data. + +| Done | Name | a | b | Out | Comment | +| ------ | ------------- | --------- | --------- | --------- | ---------------------------- | +| | | | | | **Decimal Float Conversion** | +| ✗ | __dpd_extendsddd2 | dec32 | ∅ | dec64 | conversion | +| ✗ | __bid_extendsddd2 | dec32 | ∅ | dec64 | .. | +| ✗ | __dpd_extendsdtd2 | dec32 | ∅ | dec128| .. | +| ✗ | __bid_extendsdtd2 | dec32 | ∅ | dec128| .. | +| ✗ | __dpd_extendddtd2 | dec64 | ∅ | dec128| .. | +| ✗ | __bid_extendddtd2 | dec64 | ∅ | dec128| .. | +| ✗ | __dpd_truncddsd2 | dec64 | ∅ | dec32 | .. | +| ✗ | __bid_truncddsd2 | dec64 | ∅ | dec32 | .. | +| ✗ | __dpd_trunctdsd2 | dec128 | ∅ | dec32 | .. | +| ✗ | __bid_trunctdsd2 | dec128 | ∅ | dec32 | .. | +| ✗ | __dpd_trunctddd2 | dec128 | ∅ | dec64 | .. | +| ✗ | __bid_trunctddd2 | dec128 | ∅ | dec64 | .. | +| ✗ | __dpd_extendsfdd | float | ∅ | dec64 | .. | +| ✗ | __bid_extendsfdd | float | ∅ | dec64 | .. | +| ✗ | __dpd_extendsftd | float | ∅ | dec128| .. | +| ✗ | __bid_extendsftd | float | ∅ | dec128| .. | +| ✗ | __dpd_extenddftd | double | ∅ | dec128| .. | +| ✗ | __bid_extenddftd | double | ∅ | dec128| .. | +| ✗ | __dpd_extendxftd |long double | ∅ | dec128| .. | +| ✗ | __bid_extendxftd |long double | ∅ | dec128| .. | +| ✗ | __dpd_truncdfsd | double | ∅ | dec32 | .. | +| ✗ | __bid_truncdfsd | double | ∅ | dec32 | .. | +| ✗ | __dpd_truncxfsd |long double | ∅ | dec32 | .. | +| ✗ | __bid_truncxfsd |long double | ∅ | dec32 | .. | +| ✗ | __dpd_trunctfsd |long double | ∅ | dec32 | .. | +| ✗ | __bid_trunctfsd |long double | ∅ | dec32 | .. | +| ✗ | __dpd_truncxfdd |long double | ∅ | dec64 | .. | +| ✗ | __bid_truncxfdd |long double | ∅ | dec64 | .. | +| ✗ | __dpd_trunctfdd |long double | ∅ | dec64 | .. | +| ✗ | __bid_trunctfdd |long double | ∅ | dec64 | .. | +| ✗ | __dpd_truncddsf | dec64 | ∅ | float | .. | +| ✗ | __bid_truncddsf | dec64 | ∅ | float | .. | +| ✗ | __dpd_trunctdsf | dec128 | ∅ | float | .. | +| ✗ | __bid_trunctdsf | dec128 | ∅ | float | .. | +| ✗ | __dpd_extendsddf | dec32 | ∅ | double| .. | +| ✗ | __bid_extendsddf | dec32 | ∅ | double| .. | +| ✗ | __dpd_trunctddf | dec128 | ∅ | double| .. | +| ✗ | __bid_trunctddf | dec128 | ∅ | double| .. | +| ✗ | __dpd_extendsdxf | dec32 | ∅ |long double| .. | +| ✗ | __bid_extendsdxf | dec32 | ∅ |long double| .. | +| ✗ | __dpd_extendddxf | dec64 | ∅ |long double| .. | +| ✗ | __bid_extendddxf | dec64 | ∅ |long double| .. | +| ✗ | __dpd_trunctdxf | dec128 | ∅ |long double| .. | +| ✗ | __bid_trunctdxf | dec128 | ∅ |long double| .. | +| ✗ | __dpd_extendsdtf | dec32 | ∅ |long double| .. | +| ✗ | __bid_extendsdtf | dec32 | ∅ |long double| .. | +| ✗ | __dpd_extendddtf | dec64 | ∅ |long double| .. | +| ✗ | __bid_extendddtf | dec64 | ∅ |long double| .. | +| ✗ | __dpd_extendsfsd | float | ∅ | dec32 | same size conversions | +| ✗ | __bid_extendsfsd | float | ∅ | dec32 | .. | +| ✗ | __dpd_extenddfdd | double | ∅ | dec64 | .. | +| ✗ | __bid_extenddfdd | double | ∅ | dec64 | .. | +| ✗ | __dpd_extendtftd |long double | ∅ | dec128| .. | +| ✗ | __bid_extendtftd |long double | ∅ | dec128| .. | +| ✗ | __dpd_truncsdsf | dec32 | ∅ | float | .. | +| ✗ | __bid_truncsdsf | dec32 | ∅ | float | .. | +| ✗ | __dpd_truncdddf | dec64 | ∅ | float | conversion | +| ✗ | __bid_truncdddf | dec64 | ∅ | float | .. | +| ✗ | __dpd_trunctdtf | dec128 | ∅ |long double| .. | +| ✗ | __bid_trunctdtf | dec128 | ∅ |long double| .. | +| ✗ | __dpd_fixsdsi | dec32 | ∅ | int | .. | +| ✗ | __bid_fixsdsi | dec32 | ∅ | int | .. | +| ✗ | __dpd_fixddsi | dec64 | ∅ | int | .. | +| ✗ | __bid_fixddsi | dec64 | ∅ | int | .. | +| ✗ | __dpd_fixtdsi | dec128 | ∅ | int | .. | +| ✗ | __bid_fixtdsi | dec128 | ∅ | int | .. | +| ✗ | __dpd_fixsddi | dec32 | ∅ | long | .. | +| ✗ | __bid_fixsddi | dec32 | ∅ | long | .. | +| ✗ | __dpd_fixdddi | dec64 | ∅ | long | .. | +| ✗ | __bid_fixdddi | dec64 | ∅ | long | .. | +| ✗ | __dpd_fixtddi | dec128 | ∅ | long | .. | +| ✗ | __bid_fixtddi | dec128 | ∅ | long | .. | +| ✗ | __dpd_fixunssdsi | dec32 | ∅ |unsigned int | .. All negative values become zero. | +| ✗ | __bid_fixunssdsi | dec32 | ∅ |unsigned int | .. | +| ✗ | __dpd_fixunsddsi | dec64 | ∅ |unsigned int | .. | +| ✗ | __bid_fixunsddsi | dec64 | ∅ |unsigned int | .. | +| ✗ | __dpd_fixunstdsi | dec128 | ∅ |unsigned int | .. | +| ✗ | __bid_fixunstdsi | dec128 | ∅ |unsigned int | .. | +| ✗ | __dpd_fixunssddi | dec32 | ∅ |unsigned long| .. | +| ✗ | __bid_fixunssddi | dec32 | ∅ |unsigned long| .. | +| ✗ | __dpd_fixunsdddi | dec64 | ∅ |unsigned long| .. | +| ✗ | __bid_fixunsdddi | dec64 | ∅ |unsigned long| .. | +| ✗ | __dpd_fixunstddi | dec128 | ∅ |unsigned long| .. | +| ✗ | __bid_fixunstddi | dec128 | ∅ |unsigned long| .. | +| ✗ | __dpd_floatsisd | int | ∅ | dec32 | .. | +| ✗ | __bid_floatsisd | int | ∅ | dec32 | .. | +| ✗ | __dpd_floatsidd | int | ∅ | dec64 | .. | +| ✗ | __bid_floatsidd | int | ∅ | dec64 | .. | +| ✗ | __dpd_floatsitd | int | ∅ | dec128 | .. | +| ✗ | __bid_floatsitd | int | ∅ | dec128 | .. | +| ✗ | __dpd_floatdisd | long | ∅ | dec32 | .. | +| ✗ | __bid_floatdisd | long | ∅ | dec32 | .. | +| ✗ | __dpd_floatdidd | long | ∅ | dec64 | .. | +| ✗ | __bid_floatdidd | long | ∅ | dec64 | .. | +| ✗ | __dpd_floatditd | long | ∅ | dec128 | .. | +| ✗ | __bid_floatditd | long | ∅ | dec128 | .. | +| ✗ | __dpd_floatunssisd | unsigned int| ∅ | dec32 | .. | +| ✗ | __bid_floatunssisd | unsigned int| ∅ | dec32 | .. | +| ✗ | __dpd_floatunssidd | unsigned int| ∅ | dec64 | .. | +| ✗ | __bid_floatunssidd | unsigned int| ∅ | dec64 | .. | +| ✗ | __dpd_floatunssitd | unsigned int| ∅ | dec128 | .. | +| ✗ | __bid_floatunssitd | unsigned int| ∅ | dec128 | .. | +| ✗ | __dpd_floatunsdisd |unsigned long| ∅ | dec32 | .. | +| ✗ | __bid_floatunsdisd |unsigned long| ∅ | dec32 | .. | +| ✗ | __dpd_floatunsdidd |unsigned long| ∅ | dec64 | .. | +| ✗ | __bid_floatunsdidd |unsigned long| ∅ | dec64 | .. | +| ✗ | __dpd_floatunsditd |unsigned long| ∅ | dec128 | .. | +| ✗ | __bid_floatunsditd |unsigned long| ∅ | dec128 | .. | +| | | | | | **Decimal Float Comparison** | +| ✗ | __dpd_unordsd2 | dec32 | dec32 | c_int | `a +-NaN or a +-NaN -> 1(nonzero), else -> 0` | +| ✗ | __bid_unordsd2 | dec32 | dec32 | c_int | .. | +| ✗ | __dpd_unorddd2 | dec64 | dec64 | c_int | .. | +| ✗ | __bid_unorddd2 | dec64 | dec64 | c_int | .. | +| ✗ | __dpd_unordtd2 | dec128 | dec128 | c_int | .. | +| ✗ | __bid_unordtd2 | dec128 | dec128 | c_int | .. | +| ✗ | __dpd_eqsd2 | dec32 | dec32 | c_int |`a!=+-NaN and b!=+-Nan and a==b -> 0, else -> 1(nonzero)`| +| ✗ | __bid_eqsd2 | dec32 | dec32 | c_int | .. | +| ✗ | __dpd_eqdd2 | dec64 | dec64 | c_int | .. | +| ✗ | __bid_eqdd2 | dec64 | dec64 | c_int | .. | +| ✗ | __dpd_eqtd2 | dec128 | dec128 | c_int | .. | +| ✗ | __bid_eqtd2 | dec128 | dec128 | c_int | .. | +| ✗ | __dpd_nesd2 | dec32 | dec32 | c_int | `a==+-NaN or b==+-NaN or a!=b -> 1(nonzero), else -> 0` | +| ✗ | __bid_nesd2 | dec32 | dec32 | c_int | .. | +| ✗ | __dpd_nedd2 | dec64 | dec64 | c_int | .. | +| ✗ | __bid_nedd2 | dec64 | dec64 | c_int | .. | +| ✗ | __dpd_netd2 | dec128 | dec128 | c_int | .. | +| ✗ | __bid_netd2 | dec128 | dec128 | c_int | .. | +| ✗ | __dpd_gesd2 | dec32 | dec32 | c_int | `a!=+-NaN and b!=+-NaN and a>=b -> >=0, else -> <0` | +| ✗ | __bid_gesd2 | dec32 | dec32 | c_int | .. | +| ✗ | __dpd_gedd2 | dec64 | dec64 | c_int | .. | +| ✗ | __bid_gedd2 | dec64 | dec64 | c_int | .. | +| ✗ | __dpd_getd2 | dec128 | dec128 | c_int | .. | +| ✗ | __bid_getd2 | dec128 | dec128 | c_int | .. | +| ✗ | __dpd_ltsd2 | dec32 | dec32 | c_int | `a!=+-NaN and b!=+-NaN and a <0, else -> >=0` | +| ✗ | __bid_ltsd2 | dec32 | dec32 | c_int | .. | +| ✗ | __dpd_ltdd2 | dec64 | dec64 | c_int | .. | +| ✗ | __bid_ltdd2 | dec64 | dec64 | c_int | .. | +| ✗ | __dpd_lttd2 | dec128 | dec128 | c_int | .. | +| ✗ | __bid_lttd2 | dec128 | dec128 | c_int | .. | +| ✗ | __dpd_lesd2 | dec32 | dec32 | c_int | `a!=+-NaN and b!=+-NaN and a<=b -> <=0, else -> >=0` | +| ✗ | __bid_lesd2 | dec32 | dec32 | c_int | .. | +| ✗ | __dpd_ledd2 | dec64 | dec64 | c_int | .. | +| ✗ | __bid_ledd2 | dec64 | dec64 | c_int | .. | +| ✗ | __dpd_letd2 | dec128 | dec128 | c_int | .. | +| ✗ | __bid_letd2 | dec128 | dec128 | c_int | .. | +| ✗ | __dpd_gtsd2 | dec32 | dec32 | c_int | `a!=+-NaN and b!=+-NaN and a>b -> >0, else -> <=0` | +| ✗ | __bid_gtsd2 | dec32 | dec32 | c_int | .. | +| ✗ | __dpd_gtdd2 | dec64 | dec64 | c_int | .. | +| ✗ | __bid_gtdd2 | dec64 | dec64 | c_int | .. | +| ✗ | __dpd_gttd2 | dec128 | dec128 | c_int | .. | +| ✗ | __bid_gttd2 | dec128 | dec128 | c_int | .. | +| | | | | | **Decimal Float Arithmetic**[^options] | +| ✗ | __dpd_addsd3 | dec32 | dec32 | dec32 |`a + b`| +| ✗ | __bid_addsd3 | dec32 | dec32 | dec32 | .. | +| ✗ | __dpd_adddd3 | dec64 | dec64 | dec64 | .. | +| ✗ | __bid_adddd3 | dec64 | dec64 | dec64 | .. | +| ✗ | __dpd_addtd3 | dec128 | dec128 | dec128 | .. | +| ✗ | __bid_addtd3 | dec128 | dec128 | dec128 | .. | +| ✗ | __dpd_subsd3 | dec32 | dec32 | dec32 |`a - b`| +| ✗ | __bid_subsd3 | dec32 | dec32 | dec32 | .. | +| ✗ | __dpd_subdd3 | dec64 | dec64 | dec64 | .. | +| ✗ | __bid_subdd3 | dec64 | dec64 | dec64 | .. | +| ✗ | __dpd_subtd3 | dec128 | dec128 | dec128 | .. | +| ✗ | __bid_subtd3 | dec128 | dec128 | dec128 | .. | +| ✗ | __dpd_mulsd3 | dec32 | dec32 | dec32 |`a * b`| +| ✗ | __bid_mulsd3 | dec32 | dec32 | dec32 | .. | +| ✗ | __dpd_muldd3 | dec64 | dec64 | dec64 | .. | +| ✗ | __bid_muldd3 | dec64 | dec64 | dec64 | .. | +| ✗ | __dpd_multd3 | dec128 | dec128 | dec128 | .. | +| ✗ | __bid_multd3 | dec128 | dec128 | dec128 | .. | +| ✗ | __dpd_divsd3 | dec32 | dec32 | dec32 |`a / b`| +| ✗ | __bid_divsd3 | dec32 | dec32 | dec32 | .. | +| ✗ | __dpd_divdd3 | dec64 | dec64 | dec64 | .. | +| ✗ | __bid_divdd3 | dec64 | dec64 | dec64 | .. | +| ✗ | __dpd_divtd3 | dec128 | dec128 | dec128 | .. | +| ✗ | __bid_divtd3 | dec128 | dec128 | dec128 | .. | +| ✗ | __dpd_negsd2 | dec32 | dec32 | dec32 | `-a` | +| ✗ | __bid_negsd2 | dec32 | dec32 | dec32 | .. | +| ✗ | __dpd_negdd2 | dec64 | dec64 | dec64 | .. | +| ✗ | __bid_negdd2 | dec64 | dec64 | dec64 | .. | +| ✗ | __dpd_negtd2 | dec128 | dec128 | dec128 | .. | +| ✗ | __bid_negtd2 | dec128 | dec128 | dec128 | .. | + +[^options]: These numbers include options with routines for +-0 and +-Nan. + +Fixed-point fractional library routines + +TODO brief explanation + implementation + +| Done | Name | a | b | Out | Comment | +| ------ | ------------- | --------- | --------- | --------- | -------------------------- | +| | | | | | **Fixed-Point Fractional** | + +Further content: +- aarch64 outline atomics +- atomics +- msvc things like _alldiv, _aulldiv, _allrem +- clear cache +- tls emulation +- math routines (cos, sin, tan, ceil, floor, exp, exp2, fabs, log, log10, log2, sincos, sqrt) +- bcmp +- ieee float routines (fma, fmax, fmin, fmod, fabs, float rounding, ) +- arm routines (memory routines + memclr [setting to 0], divmod routines and stubs for unwind_cpp) +- memory routines (memcmp, memcpy, memset, memmove) +- objective-c __isPlatformVersionAtLeast check +- stack probe routines + +Future work + +Arbitrary length integer library routines -- 2.54.0 From 873bb29c984b976021fb9ca95ad3298e03a8b3ff Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 2 Feb 2023 17:32:06 -0700 Subject: [PATCH 80/84] introduce ZON: Zig Object Notation * std.zig.parse is moved to std.zig.Ast.parse * the new function has an additional parameter that requires passing Mode.zig or Mode.zon * moved parser.zig code to Parse.zig * added parseZon function next to parseRoot function --- CMakeLists.txt | 2 +- lib/std/Build/OptionsStep.zig | 2 +- lib/std/zig.zig | 1 - lib/std/zig/Ast.zig | 78 +- lib/std/zig/Parse.zig | 3816 ++++++++++++++++++++++++++++++++ lib/std/zig/parse.zig | 3852 --------------------------------- lib/std/zig/parser_test.zig | 4 +- lib/std/zig/perf_test.zig | 3 +- src/Module.zig | 6 +- src/main.zig | 10 +- 10 files changed, 3898 insertions(+), 3876 deletions(-) create mode 100644 lib/std/zig/Parse.zig delete mode 100644 lib/std/zig/parse.zig diff --git a/CMakeLists.txt b/CMakeLists.txt index 8a9de7bdc1f3de7d772f5059792cfff1e4c7bb21..f8029fdcdec79a23b96815ac3251083bbbf9214f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -513,7 +513,7 @@ set(ZIG_STAGE2_SOURCES "${CMAKE_SOURCE_DIR}/lib/std/zig/Ast.zig" "${CMAKE_SOURCE_DIR}/lib/std/zig/CrossTarget.zig" "${CMAKE_SOURCE_DIR}/lib/std/zig/c_builtins.zig" - "${CMAKE_SOURCE_DIR}/lib/std/zig/parse.zig" + "${CMAKE_SOURCE_DIR}/lib/std/zig/Parse.zig" "${CMAKE_SOURCE_DIR}/lib/std/zig/render.zig" "${CMAKE_SOURCE_DIR}/lib/std/zig/string_literal.zig" "${CMAKE_SOURCE_DIR}/lib/std/zig/system.zig" diff --git a/lib/std/Build/OptionsStep.zig b/lib/std/Build/OptionsStep.zig index a3537375128539652844346116fcc1ad28a23345..c1d2c8454a306634591549dbf153b5b5e4b09683 100644 --- a/lib/std/Build/OptionsStep.zig +++ b/lib/std/Build/OptionsStep.zig @@ -367,5 +367,5 @@ test "OptionsStep" { \\ , options.contents.items); - _ = try std.zig.parse(arena.allocator(), try options.contents.toOwnedSliceSentinel(0)); + _ = try std.zig.Ast.parse(arena.allocator(), try options.contents.toOwnedSliceSentinel(0), .zig); } diff --git a/lib/std/zig.zig b/lib/std/zig.zig index bce8f6ce3cf8dfcf726f98491db8c4e789b07499..f85cf75e60ff1256a2c8edbdff6ac213f1279029 100644 --- a/lib/std/zig.zig +++ b/lib/std/zig.zig @@ -8,7 +8,6 @@ pub const Tokenizer = tokenizer.Tokenizer; pub const fmtId = fmt.fmtId; pub const fmtEscapes = fmt.fmtEscapes; pub const isValidId = fmt.isValidId; -pub const parse = @import("zig/parse.zig").parse; pub const string_literal = @import("zig/string_literal.zig"); pub const number_literal = @import("zig/number_literal.zig"); pub const primitives = @import("zig/primitives.zig"); diff --git a/lib/std/zig/Ast.zig b/lib/std/zig/Ast.zig index f312093aa3db77f4c3a55b645eb747f716bf13e6..a9a02606ebfd3992ae280ee06c20dc7e353f2770 100644 --- a/lib/std/zig/Ast.zig +++ b/lib/std/zig/Ast.zig @@ -11,13 +11,6 @@ extra_data: []Node.Index, errors: []const Error, -const std = @import("../std.zig"); -const assert = std.debug.assert; -const testing = std.testing; -const mem = std.mem; -const Token = std.zig.Token; -const Ast = @This(); - pub const TokenIndex = u32; pub const ByteOffset = u32; @@ -34,7 +27,7 @@ pub const Location = struct { line_end: usize, }; -pub fn deinit(tree: *Ast, gpa: mem.Allocator) void { +pub fn deinit(tree: *Ast, gpa: Allocator) void { tree.tokens.deinit(gpa); tree.nodes.deinit(gpa); gpa.free(tree.extra_data); @@ -48,11 +41,69 @@ pub const RenderError = error{ OutOfMemory, }; +pub const Mode = enum { zig, zon }; + +/// Result should be freed with tree.deinit() when there are +/// no more references to any of the tokens or nodes. +pub fn parse(gpa: Allocator, source: [:0]const u8, mode: Mode) Allocator.Error!Ast { + var tokens = Ast.TokenList{}; + defer tokens.deinit(gpa); + + // Empirically, the zig std lib has an 8:1 ratio of source bytes to token count. + const estimated_token_count = source.len / 8; + try tokens.ensureTotalCapacity(gpa, estimated_token_count); + + var tokenizer = std.zig.Tokenizer.init(source); + while (true) { + const token = tokenizer.next(); + try tokens.append(gpa, .{ + .tag = token.tag, + .start = @intCast(u32, token.loc.start), + }); + if (token.tag == .eof) break; + } + + var parser: Parse = .{ + .source = source, + .gpa = gpa, + .token_tags = tokens.items(.tag), + .token_starts = tokens.items(.start), + .errors = .{}, + .nodes = .{}, + .extra_data = .{}, + .scratch = .{}, + .tok_i = 0, + }; + defer parser.errors.deinit(gpa); + defer parser.nodes.deinit(gpa); + defer parser.extra_data.deinit(gpa); + defer parser.scratch.deinit(gpa); + + // Empirically, Zig source code has a 2:1 ratio of tokens to AST nodes. + // Make sure at least 1 so we can use appendAssumeCapacity on the root node below. + const estimated_node_count = (tokens.len + 2) / 2; + try parser.nodes.ensureTotalCapacity(gpa, estimated_node_count); + + switch (mode) { + .zig => try parser.parseRoot(), + .zon => try parser.parseZon(), + } + + // TODO experiment with compacting the MultiArrayList slices here + return Ast{ + .source = source, + .tokens = tokens.toOwnedSlice(), + .nodes = parser.nodes.toOwnedSlice(), + .extra_data = try parser.extra_data.toOwnedSlice(gpa), + .errors = try parser.errors.toOwnedSlice(gpa), + }; +} + /// `gpa` is used for allocating the resulting formatted source code, as well as /// for allocating extra stack memory if needed, because this function utilizes recursion. /// Note: that's not actually true yet, see https://github.com/ziglang/zig/issues/1006. /// Caller owns the returned slice of bytes, allocated with `gpa`. -pub fn render(tree: Ast, gpa: mem.Allocator) RenderError![]u8 { +pub fn render(tree: Ast, gpa: Allocator) RenderError![]u8 { var buffer = std.ArrayList(u8).init(gpa); defer buffer.deinit(); @@ -3347,3 +3398,12 @@ pub const Node = struct { rparen: TokenIndex, }; }; + +const std = @import("../std.zig"); +const assert = std.debug.assert; +const testing = std.testing; +const mem = std.mem; +const Token = std.zig.Token; +const Ast = @This(); +const Allocator = std.mem.Allocator; +const Parse = @import("Parse.zig"); diff --git a/lib/std/zig/Parse.zig b/lib/std/zig/Parse.zig new file mode 100644 index 0000000000000000000000000000000000000000..f599a08f55259efb914a069e6d27c1741698a268 --- /dev/null +++ b/lib/std/zig/Parse.zig @@ -0,0 +1,3816 @@ +//! Represents in-progress parsing, will be converted to an Ast after completion. + +pub const Error = error{ParseError} || Allocator.Error; + +gpa: Allocator, +source: []const u8, +token_tags: []const Token.Tag, +token_starts: []const Ast.ByteOffset, +tok_i: TokenIndex, +errors: std.ArrayListUnmanaged(AstError), +nodes: Ast.NodeList, +extra_data: std.ArrayListUnmanaged(Node.Index), +scratch: std.ArrayListUnmanaged(Node.Index), + +const SmallSpan = union(enum) { + zero_or_one: Node.Index, + multi: Node.SubRange, +}; + +const Members = struct { + len: usize, + lhs: Node.Index, + rhs: Node.Index, + trailing: bool, + + fn toSpan(self: Members, p: *Parse) !Node.SubRange { + if (self.len <= 2) { + const nodes = [2]Node.Index{ self.lhs, self.rhs }; + return p.listToSpan(nodes[0..self.len]); + } else { + return Node.SubRange{ .start = self.lhs, .end = self.rhs }; + } + } +}; + +fn listToSpan(p: *Parse, list: []const Node.Index) !Node.SubRange { + try p.extra_data.appendSlice(p.gpa, list); + return Node.SubRange{ + .start = @intCast(Node.Index, p.extra_data.items.len - list.len), + .end = @intCast(Node.Index, p.extra_data.items.len), + }; +} + +fn addNode(p: *Parse, elem: Ast.NodeList.Elem) Allocator.Error!Node.Index { + const result = @intCast(Node.Index, p.nodes.len); + try p.nodes.append(p.gpa, elem); + return result; +} + +fn setNode(p: *Parse, i: usize, elem: Ast.NodeList.Elem) Node.Index { + p.nodes.set(i, elem); + return @intCast(Node.Index, i); +} + +fn reserveNode(p: *Parse, tag: Ast.Node.Tag) !usize { + try p.nodes.resize(p.gpa, p.nodes.len + 1); + p.nodes.items(.tag)[p.nodes.len - 1] = tag; + return p.nodes.len - 1; +} + +fn unreserveNode(p: *Parse, node_index: usize) void { + if (p.nodes.len == node_index) { + p.nodes.resize(p.gpa, p.nodes.len - 1) catch unreachable; + } else { + // There is zombie node left in the tree, let's make it as inoffensive as possible + // (sadly there's no no-op node) + p.nodes.items(.tag)[node_index] = .unreachable_literal; + p.nodes.items(.main_token)[node_index] = p.tok_i; + } +} + +fn addExtra(p: *Parse, extra: anytype) Allocator.Error!Node.Index { + const fields = std.meta.fields(@TypeOf(extra)); + try p.extra_data.ensureUnusedCapacity(p.gpa, fields.len); + const result = @intCast(u32, p.extra_data.items.len); + inline for (fields) |field| { + comptime assert(field.type == Node.Index); + p.extra_data.appendAssumeCapacity(@field(extra, field.name)); + } + return result; +} + +fn warnExpected(p: *Parse, expected_token: Token.Tag) error{OutOfMemory}!void { + @setCold(true); + try p.warnMsg(.{ + .tag = .expected_token, + .token = p.tok_i, + .extra = .{ .expected_tag = expected_token }, + }); +} + +fn warn(p: *Parse, error_tag: AstError.Tag) error{OutOfMemory}!void { + @setCold(true); + try p.warnMsg(.{ .tag = error_tag, .token = p.tok_i }); +} + +fn warnMsg(p: *Parse, msg: Ast.Error) error{OutOfMemory}!void { + @setCold(true); + switch (msg.tag) { + .expected_semi_after_decl, + .expected_semi_after_stmt, + .expected_comma_after_field, + .expected_comma_after_arg, + .expected_comma_after_param, + .expected_comma_after_initializer, + .expected_comma_after_switch_prong, + .expected_semi_or_else, + .expected_semi_or_lbrace, + .expected_token, + .expected_block, + .expected_block_or_assignment, + .expected_block_or_expr, + .expected_block_or_field, + .expected_expr, + .expected_expr_or_assignment, + .expected_fn, + .expected_inlinable, + .expected_labelable, + .expected_param_list, + .expected_prefix_expr, + .expected_primary_type_expr, + .expected_pub_item, + .expected_return_type, + .expected_suffix_op, + .expected_type_expr, + .expected_var_decl, + .expected_var_decl_or_fn, + .expected_loop_payload, + .expected_container, + => if (msg.token != 0 and !p.tokensOnSameLine(msg.token - 1, msg.token)) { + var copy = msg; + copy.token_is_prev = true; + copy.token -= 1; + return p.errors.append(p.gpa, copy); + }, + else => {}, + } + try p.errors.append(p.gpa, msg); +} + +fn fail(p: *Parse, tag: Ast.Error.Tag) error{ ParseError, OutOfMemory } { + @setCold(true); + return p.failMsg(.{ .tag = tag, .token = p.tok_i }); +} + +fn failExpected(p: *Parse, expected_token: Token.Tag) error{ ParseError, OutOfMemory } { + @setCold(true); + return p.failMsg(.{ + .tag = .expected_token, + .token = p.tok_i, + .extra = .{ .expected_tag = expected_token }, + }); +} + +fn failMsg(p: *Parse, msg: Ast.Error) error{ ParseError, OutOfMemory } { + @setCold(true); + try p.warnMsg(msg); + return error.ParseError; +} + +/// Root <- skip container_doc_comment? ContainerMembers eof +pub fn parseRoot(p: *Parse) !void { + // Root node must be index 0. + p.nodes.appendAssumeCapacity(.{ + .tag = .root, + .main_token = 0, + .data = undefined, + }); + const root_members = try p.parseContainerMembers(); + const root_decls = try root_members.toSpan(p); + if (p.token_tags[p.tok_i] != .eof) { + try p.warnExpected(.eof); + } + p.nodes.items(.data)[0] = .{ + .lhs = root_decls.start, + .rhs = root_decls.end, + }; +} + +/// Parse in ZON mode. Subset of the language. +/// TODO: set a flag in Parse struct, and honor that flag +/// by emitting compilation errors when non-zon nodes are encountered. +pub fn parseZon(p: *Parse) !void { + const node_index = p.parseExpr() catch |err| switch (err) { + error.ParseError => { + assert(p.errors.items.len > 0); + return; + }, + else => |e| return e, + }; + assert(node_index == 0); + if (p.token_tags[p.tok_i] != .eof) { + try p.warnExpected(.eof); + } +} + +/// ContainerMembers <- ContainerDeclarations (ContainerField COMMA)* (ContainerField / ContainerDeclarations) +/// +/// ContainerDeclarations +/// <- TestDecl ContainerDeclarations +/// / ComptimeDecl ContainerDeclarations +/// / doc_comment? KEYWORD_pub? Decl ContainerDeclarations +/// / +/// +/// ComptimeDecl <- KEYWORD_comptime Block +fn parseContainerMembers(p: *Parse) !Members { + const scratch_top = p.scratch.items.len; + defer p.scratch.shrinkRetainingCapacity(scratch_top); + + var field_state: union(enum) { + /// No fields have been seen. + none, + /// Currently parsing fields. + seen, + /// Saw fields and then a declaration after them. + /// Payload is first token of previous declaration. + end: Node.Index, + /// There was a declaration between fields, don't report more errors. + err, + } = .none; + + var last_field: TokenIndex = undefined; + + // Skip container doc comments. + while (p.eatToken(.container_doc_comment)) |_| {} + + var trailing = false; + while (true) { + const doc_comment = try p.eatDocComments(); + + switch (p.token_tags[p.tok_i]) { + .keyword_test => { + if (doc_comment) |some| { + try p.warnMsg(.{ .tag = .test_doc_comment, .token = some }); + } + const test_decl_node = try p.expectTestDeclRecoverable(); + if (test_decl_node != 0) { + if (field_state == .seen) { + field_state = .{ .end = test_decl_node }; + } + try p.scratch.append(p.gpa, test_decl_node); + } + trailing = false; + }, + .keyword_comptime => switch (p.token_tags[p.tok_i + 1]) { + .l_brace => { + if (doc_comment) |some| { + try p.warnMsg(.{ .tag = .comptime_doc_comment, .token = some }); + } + const comptime_token = p.nextToken(); + const block = p.parseBlock() catch |err| switch (err) { + error.OutOfMemory => return error.OutOfMemory, + error.ParseError => blk: { + p.findNextContainerMember(); + break :blk null_node; + }, + }; + if (block != 0) { + const comptime_node = try p.addNode(.{ + .tag = .@"comptime", + .main_token = comptime_token, + .data = .{ + .lhs = block, + .rhs = undefined, + }, + }); + if (field_state == .seen) { + field_state = .{ .end = comptime_node }; + } + try p.scratch.append(p.gpa, comptime_node); + } + trailing = false; + }, + else => { + const identifier = p.tok_i; + defer last_field = identifier; + const container_field = p.expectContainerField() catch |err| switch (err) { + error.OutOfMemory => return error.OutOfMemory, + error.ParseError => { + p.findNextContainerMember(); + continue; + }, + }; + switch (field_state) { + .none => field_state = .seen, + .err, .seen => {}, + .end => |node| { + try p.warnMsg(.{ + .tag = .decl_between_fields, + .token = p.nodes.items(.main_token)[node], + }); + try p.warnMsg(.{ + .tag = .previous_field, + .is_note = true, + .token = last_field, + }); + try p.warnMsg(.{ + .tag = .next_field, + .is_note = true, + .token = identifier, + }); + // Continue parsing; error will be reported later. + field_state = .err; + }, + } + try p.scratch.append(p.gpa, container_field); + switch (p.token_tags[p.tok_i]) { + .comma => { + p.tok_i += 1; + trailing = true; + continue; + }, + .r_brace, .eof => { + trailing = false; + break; + }, + else => {}, + } + // There is not allowed to be a decl after a field with no comma. + // Report error but recover parser. + try p.warn(.expected_comma_after_field); + p.findNextContainerMember(); + }, + }, + .keyword_pub => { + p.tok_i += 1; + const top_level_decl = try p.expectTopLevelDeclRecoverable(); + if (top_level_decl != 0) { + if (field_state == .seen) { + field_state = .{ .end = top_level_decl }; + } + try p.scratch.append(p.gpa, top_level_decl); + } + trailing = p.token_tags[p.tok_i - 1] == .semicolon; + }, + .keyword_usingnamespace => { + const node = try p.expectUsingNamespaceRecoverable(); + if (node != 0) { + if (field_state == .seen) { + field_state = .{ .end = node }; + } + try p.scratch.append(p.gpa, node); + } + trailing = p.token_tags[p.tok_i - 1] == .semicolon; + }, + .keyword_const, + .keyword_var, + .keyword_threadlocal, + .keyword_export, + .keyword_extern, + .keyword_inline, + .keyword_noinline, + .keyword_fn, + => { + const top_level_decl = try p.expectTopLevelDeclRecoverable(); + if (top_level_decl != 0) { + if (field_state == .seen) { + field_state = .{ .end = top_level_decl }; + } + try p.scratch.append(p.gpa, top_level_decl); + } + trailing = p.token_tags[p.tok_i - 1] == .semicolon; + }, + .eof, .r_brace => { + if (doc_comment) |tok| { + try p.warnMsg(.{ + .tag = .unattached_doc_comment, + .token = tok, + }); + } + break; + }, + else => { + const c_container = p.parseCStyleContainer() catch |err| switch (err) { + error.OutOfMemory => return error.OutOfMemory, + error.ParseError => false, + }; + if (c_container) continue; + + const identifier = p.tok_i; + defer last_field = identifier; + const container_field = p.expectContainerField() catch |err| switch (err) { + error.OutOfMemory => return error.OutOfMemory, + error.ParseError => { + p.findNextContainerMember(); + continue; + }, + }; + switch (field_state) { + .none => field_state = .seen, + .err, .seen => {}, + .end => |node| { + try p.warnMsg(.{ + .tag = .decl_between_fields, + .token = p.nodes.items(.main_token)[node], + }); + try p.warnMsg(.{ + .tag = .previous_field, + .is_note = true, + .token = last_field, + }); + try p.warnMsg(.{ + .tag = .next_field, + .is_note = true, + .token = identifier, + }); + // Continue parsing; error will be reported later. + field_state = .err; + }, + } + try p.scratch.append(p.gpa, container_field); + switch (p.token_tags[p.tok_i]) { + .comma => { + p.tok_i += 1; + trailing = true; + continue; + }, + .r_brace, .eof => { + trailing = false; + break; + }, + else => {}, + } + // There is not allowed to be a decl after a field with no comma. + // Report error but recover parser. + try p.warn(.expected_comma_after_field); + if (p.token_tags[p.tok_i] == .semicolon and p.token_tags[identifier] == .identifier) { + try p.warnMsg(.{ + .tag = .var_const_decl, + .is_note = true, + .token = identifier, + }); + } + p.findNextContainerMember(); + continue; + }, + } + } + + const items = p.scratch.items[scratch_top..]; + switch (items.len) { + 0 => return Members{ + .len = 0, + .lhs = 0, + .rhs = 0, + .trailing = trailing, + }, + 1 => return Members{ + .len = 1, + .lhs = items[0], + .rhs = 0, + .trailing = trailing, + }, + 2 => return Members{ + .len = 2, + .lhs = items[0], + .rhs = items[1], + .trailing = trailing, + }, + else => { + const span = try p.listToSpan(items); + return Members{ + .len = items.len, + .lhs = span.start, + .rhs = span.end, + .trailing = trailing, + }; + }, + } +} + +/// Attempts to find next container member by searching for certain tokens +fn findNextContainerMember(p: *Parse) void { + var level: u32 = 0; + while (true) { + const tok = p.nextToken(); + switch (p.token_tags[tok]) { + // Any of these can start a new top level declaration. + .keyword_test, + .keyword_comptime, + .keyword_pub, + .keyword_export, + .keyword_extern, + .keyword_inline, + .keyword_noinline, + .keyword_usingnamespace, + .keyword_threadlocal, + .keyword_const, + .keyword_var, + .keyword_fn, + => { + if (level == 0) { + p.tok_i -= 1; + return; + } + }, + .identifier => { + if (p.token_tags[tok + 1] == .comma and level == 0) { + p.tok_i -= 1; + return; + } + }, + .comma, .semicolon => { + // this decl was likely meant to end here + if (level == 0) { + return; + } + }, + .l_paren, .l_bracket, .l_brace => level += 1, + .r_paren, .r_bracket => { + if (level != 0) level -= 1; + }, + .r_brace => { + if (level == 0) { + // end of container, exit + p.tok_i -= 1; + return; + } + level -= 1; + }, + .eof => { + p.tok_i -= 1; + return; + }, + else => {}, + } + } +} + +/// Attempts to find the next statement by searching for a semicolon +fn findNextStmt(p: *Parse) void { + var level: u32 = 0; + while (true) { + const tok = p.nextToken(); + switch (p.token_tags[tok]) { + .l_brace => level += 1, + .r_brace => { + if (level == 0) { + p.tok_i -= 1; + return; + } + level -= 1; + }, + .semicolon => { + if (level == 0) { + return; + } + }, + .eof => { + p.tok_i -= 1; + return; + }, + else => {}, + } + } +} + +/// TestDecl <- KEYWORD_test (STRINGLITERALSINGLE / IDENTIFIER)? Block +fn expectTestDecl(p: *Parse) !Node.Index { + const test_token = p.assertToken(.keyword_test); + const name_token = switch (p.token_tags[p.nextToken()]) { + .string_literal, .identifier => p.tok_i - 1, + else => blk: { + p.tok_i -= 1; + break :blk null; + }, + }; + const block_node = try p.parseBlock(); + if (block_node == 0) return p.fail(.expected_block); + return p.addNode(.{ + .tag = .test_decl, + .main_token = test_token, + .data = .{ + .lhs = name_token orelse 0, + .rhs = block_node, + }, + }); +} + +fn expectTestDeclRecoverable(p: *Parse) error{OutOfMemory}!Node.Index { + return p.expectTestDecl() catch |err| switch (err) { + error.OutOfMemory => return error.OutOfMemory, + error.ParseError => { + p.findNextContainerMember(); + return null_node; + }, + }; +} + +/// Decl +/// <- (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE? / (KEYWORD_inline / KEYWORD_noinline))? FnProto (SEMICOLON / Block) +/// / (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE?)? KEYWORD_threadlocal? VarDecl +/// / KEYWORD_usingnamespace Expr SEMICOLON +fn expectTopLevelDecl(p: *Parse) !Node.Index { + const extern_export_inline_token = p.nextToken(); + var is_extern: bool = false; + var expect_fn: bool = false; + var expect_var_or_fn: bool = false; + switch (p.token_tags[extern_export_inline_token]) { + .keyword_extern => { + _ = p.eatToken(.string_literal); + is_extern = true; + expect_var_or_fn = true; + }, + .keyword_export => expect_var_or_fn = true, + .keyword_inline, .keyword_noinline => expect_fn = true, + else => p.tok_i -= 1, + } + const fn_proto = try p.parseFnProto(); + if (fn_proto != 0) { + switch (p.token_tags[p.tok_i]) { + .semicolon => { + p.tok_i += 1; + return fn_proto; + }, + .l_brace => { + if (is_extern) { + try p.warnMsg(.{ .tag = .extern_fn_body, .token = extern_export_inline_token }); + return null_node; + } + const fn_decl_index = try p.reserveNode(.fn_decl); + errdefer p.unreserveNode(fn_decl_index); + + const body_block = try p.parseBlock(); + assert(body_block != 0); + return p.setNode(fn_decl_index, .{ + .tag = .fn_decl, + .main_token = p.nodes.items(.main_token)[fn_proto], + .data = .{ + .lhs = fn_proto, + .rhs = body_block, + }, + }); + }, + else => { + // Since parseBlock only return error.ParseError on + // a missing '}' we can assume this function was + // supposed to end here. + try p.warn(.expected_semi_or_lbrace); + return null_node; + }, + } + } + if (expect_fn) { + try p.warn(.expected_fn); + return error.ParseError; + } + + const thread_local_token = p.eatToken(.keyword_threadlocal); + const var_decl = try p.parseVarDecl(); + if (var_decl != 0) { + try p.expectSemicolon(.expected_semi_after_decl, false); + return var_decl; + } + if (thread_local_token != null) { + return p.fail(.expected_var_decl); + } + if (expect_var_or_fn) { + return p.fail(.expected_var_decl_or_fn); + } + if (p.token_tags[p.tok_i] != .keyword_usingnamespace) { + return p.fail(.expected_pub_item); + } + return p.expectUsingNamespace(); +} + +fn expectTopLevelDeclRecoverable(p: *Parse) error{OutOfMemory}!Node.Index { + return p.expectTopLevelDecl() catch |err| switch (err) { + error.OutOfMemory => return error.OutOfMemory, + error.ParseError => { + p.findNextContainerMember(); + return null_node; + }, + }; +} + +fn expectUsingNamespace(p: *Parse) !Node.Index { + const usingnamespace_token = p.assertToken(.keyword_usingnamespace); + const expr = try p.expectExpr(); + try p.expectSemicolon(.expected_semi_after_decl, false); + return p.addNode(.{ + .tag = .@"usingnamespace", + .main_token = usingnamespace_token, + .data = .{ + .lhs = expr, + .rhs = undefined, + }, + }); +} + +fn expectUsingNamespaceRecoverable(p: *Parse) error{OutOfMemory}!Node.Index { + return p.expectUsingNamespace() catch |err| switch (err) { + error.OutOfMemory => return error.OutOfMemory, + error.ParseError => { + p.findNextContainerMember(); + return null_node; + }, + }; +} + +/// FnProto <- KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? AddrSpace? LinkSection? CallConv? EXCLAMATIONMARK? TypeExpr +fn parseFnProto(p: *Parse) !Node.Index { + const fn_token = p.eatToken(.keyword_fn) orelse return null_node; + + // We want the fn proto node to be before its children in the array. + const fn_proto_index = try p.reserveNode(.fn_proto); + errdefer p.unreserveNode(fn_proto_index); + + _ = p.eatToken(.identifier); + const params = try p.parseParamDeclList(); + const align_expr = try p.parseByteAlign(); + const addrspace_expr = try p.parseAddrSpace(); + const section_expr = try p.parseLinkSection(); + const callconv_expr = try p.parseCallconv(); + _ = p.eatToken(.bang); + + const return_type_expr = try p.parseTypeExpr(); + if (return_type_expr == 0) { + // most likely the user forgot to specify the return type. + // Mark return type as invalid and try to continue. + try p.warn(.expected_return_type); + } + + if (align_expr == 0 and section_expr == 0 and callconv_expr == 0 and addrspace_expr == 0) { + switch (params) { + .zero_or_one => |param| return p.setNode(fn_proto_index, .{ + .tag = .fn_proto_simple, + .main_token = fn_token, + .data = .{ + .lhs = param, + .rhs = return_type_expr, + }, + }), + .multi => |span| { + return p.setNode(fn_proto_index, .{ + .tag = .fn_proto_multi, + .main_token = fn_token, + .data = .{ + .lhs = try p.addExtra(Node.SubRange{ + .start = span.start, + .end = span.end, + }), + .rhs = return_type_expr, + }, + }); + }, + } + } + switch (params) { + .zero_or_one => |param| return p.setNode(fn_proto_index, .{ + .tag = .fn_proto_one, + .main_token = fn_token, + .data = .{ + .lhs = try p.addExtra(Node.FnProtoOne{ + .param = param, + .align_expr = align_expr, + .addrspace_expr = addrspace_expr, + .section_expr = section_expr, + .callconv_expr = callconv_expr, + }), + .rhs = return_type_expr, + }, + }), + .multi => |span| { + return p.setNode(fn_proto_index, .{ + .tag = .fn_proto, + .main_token = fn_token, + .data = .{ + .lhs = try p.addExtra(Node.FnProto{ + .params_start = span.start, + .params_end = span.end, + .align_expr = align_expr, + .addrspace_expr = addrspace_expr, + .section_expr = section_expr, + .callconv_expr = callconv_expr, + }), + .rhs = return_type_expr, + }, + }); + }, + } +} + +/// VarDecl <- (KEYWORD_const / KEYWORD_var) IDENTIFIER (COLON TypeExpr)? ByteAlign? AddrSpace? LinkSection? (EQUAL Expr)? SEMICOLON +fn parseVarDecl(p: *Parse) !Node.Index { + const mut_token = p.eatToken(.keyword_const) orelse + p.eatToken(.keyword_var) orelse + return null_node; + + _ = try p.expectToken(.identifier); + const type_node: Node.Index = if (p.eatToken(.colon) == null) 0 else try p.expectTypeExpr(); + const align_node = try p.parseByteAlign(); + const addrspace_node = try p.parseAddrSpace(); + const section_node = try p.parseLinkSection(); + const init_node: Node.Index = switch (p.token_tags[p.tok_i]) { + .equal_equal => blk: { + try p.warn(.wrong_equal_var_decl); + p.tok_i += 1; + break :blk try p.expectExpr(); + }, + .equal => blk: { + p.tok_i += 1; + break :blk try p.expectExpr(); + }, + else => 0, + }; + if (section_node == 0 and addrspace_node == 0) { + if (align_node == 0) { + return p.addNode(.{ + .tag = .simple_var_decl, + .main_token = mut_token, + .data = .{ + .lhs = type_node, + .rhs = init_node, + }, + }); + } else if (type_node == 0) { + return p.addNode(.{ + .tag = .aligned_var_decl, + .main_token = mut_token, + .data = .{ + .lhs = align_node, + .rhs = init_node, + }, + }); + } else { + return p.addNode(.{ + .tag = .local_var_decl, + .main_token = mut_token, + .data = .{ + .lhs = try p.addExtra(Node.LocalVarDecl{ + .type_node = type_node, + .align_node = align_node, + }), + .rhs = init_node, + }, + }); + } + } else { + return p.addNode(.{ + .tag = .global_var_decl, + .main_token = mut_token, + .data = .{ + .lhs = try p.addExtra(Node.GlobalVarDecl{ + .type_node = type_node, + .align_node = align_node, + .addrspace_node = addrspace_node, + .section_node = section_node, + }), + .rhs = init_node, + }, + }); + } +} + +/// ContainerField +/// <- doc_comment? KEYWORD_comptime? IDENTIFIER (COLON TypeExpr)? ByteAlign? (EQUAL Expr)? +/// / doc_comment? KEYWORD_comptime? (IDENTIFIER COLON)? !KEYWORD_fn TypeExpr ByteAlign? (EQUAL Expr)? +fn expectContainerField(p: *Parse) !Node.Index { + var main_token = p.tok_i; + _ = p.eatToken(.keyword_comptime); + const tuple_like = p.token_tags[p.tok_i] != .identifier or p.token_tags[p.tok_i + 1] != .colon; + if (!tuple_like) { + main_token = p.assertToken(.identifier); + } + + var align_expr: Node.Index = 0; + var type_expr: Node.Index = 0; + if (p.eatToken(.colon) != null or tuple_like) { + type_expr = try p.expectTypeExpr(); + align_expr = try p.parseByteAlign(); + } + + const value_expr: Node.Index = if (p.eatToken(.equal) == null) 0 else try p.expectExpr(); + + if (align_expr == 0) { + return p.addNode(.{ + .tag = .container_field_init, + .main_token = main_token, + .data = .{ + .lhs = type_expr, + .rhs = value_expr, + }, + }); + } else if (value_expr == 0) { + return p.addNode(.{ + .tag = .container_field_align, + .main_token = main_token, + .data = .{ + .lhs = type_expr, + .rhs = align_expr, + }, + }); + } else { + return p.addNode(.{ + .tag = .container_field, + .main_token = main_token, + .data = .{ + .lhs = type_expr, + .rhs = try p.addExtra(Node.ContainerField{ + .value_expr = value_expr, + .align_expr = align_expr, + }), + }, + }); + } +} + +/// Statement +/// <- KEYWORD_comptime? VarDecl +/// / KEYWORD_comptime BlockExprStatement +/// / KEYWORD_nosuspend BlockExprStatement +/// / KEYWORD_suspend BlockExprStatement +/// / KEYWORD_defer BlockExprStatement +/// / KEYWORD_errdefer Payload? BlockExprStatement +/// / IfStatement +/// / LabeledStatement +/// / SwitchExpr +/// / AssignExpr SEMICOLON +fn parseStatement(p: *Parse, allow_defer_var: bool) Error!Node.Index { + const comptime_token = p.eatToken(.keyword_comptime); + + if (allow_defer_var) { + const var_decl = try p.parseVarDecl(); + if (var_decl != 0) { + try p.expectSemicolon(.expected_semi_after_decl, true); + return var_decl; + } + } + + if (comptime_token) |token| { + return p.addNode(.{ + .tag = .@"comptime", + .main_token = token, + .data = .{ + .lhs = try p.expectBlockExprStatement(), + .rhs = undefined, + }, + }); + } + + switch (p.token_tags[p.tok_i]) { + .keyword_nosuspend => { + return p.addNode(.{ + .tag = .@"nosuspend", + .main_token = p.nextToken(), + .data = .{ + .lhs = try p.expectBlockExprStatement(), + .rhs = undefined, + }, + }); + }, + .keyword_suspend => { + const token = p.nextToken(); + const block_expr = try p.expectBlockExprStatement(); + return p.addNode(.{ + .tag = .@"suspend", + .main_token = token, + .data = .{ + .lhs = block_expr, + .rhs = undefined, + }, + }); + }, + .keyword_defer => if (allow_defer_var) return p.addNode(.{ + .tag = .@"defer", + .main_token = p.nextToken(), + .data = .{ + .lhs = undefined, + .rhs = try p.expectBlockExprStatement(), + }, + }), + .keyword_errdefer => if (allow_defer_var) return p.addNode(.{ + .tag = .@"errdefer", + .main_token = p.nextToken(), + .data = .{ + .lhs = try p.parsePayload(), + .rhs = try p.expectBlockExprStatement(), + }, + }), + .keyword_switch => return p.expectSwitchExpr(), + .keyword_if => return p.expectIfStatement(), + .keyword_enum, .keyword_struct, .keyword_union => { + const identifier = p.tok_i + 1; + if (try p.parseCStyleContainer()) { + // Return something so that `expectStatement` is happy. + return p.addNode(.{ + .tag = .identifier, + .main_token = identifier, + .data = .{ + .lhs = undefined, + .rhs = undefined, + }, + }); + } + }, + else => {}, + } + + const labeled_statement = try p.parseLabeledStatement(); + if (labeled_statement != 0) return labeled_statement; + + const assign_expr = try p.parseAssignExpr(); + if (assign_expr != 0) { + try p.expectSemicolon(.expected_semi_after_stmt, true); + return assign_expr; + } + + return null_node; +} + +fn expectStatement(p: *Parse, allow_defer_var: bool) !Node.Index { + const statement = try p.parseStatement(allow_defer_var); + if (statement == 0) { + return p.fail(.expected_statement); + } + return statement; +} + +/// If a parse error occurs, reports an error, but then finds the next statement +/// and returns that one instead. If a parse error occurs but there is no following +/// statement, returns 0. +fn expectStatementRecoverable(p: *Parse) Error!Node.Index { + while (true) { + return p.expectStatement(true) catch |err| switch (err) { + error.OutOfMemory => return error.OutOfMemory, + error.ParseError => { + p.findNextStmt(); // Try to skip to the next statement. + switch (p.token_tags[p.tok_i]) { + .r_brace => return null_node, + .eof => return error.ParseError, + else => continue, + } + }, + }; + } +} + +/// IfStatement +/// <- IfPrefix BlockExpr ( KEYWORD_else Payload? Statement )? +/// / IfPrefix AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement ) +fn expectIfStatement(p: *Parse) !Node.Index { + const if_token = p.assertToken(.keyword_if); + _ = try p.expectToken(.l_paren); + const condition = try p.expectExpr(); + _ = try p.expectToken(.r_paren); + _ = try p.parsePtrPayload(); + + // TODO propose to change the syntax so that semicolons are always required + // inside if statements, even if there is an `else`. + var else_required = false; + const then_expr = blk: { + const block_expr = try p.parseBlockExpr(); + if (block_expr != 0) break :blk block_expr; + const assign_expr = try p.parseAssignExpr(); + if (assign_expr == 0) { + return p.fail(.expected_block_or_assignment); + } + if (p.eatToken(.semicolon)) |_| { + return p.addNode(.{ + .tag = .if_simple, + .main_token = if_token, + .data = .{ + .lhs = condition, + .rhs = assign_expr, + }, + }); + } + else_required = true; + break :blk assign_expr; + }; + _ = p.eatToken(.keyword_else) orelse { + if (else_required) { + try p.warn(.expected_semi_or_else); + } + return p.addNode(.{ + .tag = .if_simple, + .main_token = if_token, + .data = .{ + .lhs = condition, + .rhs = then_expr, + }, + }); + }; + _ = try p.parsePayload(); + const else_expr = try p.expectStatement(false); + return p.addNode(.{ + .tag = .@"if", + .main_token = if_token, + .data = .{ + .lhs = condition, + .rhs = try p.addExtra(Node.If{ + .then_expr = then_expr, + .else_expr = else_expr, + }), + }, + }); +} + +/// LabeledStatement <- BlockLabel? (Block / LoopStatement) +fn parseLabeledStatement(p: *Parse) !Node.Index { + const label_token = p.parseBlockLabel(); + const block = try p.parseBlock(); + if (block != 0) return block; + + const loop_stmt = try p.parseLoopStatement(); + if (loop_stmt != 0) return loop_stmt; + + if (label_token != 0) { + const after_colon = p.tok_i; + const node = try p.parseTypeExpr(); + if (node != 0) { + const a = try p.parseByteAlign(); + const b = try p.parseAddrSpace(); + const c = try p.parseLinkSection(); + const d = if (p.eatToken(.equal) == null) 0 else try p.expectExpr(); + if (a != 0 or b != 0 or c != 0 or d != 0) { + return p.failMsg(.{ .tag = .expected_var_const, .token = label_token }); + } + } + return p.failMsg(.{ .tag = .expected_labelable, .token = after_colon }); + } + + return null_node; +} + +/// LoopStatement <- KEYWORD_inline? (ForStatement / WhileStatement) +fn parseLoopStatement(p: *Parse) !Node.Index { + const inline_token = p.eatToken(.keyword_inline); + + const for_statement = try p.parseForStatement(); + if (for_statement != 0) return for_statement; + + const while_statement = try p.parseWhileStatement(); + if (while_statement != 0) return while_statement; + + if (inline_token == null) return null_node; + + // If we've seen "inline", there should have been a "for" or "while" + return p.fail(.expected_inlinable); +} + +/// ForPrefix <- KEYWORD_for LPAREN Expr RPAREN PtrIndexPayload +/// +/// ForStatement +/// <- ForPrefix BlockExpr ( KEYWORD_else Statement )? +/// / ForPrefix AssignExpr ( SEMICOLON / KEYWORD_else Statement ) +fn parseForStatement(p: *Parse) !Node.Index { + const for_token = p.eatToken(.keyword_for) orelse return null_node; + _ = try p.expectToken(.l_paren); + const array_expr = try p.expectExpr(); + _ = try p.expectToken(.r_paren); + const found_payload = try p.parsePtrIndexPayload(); + if (found_payload == 0) try p.warn(.expected_loop_payload); + + // TODO propose to change the syntax so that semicolons are always required + // inside while statements, even if there is an `else`. + var else_required = false; + const then_expr = blk: { + const block_expr = try p.parseBlockExpr(); + if (block_expr != 0) break :blk block_expr; + const assign_expr = try p.parseAssignExpr(); + if (assign_expr == 0) { + return p.fail(.expected_block_or_assignment); + } + if (p.eatToken(.semicolon)) |_| { + return p.addNode(.{ + .tag = .for_simple, + .main_token = for_token, + .data = .{ + .lhs = array_expr, + .rhs = assign_expr, + }, + }); + } + else_required = true; + break :blk assign_expr; + }; + _ = p.eatToken(.keyword_else) orelse { + if (else_required) { + try p.warn(.expected_semi_or_else); + } + return p.addNode(.{ + .tag = .for_simple, + .main_token = for_token, + .data = .{ + .lhs = array_expr, + .rhs = then_expr, + }, + }); + }; + return p.addNode(.{ + .tag = .@"for", + .main_token = for_token, + .data = .{ + .lhs = array_expr, + .rhs = try p.addExtra(Node.If{ + .then_expr = then_expr, + .else_expr = try p.expectStatement(false), + }), + }, + }); +} + +/// WhilePrefix <- KEYWORD_while LPAREN Expr RPAREN PtrPayload? WhileContinueExpr? +/// +/// WhileStatement +/// <- WhilePrefix BlockExpr ( KEYWORD_else Payload? Statement )? +/// / WhilePrefix AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement ) +fn parseWhileStatement(p: *Parse) !Node.Index { + const while_token = p.eatToken(.keyword_while) orelse return null_node; + _ = try p.expectToken(.l_paren); + const condition = try p.expectExpr(); + _ = try p.expectToken(.r_paren); + _ = try p.parsePtrPayload(); + const cont_expr = try p.parseWhileContinueExpr(); + + // TODO propose to change the syntax so that semicolons are always required + // inside while statements, even if there is an `else`. + var else_required = false; + const then_expr = blk: { + const block_expr = try p.parseBlockExpr(); + if (block_expr != 0) break :blk block_expr; + const assign_expr = try p.parseAssignExpr(); + if (assign_expr == 0) { + return p.fail(.expected_block_or_assignment); + } + if (p.eatToken(.semicolon)) |_| { + if (cont_expr == 0) { + return p.addNode(.{ + .tag = .while_simple, + .main_token = while_token, + .data = .{ + .lhs = condition, + .rhs = assign_expr, + }, + }); + } else { + return p.addNode(.{ + .tag = .while_cont, + .main_token = while_token, + .data = .{ + .lhs = condition, + .rhs = try p.addExtra(Node.WhileCont{ + .cont_expr = cont_expr, + .then_expr = assign_expr, + }), + }, + }); + } + } + else_required = true; + break :blk assign_expr; + }; + _ = p.eatToken(.keyword_else) orelse { + if (else_required) { + try p.warn(.expected_semi_or_else); + } + if (cont_expr == 0) { + return p.addNode(.{ + .tag = .while_simple, + .main_token = while_token, + .data = .{ + .lhs = condition, + .rhs = then_expr, + }, + }); + } else { + return p.addNode(.{ + .tag = .while_cont, + .main_token = while_token, + .data = .{ + .lhs = condition, + .rhs = try p.addExtra(Node.WhileCont{ + .cont_expr = cont_expr, + .then_expr = then_expr, + }), + }, + }); + } + }; + _ = try p.parsePayload(); + const else_expr = try p.expectStatement(false); + return p.addNode(.{ + .tag = .@"while", + .main_token = while_token, + .data = .{ + .lhs = condition, + .rhs = try p.addExtra(Node.While{ + .cont_expr = cont_expr, + .then_expr = then_expr, + .else_expr = else_expr, + }), + }, + }); +} + +/// BlockExprStatement +/// <- BlockExpr +/// / AssignExpr SEMICOLON +fn parseBlockExprStatement(p: *Parse) !Node.Index { + const block_expr = try p.parseBlockExpr(); + if (block_expr != 0) { + return block_expr; + } + const assign_expr = try p.parseAssignExpr(); + if (assign_expr != 0) { + try p.expectSemicolon(.expected_semi_after_stmt, true); + return assign_expr; + } + return null_node; +} + +fn expectBlockExprStatement(p: *Parse) !Node.Index { + const node = try p.parseBlockExprStatement(); + if (node == 0) { + return p.fail(.expected_block_or_expr); + } + return node; +} + +/// BlockExpr <- BlockLabel? Block +fn parseBlockExpr(p: *Parse) Error!Node.Index { + switch (p.token_tags[p.tok_i]) { + .identifier => { + if (p.token_tags[p.tok_i + 1] == .colon and + p.token_tags[p.tok_i + 2] == .l_brace) + { + p.tok_i += 2; + return p.parseBlock(); + } else { + return null_node; + } + }, + .l_brace => return p.parseBlock(), + else => return null_node, + } +} + +/// AssignExpr <- Expr (AssignOp Expr)? +/// +/// AssignOp +/// <- ASTERISKEQUAL +/// / ASTERISKPIPEEQUAL +/// / SLASHEQUAL +/// / PERCENTEQUAL +/// / PLUSEQUAL +/// / PLUSPIPEEQUAL +/// / MINUSEQUAL +/// / MINUSPIPEEQUAL +/// / LARROW2EQUAL +/// / LARROW2PIPEEQUAL +/// / RARROW2EQUAL +/// / AMPERSANDEQUAL +/// / CARETEQUAL +/// / PIPEEQUAL +/// / ASTERISKPERCENTEQUAL +/// / PLUSPERCENTEQUAL +/// / MINUSPERCENTEQUAL +/// / EQUAL +fn parseAssignExpr(p: *Parse) !Node.Index { + const expr = try p.parseExpr(); + if (expr == 0) return null_node; + + const tag: Node.Tag = switch (p.token_tags[p.tok_i]) { + .asterisk_equal => .assign_mul, + .slash_equal => .assign_div, + .percent_equal => .assign_mod, + .plus_equal => .assign_add, + .minus_equal => .assign_sub, + .angle_bracket_angle_bracket_left_equal => .assign_shl, + .angle_bracket_angle_bracket_left_pipe_equal => .assign_shl_sat, + .angle_bracket_angle_bracket_right_equal => .assign_shr, + .ampersand_equal => .assign_bit_and, + .caret_equal => .assign_bit_xor, + .pipe_equal => .assign_bit_or, + .asterisk_percent_equal => .assign_mul_wrap, + .plus_percent_equal => .assign_add_wrap, + .minus_percent_equal => .assign_sub_wrap, + .asterisk_pipe_equal => .assign_mul_sat, + .plus_pipe_equal => .assign_add_sat, + .minus_pipe_equal => .assign_sub_sat, + .equal => .assign, + else => return expr, + }; + return p.addNode(.{ + .tag = tag, + .main_token = p.nextToken(), + .data = .{ + .lhs = expr, + .rhs = try p.expectExpr(), + }, + }); +} + +fn expectAssignExpr(p: *Parse) !Node.Index { + const expr = try p.parseAssignExpr(); + if (expr == 0) { + return p.fail(.expected_expr_or_assignment); + } + return expr; +} + +fn parseExpr(p: *Parse) Error!Node.Index { + return p.parseExprPrecedence(0); +} + +fn expectExpr(p: *Parse) Error!Node.Index { + const node = try p.parseExpr(); + if (node == 0) { + return p.fail(.expected_expr); + } else { + return node; + } +} + +const Assoc = enum { + left, + none, +}; + +const OperInfo = struct { + prec: i8, + tag: Node.Tag, + assoc: Assoc = Assoc.left, +}; + +// A table of binary operator information. Higher precedence numbers are +// stickier. All operators at the same precedence level should have the same +// associativity. +const operTable = std.enums.directEnumArrayDefault(Token.Tag, OperInfo, .{ .prec = -1, .tag = Node.Tag.root }, 0, .{ + .keyword_or = .{ .prec = 10, .tag = .bool_or }, + + .keyword_and = .{ .prec = 20, .tag = .bool_and }, + + .equal_equal = .{ .prec = 30, .tag = .equal_equal, .assoc = Assoc.none }, + .bang_equal = .{ .prec = 30, .tag = .bang_equal, .assoc = Assoc.none }, + .angle_bracket_left = .{ .prec = 30, .tag = .less_than, .assoc = Assoc.none }, + .angle_bracket_right = .{ .prec = 30, .tag = .greater_than, .assoc = Assoc.none }, + .angle_bracket_left_equal = .{ .prec = 30, .tag = .less_or_equal, .assoc = Assoc.none }, + .angle_bracket_right_equal = .{ .prec = 30, .tag = .greater_or_equal, .assoc = Assoc.none }, + + .ampersand = .{ .prec = 40, .tag = .bit_and }, + .caret = .{ .prec = 40, .tag = .bit_xor }, + .pipe = .{ .prec = 40, .tag = .bit_or }, + .keyword_orelse = .{ .prec = 40, .tag = .@"orelse" }, + .keyword_catch = .{ .prec = 40, .tag = .@"catch" }, + + .angle_bracket_angle_bracket_left = .{ .prec = 50, .tag = .shl }, + .angle_bracket_angle_bracket_left_pipe = .{ .prec = 50, .tag = .shl_sat }, + .angle_bracket_angle_bracket_right = .{ .prec = 50, .tag = .shr }, + + .plus = .{ .prec = 60, .tag = .add }, + .minus = .{ .prec = 60, .tag = .sub }, + .plus_plus = .{ .prec = 60, .tag = .array_cat }, + .plus_percent = .{ .prec = 60, .tag = .add_wrap }, + .minus_percent = .{ .prec = 60, .tag = .sub_wrap }, + .plus_pipe = .{ .prec = 60, .tag = .add_sat }, + .minus_pipe = .{ .prec = 60, .tag = .sub_sat }, + + .pipe_pipe = .{ .prec = 70, .tag = .merge_error_sets }, + .asterisk = .{ .prec = 70, .tag = .mul }, + .slash = .{ .prec = 70, .tag = .div }, + .percent = .{ .prec = 70, .tag = .mod }, + .asterisk_asterisk = .{ .prec = 70, .tag = .array_mult }, + .asterisk_percent = .{ .prec = 70, .tag = .mul_wrap }, + .asterisk_pipe = .{ .prec = 70, .tag = .mul_sat }, +}); + +fn parseExprPrecedence(p: *Parse, min_prec: i32) Error!Node.Index { + assert(min_prec >= 0); + var node = try p.parsePrefixExpr(); + if (node == 0) { + return null_node; + } + + var banned_prec: i8 = -1; + + while (true) { + const tok_tag = p.token_tags[p.tok_i]; + const info = operTable[@intCast(usize, @enumToInt(tok_tag))]; + if (info.prec < min_prec) { + break; + } + if (info.prec == banned_prec) { + return p.fail(.chained_comparison_operators); + } + + const oper_token = p.nextToken(); + // Special-case handling for "catch" + if (tok_tag == .keyword_catch) { + _ = try p.parsePayload(); + } + const rhs = try p.parseExprPrecedence(info.prec + 1); + if (rhs == 0) { + try p.warn(.expected_expr); + return node; + } + + { + const tok_len = tok_tag.lexeme().?.len; + const char_before = p.source[p.token_starts[oper_token] - 1]; + const char_after = p.source[p.token_starts[oper_token] + tok_len]; + if (tok_tag == .ampersand and char_after == '&') { + // without types we don't know if '&&' was intended as 'bitwise_and address_of', or a c-style logical_and + // The best the parser can do is recommend changing it to 'and' or ' & &' + try p.warnMsg(.{ .tag = .invalid_ampersand_ampersand, .token = oper_token }); + } else if (std.ascii.isWhitespace(char_before) != std.ascii.isWhitespace(char_after)) { + try p.warnMsg(.{ .tag = .mismatched_binary_op_whitespace, .token = oper_token }); + } + } + + node = try p.addNode(.{ + .tag = info.tag, + .main_token = oper_token, + .data = .{ + .lhs = node, + .rhs = rhs, + }, + }); + + if (info.assoc == Assoc.none) { + banned_prec = info.prec; + } + } + + return node; +} + +/// PrefixExpr <- PrefixOp* PrimaryExpr +/// +/// PrefixOp +/// <- EXCLAMATIONMARK +/// / MINUS +/// / TILDE +/// / MINUSPERCENT +/// / AMPERSAND +/// / KEYWORD_try +/// / KEYWORD_await +fn parsePrefixExpr(p: *Parse) Error!Node.Index { + const tag: Node.Tag = switch (p.token_tags[p.tok_i]) { + .bang => .bool_not, + .minus => .negation, + .tilde => .bit_not, + .minus_percent => .negation_wrap, + .ampersand => .address_of, + .keyword_try => .@"try", + .keyword_await => .@"await", + else => return p.parsePrimaryExpr(), + }; + return p.addNode(.{ + .tag = tag, + .main_token = p.nextToken(), + .data = .{ + .lhs = try p.expectPrefixExpr(), + .rhs = undefined, + }, + }); +} + +fn expectPrefixExpr(p: *Parse) Error!Node.Index { + const node = try p.parsePrefixExpr(); + if (node == 0) { + return p.fail(.expected_prefix_expr); + } + return node; +} + +/// TypeExpr <- PrefixTypeOp* ErrorUnionExpr +/// +/// PrefixTypeOp +/// <- QUESTIONMARK +/// / KEYWORD_anyframe MINUSRARROW +/// / SliceTypeStart (ByteAlign / AddrSpace / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)* +/// / PtrTypeStart (AddrSpace / KEYWORD_align LPAREN Expr (COLON Expr COLON Expr)? RPAREN / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)* +/// / ArrayTypeStart +/// +/// SliceTypeStart <- LBRACKET (COLON Expr)? RBRACKET +/// +/// PtrTypeStart +/// <- ASTERISK +/// / ASTERISK2 +/// / LBRACKET ASTERISK (LETTERC / COLON Expr)? RBRACKET +/// +/// ArrayTypeStart <- LBRACKET Expr (COLON Expr)? RBRACKET +fn parseTypeExpr(p: *Parse) Error!Node.Index { + switch (p.token_tags[p.tok_i]) { + .question_mark => return p.addNode(.{ + .tag = .optional_type, + .main_token = p.nextToken(), + .data = .{ + .lhs = try p.expectTypeExpr(), + .rhs = undefined, + }, + }), + .keyword_anyframe => switch (p.token_tags[p.tok_i + 1]) { + .arrow => return p.addNode(.{ + .tag = .anyframe_type, + .main_token = p.nextToken(), + .data = .{ + .lhs = p.nextToken(), + .rhs = try p.expectTypeExpr(), + }, + }), + else => return p.parseErrorUnionExpr(), + }, + .asterisk => { + const asterisk = p.nextToken(); + const mods = try p.parsePtrModifiers(); + const elem_type = try p.expectTypeExpr(); + if (mods.bit_range_start != 0) { + return p.addNode(.{ + .tag = .ptr_type_bit_range, + .main_token = asterisk, + .data = .{ + .lhs = try p.addExtra(Node.PtrTypeBitRange{ + .sentinel = 0, + .align_node = mods.align_node, + .addrspace_node = mods.addrspace_node, + .bit_range_start = mods.bit_range_start, + .bit_range_end = mods.bit_range_end, + }), + .rhs = elem_type, + }, + }); + } else if (mods.addrspace_node != 0) { + return p.addNode(.{ + .tag = .ptr_type, + .main_token = asterisk, + .data = .{ + .lhs = try p.addExtra(Node.PtrType{ + .sentinel = 0, + .align_node = mods.align_node, + .addrspace_node = mods.addrspace_node, + }), + .rhs = elem_type, + }, + }); + } else { + return p.addNode(.{ + .tag = .ptr_type_aligned, + .main_token = asterisk, + .data = .{ + .lhs = mods.align_node, + .rhs = elem_type, + }, + }); + } + }, + .asterisk_asterisk => { + const asterisk = p.nextToken(); + const mods = try p.parsePtrModifiers(); + const elem_type = try p.expectTypeExpr(); + const inner: Node.Index = inner: { + if (mods.bit_range_start != 0) { + break :inner try p.addNode(.{ + .tag = .ptr_type_bit_range, + .main_token = asterisk, + .data = .{ + .lhs = try p.addExtra(Node.PtrTypeBitRange{ + .sentinel = 0, + .align_node = mods.align_node, + .addrspace_node = mods.addrspace_node, + .bit_range_start = mods.bit_range_start, + .bit_range_end = mods.bit_range_end, + }), + .rhs = elem_type, + }, + }); + } else if (mods.addrspace_node != 0) { + break :inner try p.addNode(.{ + .tag = .ptr_type, + .main_token = asterisk, + .data = .{ + .lhs = try p.addExtra(Node.PtrType{ + .sentinel = 0, + .align_node = mods.align_node, + .addrspace_node = mods.addrspace_node, + }), + .rhs = elem_type, + }, + }); + } else { + break :inner try p.addNode(.{ + .tag = .ptr_type_aligned, + .main_token = asterisk, + .data = .{ + .lhs = mods.align_node, + .rhs = elem_type, + }, + }); + } + }; + return p.addNode(.{ + .tag = .ptr_type_aligned, + .main_token = asterisk, + .data = .{ + .lhs = 0, + .rhs = inner, + }, + }); + }, + .l_bracket => switch (p.token_tags[p.tok_i + 1]) { + .asterisk => { + _ = p.nextToken(); + const asterisk = p.nextToken(); + var sentinel: Node.Index = 0; + if (p.eatToken(.identifier)) |ident| { + const ident_slice = p.source[p.token_starts[ident]..p.token_starts[ident + 1]]; + if (!std.mem.eql(u8, std.mem.trimRight(u8, ident_slice, &std.ascii.whitespace), "c")) { + p.tok_i -= 1; + } + } else if (p.eatToken(.colon)) |_| { + sentinel = try p.expectExpr(); + } + _ = try p.expectToken(.r_bracket); + const mods = try p.parsePtrModifiers(); + const elem_type = try p.expectTypeExpr(); + if (mods.bit_range_start == 0) { + if (sentinel == 0 and mods.addrspace_node == 0) { + return p.addNode(.{ + .tag = .ptr_type_aligned, + .main_token = asterisk, + .data = .{ + .lhs = mods.align_node, + .rhs = elem_type, + }, + }); + } else if (mods.align_node == 0 and mods.addrspace_node == 0) { + return p.addNode(.{ + .tag = .ptr_type_sentinel, + .main_token = asterisk, + .data = .{ + .lhs = sentinel, + .rhs = elem_type, + }, + }); + } else { + return p.addNode(.{ + .tag = .ptr_type, + .main_token = asterisk, + .data = .{ + .lhs = try p.addExtra(Node.PtrType{ + .sentinel = sentinel, + .align_node = mods.align_node, + .addrspace_node = mods.addrspace_node, + }), + .rhs = elem_type, + }, + }); + } + } else { + return p.addNode(.{ + .tag = .ptr_type_bit_range, + .main_token = asterisk, + .data = .{ + .lhs = try p.addExtra(Node.PtrTypeBitRange{ + .sentinel = sentinel, + .align_node = mods.align_node, + .addrspace_node = mods.addrspace_node, + .bit_range_start = mods.bit_range_start, + .bit_range_end = mods.bit_range_end, + }), + .rhs = elem_type, + }, + }); + } + }, + else => { + const lbracket = p.nextToken(); + const len_expr = try p.parseExpr(); + const sentinel: Node.Index = if (p.eatToken(.colon)) |_| + try p.expectExpr() + else + 0; + _ = try p.expectToken(.r_bracket); + if (len_expr == 0) { + const mods = try p.parsePtrModifiers(); + const elem_type = try p.expectTypeExpr(); + if (mods.bit_range_start != 0) { + try p.warnMsg(.{ + .tag = .invalid_bit_range, + .token = p.nodes.items(.main_token)[mods.bit_range_start], + }); + } + if (sentinel == 0 and mods.addrspace_node == 0) { + return p.addNode(.{ + .tag = .ptr_type_aligned, + .main_token = lbracket, + .data = .{ + .lhs = mods.align_node, + .rhs = elem_type, + }, + }); + } else if (mods.align_node == 0 and mods.addrspace_node == 0) { + return p.addNode(.{ + .tag = .ptr_type_sentinel, + .main_token = lbracket, + .data = .{ + .lhs = sentinel, + .rhs = elem_type, + }, + }); + } else { + return p.addNode(.{ + .tag = .ptr_type, + .main_token = lbracket, + .data = .{ + .lhs = try p.addExtra(Node.PtrType{ + .sentinel = sentinel, + .align_node = mods.align_node, + .addrspace_node = mods.addrspace_node, + }), + .rhs = elem_type, + }, + }); + } + } else { + switch (p.token_tags[p.tok_i]) { + .keyword_align, + .keyword_const, + .keyword_volatile, + .keyword_allowzero, + .keyword_addrspace, + => return p.fail(.ptr_mod_on_array_child_type), + else => {}, + } + const elem_type = try p.expectTypeExpr(); + if (sentinel == 0) { + return p.addNode(.{ + .tag = .array_type, + .main_token = lbracket, + .data = .{ + .lhs = len_expr, + .rhs = elem_type, + }, + }); + } else { + return p.addNode(.{ + .tag = .array_type_sentinel, + .main_token = lbracket, + .data = .{ + .lhs = len_expr, + .rhs = try p.addExtra(.{ + .elem_type = elem_type, + .sentinel = sentinel, + }), + }, + }); + } + } + }, + }, + else => return p.parseErrorUnionExpr(), + } +} + +fn expectTypeExpr(p: *Parse) Error!Node.Index { + const node = try p.parseTypeExpr(); + if (node == 0) { + return p.fail(.expected_type_expr); + } + return node; +} + +/// PrimaryExpr +/// <- AsmExpr +/// / IfExpr +/// / KEYWORD_break BreakLabel? Expr? +/// / KEYWORD_comptime Expr +/// / KEYWORD_nosuspend Expr +/// / KEYWORD_continue BreakLabel? +/// / KEYWORD_resume Expr +/// / KEYWORD_return Expr? +/// / BlockLabel? LoopExpr +/// / Block +/// / CurlySuffixExpr +fn parsePrimaryExpr(p: *Parse) !Node.Index { + switch (p.token_tags[p.tok_i]) { + .keyword_asm => return p.expectAsmExpr(), + .keyword_if => return p.parseIfExpr(), + .keyword_break => { + p.tok_i += 1; + return p.addNode(.{ + .tag = .@"break", + .main_token = p.tok_i - 1, + .data = .{ + .lhs = try p.parseBreakLabel(), + .rhs = try p.parseExpr(), + }, + }); + }, + .keyword_continue => { + p.tok_i += 1; + return p.addNode(.{ + .tag = .@"continue", + .main_token = p.tok_i - 1, + .data = .{ + .lhs = try p.parseBreakLabel(), + .rhs = undefined, + }, + }); + }, + .keyword_comptime => { + p.tok_i += 1; + return p.addNode(.{ + .tag = .@"comptime", + .main_token = p.tok_i - 1, + .data = .{ + .lhs = try p.expectExpr(), + .rhs = undefined, + }, + }); + }, + .keyword_nosuspend => { + p.tok_i += 1; + return p.addNode(.{ + .tag = .@"nosuspend", + .main_token = p.tok_i - 1, + .data = .{ + .lhs = try p.expectExpr(), + .rhs = undefined, + }, + }); + }, + .keyword_resume => { + p.tok_i += 1; + return p.addNode(.{ + .tag = .@"resume", + .main_token = p.tok_i - 1, + .data = .{ + .lhs = try p.expectExpr(), + .rhs = undefined, + }, + }); + }, + .keyword_return => { + p.tok_i += 1; + return p.addNode(.{ + .tag = .@"return", + .main_token = p.tok_i - 1, + .data = .{ + .lhs = try p.parseExpr(), + .rhs = undefined, + }, + }); + }, + .identifier => { + if (p.token_tags[p.tok_i + 1] == .colon) { + switch (p.token_tags[p.tok_i + 2]) { + .keyword_inline => { + p.tok_i += 3; + switch (p.token_tags[p.tok_i]) { + .keyword_for => return p.parseForExpr(), + .keyword_while => return p.parseWhileExpr(), + else => return p.fail(.expected_inlinable), + } + }, + .keyword_for => { + p.tok_i += 2; + return p.parseForExpr(); + }, + .keyword_while => { + p.tok_i += 2; + return p.parseWhileExpr(); + }, + .l_brace => { + p.tok_i += 2; + return p.parseBlock(); + }, + else => return p.parseCurlySuffixExpr(), + } + } else { + return p.parseCurlySuffixExpr(); + } + }, + .keyword_inline => { + p.tok_i += 1; + switch (p.token_tags[p.tok_i]) { + .keyword_for => return p.parseForExpr(), + .keyword_while => return p.parseWhileExpr(), + else => return p.fail(.expected_inlinable), + } + }, + .keyword_for => return p.parseForExpr(), + .keyword_while => return p.parseWhileExpr(), + .l_brace => return p.parseBlock(), + else => return p.parseCurlySuffixExpr(), + } +} + +/// IfExpr <- IfPrefix Expr (KEYWORD_else Payload? Expr)? +fn parseIfExpr(p: *Parse) !Node.Index { + return p.parseIf(expectExpr); +} + +/// Block <- LBRACE Statement* RBRACE +fn parseBlock(p: *Parse) !Node.Index { + const lbrace = p.eatToken(.l_brace) orelse return null_node; + const scratch_top = p.scratch.items.len; + defer p.scratch.shrinkRetainingCapacity(scratch_top); + while (true) { + if (p.token_tags[p.tok_i] == .r_brace) break; + const statement = try p.expectStatementRecoverable(); + if (statement == 0) break; + try p.scratch.append(p.gpa, statement); + } + _ = try p.expectToken(.r_brace); + const semicolon = (p.token_tags[p.tok_i - 2] == .semicolon); + const statements = p.scratch.items[scratch_top..]; + switch (statements.len) { + 0 => return p.addNode(.{ + .tag = .block_two, + .main_token = lbrace, + .data = .{ + .lhs = 0, + .rhs = 0, + }, + }), + 1 => return p.addNode(.{ + .tag = if (semicolon) .block_two_semicolon else .block_two, + .main_token = lbrace, + .data = .{ + .lhs = statements[0], + .rhs = 0, + }, + }), + 2 => return p.addNode(.{ + .tag = if (semicolon) .block_two_semicolon else .block_two, + .main_token = lbrace, + .data = .{ + .lhs = statements[0], + .rhs = statements[1], + }, + }), + else => { + const span = try p.listToSpan(statements); + return p.addNode(.{ + .tag = if (semicolon) .block_semicolon else .block, + .main_token = lbrace, + .data = .{ + .lhs = span.start, + .rhs = span.end, + }, + }); + }, + } +} + +/// ForPrefix <- KEYWORD_for LPAREN Expr RPAREN PtrIndexPayload +/// +/// ForExpr <- ForPrefix Expr (KEYWORD_else Expr)? +fn parseForExpr(p: *Parse) !Node.Index { + const for_token = p.eatToken(.keyword_for) orelse return null_node; + _ = try p.expectToken(.l_paren); + const array_expr = try p.expectExpr(); + _ = try p.expectToken(.r_paren); + const found_payload = try p.parsePtrIndexPayload(); + if (found_payload == 0) try p.warn(.expected_loop_payload); + + const then_expr = try p.expectExpr(); + _ = p.eatToken(.keyword_else) orelse { + return p.addNode(.{ + .tag = .for_simple, + .main_token = for_token, + .data = .{ + .lhs = array_expr, + .rhs = then_expr, + }, + }); + }; + const else_expr = try p.expectExpr(); + return p.addNode(.{ + .tag = .@"for", + .main_token = for_token, + .data = .{ + .lhs = array_expr, + .rhs = try p.addExtra(Node.If{ + .then_expr = then_expr, + .else_expr = else_expr, + }), + }, + }); +} + +/// WhilePrefix <- KEYWORD_while LPAREN Expr RPAREN PtrPayload? WhileContinueExpr? +/// +/// WhileExpr <- WhilePrefix Expr (KEYWORD_else Payload? Expr)? +fn parseWhileExpr(p: *Parse) !Node.Index { + const while_token = p.eatToken(.keyword_while) orelse return null_node; + _ = try p.expectToken(.l_paren); + const condition = try p.expectExpr(); + _ = try p.expectToken(.r_paren); + _ = try p.parsePtrPayload(); + const cont_expr = try p.parseWhileContinueExpr(); + + const then_expr = try p.expectExpr(); + _ = p.eatToken(.keyword_else) orelse { + if (cont_expr == 0) { + return p.addNode(.{ + .tag = .while_simple, + .main_token = while_token, + .data = .{ + .lhs = condition, + .rhs = then_expr, + }, + }); + } else { + return p.addNode(.{ + .tag = .while_cont, + .main_token = while_token, + .data = .{ + .lhs = condition, + .rhs = try p.addExtra(Node.WhileCont{ + .cont_expr = cont_expr, + .then_expr = then_expr, + }), + }, + }); + } + }; + _ = try p.parsePayload(); + const else_expr = try p.expectExpr(); + return p.addNode(.{ + .tag = .@"while", + .main_token = while_token, + .data = .{ + .lhs = condition, + .rhs = try p.addExtra(Node.While{ + .cont_expr = cont_expr, + .then_expr = then_expr, + .else_expr = else_expr, + }), + }, + }); +} + +/// CurlySuffixExpr <- TypeExpr InitList? +/// +/// InitList +/// <- LBRACE FieldInit (COMMA FieldInit)* COMMA? RBRACE +/// / LBRACE Expr (COMMA Expr)* COMMA? RBRACE +/// / LBRACE RBRACE +fn parseCurlySuffixExpr(p: *Parse) !Node.Index { + const lhs = try p.parseTypeExpr(); + if (lhs == 0) return null_node; + const lbrace = p.eatToken(.l_brace) orelse return lhs; + + // If there are 0 or 1 items, we can use ArrayInitOne/StructInitOne; + // otherwise we use the full ArrayInit/StructInit. + + const scratch_top = p.scratch.items.len; + defer p.scratch.shrinkRetainingCapacity(scratch_top); + const field_init = try p.parseFieldInit(); + if (field_init != 0) { + try p.scratch.append(p.gpa, field_init); + while (true) { + switch (p.token_tags[p.tok_i]) { + .comma => p.tok_i += 1, + .r_brace => { + p.tok_i += 1; + break; + }, + .colon, .r_paren, .r_bracket => return p.failExpected(.r_brace), + // Likely just a missing comma; give error but continue parsing. + else => try p.warn(.expected_comma_after_initializer), + } + if (p.eatToken(.r_brace)) |_| break; + const next = try p.expectFieldInit(); + try p.scratch.append(p.gpa, next); + } + const comma = (p.token_tags[p.tok_i - 2] == .comma); + const inits = p.scratch.items[scratch_top..]; + switch (inits.len) { + 0 => unreachable, + 1 => return p.addNode(.{ + .tag = if (comma) .struct_init_one_comma else .struct_init_one, + .main_token = lbrace, + .data = .{ + .lhs = lhs, + .rhs = inits[0], + }, + }), + else => return p.addNode(.{ + .tag = if (comma) .struct_init_comma else .struct_init, + .main_token = lbrace, + .data = .{ + .lhs = lhs, + .rhs = try p.addExtra(try p.listToSpan(inits)), + }, + }), + } + } + + while (true) { + if (p.eatToken(.r_brace)) |_| break; + const elem_init = try p.expectExpr(); + try p.scratch.append(p.gpa, elem_init); + switch (p.token_tags[p.tok_i]) { + .comma => p.tok_i += 1, + .r_brace => { + p.tok_i += 1; + break; + }, + .colon, .r_paren, .r_bracket => return p.failExpected(.r_brace), + // Likely just a missing comma; give error but continue parsing. + else => try p.warn(.expected_comma_after_initializer), + } + } + const comma = (p.token_tags[p.tok_i - 2] == .comma); + const inits = p.scratch.items[scratch_top..]; + switch (inits.len) { + 0 => return p.addNode(.{ + .tag = .struct_init_one, + .main_token = lbrace, + .data = .{ + .lhs = lhs, + .rhs = 0, + }, + }), + 1 => return p.addNode(.{ + .tag = if (comma) .array_init_one_comma else .array_init_one, + .main_token = lbrace, + .data = .{ + .lhs = lhs, + .rhs = inits[0], + }, + }), + else => return p.addNode(.{ + .tag = if (comma) .array_init_comma else .array_init, + .main_token = lbrace, + .data = .{ + .lhs = lhs, + .rhs = try p.addExtra(try p.listToSpan(inits)), + }, + }), + } +} + +/// ErrorUnionExpr <- SuffixExpr (EXCLAMATIONMARK TypeExpr)? +fn parseErrorUnionExpr(p: *Parse) !Node.Index { + const suffix_expr = try p.parseSuffixExpr(); + if (suffix_expr == 0) return null_node; + const bang = p.eatToken(.bang) orelse return suffix_expr; + return p.addNode(.{ + .tag = .error_union, + .main_token = bang, + .data = .{ + .lhs = suffix_expr, + .rhs = try p.expectTypeExpr(), + }, + }); +} + +/// SuffixExpr +/// <- KEYWORD_async PrimaryTypeExpr SuffixOp* FnCallArguments +/// / PrimaryTypeExpr (SuffixOp / FnCallArguments)* +/// +/// FnCallArguments <- LPAREN ExprList RPAREN +/// +/// ExprList <- (Expr COMMA)* Expr? +fn parseSuffixExpr(p: *Parse) !Node.Index { + if (p.eatToken(.keyword_async)) |_| { + var res = try p.expectPrimaryTypeExpr(); + while (true) { + const node = try p.parseSuffixOp(res); + if (node == 0) break; + res = node; + } + const lparen = p.eatToken(.l_paren) orelse { + try p.warn(.expected_param_list); + return res; + }; + const scratch_top = p.scratch.items.len; + defer p.scratch.shrinkRetainingCapacity(scratch_top); + while (true) { + if (p.eatToken(.r_paren)) |_| break; + const param = try p.expectExpr(); + try p.scratch.append(p.gpa, param); + switch (p.token_tags[p.tok_i]) { + .comma => p.tok_i += 1, + .r_paren => { + p.tok_i += 1; + break; + }, + .colon, .r_brace, .r_bracket => return p.failExpected(.r_paren), + // Likely just a missing comma; give error but continue parsing. + else => try p.warn(.expected_comma_after_arg), + } + } + const comma = (p.token_tags[p.tok_i - 2] == .comma); + const params = p.scratch.items[scratch_top..]; + switch (params.len) { + 0 => return p.addNode(.{ + .tag = if (comma) .async_call_one_comma else .async_call_one, + .main_token = lparen, + .data = .{ + .lhs = res, + .rhs = 0, + }, + }), + 1 => return p.addNode(.{ + .tag = if (comma) .async_call_one_comma else .async_call_one, + .main_token = lparen, + .data = .{ + .lhs = res, + .rhs = params[0], + }, + }), + else => return p.addNode(.{ + .tag = if (comma) .async_call_comma else .async_call, + .main_token = lparen, + .data = .{ + .lhs = res, + .rhs = try p.addExtra(try p.listToSpan(params)), + }, + }), + } + } + + var res = try p.parsePrimaryTypeExpr(); + if (res == 0) return res; + while (true) { + const suffix_op = try p.parseSuffixOp(res); + if (suffix_op != 0) { + res = suffix_op; + continue; + } + const lparen = p.eatToken(.l_paren) orelse return res; + const scratch_top = p.scratch.items.len; + defer p.scratch.shrinkRetainingCapacity(scratch_top); + while (true) { + if (p.eatToken(.r_paren)) |_| break; + const param = try p.expectExpr(); + try p.scratch.append(p.gpa, param); + switch (p.token_tags[p.tok_i]) { + .comma => p.tok_i += 1, + .r_paren => { + p.tok_i += 1; + break; + }, + .colon, .r_brace, .r_bracket => return p.failExpected(.r_paren), + // Likely just a missing comma; give error but continue parsing. + else => try p.warn(.expected_comma_after_arg), + } + } + const comma = (p.token_tags[p.tok_i - 2] == .comma); + const params = p.scratch.items[scratch_top..]; + res = switch (params.len) { + 0 => try p.addNode(.{ + .tag = if (comma) .call_one_comma else .call_one, + .main_token = lparen, + .data = .{ + .lhs = res, + .rhs = 0, + }, + }), + 1 => try p.addNode(.{ + .tag = if (comma) .call_one_comma else .call_one, + .main_token = lparen, + .data = .{ + .lhs = res, + .rhs = params[0], + }, + }), + else => try p.addNode(.{ + .tag = if (comma) .call_comma else .call, + .main_token = lparen, + .data = .{ + .lhs = res, + .rhs = try p.addExtra(try p.listToSpan(params)), + }, + }), + }; + } +} + +/// PrimaryTypeExpr +/// <- BUILTINIDENTIFIER FnCallArguments +/// / CHAR_LITERAL +/// / ContainerDecl +/// / DOT IDENTIFIER +/// / DOT InitList +/// / ErrorSetDecl +/// / FLOAT +/// / FnProto +/// / GroupedExpr +/// / LabeledTypeExpr +/// / IDENTIFIER +/// / IfTypeExpr +/// / INTEGER +/// / KEYWORD_comptime TypeExpr +/// / KEYWORD_error DOT IDENTIFIER +/// / KEYWORD_anyframe +/// / KEYWORD_unreachable +/// / STRINGLITERAL +/// / SwitchExpr +/// +/// ContainerDecl <- (KEYWORD_extern / KEYWORD_packed)? ContainerDeclAuto +/// +/// ContainerDeclAuto <- ContainerDeclType LBRACE container_doc_comment? ContainerMembers RBRACE +/// +/// InitList +/// <- LBRACE FieldInit (COMMA FieldInit)* COMMA? RBRACE +/// / LBRACE Expr (COMMA Expr)* COMMA? RBRACE +/// / LBRACE RBRACE +/// +/// ErrorSetDecl <- KEYWORD_error LBRACE IdentifierList RBRACE +/// +/// GroupedExpr <- LPAREN Expr RPAREN +/// +/// IfTypeExpr <- IfPrefix TypeExpr (KEYWORD_else Payload? TypeExpr)? +/// +/// LabeledTypeExpr +/// <- BlockLabel Block +/// / BlockLabel? LoopTypeExpr +/// +/// LoopTypeExpr <- KEYWORD_inline? (ForTypeExpr / WhileTypeExpr) +fn parsePrimaryTypeExpr(p: *Parse) !Node.Index { + switch (p.token_tags[p.tok_i]) { + .char_literal => return p.addNode(.{ + .tag = .char_literal, + .main_token = p.nextToken(), + .data = .{ + .lhs = undefined, + .rhs = undefined, + }, + }), + .number_literal => return p.addNode(.{ + .tag = .number_literal, + .main_token = p.nextToken(), + .data = .{ + .lhs = undefined, + .rhs = undefined, + }, + }), + .keyword_unreachable => return p.addNode(.{ + .tag = .unreachable_literal, + .main_token = p.nextToken(), + .data = .{ + .lhs = undefined, + .rhs = undefined, + }, + }), + .keyword_anyframe => return p.addNode(.{ + .tag = .anyframe_literal, + .main_token = p.nextToken(), + .data = .{ + .lhs = undefined, + .rhs = undefined, + }, + }), + .string_literal => { + const main_token = p.nextToken(); + return p.addNode(.{ + .tag = .string_literal, + .main_token = main_token, + .data = .{ + .lhs = undefined, + .rhs = undefined, + }, + }); + }, + + .builtin => return p.parseBuiltinCall(), + .keyword_fn => return p.parseFnProto(), + .keyword_if => return p.parseIf(expectTypeExpr), + .keyword_switch => return p.expectSwitchExpr(), + + .keyword_extern, + .keyword_packed, + => { + p.tok_i += 1; + return p.parseContainerDeclAuto(); + }, + + .keyword_struct, + .keyword_opaque, + .keyword_enum, + .keyword_union, + => return p.parseContainerDeclAuto(), + + .keyword_comptime => return p.addNode(.{ + .tag = .@"comptime", + .main_token = p.nextToken(), + .data = .{ + .lhs = try p.expectTypeExpr(), + .rhs = undefined, + }, + }), + .multiline_string_literal_line => { + const first_line = p.nextToken(); + while (p.token_tags[p.tok_i] == .multiline_string_literal_line) { + p.tok_i += 1; + } + return p.addNode(.{ + .tag = .multiline_string_literal, + .main_token = first_line, + .data = .{ + .lhs = first_line, + .rhs = p.tok_i - 1, + }, + }); + }, + .identifier => switch (p.token_tags[p.tok_i + 1]) { + .colon => switch (p.token_tags[p.tok_i + 2]) { + .keyword_inline => { + p.tok_i += 3; + switch (p.token_tags[p.tok_i]) { + .keyword_for => return p.parseForTypeExpr(), + .keyword_while => return p.parseWhileTypeExpr(), + else => return p.fail(.expected_inlinable), + } + }, + .keyword_for => { + p.tok_i += 2; + return p.parseForTypeExpr(); + }, + .keyword_while => { + p.tok_i += 2; + return p.parseWhileTypeExpr(); + }, + .l_brace => { + p.tok_i += 2; + return p.parseBlock(); + }, + else => return p.addNode(.{ + .tag = .identifier, + .main_token = p.nextToken(), + .data = .{ + .lhs = undefined, + .rhs = undefined, + }, + }), + }, + else => return p.addNode(.{ + .tag = .identifier, + .main_token = p.nextToken(), + .data = .{ + .lhs = undefined, + .rhs = undefined, + }, + }), + }, + .keyword_inline => { + p.tok_i += 1; + switch (p.token_tags[p.tok_i]) { + .keyword_for => return p.parseForTypeExpr(), + .keyword_while => return p.parseWhileTypeExpr(), + else => return p.fail(.expected_inlinable), + } + }, + .keyword_for => return p.parseForTypeExpr(), + .keyword_while => return p.parseWhileTypeExpr(), + .period => switch (p.token_tags[p.tok_i + 1]) { + .identifier => return p.addNode(.{ + .tag = .enum_literal, + .data = .{ + .lhs = p.nextToken(), // dot + .rhs = undefined, + }, + .main_token = p.nextToken(), // identifier + }), + .l_brace => { + const lbrace = p.tok_i + 1; + p.tok_i = lbrace + 1; + + // If there are 0, 1, or 2 items, we can use ArrayInitDotTwo/StructInitDotTwo; + // otherwise we use the full ArrayInitDot/StructInitDot. + + const scratch_top = p.scratch.items.len; + defer p.scratch.shrinkRetainingCapacity(scratch_top); + const field_init = try p.parseFieldInit(); + if (field_init != 0) { + try p.scratch.append(p.gpa, field_init); + while (true) { + switch (p.token_tags[p.tok_i]) { + .comma => p.tok_i += 1, + .r_brace => { + p.tok_i += 1; + break; + }, + .colon, .r_paren, .r_bracket => return p.failExpected(.r_brace), + // Likely just a missing comma; give error but continue parsing. + else => try p.warn(.expected_comma_after_initializer), + } + if (p.eatToken(.r_brace)) |_| break; + const next = try p.expectFieldInit(); + try p.scratch.append(p.gpa, next); + } + const comma = (p.token_tags[p.tok_i - 2] == .comma); + const inits = p.scratch.items[scratch_top..]; + switch (inits.len) { + 0 => unreachable, + 1 => return p.addNode(.{ + .tag = if (comma) .struct_init_dot_two_comma else .struct_init_dot_two, + .main_token = lbrace, + .data = .{ + .lhs = inits[0], + .rhs = 0, + }, + }), + 2 => return p.addNode(.{ + .tag = if (comma) .struct_init_dot_two_comma else .struct_init_dot_two, + .main_token = lbrace, + .data = .{ + .lhs = inits[0], + .rhs = inits[1], + }, + }), + else => { + const span = try p.listToSpan(inits); + return p.addNode(.{ + .tag = if (comma) .struct_init_dot_comma else .struct_init_dot, + .main_token = lbrace, + .data = .{ + .lhs = span.start, + .rhs = span.end, + }, + }); + }, + } + } + + while (true) { + if (p.eatToken(.r_brace)) |_| break; + const elem_init = try p.expectExpr(); + try p.scratch.append(p.gpa, elem_init); + switch (p.token_tags[p.tok_i]) { + .comma => p.tok_i += 1, + .r_brace => { + p.tok_i += 1; + break; + }, + .colon, .r_paren, .r_bracket => return p.failExpected(.r_brace), + // Likely just a missing comma; give error but continue parsing. + else => try p.warn(.expected_comma_after_initializer), + } + } + const comma = (p.token_tags[p.tok_i - 2] == .comma); + const inits = p.scratch.items[scratch_top..]; + switch (inits.len) { + 0 => return p.addNode(.{ + .tag = .struct_init_dot_two, + .main_token = lbrace, + .data = .{ + .lhs = 0, + .rhs = 0, + }, + }), + 1 => return p.addNode(.{ + .tag = if (comma) .array_init_dot_two_comma else .array_init_dot_two, + .main_token = lbrace, + .data = .{ + .lhs = inits[0], + .rhs = 0, + }, + }), + 2 => return p.addNode(.{ + .tag = if (comma) .array_init_dot_two_comma else .array_init_dot_two, + .main_token = lbrace, + .data = .{ + .lhs = inits[0], + .rhs = inits[1], + }, + }), + else => { + const span = try p.listToSpan(inits); + return p.addNode(.{ + .tag = if (comma) .array_init_dot_comma else .array_init_dot, + .main_token = lbrace, + .data = .{ + .lhs = span.start, + .rhs = span.end, + }, + }); + }, + } + }, + else => return null_node, + }, + .keyword_error => switch (p.token_tags[p.tok_i + 1]) { + .l_brace => { + const error_token = p.tok_i; + p.tok_i += 2; + while (true) { + if (p.eatToken(.r_brace)) |_| break; + _ = try p.eatDocComments(); + _ = try p.expectToken(.identifier); + switch (p.token_tags[p.tok_i]) { + .comma => p.tok_i += 1, + .r_brace => { + p.tok_i += 1; + break; + }, + .colon, .r_paren, .r_bracket => return p.failExpected(.r_brace), + // Likely just a missing comma; give error but continue parsing. + else => try p.warn(.expected_comma_after_field), + } + } + return p.addNode(.{ + .tag = .error_set_decl, + .main_token = error_token, + .data = .{ + .lhs = undefined, + .rhs = p.tok_i - 1, // rbrace + }, + }); + }, + else => { + const main_token = p.nextToken(); + const period = p.eatToken(.period); + if (period == null) try p.warnExpected(.period); + const identifier = p.eatToken(.identifier); + if (identifier == null) try p.warnExpected(.identifier); + return p.addNode(.{ + .tag = .error_value, + .main_token = main_token, + .data = .{ + .lhs = period orelse 0, + .rhs = identifier orelse 0, + }, + }); + }, + }, + .l_paren => return p.addNode(.{ + .tag = .grouped_expression, + .main_token = p.nextToken(), + .data = .{ + .lhs = try p.expectExpr(), + .rhs = try p.expectToken(.r_paren), + }, + }), + else => return null_node, + } +} + +fn expectPrimaryTypeExpr(p: *Parse) !Node.Index { + const node = try p.parsePrimaryTypeExpr(); + if (node == 0) { + return p.fail(.expected_primary_type_expr); + } + return node; +} + +/// ForPrefix <- KEYWORD_for LPAREN Expr RPAREN PtrIndexPayload +/// +/// ForTypeExpr <- ForPrefix TypeExpr (KEYWORD_else TypeExpr)? +fn parseForTypeExpr(p: *Parse) !Node.Index { + const for_token = p.eatToken(.keyword_for) orelse return null_node; + _ = try p.expectToken(.l_paren); + const array_expr = try p.expectExpr(); + _ = try p.expectToken(.r_paren); + const found_payload = try p.parsePtrIndexPayload(); + if (found_payload == 0) try p.warn(.expected_loop_payload); + + const then_expr = try p.expectTypeExpr(); + _ = p.eatToken(.keyword_else) orelse { + return p.addNode(.{ + .tag = .for_simple, + .main_token = for_token, + .data = .{ + .lhs = array_expr, + .rhs = then_expr, + }, + }); + }; + const else_expr = try p.expectTypeExpr(); + return p.addNode(.{ + .tag = .@"for", + .main_token = for_token, + .data = .{ + .lhs = array_expr, + .rhs = try p.addExtra(Node.If{ + .then_expr = then_expr, + .else_expr = else_expr, + }), + }, + }); +} + +/// WhilePrefix <- KEYWORD_while LPAREN Expr RPAREN PtrPayload? WhileContinueExpr? +/// +/// WhileTypeExpr <- WhilePrefix TypeExpr (KEYWORD_else Payload? TypeExpr)? +fn parseWhileTypeExpr(p: *Parse) !Node.Index { + const while_token = p.eatToken(.keyword_while) orelse return null_node; + _ = try p.expectToken(.l_paren); + const condition = try p.expectExpr(); + _ = try p.expectToken(.r_paren); + _ = try p.parsePtrPayload(); + const cont_expr = try p.parseWhileContinueExpr(); + + const then_expr = try p.expectTypeExpr(); + _ = p.eatToken(.keyword_else) orelse { + if (cont_expr == 0) { + return p.addNode(.{ + .tag = .while_simple, + .main_token = while_token, + .data = .{ + .lhs = condition, + .rhs = then_expr, + }, + }); + } else { + return p.addNode(.{ + .tag = .while_cont, + .main_token = while_token, + .data = .{ + .lhs = condition, + .rhs = try p.addExtra(Node.WhileCont{ + .cont_expr = cont_expr, + .then_expr = then_expr, + }), + }, + }); + } + }; + _ = try p.parsePayload(); + const else_expr = try p.expectTypeExpr(); + return p.addNode(.{ + .tag = .@"while", + .main_token = while_token, + .data = .{ + .lhs = condition, + .rhs = try p.addExtra(Node.While{ + .cont_expr = cont_expr, + .then_expr = then_expr, + .else_expr = else_expr, + }), + }, + }); +} + +/// SwitchExpr <- KEYWORD_switch LPAREN Expr RPAREN LBRACE SwitchProngList RBRACE +fn expectSwitchExpr(p: *Parse) !Node.Index { + const switch_token = p.assertToken(.keyword_switch); + _ = try p.expectToken(.l_paren); + const expr_node = try p.expectExpr(); + _ = try p.expectToken(.r_paren); + _ = try p.expectToken(.l_brace); + const cases = try p.parseSwitchProngList(); + const trailing_comma = p.token_tags[p.tok_i - 1] == .comma; + _ = try p.expectToken(.r_brace); + + return p.addNode(.{ + .tag = if (trailing_comma) .switch_comma else .@"switch", + .main_token = switch_token, + .data = .{ + .lhs = expr_node, + .rhs = try p.addExtra(Node.SubRange{ + .start = cases.start, + .end = cases.end, + }), + }, + }); +} + +/// AsmExpr <- KEYWORD_asm KEYWORD_volatile? LPAREN Expr AsmOutput? RPAREN +/// +/// AsmOutput <- COLON AsmOutputList AsmInput? +/// +/// AsmInput <- COLON AsmInputList AsmClobbers? +/// +/// AsmClobbers <- COLON StringList +/// +/// StringList <- (STRINGLITERAL COMMA)* STRINGLITERAL? +/// +/// AsmOutputList <- (AsmOutputItem COMMA)* AsmOutputItem? +/// +/// AsmInputList <- (AsmInputItem COMMA)* AsmInputItem? +fn expectAsmExpr(p: *Parse) !Node.Index { + const asm_token = p.assertToken(.keyword_asm); + _ = p.eatToken(.keyword_volatile); + _ = try p.expectToken(.l_paren); + const template = try p.expectExpr(); + + if (p.eatToken(.r_paren)) |rparen| { + return p.addNode(.{ + .tag = .asm_simple, + .main_token = asm_token, + .data = .{ + .lhs = template, + .rhs = rparen, + }, + }); + } + + _ = try p.expectToken(.colon); + + const scratch_top = p.scratch.items.len; + defer p.scratch.shrinkRetainingCapacity(scratch_top); + + while (true) { + const output_item = try p.parseAsmOutputItem(); + if (output_item == 0) break; + try p.scratch.append(p.gpa, output_item); + switch (p.token_tags[p.tok_i]) { + .comma => p.tok_i += 1, + // All possible delimiters. + .colon, .r_paren, .r_brace, .r_bracket => break, + // Likely just a missing comma; give error but continue parsing. + else => try p.warnExpected(.comma), + } + } + if (p.eatToken(.colon)) |_| { + while (true) { + const input_item = try p.parseAsmInputItem(); + if (input_item == 0) break; + try p.scratch.append(p.gpa, input_item); + switch (p.token_tags[p.tok_i]) { + .comma => p.tok_i += 1, + // All possible delimiters. + .colon, .r_paren, .r_brace, .r_bracket => break, + // Likely just a missing comma; give error but continue parsing. + else => try p.warnExpected(.comma), + } + } + if (p.eatToken(.colon)) |_| { + while (p.eatToken(.string_literal)) |_| { + switch (p.token_tags[p.tok_i]) { + .comma => p.tok_i += 1, + .colon, .r_paren, .r_brace, .r_bracket => break, + // Likely just a missing comma; give error but continue parsing. + else => try p.warnExpected(.comma), + } + } + } + } + const rparen = try p.expectToken(.r_paren); + const span = try p.listToSpan(p.scratch.items[scratch_top..]); + return p.addNode(.{ + .tag = .@"asm", + .main_token = asm_token, + .data = .{ + .lhs = template, + .rhs = try p.addExtra(Node.Asm{ + .items_start = span.start, + .items_end = span.end, + .rparen = rparen, + }), + }, + }); +} + +/// AsmOutputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN (MINUSRARROW TypeExpr / IDENTIFIER) RPAREN +fn parseAsmOutputItem(p: *Parse) !Node.Index { + _ = p.eatToken(.l_bracket) orelse return null_node; + const identifier = try p.expectToken(.identifier); + _ = try p.expectToken(.r_bracket); + _ = try p.expectToken(.string_literal); + _ = try p.expectToken(.l_paren); + const type_expr: Node.Index = blk: { + if (p.eatToken(.arrow)) |_| { + break :blk try p.expectTypeExpr(); + } else { + _ = try p.expectToken(.identifier); + break :blk null_node; + } + }; + const rparen = try p.expectToken(.r_paren); + return p.addNode(.{ + .tag = .asm_output, + .main_token = identifier, + .data = .{ + .lhs = type_expr, + .rhs = rparen, + }, + }); +} + +/// AsmInputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN Expr RPAREN +fn parseAsmInputItem(p: *Parse) !Node.Index { + _ = p.eatToken(.l_bracket) orelse return null_node; + const identifier = try p.expectToken(.identifier); + _ = try p.expectToken(.r_bracket); + _ = try p.expectToken(.string_literal); + _ = try p.expectToken(.l_paren); + const expr = try p.expectExpr(); + const rparen = try p.expectToken(.r_paren); + return p.addNode(.{ + .tag = .asm_input, + .main_token = identifier, + .data = .{ + .lhs = expr, + .rhs = rparen, + }, + }); +} + +/// BreakLabel <- COLON IDENTIFIER +fn parseBreakLabel(p: *Parse) !TokenIndex { + _ = p.eatToken(.colon) orelse return @as(TokenIndex, 0); + return p.expectToken(.identifier); +} + +/// BlockLabel <- IDENTIFIER COLON +fn parseBlockLabel(p: *Parse) TokenIndex { + if (p.token_tags[p.tok_i] == .identifier and + p.token_tags[p.tok_i + 1] == .colon) + { + const identifier = p.tok_i; + p.tok_i += 2; + return identifier; + } + return null_node; +} + +/// FieldInit <- DOT IDENTIFIER EQUAL Expr +fn parseFieldInit(p: *Parse) !Node.Index { + if (p.token_tags[p.tok_i + 0] == .period and + p.token_tags[p.tok_i + 1] == .identifier and + p.token_tags[p.tok_i + 2] == .equal) + { + p.tok_i += 3; + return p.expectExpr(); + } else { + return null_node; + } +} + +fn expectFieldInit(p: *Parse) !Node.Index { + if (p.token_tags[p.tok_i] != .period or + p.token_tags[p.tok_i + 1] != .identifier or + p.token_tags[p.tok_i + 2] != .equal) + return p.fail(.expected_initializer); + + p.tok_i += 3; + return p.expectExpr(); +} + +/// WhileContinueExpr <- COLON LPAREN AssignExpr RPAREN +fn parseWhileContinueExpr(p: *Parse) !Node.Index { + _ = p.eatToken(.colon) orelse { + if (p.token_tags[p.tok_i] == .l_paren and + p.tokensOnSameLine(p.tok_i - 1, p.tok_i)) + return p.fail(.expected_continue_expr); + return null_node; + }; + _ = try p.expectToken(.l_paren); + const node = try p.parseAssignExpr(); + if (node == 0) return p.fail(.expected_expr_or_assignment); + _ = try p.expectToken(.r_paren); + return node; +} + +/// LinkSection <- KEYWORD_linksection LPAREN Expr RPAREN +fn parseLinkSection(p: *Parse) !Node.Index { + _ = p.eatToken(.keyword_linksection) orelse return null_node; + _ = try p.expectToken(.l_paren); + const expr_node = try p.expectExpr(); + _ = try p.expectToken(.r_paren); + return expr_node; +} + +/// CallConv <- KEYWORD_callconv LPAREN Expr RPAREN +fn parseCallconv(p: *Parse) !Node.Index { + _ = p.eatToken(.keyword_callconv) orelse return null_node; + _ = try p.expectToken(.l_paren); + const expr_node = try p.expectExpr(); + _ = try p.expectToken(.r_paren); + return expr_node; +} + +/// AddrSpace <- KEYWORD_addrspace LPAREN Expr RPAREN +fn parseAddrSpace(p: *Parse) !Node.Index { + _ = p.eatToken(.keyword_addrspace) orelse return null_node; + _ = try p.expectToken(.l_paren); + const expr_node = try p.expectExpr(); + _ = try p.expectToken(.r_paren); + return expr_node; +} + +/// This function can return null nodes and then still return nodes afterwards, +/// such as in the case of anytype and `...`. Caller must look for rparen to find +/// out when there are no more param decls left. +/// +/// ParamDecl +/// <- doc_comment? (KEYWORD_noalias / KEYWORD_comptime)? (IDENTIFIER COLON)? ParamType +/// / DOT3 +/// +/// ParamType +/// <- KEYWORD_anytype +/// / TypeExpr +fn expectParamDecl(p: *Parse) !Node.Index { + _ = try p.eatDocComments(); + switch (p.token_tags[p.tok_i]) { + .keyword_noalias, .keyword_comptime => p.tok_i += 1, + .ellipsis3 => { + p.tok_i += 1; + return null_node; + }, + else => {}, + } + if (p.token_tags[p.tok_i] == .identifier and + p.token_tags[p.tok_i + 1] == .colon) + { + p.tok_i += 2; + } + switch (p.token_tags[p.tok_i]) { + .keyword_anytype => { + p.tok_i += 1; + return null_node; + }, + else => return p.expectTypeExpr(), + } +} + +/// Payload <- PIPE IDENTIFIER PIPE +fn parsePayload(p: *Parse) !TokenIndex { + _ = p.eatToken(.pipe) orelse return @as(TokenIndex, 0); + const identifier = try p.expectToken(.identifier); + _ = try p.expectToken(.pipe); + return identifier; +} + +/// PtrPayload <- PIPE ASTERISK? IDENTIFIER PIPE +fn parsePtrPayload(p: *Parse) !TokenIndex { + _ = p.eatToken(.pipe) orelse return @as(TokenIndex, 0); + _ = p.eatToken(.asterisk); + const identifier = try p.expectToken(.identifier); + _ = try p.expectToken(.pipe); + return identifier; +} + +/// Returns the first identifier token, if any. +/// +/// PtrIndexPayload <- PIPE ASTERISK? IDENTIFIER (COMMA IDENTIFIER)? PIPE +fn parsePtrIndexPayload(p: *Parse) !TokenIndex { + _ = p.eatToken(.pipe) orelse return @as(TokenIndex, 0); + _ = p.eatToken(.asterisk); + const identifier = try p.expectToken(.identifier); + if (p.eatToken(.comma) != null) { + _ = try p.expectToken(.identifier); + } + _ = try p.expectToken(.pipe); + return identifier; +} + +/// SwitchProng <- KEYWORD_inline? SwitchCase EQUALRARROW PtrIndexPayload? AssignExpr +/// +/// SwitchCase +/// <- SwitchItem (COMMA SwitchItem)* COMMA? +/// / KEYWORD_else +fn parseSwitchProng(p: *Parse) !Node.Index { + const scratch_top = p.scratch.items.len; + defer p.scratch.shrinkRetainingCapacity(scratch_top); + + const is_inline = p.eatToken(.keyword_inline) != null; + + if (p.eatToken(.keyword_else) == null) { + while (true) { + const item = try p.parseSwitchItem(); + if (item == 0) break; + try p.scratch.append(p.gpa, item); + if (p.eatToken(.comma) == null) break; + } + if (scratch_top == p.scratch.items.len) { + if (is_inline) p.tok_i -= 1; + return null_node; + } + } + const arrow_token = try p.expectToken(.equal_angle_bracket_right); + _ = try p.parsePtrIndexPayload(); + + const items = p.scratch.items[scratch_top..]; + switch (items.len) { + 0 => return p.addNode(.{ + .tag = if (is_inline) .switch_case_inline_one else .switch_case_one, + .main_token = arrow_token, + .data = .{ + .lhs = 0, + .rhs = try p.expectAssignExpr(), + }, + }), + 1 => return p.addNode(.{ + .tag = if (is_inline) .switch_case_inline_one else .switch_case_one, + .main_token = arrow_token, + .data = .{ + .lhs = items[0], + .rhs = try p.expectAssignExpr(), + }, + }), + else => return p.addNode(.{ + .tag = if (is_inline) .switch_case_inline else .switch_case, + .main_token = arrow_token, + .data = .{ + .lhs = try p.addExtra(try p.listToSpan(items)), + .rhs = try p.expectAssignExpr(), + }, + }), + } +} + +/// SwitchItem <- Expr (DOT3 Expr)? +fn parseSwitchItem(p: *Parse) !Node.Index { + const expr = try p.parseExpr(); + if (expr == 0) return null_node; + + if (p.eatToken(.ellipsis3)) |token| { + return p.addNode(.{ + .tag = .switch_range, + .main_token = token, + .data = .{ + .lhs = expr, + .rhs = try p.expectExpr(), + }, + }); + } + return expr; +} + +const PtrModifiers = struct { + align_node: Node.Index, + addrspace_node: Node.Index, + bit_range_start: Node.Index, + bit_range_end: Node.Index, +}; + +fn parsePtrModifiers(p: *Parse) !PtrModifiers { + var result: PtrModifiers = .{ + .align_node = 0, + .addrspace_node = 0, + .bit_range_start = 0, + .bit_range_end = 0, + }; + var saw_const = false; + var saw_volatile = false; + var saw_allowzero = false; + var saw_addrspace = false; + while (true) { + switch (p.token_tags[p.tok_i]) { + .keyword_align => { + if (result.align_node != 0) { + try p.warn(.extra_align_qualifier); + } + p.tok_i += 1; + _ = try p.expectToken(.l_paren); + result.align_node = try p.expectExpr(); + + if (p.eatToken(.colon)) |_| { + result.bit_range_start = try p.expectExpr(); + _ = try p.expectToken(.colon); + result.bit_range_end = try p.expectExpr(); + } + + _ = try p.expectToken(.r_paren); + }, + .keyword_const => { + if (saw_const) { + try p.warn(.extra_const_qualifier); + } + p.tok_i += 1; + saw_const = true; + }, + .keyword_volatile => { + if (saw_volatile) { + try p.warn(.extra_volatile_qualifier); + } + p.tok_i += 1; + saw_volatile = true; + }, + .keyword_allowzero => { + if (saw_allowzero) { + try p.warn(.extra_allowzero_qualifier); + } + p.tok_i += 1; + saw_allowzero = true; + }, + .keyword_addrspace => { + if (saw_addrspace) { + try p.warn(.extra_addrspace_qualifier); + } + result.addrspace_node = try p.parseAddrSpace(); + }, + else => return result, + } + } +} + +/// SuffixOp +/// <- LBRACKET Expr (DOT2 (Expr? (COLON Expr)?)?)? RBRACKET +/// / DOT IDENTIFIER +/// / DOTASTERISK +/// / DOTQUESTIONMARK +fn parseSuffixOp(p: *Parse, lhs: Node.Index) !Node.Index { + switch (p.token_tags[p.tok_i]) { + .l_bracket => { + const lbracket = p.nextToken(); + const index_expr = try p.expectExpr(); + + if (p.eatToken(.ellipsis2)) |_| { + const end_expr = try p.parseExpr(); + if (p.eatToken(.colon)) |_| { + const sentinel = try p.expectExpr(); + _ = try p.expectToken(.r_bracket); + return p.addNode(.{ + .tag = .slice_sentinel, + .main_token = lbracket, + .data = .{ + .lhs = lhs, + .rhs = try p.addExtra(Node.SliceSentinel{ + .start = index_expr, + .end = end_expr, + .sentinel = sentinel, + }), + }, + }); + } + _ = try p.expectToken(.r_bracket); + if (end_expr == 0) { + return p.addNode(.{ + .tag = .slice_open, + .main_token = lbracket, + .data = .{ + .lhs = lhs, + .rhs = index_expr, + }, + }); + } + return p.addNode(.{ + .tag = .slice, + .main_token = lbracket, + .data = .{ + .lhs = lhs, + .rhs = try p.addExtra(Node.Slice{ + .start = index_expr, + .end = end_expr, + }), + }, + }); + } + _ = try p.expectToken(.r_bracket); + return p.addNode(.{ + .tag = .array_access, + .main_token = lbracket, + .data = .{ + .lhs = lhs, + .rhs = index_expr, + }, + }); + }, + .period_asterisk => return p.addNode(.{ + .tag = .deref, + .main_token = p.nextToken(), + .data = .{ + .lhs = lhs, + .rhs = undefined, + }, + }), + .invalid_periodasterisks => { + try p.warn(.asterisk_after_ptr_deref); + return p.addNode(.{ + .tag = .deref, + .main_token = p.nextToken(), + .data = .{ + .lhs = lhs, + .rhs = undefined, + }, + }); + }, + .period => switch (p.token_tags[p.tok_i + 1]) { + .identifier => return p.addNode(.{ + .tag = .field_access, + .main_token = p.nextToken(), + .data = .{ + .lhs = lhs, + .rhs = p.nextToken(), + }, + }), + .question_mark => return p.addNode(.{ + .tag = .unwrap_optional, + .main_token = p.nextToken(), + .data = .{ + .lhs = lhs, + .rhs = p.nextToken(), + }, + }), + .l_brace => { + // this a misplaced `.{`, handle the error somewhere else + return null_node; + }, + else => { + p.tok_i += 1; + try p.warn(.expected_suffix_op); + return null_node; + }, + }, + else => return null_node, + } +} + +/// Caller must have already verified the first token. +/// +/// ContainerDeclAuto <- ContainerDeclType LBRACE container_doc_comment? ContainerMembers RBRACE +/// +/// ContainerDeclType +/// <- KEYWORD_struct (LPAREN Expr RPAREN)? +/// / KEYWORD_opaque +/// / KEYWORD_enum (LPAREN Expr RPAREN)? +/// / KEYWORD_union (LPAREN (KEYWORD_enum (LPAREN Expr RPAREN)? / Expr) RPAREN)? +fn parseContainerDeclAuto(p: *Parse) !Node.Index { + const main_token = p.nextToken(); + const arg_expr = switch (p.token_tags[main_token]) { + .keyword_opaque => null_node, + .keyword_struct, .keyword_enum => blk: { + if (p.eatToken(.l_paren)) |_| { + const expr = try p.expectExpr(); + _ = try p.expectToken(.r_paren); + break :blk expr; + } else { + break :blk null_node; + } + }, + .keyword_union => blk: { + if (p.eatToken(.l_paren)) |_| { + if (p.eatToken(.keyword_enum)) |_| { + if (p.eatToken(.l_paren)) |_| { + const enum_tag_expr = try p.expectExpr(); + _ = try p.expectToken(.r_paren); + _ = try p.expectToken(.r_paren); + + _ = try p.expectToken(.l_brace); + const members = try p.parseContainerMembers(); + const members_span = try members.toSpan(p); + _ = try p.expectToken(.r_brace); + return p.addNode(.{ + .tag = switch (members.trailing) { + true => .tagged_union_enum_tag_trailing, + false => .tagged_union_enum_tag, + }, + .main_token = main_token, + .data = .{ + .lhs = enum_tag_expr, + .rhs = try p.addExtra(members_span), + }, + }); + } else { + _ = try p.expectToken(.r_paren); + + _ = try p.expectToken(.l_brace); + const members = try p.parseContainerMembers(); + _ = try p.expectToken(.r_brace); + if (members.len <= 2) { + return p.addNode(.{ + .tag = switch (members.trailing) { + true => .tagged_union_two_trailing, + false => .tagged_union_two, + }, + .main_token = main_token, + .data = .{ + .lhs = members.lhs, + .rhs = members.rhs, + }, + }); + } else { + const span = try members.toSpan(p); + return p.addNode(.{ + .tag = switch (members.trailing) { + true => .tagged_union_trailing, + false => .tagged_union, + }, + .main_token = main_token, + .data = .{ + .lhs = span.start, + .rhs = span.end, + }, + }); + } + } + } else { + const expr = try p.expectExpr(); + _ = try p.expectToken(.r_paren); + break :blk expr; + } + } else { + break :blk null_node; + } + }, + else => { + p.tok_i -= 1; + return p.fail(.expected_container); + }, + }; + _ = try p.expectToken(.l_brace); + const members = try p.parseContainerMembers(); + _ = try p.expectToken(.r_brace); + if (arg_expr == 0) { + if (members.len <= 2) { + return p.addNode(.{ + .tag = switch (members.trailing) { + true => .container_decl_two_trailing, + false => .container_decl_two, + }, + .main_token = main_token, + .data = .{ + .lhs = members.lhs, + .rhs = members.rhs, + }, + }); + } else { + const span = try members.toSpan(p); + return p.addNode(.{ + .tag = switch (members.trailing) { + true => .container_decl_trailing, + false => .container_decl, + }, + .main_token = main_token, + .data = .{ + .lhs = span.start, + .rhs = span.end, + }, + }); + } + } else { + const span = try members.toSpan(p); + return p.addNode(.{ + .tag = switch (members.trailing) { + true => .container_decl_arg_trailing, + false => .container_decl_arg, + }, + .main_token = main_token, + .data = .{ + .lhs = arg_expr, + .rhs = try p.addExtra(Node.SubRange{ + .start = span.start, + .end = span.end, + }), + }, + }); + } +} + +/// Give a helpful error message for those transitioning from +/// C's 'struct Foo {};' to Zig's 'const Foo = struct {};'. +fn parseCStyleContainer(p: *Parse) Error!bool { + const main_token = p.tok_i; + switch (p.token_tags[p.tok_i]) { + .keyword_enum, .keyword_union, .keyword_struct => {}, + else => return false, + } + const identifier = p.tok_i + 1; + if (p.token_tags[identifier] != .identifier) return false; + p.tok_i += 2; + + try p.warnMsg(.{ + .tag = .c_style_container, + .token = identifier, + .extra = .{ .expected_tag = p.token_tags[main_token] }, + }); + try p.warnMsg(.{ + .tag = .zig_style_container, + .is_note = true, + .token = identifier, + .extra = .{ .expected_tag = p.token_tags[main_token] }, + }); + + _ = try p.expectToken(.l_brace); + _ = try p.parseContainerMembers(); + _ = try p.expectToken(.r_brace); + try p.expectSemicolon(.expected_semi_after_decl, true); + return true; +} + +/// Holds temporary data until we are ready to construct the full ContainerDecl AST node. +/// +/// ByteAlign <- KEYWORD_align LPAREN Expr RPAREN +fn parseByteAlign(p: *Parse) !Node.Index { + _ = p.eatToken(.keyword_align) orelse return null_node; + _ = try p.expectToken(.l_paren); + const expr = try p.expectExpr(); + _ = try p.expectToken(.r_paren); + return expr; +} + +/// SwitchProngList <- (SwitchProng COMMA)* SwitchProng? +fn parseSwitchProngList(p: *Parse) !Node.SubRange { + const scratch_top = p.scratch.items.len; + defer p.scratch.shrinkRetainingCapacity(scratch_top); + + while (true) { + const item = try parseSwitchProng(p); + if (item == 0) break; + + try p.scratch.append(p.gpa, item); + + switch (p.token_tags[p.tok_i]) { + .comma => p.tok_i += 1, + // All possible delimiters. + .colon, .r_paren, .r_brace, .r_bracket => break, + // Likely just a missing comma; give error but continue parsing. + else => try p.warn(.expected_comma_after_switch_prong), + } + } + return p.listToSpan(p.scratch.items[scratch_top..]); +} + +/// ParamDeclList <- (ParamDecl COMMA)* ParamDecl? +fn parseParamDeclList(p: *Parse) !SmallSpan { + _ = try p.expectToken(.l_paren); + const scratch_top = p.scratch.items.len; + defer p.scratch.shrinkRetainingCapacity(scratch_top); + var varargs: union(enum) { none, seen, nonfinal: TokenIndex } = .none; + while (true) { + if (p.eatToken(.r_paren)) |_| break; + if (varargs == .seen) varargs = .{ .nonfinal = p.tok_i }; + const param = try p.expectParamDecl(); + if (param != 0) { + try p.scratch.append(p.gpa, param); + } else if (p.token_tags[p.tok_i - 1] == .ellipsis3) { + if (varargs == .none) varargs = .seen; + } + switch (p.token_tags[p.tok_i]) { + .comma => p.tok_i += 1, + .r_paren => { + p.tok_i += 1; + break; + }, + .colon, .r_brace, .r_bracket => return p.failExpected(.r_paren), + // Likely just a missing comma; give error but continue parsing. + else => try p.warn(.expected_comma_after_param), + } + } + if (varargs == .nonfinal) { + try p.warnMsg(.{ .tag = .varargs_nonfinal, .token = varargs.nonfinal }); + } + const params = p.scratch.items[scratch_top..]; + return switch (params.len) { + 0 => SmallSpan{ .zero_or_one = 0 }, + 1 => SmallSpan{ .zero_or_one = params[0] }, + else => SmallSpan{ .multi = try p.listToSpan(params) }, + }; +} + +/// FnCallArguments <- LPAREN ExprList RPAREN +/// +/// ExprList <- (Expr COMMA)* Expr? +fn parseBuiltinCall(p: *Parse) !Node.Index { + const builtin_token = p.assertToken(.builtin); + if (p.token_tags[p.nextToken()] != .l_paren) { + p.tok_i -= 1; + try p.warn(.expected_param_list); + // Pretend this was an identifier so we can continue parsing. + return p.addNode(.{ + .tag = .identifier, + .main_token = builtin_token, + .data = .{ + .lhs = undefined, + .rhs = undefined, + }, + }); + } + const scratch_top = p.scratch.items.len; + defer p.scratch.shrinkRetainingCapacity(scratch_top); + while (true) { + if (p.eatToken(.r_paren)) |_| break; + const param = try p.expectExpr(); + try p.scratch.append(p.gpa, param); + switch (p.token_tags[p.tok_i]) { + .comma => p.tok_i += 1, + .r_paren => { + p.tok_i += 1; + break; + }, + // Likely just a missing comma; give error but continue parsing. + else => try p.warn(.expected_comma_after_arg), + } + } + const comma = (p.token_tags[p.tok_i - 2] == .comma); + const params = p.scratch.items[scratch_top..]; + switch (params.len) { + 0 => return p.addNode(.{ + .tag = .builtin_call_two, + .main_token = builtin_token, + .data = .{ + .lhs = 0, + .rhs = 0, + }, + }), + 1 => return p.addNode(.{ + .tag = if (comma) .builtin_call_two_comma else .builtin_call_two, + .main_token = builtin_token, + .data = .{ + .lhs = params[0], + .rhs = 0, + }, + }), + 2 => return p.addNode(.{ + .tag = if (comma) .builtin_call_two_comma else .builtin_call_two, + .main_token = builtin_token, + .data = .{ + .lhs = params[0], + .rhs = params[1], + }, + }), + else => { + const span = try p.listToSpan(params); + return p.addNode(.{ + .tag = if (comma) .builtin_call_comma else .builtin_call, + .main_token = builtin_token, + .data = .{ + .lhs = span.start, + .rhs = span.end, + }, + }); + }, + } +} + +/// IfPrefix <- KEYWORD_if LPAREN Expr RPAREN PtrPayload? +fn parseIf(p: *Parse, comptime bodyParseFn: fn (p: *Parse) Error!Node.Index) !Node.Index { + const if_token = p.eatToken(.keyword_if) orelse return null_node; + _ = try p.expectToken(.l_paren); + const condition = try p.expectExpr(); + _ = try p.expectToken(.r_paren); + _ = try p.parsePtrPayload(); + + const then_expr = try bodyParseFn(p); + assert(then_expr != 0); + + _ = p.eatToken(.keyword_else) orelse return p.addNode(.{ + .tag = .if_simple, + .main_token = if_token, + .data = .{ + .lhs = condition, + .rhs = then_expr, + }, + }); + _ = try p.parsePayload(); + const else_expr = try bodyParseFn(p); + assert(then_expr != 0); + + return p.addNode(.{ + .tag = .@"if", + .main_token = if_token, + .data = .{ + .lhs = condition, + .rhs = try p.addExtra(Node.If{ + .then_expr = then_expr, + .else_expr = else_expr, + }), + }, + }); +} + +/// Skips over doc comment tokens. Returns the first one, if any. +fn eatDocComments(p: *Parse) !?TokenIndex { + if (p.eatToken(.doc_comment)) |tok| { + var first_line = tok; + if (tok > 0 and tokensOnSameLine(p, tok - 1, tok)) { + try p.warnMsg(.{ + .tag = .same_line_doc_comment, + .token = tok, + }); + first_line = p.eatToken(.doc_comment) orelse return null; + } + while (p.eatToken(.doc_comment)) |_| {} + return first_line; + } + return null; +} + +fn tokensOnSameLine(p: *Parse, token1: TokenIndex, token2: TokenIndex) bool { + return std.mem.indexOfScalar(u8, p.source[p.token_starts[token1]..p.token_starts[token2]], '\n') == null; +} + +fn eatToken(p: *Parse, tag: Token.Tag) ?TokenIndex { + return if (p.token_tags[p.tok_i] == tag) p.nextToken() else null; +} + +fn assertToken(p: *Parse, tag: Token.Tag) TokenIndex { + const token = p.nextToken(); + assert(p.token_tags[token] == tag); + return token; +} + +fn expectToken(p: *Parse, tag: Token.Tag) Error!TokenIndex { + if (p.token_tags[p.tok_i] != tag) { + return p.failMsg(.{ + .tag = .expected_token, + .token = p.tok_i, + .extra = .{ .expected_tag = tag }, + }); + } + return p.nextToken(); +} + +fn expectSemicolon(p: *Parse, error_tag: AstError.Tag, recoverable: bool) Error!void { + if (p.token_tags[p.tok_i] == .semicolon) { + _ = p.nextToken(); + return; + } + try p.warn(error_tag); + if (!recoverable) return error.ParseError; +} + +fn nextToken(p: *Parse) TokenIndex { + const result = p.tok_i; + p.tok_i += 1; + return result; +} + +const null_node: Node.Index = 0; + +const Parse = @This(); +const std = @import("../std.zig"); +const assert = std.debug.assert; +const Allocator = std.mem.Allocator; +const Ast = std.zig.Ast; +const Node = Ast.Node; +const AstError = Ast.Error; +const TokenIndex = Ast.TokenIndex; +const Token = std.zig.Token; + +test { + _ = @import("parser_test.zig"); +} diff --git a/lib/std/zig/parse.zig b/lib/std/zig/parse.zig deleted file mode 100644 index fdb122b19d0027c54a03c3899b3cb88133989e59..0000000000000000000000000000000000000000 --- a/lib/std/zig/parse.zig +++ /dev/null @@ -1,3852 +0,0 @@ -const std = @import("../std.zig"); -const assert = std.debug.assert; -const Allocator = std.mem.Allocator; -const Ast = std.zig.Ast; -const Node = Ast.Node; -const AstError = Ast.Error; -const TokenIndex = Ast.TokenIndex; -const Token = std.zig.Token; - -pub const Error = error{ParseError} || Allocator.Error; - -/// Result should be freed with tree.deinit() when there are -/// no more references to any of the tokens or nodes. -pub fn parse(gpa: Allocator, source: [:0]const u8) Allocator.Error!Ast { - var tokens = Ast.TokenList{}; - defer tokens.deinit(gpa); - - // Empirically, the zig std lib has an 8:1 ratio of source bytes to token count. - const estimated_token_count = source.len / 8; - try tokens.ensureTotalCapacity(gpa, estimated_token_count); - - var tokenizer = std.zig.Tokenizer.init(source); - while (true) { - const token = tokenizer.next(); - try tokens.append(gpa, .{ - .tag = token.tag, - .start = @intCast(u32, token.loc.start), - }); - if (token.tag == .eof) break; - } - - var parser: Parser = .{ - .source = source, - .gpa = gpa, - .token_tags = tokens.items(.tag), - .token_starts = tokens.items(.start), - .errors = .{}, - .nodes = .{}, - .extra_data = .{}, - .scratch = .{}, - .tok_i = 0, - }; - defer parser.errors.deinit(gpa); - defer parser.nodes.deinit(gpa); - defer parser.extra_data.deinit(gpa); - defer parser.scratch.deinit(gpa); - - // Empirically, Zig source code has a 2:1 ratio of tokens to AST nodes. - // Make sure at least 1 so we can use appendAssumeCapacity on the root node below. - const estimated_node_count = (tokens.len + 2) / 2; - try parser.nodes.ensureTotalCapacity(gpa, estimated_node_count); - - try parser.parseRoot(); - - // TODO experiment with compacting the MultiArrayList slices here - return Ast{ - .source = source, - .tokens = tokens.toOwnedSlice(), - .nodes = parser.nodes.toOwnedSlice(), - .extra_data = try parser.extra_data.toOwnedSlice(gpa), - .errors = try parser.errors.toOwnedSlice(gpa), - }; -} - -const null_node: Node.Index = 0; - -/// Represents in-progress parsing, will be converted to an Ast after completion. -const Parser = struct { - gpa: Allocator, - source: []const u8, - token_tags: []const Token.Tag, - token_starts: []const Ast.ByteOffset, - tok_i: TokenIndex, - errors: std.ArrayListUnmanaged(AstError), - nodes: Ast.NodeList, - extra_data: std.ArrayListUnmanaged(Node.Index), - scratch: std.ArrayListUnmanaged(Node.Index), - - const SmallSpan = union(enum) { - zero_or_one: Node.Index, - multi: Node.SubRange, - }; - - const Members = struct { - len: usize, - lhs: Node.Index, - rhs: Node.Index, - trailing: bool, - - fn toSpan(self: Members, p: *Parser) !Node.SubRange { - if (self.len <= 2) { - const nodes = [2]Node.Index{ self.lhs, self.rhs }; - return p.listToSpan(nodes[0..self.len]); - } else { - return Node.SubRange{ .start = self.lhs, .end = self.rhs }; - } - } - }; - - fn listToSpan(p: *Parser, list: []const Node.Index) !Node.SubRange { - try p.extra_data.appendSlice(p.gpa, list); - return Node.SubRange{ - .start = @intCast(Node.Index, p.extra_data.items.len - list.len), - .end = @intCast(Node.Index, p.extra_data.items.len), - }; - } - - fn addNode(p: *Parser, elem: Ast.NodeList.Elem) Allocator.Error!Node.Index { - const result = @intCast(Node.Index, p.nodes.len); - try p.nodes.append(p.gpa, elem); - return result; - } - - fn setNode(p: *Parser, i: usize, elem: Ast.NodeList.Elem) Node.Index { - p.nodes.set(i, elem); - return @intCast(Node.Index, i); - } - - fn reserveNode(p: *Parser, tag: Ast.Node.Tag) !usize { - try p.nodes.resize(p.gpa, p.nodes.len + 1); - p.nodes.items(.tag)[p.nodes.len - 1] = tag; - return p.nodes.len - 1; - } - - fn unreserveNode(p: *Parser, node_index: usize) void { - if (p.nodes.len == node_index) { - p.nodes.resize(p.gpa, p.nodes.len - 1) catch unreachable; - } else { - // There is zombie node left in the tree, let's make it as inoffensive as possible - // (sadly there's no no-op node) - p.nodes.items(.tag)[node_index] = .unreachable_literal; - p.nodes.items(.main_token)[node_index] = p.tok_i; - } - } - - fn addExtra(p: *Parser, extra: anytype) Allocator.Error!Node.Index { - const fields = std.meta.fields(@TypeOf(extra)); - try p.extra_data.ensureUnusedCapacity(p.gpa, fields.len); - const result = @intCast(u32, p.extra_data.items.len); - inline for (fields) |field| { - comptime assert(field.type == Node.Index); - p.extra_data.appendAssumeCapacity(@field(extra, field.name)); - } - return result; - } - - fn warnExpected(p: *Parser, expected_token: Token.Tag) error{OutOfMemory}!void { - @setCold(true); - try p.warnMsg(.{ - .tag = .expected_token, - .token = p.tok_i, - .extra = .{ .expected_tag = expected_token }, - }); - } - - fn warn(p: *Parser, error_tag: AstError.Tag) error{OutOfMemory}!void { - @setCold(true); - try p.warnMsg(.{ .tag = error_tag, .token = p.tok_i }); - } - - fn warnMsg(p: *Parser, msg: Ast.Error) error{OutOfMemory}!void { - @setCold(true); - switch (msg.tag) { - .expected_semi_after_decl, - .expected_semi_after_stmt, - .expected_comma_after_field, - .expected_comma_after_arg, - .expected_comma_after_param, - .expected_comma_after_initializer, - .expected_comma_after_switch_prong, - .expected_semi_or_else, - .expected_semi_or_lbrace, - .expected_token, - .expected_block, - .expected_block_or_assignment, - .expected_block_or_expr, - .expected_block_or_field, - .expected_expr, - .expected_expr_or_assignment, - .expected_fn, - .expected_inlinable, - .expected_labelable, - .expected_param_list, - .expected_prefix_expr, - .expected_primary_type_expr, - .expected_pub_item, - .expected_return_type, - .expected_suffix_op, - .expected_type_expr, - .expected_var_decl, - .expected_var_decl_or_fn, - .expected_loop_payload, - .expected_container, - => if (msg.token != 0 and !p.tokensOnSameLine(msg.token - 1, msg.token)) { - var copy = msg; - copy.token_is_prev = true; - copy.token -= 1; - return p.errors.append(p.gpa, copy); - }, - else => {}, - } - try p.errors.append(p.gpa, msg); - } - - fn fail(p: *Parser, tag: Ast.Error.Tag) error{ ParseError, OutOfMemory } { - @setCold(true); - return p.failMsg(.{ .tag = tag, .token = p.tok_i }); - } - - fn failExpected(p: *Parser, expected_token: Token.Tag) error{ ParseError, OutOfMemory } { - @setCold(true); - return p.failMsg(.{ - .tag = .expected_token, - .token = p.tok_i, - .extra = .{ .expected_tag = expected_token }, - }); - } - - fn failMsg(p: *Parser, msg: Ast.Error) error{ ParseError, OutOfMemory } { - @setCold(true); - try p.warnMsg(msg); - return error.ParseError; - } - - /// Root <- skip container_doc_comment? ContainerMembers eof - fn parseRoot(p: *Parser) !void { - // Root node must be index 0. - p.nodes.appendAssumeCapacity(.{ - .tag = .root, - .main_token = 0, - .data = undefined, - }); - const root_members = try p.parseContainerMembers(); - const root_decls = try root_members.toSpan(p); - if (p.token_tags[p.tok_i] != .eof) { - try p.warnExpected(.eof); - } - p.nodes.items(.data)[0] = .{ - .lhs = root_decls.start, - .rhs = root_decls.end, - }; - } - - /// ContainerMembers <- ContainerDeclarations (ContainerField COMMA)* (ContainerField / ContainerDeclarations) - /// - /// ContainerDeclarations - /// <- TestDecl ContainerDeclarations - /// / ComptimeDecl ContainerDeclarations - /// / doc_comment? KEYWORD_pub? Decl ContainerDeclarations - /// / - /// - /// ComptimeDecl <- KEYWORD_comptime Block - fn parseContainerMembers(p: *Parser) !Members { - const scratch_top = p.scratch.items.len; - defer p.scratch.shrinkRetainingCapacity(scratch_top); - - var field_state: union(enum) { - /// No fields have been seen. - none, - /// Currently parsing fields. - seen, - /// Saw fields and then a declaration after them. - /// Payload is first token of previous declaration. - end: Node.Index, - /// There was a declaration between fields, don't report more errors. - err, - } = .none; - - var last_field: TokenIndex = undefined; - - // Skip container doc comments. - while (p.eatToken(.container_doc_comment)) |_| {} - - var trailing = false; - while (true) { - const doc_comment = try p.eatDocComments(); - - switch (p.token_tags[p.tok_i]) { - .keyword_test => { - if (doc_comment) |some| { - try p.warnMsg(.{ .tag = .test_doc_comment, .token = some }); - } - const test_decl_node = try p.expectTestDeclRecoverable(); - if (test_decl_node != 0) { - if (field_state == .seen) { - field_state = .{ .end = test_decl_node }; - } - try p.scratch.append(p.gpa, test_decl_node); - } - trailing = false; - }, - .keyword_comptime => switch (p.token_tags[p.tok_i + 1]) { - .l_brace => { - if (doc_comment) |some| { - try p.warnMsg(.{ .tag = .comptime_doc_comment, .token = some }); - } - const comptime_token = p.nextToken(); - const block = p.parseBlock() catch |err| switch (err) { - error.OutOfMemory => return error.OutOfMemory, - error.ParseError => blk: { - p.findNextContainerMember(); - break :blk null_node; - }, - }; - if (block != 0) { - const comptime_node = try p.addNode(.{ - .tag = .@"comptime", - .main_token = comptime_token, - .data = .{ - .lhs = block, - .rhs = undefined, - }, - }); - if (field_state == .seen) { - field_state = .{ .end = comptime_node }; - } - try p.scratch.append(p.gpa, comptime_node); - } - trailing = false; - }, - else => { - const identifier = p.tok_i; - defer last_field = identifier; - const container_field = p.expectContainerField() catch |err| switch (err) { - error.OutOfMemory => return error.OutOfMemory, - error.ParseError => { - p.findNextContainerMember(); - continue; - }, - }; - switch (field_state) { - .none => field_state = .seen, - .err, .seen => {}, - .end => |node| { - try p.warnMsg(.{ - .tag = .decl_between_fields, - .token = p.nodes.items(.main_token)[node], - }); - try p.warnMsg(.{ - .tag = .previous_field, - .is_note = true, - .token = last_field, - }); - try p.warnMsg(.{ - .tag = .next_field, - .is_note = true, - .token = identifier, - }); - // Continue parsing; error will be reported later. - field_state = .err; - }, - } - try p.scratch.append(p.gpa, container_field); - switch (p.token_tags[p.tok_i]) { - .comma => { - p.tok_i += 1; - trailing = true; - continue; - }, - .r_brace, .eof => { - trailing = false; - break; - }, - else => {}, - } - // There is not allowed to be a decl after a field with no comma. - // Report error but recover parser. - try p.warn(.expected_comma_after_field); - p.findNextContainerMember(); - }, - }, - .keyword_pub => { - p.tok_i += 1; - const top_level_decl = try p.expectTopLevelDeclRecoverable(); - if (top_level_decl != 0) { - if (field_state == .seen) { - field_state = .{ .end = top_level_decl }; - } - try p.scratch.append(p.gpa, top_level_decl); - } - trailing = p.token_tags[p.tok_i - 1] == .semicolon; - }, - .keyword_usingnamespace => { - const node = try p.expectUsingNamespaceRecoverable(); - if (node != 0) { - if (field_state == .seen) { - field_state = .{ .end = node }; - } - try p.scratch.append(p.gpa, node); - } - trailing = p.token_tags[p.tok_i - 1] == .semicolon; - }, - .keyword_const, - .keyword_var, - .keyword_threadlocal, - .keyword_export, - .keyword_extern, - .keyword_inline, - .keyword_noinline, - .keyword_fn, - => { - const top_level_decl = try p.expectTopLevelDeclRecoverable(); - if (top_level_decl != 0) { - if (field_state == .seen) { - field_state = .{ .end = top_level_decl }; - } - try p.scratch.append(p.gpa, top_level_decl); - } - trailing = p.token_tags[p.tok_i - 1] == .semicolon; - }, - .eof, .r_brace => { - if (doc_comment) |tok| { - try p.warnMsg(.{ - .tag = .unattached_doc_comment, - .token = tok, - }); - } - break; - }, - else => { - const c_container = p.parseCStyleContainer() catch |err| switch (err) { - error.OutOfMemory => return error.OutOfMemory, - error.ParseError => false, - }; - if (c_container) continue; - - const identifier = p.tok_i; - defer last_field = identifier; - const container_field = p.expectContainerField() catch |err| switch (err) { - error.OutOfMemory => return error.OutOfMemory, - error.ParseError => { - p.findNextContainerMember(); - continue; - }, - }; - switch (field_state) { - .none => field_state = .seen, - .err, .seen => {}, - .end => |node| { - try p.warnMsg(.{ - .tag = .decl_between_fields, - .token = p.nodes.items(.main_token)[node], - }); - try p.warnMsg(.{ - .tag = .previous_field, - .is_note = true, - .token = last_field, - }); - try p.warnMsg(.{ - .tag = .next_field, - .is_note = true, - .token = identifier, - }); - // Continue parsing; error will be reported later. - field_state = .err; - }, - } - try p.scratch.append(p.gpa, container_field); - switch (p.token_tags[p.tok_i]) { - .comma => { - p.tok_i += 1; - trailing = true; - continue; - }, - .r_brace, .eof => { - trailing = false; - break; - }, - else => {}, - } - // There is not allowed to be a decl after a field with no comma. - // Report error but recover parser. - try p.warn(.expected_comma_after_field); - if (p.token_tags[p.tok_i] == .semicolon and p.token_tags[identifier] == .identifier) { - try p.warnMsg(.{ - .tag = .var_const_decl, - .is_note = true, - .token = identifier, - }); - } - p.findNextContainerMember(); - continue; - }, - } - } - - const items = p.scratch.items[scratch_top..]; - switch (items.len) { - 0 => return Members{ - .len = 0, - .lhs = 0, - .rhs = 0, - .trailing = trailing, - }, - 1 => return Members{ - .len = 1, - .lhs = items[0], - .rhs = 0, - .trailing = trailing, - }, - 2 => return Members{ - .len = 2, - .lhs = items[0], - .rhs = items[1], - .trailing = trailing, - }, - else => { - const span = try p.listToSpan(items); - return Members{ - .len = items.len, - .lhs = span.start, - .rhs = span.end, - .trailing = trailing, - }; - }, - } - } - - /// Attempts to find next container member by searching for certain tokens - fn findNextContainerMember(p: *Parser) void { - var level: u32 = 0; - while (true) { - const tok = p.nextToken(); - switch (p.token_tags[tok]) { - // Any of these can start a new top level declaration. - .keyword_test, - .keyword_comptime, - .keyword_pub, - .keyword_export, - .keyword_extern, - .keyword_inline, - .keyword_noinline, - .keyword_usingnamespace, - .keyword_threadlocal, - .keyword_const, - .keyword_var, - .keyword_fn, - => { - if (level == 0) { - p.tok_i -= 1; - return; - } - }, - .identifier => { - if (p.token_tags[tok + 1] == .comma and level == 0) { - p.tok_i -= 1; - return; - } - }, - .comma, .semicolon => { - // this decl was likely meant to end here - if (level == 0) { - return; - } - }, - .l_paren, .l_bracket, .l_brace => level += 1, - .r_paren, .r_bracket => { - if (level != 0) level -= 1; - }, - .r_brace => { - if (level == 0) { - // end of container, exit - p.tok_i -= 1; - return; - } - level -= 1; - }, - .eof => { - p.tok_i -= 1; - return; - }, - else => {}, - } - } - } - - /// Attempts to find the next statement by searching for a semicolon - fn findNextStmt(p: *Parser) void { - var level: u32 = 0; - while (true) { - const tok = p.nextToken(); - switch (p.token_tags[tok]) { - .l_brace => level += 1, - .r_brace => { - if (level == 0) { - p.tok_i -= 1; - return; - } - level -= 1; - }, - .semicolon => { - if (level == 0) { - return; - } - }, - .eof => { - p.tok_i -= 1; - return; - }, - else => {}, - } - } - } - - /// TestDecl <- KEYWORD_test (STRINGLITERALSINGLE / IDENTIFIER)? Block - fn expectTestDecl(p: *Parser) !Node.Index { - const test_token = p.assertToken(.keyword_test); - const name_token = switch (p.token_tags[p.nextToken()]) { - .string_literal, .identifier => p.tok_i - 1, - else => blk: { - p.tok_i -= 1; - break :blk null; - }, - }; - const block_node = try p.parseBlock(); - if (block_node == 0) return p.fail(.expected_block); - return p.addNode(.{ - .tag = .test_decl, - .main_token = test_token, - .data = .{ - .lhs = name_token orelse 0, - .rhs = block_node, - }, - }); - } - - fn expectTestDeclRecoverable(p: *Parser) error{OutOfMemory}!Node.Index { - return p.expectTestDecl() catch |err| switch (err) { - error.OutOfMemory => return error.OutOfMemory, - error.ParseError => { - p.findNextContainerMember(); - return null_node; - }, - }; - } - - /// Decl - /// <- (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE? / (KEYWORD_inline / KEYWORD_noinline))? FnProto (SEMICOLON / Block) - /// / (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE?)? KEYWORD_threadlocal? VarDecl - /// / KEYWORD_usingnamespace Expr SEMICOLON - fn expectTopLevelDecl(p: *Parser) !Node.Index { - const extern_export_inline_token = p.nextToken(); - var is_extern: bool = false; - var expect_fn: bool = false; - var expect_var_or_fn: bool = false; - switch (p.token_tags[extern_export_inline_token]) { - .keyword_extern => { - _ = p.eatToken(.string_literal); - is_extern = true; - expect_var_or_fn = true; - }, - .keyword_export => expect_var_or_fn = true, - .keyword_inline, .keyword_noinline => expect_fn = true, - else => p.tok_i -= 1, - } - const fn_proto = try p.parseFnProto(); - if (fn_proto != 0) { - switch (p.token_tags[p.tok_i]) { - .semicolon => { - p.tok_i += 1; - return fn_proto; - }, - .l_brace => { - if (is_extern) { - try p.warnMsg(.{ .tag = .extern_fn_body, .token = extern_export_inline_token }); - return null_node; - } - const fn_decl_index = try p.reserveNode(.fn_decl); - errdefer p.unreserveNode(fn_decl_index); - - const body_block = try p.parseBlock(); - assert(body_block != 0); - return p.setNode(fn_decl_index, .{ - .tag = .fn_decl, - .main_token = p.nodes.items(.main_token)[fn_proto], - .data = .{ - .lhs = fn_proto, - .rhs = body_block, - }, - }); - }, - else => { - // Since parseBlock only return error.ParseError on - // a missing '}' we can assume this function was - // supposed to end here. - try p.warn(.expected_semi_or_lbrace); - return null_node; - }, - } - } - if (expect_fn) { - try p.warn(.expected_fn); - return error.ParseError; - } - - const thread_local_token = p.eatToken(.keyword_threadlocal); - const var_decl = try p.parseVarDecl(); - if (var_decl != 0) { - try p.expectSemicolon(.expected_semi_after_decl, false); - return var_decl; - } - if (thread_local_token != null) { - return p.fail(.expected_var_decl); - } - if (expect_var_or_fn) { - return p.fail(.expected_var_decl_or_fn); - } - if (p.token_tags[p.tok_i] != .keyword_usingnamespace) { - return p.fail(.expected_pub_item); - } - return p.expectUsingNamespace(); - } - - fn expectTopLevelDeclRecoverable(p: *Parser) error{OutOfMemory}!Node.Index { - return p.expectTopLevelDecl() catch |err| switch (err) { - error.OutOfMemory => return error.OutOfMemory, - error.ParseError => { - p.findNextContainerMember(); - return null_node; - }, - }; - } - - fn expectUsingNamespace(p: *Parser) !Node.Index { - const usingnamespace_token = p.assertToken(.keyword_usingnamespace); - const expr = try p.expectExpr(); - try p.expectSemicolon(.expected_semi_after_decl, false); - return p.addNode(.{ - .tag = .@"usingnamespace", - .main_token = usingnamespace_token, - .data = .{ - .lhs = expr, - .rhs = undefined, - }, - }); - } - - fn expectUsingNamespaceRecoverable(p: *Parser) error{OutOfMemory}!Node.Index { - return p.expectUsingNamespace() catch |err| switch (err) { - error.OutOfMemory => return error.OutOfMemory, - error.ParseError => { - p.findNextContainerMember(); - return null_node; - }, - }; - } - - /// FnProto <- KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? AddrSpace? LinkSection? CallConv? EXCLAMATIONMARK? TypeExpr - fn parseFnProto(p: *Parser) !Node.Index { - const fn_token = p.eatToken(.keyword_fn) orelse return null_node; - - // We want the fn proto node to be before its children in the array. - const fn_proto_index = try p.reserveNode(.fn_proto); - errdefer p.unreserveNode(fn_proto_index); - - _ = p.eatToken(.identifier); - const params = try p.parseParamDeclList(); - const align_expr = try p.parseByteAlign(); - const addrspace_expr = try p.parseAddrSpace(); - const section_expr = try p.parseLinkSection(); - const callconv_expr = try p.parseCallconv(); - _ = p.eatToken(.bang); - - const return_type_expr = try p.parseTypeExpr(); - if (return_type_expr == 0) { - // most likely the user forgot to specify the return type. - // Mark return type as invalid and try to continue. - try p.warn(.expected_return_type); - } - - if (align_expr == 0 and section_expr == 0 and callconv_expr == 0 and addrspace_expr == 0) { - switch (params) { - .zero_or_one => |param| return p.setNode(fn_proto_index, .{ - .tag = .fn_proto_simple, - .main_token = fn_token, - .data = .{ - .lhs = param, - .rhs = return_type_expr, - }, - }), - .multi => |span| { - return p.setNode(fn_proto_index, .{ - .tag = .fn_proto_multi, - .main_token = fn_token, - .data = .{ - .lhs = try p.addExtra(Node.SubRange{ - .start = span.start, - .end = span.end, - }), - .rhs = return_type_expr, - }, - }); - }, - } - } - switch (params) { - .zero_or_one => |param| return p.setNode(fn_proto_index, .{ - .tag = .fn_proto_one, - .main_token = fn_token, - .data = .{ - .lhs = try p.addExtra(Node.FnProtoOne{ - .param = param, - .align_expr = align_expr, - .addrspace_expr = addrspace_expr, - .section_expr = section_expr, - .callconv_expr = callconv_expr, - }), - .rhs = return_type_expr, - }, - }), - .multi => |span| { - return p.setNode(fn_proto_index, .{ - .tag = .fn_proto, - .main_token = fn_token, - .data = .{ - .lhs = try p.addExtra(Node.FnProto{ - .params_start = span.start, - .params_end = span.end, - .align_expr = align_expr, - .addrspace_expr = addrspace_expr, - .section_expr = section_expr, - .callconv_expr = callconv_expr, - }), - .rhs = return_type_expr, - }, - }); - }, - } - } - - /// VarDecl <- (KEYWORD_const / KEYWORD_var) IDENTIFIER (COLON TypeExpr)? ByteAlign? AddrSpace? LinkSection? (EQUAL Expr)? SEMICOLON - fn parseVarDecl(p: *Parser) !Node.Index { - const mut_token = p.eatToken(.keyword_const) orelse - p.eatToken(.keyword_var) orelse - return null_node; - - _ = try p.expectToken(.identifier); - const type_node: Node.Index = if (p.eatToken(.colon) == null) 0 else try p.expectTypeExpr(); - const align_node = try p.parseByteAlign(); - const addrspace_node = try p.parseAddrSpace(); - const section_node = try p.parseLinkSection(); - const init_node: Node.Index = switch (p.token_tags[p.tok_i]) { - .equal_equal => blk: { - try p.warn(.wrong_equal_var_decl); - p.tok_i += 1; - break :blk try p.expectExpr(); - }, - .equal => blk: { - p.tok_i += 1; - break :blk try p.expectExpr(); - }, - else => 0, - }; - if (section_node == 0 and addrspace_node == 0) { - if (align_node == 0) { - return p.addNode(.{ - .tag = .simple_var_decl, - .main_token = mut_token, - .data = .{ - .lhs = type_node, - .rhs = init_node, - }, - }); - } else if (type_node == 0) { - return p.addNode(.{ - .tag = .aligned_var_decl, - .main_token = mut_token, - .data = .{ - .lhs = align_node, - .rhs = init_node, - }, - }); - } else { - return p.addNode(.{ - .tag = .local_var_decl, - .main_token = mut_token, - .data = .{ - .lhs = try p.addExtra(Node.LocalVarDecl{ - .type_node = type_node, - .align_node = align_node, - }), - .rhs = init_node, - }, - }); - } - } else { - return p.addNode(.{ - .tag = .global_var_decl, - .main_token = mut_token, - .data = .{ - .lhs = try p.addExtra(Node.GlobalVarDecl{ - .type_node = type_node, - .align_node = align_node, - .addrspace_node = addrspace_node, - .section_node = section_node, - }), - .rhs = init_node, - }, - }); - } - } - - /// ContainerField - /// <- doc_comment? KEYWORD_comptime? IDENTIFIER (COLON TypeExpr)? ByteAlign? (EQUAL Expr)? - /// / doc_comment? KEYWORD_comptime? (IDENTIFIER COLON)? !KEYWORD_fn TypeExpr ByteAlign? (EQUAL Expr)? - fn expectContainerField(p: *Parser) !Node.Index { - var main_token = p.tok_i; - _ = p.eatToken(.keyword_comptime); - const tuple_like = p.token_tags[p.tok_i] != .identifier or p.token_tags[p.tok_i + 1] != .colon; - if (!tuple_like) { - main_token = p.assertToken(.identifier); - } - - var align_expr: Node.Index = 0; - var type_expr: Node.Index = 0; - if (p.eatToken(.colon) != null or tuple_like) { - type_expr = try p.expectTypeExpr(); - align_expr = try p.parseByteAlign(); - } - - const value_expr: Node.Index = if (p.eatToken(.equal) == null) 0 else try p.expectExpr(); - - if (align_expr == 0) { - return p.addNode(.{ - .tag = .container_field_init, - .main_token = main_token, - .data = .{ - .lhs = type_expr, - .rhs = value_expr, - }, - }); - } else if (value_expr == 0) { - return p.addNode(.{ - .tag = .container_field_align, - .main_token = main_token, - .data = .{ - .lhs = type_expr, - .rhs = align_expr, - }, - }); - } else { - return p.addNode(.{ - .tag = .container_field, - .main_token = main_token, - .data = .{ - .lhs = type_expr, - .rhs = try p.addExtra(Node.ContainerField{ - .value_expr = value_expr, - .align_expr = align_expr, - }), - }, - }); - } - } - - /// Statement - /// <- KEYWORD_comptime? VarDecl - /// / KEYWORD_comptime BlockExprStatement - /// / KEYWORD_nosuspend BlockExprStatement - /// / KEYWORD_suspend BlockExprStatement - /// / KEYWORD_defer BlockExprStatement - /// / KEYWORD_errdefer Payload? BlockExprStatement - /// / IfStatement - /// / LabeledStatement - /// / SwitchExpr - /// / AssignExpr SEMICOLON - fn parseStatement(p: *Parser, allow_defer_var: bool) Error!Node.Index { - const comptime_token = p.eatToken(.keyword_comptime); - - if (allow_defer_var) { - const var_decl = try p.parseVarDecl(); - if (var_decl != 0) { - try p.expectSemicolon(.expected_semi_after_decl, true); - return var_decl; - } - } - - if (comptime_token) |token| { - return p.addNode(.{ - .tag = .@"comptime", - .main_token = token, - .data = .{ - .lhs = try p.expectBlockExprStatement(), - .rhs = undefined, - }, - }); - } - - switch (p.token_tags[p.tok_i]) { - .keyword_nosuspend => { - return p.addNode(.{ - .tag = .@"nosuspend", - .main_token = p.nextToken(), - .data = .{ - .lhs = try p.expectBlockExprStatement(), - .rhs = undefined, - }, - }); - }, - .keyword_suspend => { - const token = p.nextToken(); - const block_expr = try p.expectBlockExprStatement(); - return p.addNode(.{ - .tag = .@"suspend", - .main_token = token, - .data = .{ - .lhs = block_expr, - .rhs = undefined, - }, - }); - }, - .keyword_defer => if (allow_defer_var) return p.addNode(.{ - .tag = .@"defer", - .main_token = p.nextToken(), - .data = .{ - .lhs = undefined, - .rhs = try p.expectBlockExprStatement(), - }, - }), - .keyword_errdefer => if (allow_defer_var) return p.addNode(.{ - .tag = .@"errdefer", - .main_token = p.nextToken(), - .data = .{ - .lhs = try p.parsePayload(), - .rhs = try p.expectBlockExprStatement(), - }, - }), - .keyword_switch => return p.expectSwitchExpr(), - .keyword_if => return p.expectIfStatement(), - .keyword_enum, .keyword_struct, .keyword_union => { - const identifier = p.tok_i + 1; - if (try p.parseCStyleContainer()) { - // Return something so that `expectStatement` is happy. - return p.addNode(.{ - .tag = .identifier, - .main_token = identifier, - .data = .{ - .lhs = undefined, - .rhs = undefined, - }, - }); - } - }, - else => {}, - } - - const labeled_statement = try p.parseLabeledStatement(); - if (labeled_statement != 0) return labeled_statement; - - const assign_expr = try p.parseAssignExpr(); - if (assign_expr != 0) { - try p.expectSemicolon(.expected_semi_after_stmt, true); - return assign_expr; - } - - return null_node; - } - - fn expectStatement(p: *Parser, allow_defer_var: bool) !Node.Index { - const statement = try p.parseStatement(allow_defer_var); - if (statement == 0) { - return p.fail(.expected_statement); - } - return statement; - } - - /// If a parse error occurs, reports an error, but then finds the next statement - /// and returns that one instead. If a parse error occurs but there is no following - /// statement, returns 0. - fn expectStatementRecoverable(p: *Parser) Error!Node.Index { - while (true) { - return p.expectStatement(true) catch |err| switch (err) { - error.OutOfMemory => return error.OutOfMemory, - error.ParseError => { - p.findNextStmt(); // Try to skip to the next statement. - switch (p.token_tags[p.tok_i]) { - .r_brace => return null_node, - .eof => return error.ParseError, - else => continue, - } - }, - }; - } - } - - /// IfStatement - /// <- IfPrefix BlockExpr ( KEYWORD_else Payload? Statement )? - /// / IfPrefix AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement ) - fn expectIfStatement(p: *Parser) !Node.Index { - const if_token = p.assertToken(.keyword_if); - _ = try p.expectToken(.l_paren); - const condition = try p.expectExpr(); - _ = try p.expectToken(.r_paren); - _ = try p.parsePtrPayload(); - - // TODO propose to change the syntax so that semicolons are always required - // inside if statements, even if there is an `else`. - var else_required = false; - const then_expr = blk: { - const block_expr = try p.parseBlockExpr(); - if (block_expr != 0) break :blk block_expr; - const assign_expr = try p.parseAssignExpr(); - if (assign_expr == 0) { - return p.fail(.expected_block_or_assignment); - } - if (p.eatToken(.semicolon)) |_| { - return p.addNode(.{ - .tag = .if_simple, - .main_token = if_token, - .data = .{ - .lhs = condition, - .rhs = assign_expr, - }, - }); - } - else_required = true; - break :blk assign_expr; - }; - _ = p.eatToken(.keyword_else) orelse { - if (else_required) { - try p.warn(.expected_semi_or_else); - } - return p.addNode(.{ - .tag = .if_simple, - .main_token = if_token, - .data = .{ - .lhs = condition, - .rhs = then_expr, - }, - }); - }; - _ = try p.parsePayload(); - const else_expr = try p.expectStatement(false); - return p.addNode(.{ - .tag = .@"if", - .main_token = if_token, - .data = .{ - .lhs = condition, - .rhs = try p.addExtra(Node.If{ - .then_expr = then_expr, - .else_expr = else_expr, - }), - }, - }); - } - - /// LabeledStatement <- BlockLabel? (Block / LoopStatement) - fn parseLabeledStatement(p: *Parser) !Node.Index { - const label_token = p.parseBlockLabel(); - const block = try p.parseBlock(); - if (block != 0) return block; - - const loop_stmt = try p.parseLoopStatement(); - if (loop_stmt != 0) return loop_stmt; - - if (label_token != 0) { - const after_colon = p.tok_i; - const node = try p.parseTypeExpr(); - if (node != 0) { - const a = try p.parseByteAlign(); - const b = try p.parseAddrSpace(); - const c = try p.parseLinkSection(); - const d = if (p.eatToken(.equal) == null) 0 else try p.expectExpr(); - if (a != 0 or b != 0 or c != 0 or d != 0) { - return p.failMsg(.{ .tag = .expected_var_const, .token = label_token }); - } - } - return p.failMsg(.{ .tag = .expected_labelable, .token = after_colon }); - } - - return null_node; - } - - /// LoopStatement <- KEYWORD_inline? (ForStatement / WhileStatement) - fn parseLoopStatement(p: *Parser) !Node.Index { - const inline_token = p.eatToken(.keyword_inline); - - const for_statement = try p.parseForStatement(); - if (for_statement != 0) return for_statement; - - const while_statement = try p.parseWhileStatement(); - if (while_statement != 0) return while_statement; - - if (inline_token == null) return null_node; - - // If we've seen "inline", there should have been a "for" or "while" - return p.fail(.expected_inlinable); - } - - /// ForPrefix <- KEYWORD_for LPAREN Expr RPAREN PtrIndexPayload - /// - /// ForStatement - /// <- ForPrefix BlockExpr ( KEYWORD_else Statement )? - /// / ForPrefix AssignExpr ( SEMICOLON / KEYWORD_else Statement ) - fn parseForStatement(p: *Parser) !Node.Index { - const for_token = p.eatToken(.keyword_for) orelse return null_node; - _ = try p.expectToken(.l_paren); - const array_expr = try p.expectExpr(); - _ = try p.expectToken(.r_paren); - const found_payload = try p.parsePtrIndexPayload(); - if (found_payload == 0) try p.warn(.expected_loop_payload); - - // TODO propose to change the syntax so that semicolons are always required - // inside while statements, even if there is an `else`. - var else_required = false; - const then_expr = blk: { - const block_expr = try p.parseBlockExpr(); - if (block_expr != 0) break :blk block_expr; - const assign_expr = try p.parseAssignExpr(); - if (assign_expr == 0) { - return p.fail(.expected_block_or_assignment); - } - if (p.eatToken(.semicolon)) |_| { - return p.addNode(.{ - .tag = .for_simple, - .main_token = for_token, - .data = .{ - .lhs = array_expr, - .rhs = assign_expr, - }, - }); - } - else_required = true; - break :blk assign_expr; - }; - _ = p.eatToken(.keyword_else) orelse { - if (else_required) { - try p.warn(.expected_semi_or_else); - } - return p.addNode(.{ - .tag = .for_simple, - .main_token = for_token, - .data = .{ - .lhs = array_expr, - .rhs = then_expr, - }, - }); - }; - return p.addNode(.{ - .tag = .@"for", - .main_token = for_token, - .data = .{ - .lhs = array_expr, - .rhs = try p.addExtra(Node.If{ - .then_expr = then_expr, - .else_expr = try p.expectStatement(false), - }), - }, - }); - } - - /// WhilePrefix <- KEYWORD_while LPAREN Expr RPAREN PtrPayload? WhileContinueExpr? - /// - /// WhileStatement - /// <- WhilePrefix BlockExpr ( KEYWORD_else Payload? Statement )? - /// / WhilePrefix AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement ) - fn parseWhileStatement(p: *Parser) !Node.Index { - const while_token = p.eatToken(.keyword_while) orelse return null_node; - _ = try p.expectToken(.l_paren); - const condition = try p.expectExpr(); - _ = try p.expectToken(.r_paren); - _ = try p.parsePtrPayload(); - const cont_expr = try p.parseWhileContinueExpr(); - - // TODO propose to change the syntax so that semicolons are always required - // inside while statements, even if there is an `else`. - var else_required = false; - const then_expr = blk: { - const block_expr = try p.parseBlockExpr(); - if (block_expr != 0) break :blk block_expr; - const assign_expr = try p.parseAssignExpr(); - if (assign_expr == 0) { - return p.fail(.expected_block_or_assignment); - } - if (p.eatToken(.semicolon)) |_| { - if (cont_expr == 0) { - return p.addNode(.{ - .tag = .while_simple, - .main_token = while_token, - .data = .{ - .lhs = condition, - .rhs = assign_expr, - }, - }); - } else { - return p.addNode(.{ - .tag = .while_cont, - .main_token = while_token, - .data = .{ - .lhs = condition, - .rhs = try p.addExtra(Node.WhileCont{ - .cont_expr = cont_expr, - .then_expr = assign_expr, - }), - }, - }); - } - } - else_required = true; - break :blk assign_expr; - }; - _ = p.eatToken(.keyword_else) orelse { - if (else_required) { - try p.warn(.expected_semi_or_else); - } - if (cont_expr == 0) { - return p.addNode(.{ - .tag = .while_simple, - .main_token = while_token, - .data = .{ - .lhs = condition, - .rhs = then_expr, - }, - }); - } else { - return p.addNode(.{ - .tag = .while_cont, - .main_token = while_token, - .data = .{ - .lhs = condition, - .rhs = try p.addExtra(Node.WhileCont{ - .cont_expr = cont_expr, - .then_expr = then_expr, - }), - }, - }); - } - }; - _ = try p.parsePayload(); - const else_expr = try p.expectStatement(false); - return p.addNode(.{ - .tag = .@"while", - .main_token = while_token, - .data = .{ - .lhs = condition, - .rhs = try p.addExtra(Node.While{ - .cont_expr = cont_expr, - .then_expr = then_expr, - .else_expr = else_expr, - }), - }, - }); - } - - /// BlockExprStatement - /// <- BlockExpr - /// / AssignExpr SEMICOLON - fn parseBlockExprStatement(p: *Parser) !Node.Index { - const block_expr = try p.parseBlockExpr(); - if (block_expr != 0) { - return block_expr; - } - const assign_expr = try p.parseAssignExpr(); - if (assign_expr != 0) { - try p.expectSemicolon(.expected_semi_after_stmt, true); - return assign_expr; - } - return null_node; - } - - fn expectBlockExprStatement(p: *Parser) !Node.Index { - const node = try p.parseBlockExprStatement(); - if (node == 0) { - return p.fail(.expected_block_or_expr); - } - return node; - } - - /// BlockExpr <- BlockLabel? Block - fn parseBlockExpr(p: *Parser) Error!Node.Index { - switch (p.token_tags[p.tok_i]) { - .identifier => { - if (p.token_tags[p.tok_i + 1] == .colon and - p.token_tags[p.tok_i + 2] == .l_brace) - { - p.tok_i += 2; - return p.parseBlock(); - } else { - return null_node; - } - }, - .l_brace => return p.parseBlock(), - else => return null_node, - } - } - - /// AssignExpr <- Expr (AssignOp Expr)? - /// - /// AssignOp - /// <- ASTERISKEQUAL - /// / ASTERISKPIPEEQUAL - /// / SLASHEQUAL - /// / PERCENTEQUAL - /// / PLUSEQUAL - /// / PLUSPIPEEQUAL - /// / MINUSEQUAL - /// / MINUSPIPEEQUAL - /// / LARROW2EQUAL - /// / LARROW2PIPEEQUAL - /// / RARROW2EQUAL - /// / AMPERSANDEQUAL - /// / CARETEQUAL - /// / PIPEEQUAL - /// / ASTERISKPERCENTEQUAL - /// / PLUSPERCENTEQUAL - /// / MINUSPERCENTEQUAL - /// / EQUAL - fn parseAssignExpr(p: *Parser) !Node.Index { - const expr = try p.parseExpr(); - if (expr == 0) return null_node; - - const tag: Node.Tag = switch (p.token_tags[p.tok_i]) { - .asterisk_equal => .assign_mul, - .slash_equal => .assign_div, - .percent_equal => .assign_mod, - .plus_equal => .assign_add, - .minus_equal => .assign_sub, - .angle_bracket_angle_bracket_left_equal => .assign_shl, - .angle_bracket_angle_bracket_left_pipe_equal => .assign_shl_sat, - .angle_bracket_angle_bracket_right_equal => .assign_shr, - .ampersand_equal => .assign_bit_and, - .caret_equal => .assign_bit_xor, - .pipe_equal => .assign_bit_or, - .asterisk_percent_equal => .assign_mul_wrap, - .plus_percent_equal => .assign_add_wrap, - .minus_percent_equal => .assign_sub_wrap, - .asterisk_pipe_equal => .assign_mul_sat, - .plus_pipe_equal => .assign_add_sat, - .minus_pipe_equal => .assign_sub_sat, - .equal => .assign, - else => return expr, - }; - return p.addNode(.{ - .tag = tag, - .main_token = p.nextToken(), - .data = .{ - .lhs = expr, - .rhs = try p.expectExpr(), - }, - }); - } - - fn expectAssignExpr(p: *Parser) !Node.Index { - const expr = try p.parseAssignExpr(); - if (expr == 0) { - return p.fail(.expected_expr_or_assignment); - } - return expr; - } - - fn parseExpr(p: *Parser) Error!Node.Index { - return p.parseExprPrecedence(0); - } - - fn expectExpr(p: *Parser) Error!Node.Index { - const node = try p.parseExpr(); - if (node == 0) { - return p.fail(.expected_expr); - } else { - return node; - } - } - - const Assoc = enum { - left, - none, - }; - - const OperInfo = struct { - prec: i8, - tag: Node.Tag, - assoc: Assoc = Assoc.left, - }; - - // A table of binary operator information. Higher precedence numbers are - // stickier. All operators at the same precedence level should have the same - // associativity. - const operTable = std.enums.directEnumArrayDefault(Token.Tag, OperInfo, .{ .prec = -1, .tag = Node.Tag.root }, 0, .{ - .keyword_or = .{ .prec = 10, .tag = .bool_or }, - - .keyword_and = .{ .prec = 20, .tag = .bool_and }, - - .equal_equal = .{ .prec = 30, .tag = .equal_equal, .assoc = Assoc.none }, - .bang_equal = .{ .prec = 30, .tag = .bang_equal, .assoc = Assoc.none }, - .angle_bracket_left = .{ .prec = 30, .tag = .less_than, .assoc = Assoc.none }, - .angle_bracket_right = .{ .prec = 30, .tag = .greater_than, .assoc = Assoc.none }, - .angle_bracket_left_equal = .{ .prec = 30, .tag = .less_or_equal, .assoc = Assoc.none }, - .angle_bracket_right_equal = .{ .prec = 30, .tag = .greater_or_equal, .assoc = Assoc.none }, - - .ampersand = .{ .prec = 40, .tag = .bit_and }, - .caret = .{ .prec = 40, .tag = .bit_xor }, - .pipe = .{ .prec = 40, .tag = .bit_or }, - .keyword_orelse = .{ .prec = 40, .tag = .@"orelse" }, - .keyword_catch = .{ .prec = 40, .tag = .@"catch" }, - - .angle_bracket_angle_bracket_left = .{ .prec = 50, .tag = .shl }, - .angle_bracket_angle_bracket_left_pipe = .{ .prec = 50, .tag = .shl_sat }, - .angle_bracket_angle_bracket_right = .{ .prec = 50, .tag = .shr }, - - .plus = .{ .prec = 60, .tag = .add }, - .minus = .{ .prec = 60, .tag = .sub }, - .plus_plus = .{ .prec = 60, .tag = .array_cat }, - .plus_percent = .{ .prec = 60, .tag = .add_wrap }, - .minus_percent = .{ .prec = 60, .tag = .sub_wrap }, - .plus_pipe = .{ .prec = 60, .tag = .add_sat }, - .minus_pipe = .{ .prec = 60, .tag = .sub_sat }, - - .pipe_pipe = .{ .prec = 70, .tag = .merge_error_sets }, - .asterisk = .{ .prec = 70, .tag = .mul }, - .slash = .{ .prec = 70, .tag = .div }, - .percent = .{ .prec = 70, .tag = .mod }, - .asterisk_asterisk = .{ .prec = 70, .tag = .array_mult }, - .asterisk_percent = .{ .prec = 70, .tag = .mul_wrap }, - .asterisk_pipe = .{ .prec = 70, .tag = .mul_sat }, - }); - - fn parseExprPrecedence(p: *Parser, min_prec: i32) Error!Node.Index { - assert(min_prec >= 0); - var node = try p.parsePrefixExpr(); - if (node == 0) { - return null_node; - } - - var banned_prec: i8 = -1; - - while (true) { - const tok_tag = p.token_tags[p.tok_i]; - const info = operTable[@intCast(usize, @enumToInt(tok_tag))]; - if (info.prec < min_prec) { - break; - } - if (info.prec == banned_prec) { - return p.fail(.chained_comparison_operators); - } - - const oper_token = p.nextToken(); - // Special-case handling for "catch" - if (tok_tag == .keyword_catch) { - _ = try p.parsePayload(); - } - const rhs = try p.parseExprPrecedence(info.prec + 1); - if (rhs == 0) { - try p.warn(.expected_expr); - return node; - } - - { - const tok_len = tok_tag.lexeme().?.len; - const char_before = p.source[p.token_starts[oper_token] - 1]; - const char_after = p.source[p.token_starts[oper_token] + tok_len]; - if (tok_tag == .ampersand and char_after == '&') { - // without types we don't know if '&&' was intended as 'bitwise_and address_of', or a c-style logical_and - // The best the parser can do is recommend changing it to 'and' or ' & &' - try p.warnMsg(.{ .tag = .invalid_ampersand_ampersand, .token = oper_token }); - } else if (std.ascii.isWhitespace(char_before) != std.ascii.isWhitespace(char_after)) { - try p.warnMsg(.{ .tag = .mismatched_binary_op_whitespace, .token = oper_token }); - } - } - - node = try p.addNode(.{ - .tag = info.tag, - .main_token = oper_token, - .data = .{ - .lhs = node, - .rhs = rhs, - }, - }); - - if (info.assoc == Assoc.none) { - banned_prec = info.prec; - } - } - - return node; - } - - /// PrefixExpr <- PrefixOp* PrimaryExpr - /// - /// PrefixOp - /// <- EXCLAMATIONMARK - /// / MINUS - /// / TILDE - /// / MINUSPERCENT - /// / AMPERSAND - /// / KEYWORD_try - /// / KEYWORD_await - fn parsePrefixExpr(p: *Parser) Error!Node.Index { - const tag: Node.Tag = switch (p.token_tags[p.tok_i]) { - .bang => .bool_not, - .minus => .negation, - .tilde => .bit_not, - .minus_percent => .negation_wrap, - .ampersand => .address_of, - .keyword_try => .@"try", - .keyword_await => .@"await", - else => return p.parsePrimaryExpr(), - }; - return p.addNode(.{ - .tag = tag, - .main_token = p.nextToken(), - .data = .{ - .lhs = try p.expectPrefixExpr(), - .rhs = undefined, - }, - }); - } - - fn expectPrefixExpr(p: *Parser) Error!Node.Index { - const node = try p.parsePrefixExpr(); - if (node == 0) { - return p.fail(.expected_prefix_expr); - } - return node; - } - - /// TypeExpr <- PrefixTypeOp* ErrorUnionExpr - /// - /// PrefixTypeOp - /// <- QUESTIONMARK - /// / KEYWORD_anyframe MINUSRARROW - /// / SliceTypeStart (ByteAlign / AddrSpace / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)* - /// / PtrTypeStart (AddrSpace / KEYWORD_align LPAREN Expr (COLON Expr COLON Expr)? RPAREN / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)* - /// / ArrayTypeStart - /// - /// SliceTypeStart <- LBRACKET (COLON Expr)? RBRACKET - /// - /// PtrTypeStart - /// <- ASTERISK - /// / ASTERISK2 - /// / LBRACKET ASTERISK (LETTERC / COLON Expr)? RBRACKET - /// - /// ArrayTypeStart <- LBRACKET Expr (COLON Expr)? RBRACKET - fn parseTypeExpr(p: *Parser) Error!Node.Index { - switch (p.token_tags[p.tok_i]) { - .question_mark => return p.addNode(.{ - .tag = .optional_type, - .main_token = p.nextToken(), - .data = .{ - .lhs = try p.expectTypeExpr(), - .rhs = undefined, - }, - }), - .keyword_anyframe => switch (p.token_tags[p.tok_i + 1]) { - .arrow => return p.addNode(.{ - .tag = .anyframe_type, - .main_token = p.nextToken(), - .data = .{ - .lhs = p.nextToken(), - .rhs = try p.expectTypeExpr(), - }, - }), - else => return p.parseErrorUnionExpr(), - }, - .asterisk => { - const asterisk = p.nextToken(); - const mods = try p.parsePtrModifiers(); - const elem_type = try p.expectTypeExpr(); - if (mods.bit_range_start != 0) { - return p.addNode(.{ - .tag = .ptr_type_bit_range, - .main_token = asterisk, - .data = .{ - .lhs = try p.addExtra(Node.PtrTypeBitRange{ - .sentinel = 0, - .align_node = mods.align_node, - .addrspace_node = mods.addrspace_node, - .bit_range_start = mods.bit_range_start, - .bit_range_end = mods.bit_range_end, - }), - .rhs = elem_type, - }, - }); - } else if (mods.addrspace_node != 0) { - return p.addNode(.{ - .tag = .ptr_type, - .main_token = asterisk, - .data = .{ - .lhs = try p.addExtra(Node.PtrType{ - .sentinel = 0, - .align_node = mods.align_node, - .addrspace_node = mods.addrspace_node, - }), - .rhs = elem_type, - }, - }); - } else { - return p.addNode(.{ - .tag = .ptr_type_aligned, - .main_token = asterisk, - .data = .{ - .lhs = mods.align_node, - .rhs = elem_type, - }, - }); - } - }, - .asterisk_asterisk => { - const asterisk = p.nextToken(); - const mods = try p.parsePtrModifiers(); - const elem_type = try p.expectTypeExpr(); - const inner: Node.Index = inner: { - if (mods.bit_range_start != 0) { - break :inner try p.addNode(.{ - .tag = .ptr_type_bit_range, - .main_token = asterisk, - .data = .{ - .lhs = try p.addExtra(Node.PtrTypeBitRange{ - .sentinel = 0, - .align_node = mods.align_node, - .addrspace_node = mods.addrspace_node, - .bit_range_start = mods.bit_range_start, - .bit_range_end = mods.bit_range_end, - }), - .rhs = elem_type, - }, - }); - } else if (mods.addrspace_node != 0) { - break :inner try p.addNode(.{ - .tag = .ptr_type, - .main_token = asterisk, - .data = .{ - .lhs = try p.addExtra(Node.PtrType{ - .sentinel = 0, - .align_node = mods.align_node, - .addrspace_node = mods.addrspace_node, - }), - .rhs = elem_type, - }, - }); - } else { - break :inner try p.addNode(.{ - .tag = .ptr_type_aligned, - .main_token = asterisk, - .data = .{ - .lhs = mods.align_node, - .rhs = elem_type, - }, - }); - } - }; - return p.addNode(.{ - .tag = .ptr_type_aligned, - .main_token = asterisk, - .data = .{ - .lhs = 0, - .rhs = inner, - }, - }); - }, - .l_bracket => switch (p.token_tags[p.tok_i + 1]) { - .asterisk => { - _ = p.nextToken(); - const asterisk = p.nextToken(); - var sentinel: Node.Index = 0; - if (p.eatToken(.identifier)) |ident| { - const ident_slice = p.source[p.token_starts[ident]..p.token_starts[ident + 1]]; - if (!std.mem.eql(u8, std.mem.trimRight(u8, ident_slice, &std.ascii.whitespace), "c")) { - p.tok_i -= 1; - } - } else if (p.eatToken(.colon)) |_| { - sentinel = try p.expectExpr(); - } - _ = try p.expectToken(.r_bracket); - const mods = try p.parsePtrModifiers(); - const elem_type = try p.expectTypeExpr(); - if (mods.bit_range_start == 0) { - if (sentinel == 0 and mods.addrspace_node == 0) { - return p.addNode(.{ - .tag = .ptr_type_aligned, - .main_token = asterisk, - .data = .{ - .lhs = mods.align_node, - .rhs = elem_type, - }, - }); - } else if (mods.align_node == 0 and mods.addrspace_node == 0) { - return p.addNode(.{ - .tag = .ptr_type_sentinel, - .main_token = asterisk, - .data = .{ - .lhs = sentinel, - .rhs = elem_type, - }, - }); - } else { - return p.addNode(.{ - .tag = .ptr_type, - .main_token = asterisk, - .data = .{ - .lhs = try p.addExtra(Node.PtrType{ - .sentinel = sentinel, - .align_node = mods.align_node, - .addrspace_node = mods.addrspace_node, - }), - .rhs = elem_type, - }, - }); - } - } else { - return p.addNode(.{ - .tag = .ptr_type_bit_range, - .main_token = asterisk, - .data = .{ - .lhs = try p.addExtra(Node.PtrTypeBitRange{ - .sentinel = sentinel, - .align_node = mods.align_node, - .addrspace_node = mods.addrspace_node, - .bit_range_start = mods.bit_range_start, - .bit_range_end = mods.bit_range_end, - }), - .rhs = elem_type, - }, - }); - } - }, - else => { - const lbracket = p.nextToken(); - const len_expr = try p.parseExpr(); - const sentinel: Node.Index = if (p.eatToken(.colon)) |_| - try p.expectExpr() - else - 0; - _ = try p.expectToken(.r_bracket); - if (len_expr == 0) { - const mods = try p.parsePtrModifiers(); - const elem_type = try p.expectTypeExpr(); - if (mods.bit_range_start != 0) { - try p.warnMsg(.{ - .tag = .invalid_bit_range, - .token = p.nodes.items(.main_token)[mods.bit_range_start], - }); - } - if (sentinel == 0 and mods.addrspace_node == 0) { - return p.addNode(.{ - .tag = .ptr_type_aligned, - .main_token = lbracket, - .data = .{ - .lhs = mods.align_node, - .rhs = elem_type, - }, - }); - } else if (mods.align_node == 0 and mods.addrspace_node == 0) { - return p.addNode(.{ - .tag = .ptr_type_sentinel, - .main_token = lbracket, - .data = .{ - .lhs = sentinel, - .rhs = elem_type, - }, - }); - } else { - return p.addNode(.{ - .tag = .ptr_type, - .main_token = lbracket, - .data = .{ - .lhs = try p.addExtra(Node.PtrType{ - .sentinel = sentinel, - .align_node = mods.align_node, - .addrspace_node = mods.addrspace_node, - }), - .rhs = elem_type, - }, - }); - } - } else { - switch (p.token_tags[p.tok_i]) { - .keyword_align, - .keyword_const, - .keyword_volatile, - .keyword_allowzero, - .keyword_addrspace, - => return p.fail(.ptr_mod_on_array_child_type), - else => {}, - } - const elem_type = try p.expectTypeExpr(); - if (sentinel == 0) { - return p.addNode(.{ - .tag = .array_type, - .main_token = lbracket, - .data = .{ - .lhs = len_expr, - .rhs = elem_type, - }, - }); - } else { - return p.addNode(.{ - .tag = .array_type_sentinel, - .main_token = lbracket, - .data = .{ - .lhs = len_expr, - .rhs = try p.addExtra(.{ - .elem_type = elem_type, - .sentinel = sentinel, - }), - }, - }); - } - } - }, - }, - else => return p.parseErrorUnionExpr(), - } - } - - fn expectTypeExpr(p: *Parser) Error!Node.Index { - const node = try p.parseTypeExpr(); - if (node == 0) { - return p.fail(.expected_type_expr); - } - return node; - } - - /// PrimaryExpr - /// <- AsmExpr - /// / IfExpr - /// / KEYWORD_break BreakLabel? Expr? - /// / KEYWORD_comptime Expr - /// / KEYWORD_nosuspend Expr - /// / KEYWORD_continue BreakLabel? - /// / KEYWORD_resume Expr - /// / KEYWORD_return Expr? - /// / BlockLabel? LoopExpr - /// / Block - /// / CurlySuffixExpr - fn parsePrimaryExpr(p: *Parser) !Node.Index { - switch (p.token_tags[p.tok_i]) { - .keyword_asm => return p.expectAsmExpr(), - .keyword_if => return p.parseIfExpr(), - .keyword_break => { - p.tok_i += 1; - return p.addNode(.{ - .tag = .@"break", - .main_token = p.tok_i - 1, - .data = .{ - .lhs = try p.parseBreakLabel(), - .rhs = try p.parseExpr(), - }, - }); - }, - .keyword_continue => { - p.tok_i += 1; - return p.addNode(.{ - .tag = .@"continue", - .main_token = p.tok_i - 1, - .data = .{ - .lhs = try p.parseBreakLabel(), - .rhs = undefined, - }, - }); - }, - .keyword_comptime => { - p.tok_i += 1; - return p.addNode(.{ - .tag = .@"comptime", - .main_token = p.tok_i - 1, - .data = .{ - .lhs = try p.expectExpr(), - .rhs = undefined, - }, - }); - }, - .keyword_nosuspend => { - p.tok_i += 1; - return p.addNode(.{ - .tag = .@"nosuspend", - .main_token = p.tok_i - 1, - .data = .{ - .lhs = try p.expectExpr(), - .rhs = undefined, - }, - }); - }, - .keyword_resume => { - p.tok_i += 1; - return p.addNode(.{ - .tag = .@"resume", - .main_token = p.tok_i - 1, - .data = .{ - .lhs = try p.expectExpr(), - .rhs = undefined, - }, - }); - }, - .keyword_return => { - p.tok_i += 1; - return p.addNode(.{ - .tag = .@"return", - .main_token = p.tok_i - 1, - .data = .{ - .lhs = try p.parseExpr(), - .rhs = undefined, - }, - }); - }, - .identifier => { - if (p.token_tags[p.tok_i + 1] == .colon) { - switch (p.token_tags[p.tok_i + 2]) { - .keyword_inline => { - p.tok_i += 3; - switch (p.token_tags[p.tok_i]) { - .keyword_for => return p.parseForExpr(), - .keyword_while => return p.parseWhileExpr(), - else => return p.fail(.expected_inlinable), - } - }, - .keyword_for => { - p.tok_i += 2; - return p.parseForExpr(); - }, - .keyword_while => { - p.tok_i += 2; - return p.parseWhileExpr(); - }, - .l_brace => { - p.tok_i += 2; - return p.parseBlock(); - }, - else => return p.parseCurlySuffixExpr(), - } - } else { - return p.parseCurlySuffixExpr(); - } - }, - .keyword_inline => { - p.tok_i += 1; - switch (p.token_tags[p.tok_i]) { - .keyword_for => return p.parseForExpr(), - .keyword_while => return p.parseWhileExpr(), - else => return p.fail(.expected_inlinable), - } - }, - .keyword_for => return p.parseForExpr(), - .keyword_while => return p.parseWhileExpr(), - .l_brace => return p.parseBlock(), - else => return p.parseCurlySuffixExpr(), - } - } - - /// IfExpr <- IfPrefix Expr (KEYWORD_else Payload? Expr)? - fn parseIfExpr(p: *Parser) !Node.Index { - return p.parseIf(expectExpr); - } - - /// Block <- LBRACE Statement* RBRACE - fn parseBlock(p: *Parser) !Node.Index { - const lbrace = p.eatToken(.l_brace) orelse return null_node; - const scratch_top = p.scratch.items.len; - defer p.scratch.shrinkRetainingCapacity(scratch_top); - while (true) { - if (p.token_tags[p.tok_i] == .r_brace) break; - const statement = try p.expectStatementRecoverable(); - if (statement == 0) break; - try p.scratch.append(p.gpa, statement); - } - _ = try p.expectToken(.r_brace); - const semicolon = (p.token_tags[p.tok_i - 2] == .semicolon); - const statements = p.scratch.items[scratch_top..]; - switch (statements.len) { - 0 => return p.addNode(.{ - .tag = .block_two, - .main_token = lbrace, - .data = .{ - .lhs = 0, - .rhs = 0, - }, - }), - 1 => return p.addNode(.{ - .tag = if (semicolon) .block_two_semicolon else .block_two, - .main_token = lbrace, - .data = .{ - .lhs = statements[0], - .rhs = 0, - }, - }), - 2 => return p.addNode(.{ - .tag = if (semicolon) .block_two_semicolon else .block_two, - .main_token = lbrace, - .data = .{ - .lhs = statements[0], - .rhs = statements[1], - }, - }), - else => { - const span = try p.listToSpan(statements); - return p.addNode(.{ - .tag = if (semicolon) .block_semicolon else .block, - .main_token = lbrace, - .data = .{ - .lhs = span.start, - .rhs = span.end, - }, - }); - }, - } - } - - /// ForPrefix <- KEYWORD_for LPAREN Expr RPAREN PtrIndexPayload - /// - /// ForExpr <- ForPrefix Expr (KEYWORD_else Expr)? - fn parseForExpr(p: *Parser) !Node.Index { - const for_token = p.eatToken(.keyword_for) orelse return null_node; - _ = try p.expectToken(.l_paren); - const array_expr = try p.expectExpr(); - _ = try p.expectToken(.r_paren); - const found_payload = try p.parsePtrIndexPayload(); - if (found_payload == 0) try p.warn(.expected_loop_payload); - - const then_expr = try p.expectExpr(); - _ = p.eatToken(.keyword_else) orelse { - return p.addNode(.{ - .tag = .for_simple, - .main_token = for_token, - .data = .{ - .lhs = array_expr, - .rhs = then_expr, - }, - }); - }; - const else_expr = try p.expectExpr(); - return p.addNode(.{ - .tag = .@"for", - .main_token = for_token, - .data = .{ - .lhs = array_expr, - .rhs = try p.addExtra(Node.If{ - .then_expr = then_expr, - .else_expr = else_expr, - }), - }, - }); - } - - /// WhilePrefix <- KEYWORD_while LPAREN Expr RPAREN PtrPayload? WhileContinueExpr? - /// - /// WhileExpr <- WhilePrefix Expr (KEYWORD_else Payload? Expr)? - fn parseWhileExpr(p: *Parser) !Node.Index { - const while_token = p.eatToken(.keyword_while) orelse return null_node; - _ = try p.expectToken(.l_paren); - const condition = try p.expectExpr(); - _ = try p.expectToken(.r_paren); - _ = try p.parsePtrPayload(); - const cont_expr = try p.parseWhileContinueExpr(); - - const then_expr = try p.expectExpr(); - _ = p.eatToken(.keyword_else) orelse { - if (cont_expr == 0) { - return p.addNode(.{ - .tag = .while_simple, - .main_token = while_token, - .data = .{ - .lhs = condition, - .rhs = then_expr, - }, - }); - } else { - return p.addNode(.{ - .tag = .while_cont, - .main_token = while_token, - .data = .{ - .lhs = condition, - .rhs = try p.addExtra(Node.WhileCont{ - .cont_expr = cont_expr, - .then_expr = then_expr, - }), - }, - }); - } - }; - _ = try p.parsePayload(); - const else_expr = try p.expectExpr(); - return p.addNode(.{ - .tag = .@"while", - .main_token = while_token, - .data = .{ - .lhs = condition, - .rhs = try p.addExtra(Node.While{ - .cont_expr = cont_expr, - .then_expr = then_expr, - .else_expr = else_expr, - }), - }, - }); - } - - /// CurlySuffixExpr <- TypeExpr InitList? - /// - /// InitList - /// <- LBRACE FieldInit (COMMA FieldInit)* COMMA? RBRACE - /// / LBRACE Expr (COMMA Expr)* COMMA? RBRACE - /// / LBRACE RBRACE - fn parseCurlySuffixExpr(p: *Parser) !Node.Index { - const lhs = try p.parseTypeExpr(); - if (lhs == 0) return null_node; - const lbrace = p.eatToken(.l_brace) orelse return lhs; - - // If there are 0 or 1 items, we can use ArrayInitOne/StructInitOne; - // otherwise we use the full ArrayInit/StructInit. - - const scratch_top = p.scratch.items.len; - defer p.scratch.shrinkRetainingCapacity(scratch_top); - const field_init = try p.parseFieldInit(); - if (field_init != 0) { - try p.scratch.append(p.gpa, field_init); - while (true) { - switch (p.token_tags[p.tok_i]) { - .comma => p.tok_i += 1, - .r_brace => { - p.tok_i += 1; - break; - }, - .colon, .r_paren, .r_bracket => return p.failExpected(.r_brace), - // Likely just a missing comma; give error but continue parsing. - else => try p.warn(.expected_comma_after_initializer), - } - if (p.eatToken(.r_brace)) |_| break; - const next = try p.expectFieldInit(); - try p.scratch.append(p.gpa, next); - } - const comma = (p.token_tags[p.tok_i - 2] == .comma); - const inits = p.scratch.items[scratch_top..]; - switch (inits.len) { - 0 => unreachable, - 1 => return p.addNode(.{ - .tag = if (comma) .struct_init_one_comma else .struct_init_one, - .main_token = lbrace, - .data = .{ - .lhs = lhs, - .rhs = inits[0], - }, - }), - else => return p.addNode(.{ - .tag = if (comma) .struct_init_comma else .struct_init, - .main_token = lbrace, - .data = .{ - .lhs = lhs, - .rhs = try p.addExtra(try p.listToSpan(inits)), - }, - }), - } - } - - while (true) { - if (p.eatToken(.r_brace)) |_| break; - const elem_init = try p.expectExpr(); - try p.scratch.append(p.gpa, elem_init); - switch (p.token_tags[p.tok_i]) { - .comma => p.tok_i += 1, - .r_brace => { - p.tok_i += 1; - break; - }, - .colon, .r_paren, .r_bracket => return p.failExpected(.r_brace), - // Likely just a missing comma; give error but continue parsing. - else => try p.warn(.expected_comma_after_initializer), - } - } - const comma = (p.token_tags[p.tok_i - 2] == .comma); - const inits = p.scratch.items[scratch_top..]; - switch (inits.len) { - 0 => return p.addNode(.{ - .tag = .struct_init_one, - .main_token = lbrace, - .data = .{ - .lhs = lhs, - .rhs = 0, - }, - }), - 1 => return p.addNode(.{ - .tag = if (comma) .array_init_one_comma else .array_init_one, - .main_token = lbrace, - .data = .{ - .lhs = lhs, - .rhs = inits[0], - }, - }), - else => return p.addNode(.{ - .tag = if (comma) .array_init_comma else .array_init, - .main_token = lbrace, - .data = .{ - .lhs = lhs, - .rhs = try p.addExtra(try p.listToSpan(inits)), - }, - }), - } - } - - /// ErrorUnionExpr <- SuffixExpr (EXCLAMATIONMARK TypeExpr)? - fn parseErrorUnionExpr(p: *Parser) !Node.Index { - const suffix_expr = try p.parseSuffixExpr(); - if (suffix_expr == 0) return null_node; - const bang = p.eatToken(.bang) orelse return suffix_expr; - return p.addNode(.{ - .tag = .error_union, - .main_token = bang, - .data = .{ - .lhs = suffix_expr, - .rhs = try p.expectTypeExpr(), - }, - }); - } - - /// SuffixExpr - /// <- KEYWORD_async PrimaryTypeExpr SuffixOp* FnCallArguments - /// / PrimaryTypeExpr (SuffixOp / FnCallArguments)* - /// - /// FnCallArguments <- LPAREN ExprList RPAREN - /// - /// ExprList <- (Expr COMMA)* Expr? - fn parseSuffixExpr(p: *Parser) !Node.Index { - if (p.eatToken(.keyword_async)) |_| { - var res = try p.expectPrimaryTypeExpr(); - while (true) { - const node = try p.parseSuffixOp(res); - if (node == 0) break; - res = node; - } - const lparen = p.eatToken(.l_paren) orelse { - try p.warn(.expected_param_list); - return res; - }; - const scratch_top = p.scratch.items.len; - defer p.scratch.shrinkRetainingCapacity(scratch_top); - while (true) { - if (p.eatToken(.r_paren)) |_| break; - const param = try p.expectExpr(); - try p.scratch.append(p.gpa, param); - switch (p.token_tags[p.tok_i]) { - .comma => p.tok_i += 1, - .r_paren => { - p.tok_i += 1; - break; - }, - .colon, .r_brace, .r_bracket => return p.failExpected(.r_paren), - // Likely just a missing comma; give error but continue parsing. - else => try p.warn(.expected_comma_after_arg), - } - } - const comma = (p.token_tags[p.tok_i - 2] == .comma); - const params = p.scratch.items[scratch_top..]; - switch (params.len) { - 0 => return p.addNode(.{ - .tag = if (comma) .async_call_one_comma else .async_call_one, - .main_token = lparen, - .data = .{ - .lhs = res, - .rhs = 0, - }, - }), - 1 => return p.addNode(.{ - .tag = if (comma) .async_call_one_comma else .async_call_one, - .main_token = lparen, - .data = .{ - .lhs = res, - .rhs = params[0], - }, - }), - else => return p.addNode(.{ - .tag = if (comma) .async_call_comma else .async_call, - .main_token = lparen, - .data = .{ - .lhs = res, - .rhs = try p.addExtra(try p.listToSpan(params)), - }, - }), - } - } - - var res = try p.parsePrimaryTypeExpr(); - if (res == 0) return res; - while (true) { - const suffix_op = try p.parseSuffixOp(res); - if (suffix_op != 0) { - res = suffix_op; - continue; - } - const lparen = p.eatToken(.l_paren) orelse return res; - const scratch_top = p.scratch.items.len; - defer p.scratch.shrinkRetainingCapacity(scratch_top); - while (true) { - if (p.eatToken(.r_paren)) |_| break; - const param = try p.expectExpr(); - try p.scratch.append(p.gpa, param); - switch (p.token_tags[p.tok_i]) { - .comma => p.tok_i += 1, - .r_paren => { - p.tok_i += 1; - break; - }, - .colon, .r_brace, .r_bracket => return p.failExpected(.r_paren), - // Likely just a missing comma; give error but continue parsing. - else => try p.warn(.expected_comma_after_arg), - } - } - const comma = (p.token_tags[p.tok_i - 2] == .comma); - const params = p.scratch.items[scratch_top..]; - res = switch (params.len) { - 0 => try p.addNode(.{ - .tag = if (comma) .call_one_comma else .call_one, - .main_token = lparen, - .data = .{ - .lhs = res, - .rhs = 0, - }, - }), - 1 => try p.addNode(.{ - .tag = if (comma) .call_one_comma else .call_one, - .main_token = lparen, - .data = .{ - .lhs = res, - .rhs = params[0], - }, - }), - else => try p.addNode(.{ - .tag = if (comma) .call_comma else .call, - .main_token = lparen, - .data = .{ - .lhs = res, - .rhs = try p.addExtra(try p.listToSpan(params)), - }, - }), - }; - } - } - - /// PrimaryTypeExpr - /// <- BUILTINIDENTIFIER FnCallArguments - /// / CHAR_LITERAL - /// / ContainerDecl - /// / DOT IDENTIFIER - /// / DOT InitList - /// / ErrorSetDecl - /// / FLOAT - /// / FnProto - /// / GroupedExpr - /// / LabeledTypeExpr - /// / IDENTIFIER - /// / IfTypeExpr - /// / INTEGER - /// / KEYWORD_comptime TypeExpr - /// / KEYWORD_error DOT IDENTIFIER - /// / KEYWORD_anyframe - /// / KEYWORD_unreachable - /// / STRINGLITERAL - /// / SwitchExpr - /// - /// ContainerDecl <- (KEYWORD_extern / KEYWORD_packed)? ContainerDeclAuto - /// - /// ContainerDeclAuto <- ContainerDeclType LBRACE container_doc_comment? ContainerMembers RBRACE - /// - /// InitList - /// <- LBRACE FieldInit (COMMA FieldInit)* COMMA? RBRACE - /// / LBRACE Expr (COMMA Expr)* COMMA? RBRACE - /// / LBRACE RBRACE - /// - /// ErrorSetDecl <- KEYWORD_error LBRACE IdentifierList RBRACE - /// - /// GroupedExpr <- LPAREN Expr RPAREN - /// - /// IfTypeExpr <- IfPrefix TypeExpr (KEYWORD_else Payload? TypeExpr)? - /// - /// LabeledTypeExpr - /// <- BlockLabel Block - /// / BlockLabel? LoopTypeExpr - /// - /// LoopTypeExpr <- KEYWORD_inline? (ForTypeExpr / WhileTypeExpr) - fn parsePrimaryTypeExpr(p: *Parser) !Node.Index { - switch (p.token_tags[p.tok_i]) { - .char_literal => return p.addNode(.{ - .tag = .char_literal, - .main_token = p.nextToken(), - .data = .{ - .lhs = undefined, - .rhs = undefined, - }, - }), - .number_literal => return p.addNode(.{ - .tag = .number_literal, - .main_token = p.nextToken(), - .data = .{ - .lhs = undefined, - .rhs = undefined, - }, - }), - .keyword_unreachable => return p.addNode(.{ - .tag = .unreachable_literal, - .main_token = p.nextToken(), - .data = .{ - .lhs = undefined, - .rhs = undefined, - }, - }), - .keyword_anyframe => return p.addNode(.{ - .tag = .anyframe_literal, - .main_token = p.nextToken(), - .data = .{ - .lhs = undefined, - .rhs = undefined, - }, - }), - .string_literal => { - const main_token = p.nextToken(); - return p.addNode(.{ - .tag = .string_literal, - .main_token = main_token, - .data = .{ - .lhs = undefined, - .rhs = undefined, - }, - }); - }, - - .builtin => return p.parseBuiltinCall(), - .keyword_fn => return p.parseFnProto(), - .keyword_if => return p.parseIf(expectTypeExpr), - .keyword_switch => return p.expectSwitchExpr(), - - .keyword_extern, - .keyword_packed, - => { - p.tok_i += 1; - return p.parseContainerDeclAuto(); - }, - - .keyword_struct, - .keyword_opaque, - .keyword_enum, - .keyword_union, - => return p.parseContainerDeclAuto(), - - .keyword_comptime => return p.addNode(.{ - .tag = .@"comptime", - .main_token = p.nextToken(), - .data = .{ - .lhs = try p.expectTypeExpr(), - .rhs = undefined, - }, - }), - .multiline_string_literal_line => { - const first_line = p.nextToken(); - while (p.token_tags[p.tok_i] == .multiline_string_literal_line) { - p.tok_i += 1; - } - return p.addNode(.{ - .tag = .multiline_string_literal, - .main_token = first_line, - .data = .{ - .lhs = first_line, - .rhs = p.tok_i - 1, - }, - }); - }, - .identifier => switch (p.token_tags[p.tok_i + 1]) { - .colon => switch (p.token_tags[p.tok_i + 2]) { - .keyword_inline => { - p.tok_i += 3; - switch (p.token_tags[p.tok_i]) { - .keyword_for => return p.parseForTypeExpr(), - .keyword_while => return p.parseWhileTypeExpr(), - else => return p.fail(.expected_inlinable), - } - }, - .keyword_for => { - p.tok_i += 2; - return p.parseForTypeExpr(); - }, - .keyword_while => { - p.tok_i += 2; - return p.parseWhileTypeExpr(); - }, - .l_brace => { - p.tok_i += 2; - return p.parseBlock(); - }, - else => return p.addNode(.{ - .tag = .identifier, - .main_token = p.nextToken(), - .data = .{ - .lhs = undefined, - .rhs = undefined, - }, - }), - }, - else => return p.addNode(.{ - .tag = .identifier, - .main_token = p.nextToken(), - .data = .{ - .lhs = undefined, - .rhs = undefined, - }, - }), - }, - .keyword_inline => { - p.tok_i += 1; - switch (p.token_tags[p.tok_i]) { - .keyword_for => return p.parseForTypeExpr(), - .keyword_while => return p.parseWhileTypeExpr(), - else => return p.fail(.expected_inlinable), - } - }, - .keyword_for => return p.parseForTypeExpr(), - .keyword_while => return p.parseWhileTypeExpr(), - .period => switch (p.token_tags[p.tok_i + 1]) { - .identifier => return p.addNode(.{ - .tag = .enum_literal, - .data = .{ - .lhs = p.nextToken(), // dot - .rhs = undefined, - }, - .main_token = p.nextToken(), // identifier - }), - .l_brace => { - const lbrace = p.tok_i + 1; - p.tok_i = lbrace + 1; - - // If there are 0, 1, or 2 items, we can use ArrayInitDotTwo/StructInitDotTwo; - // otherwise we use the full ArrayInitDot/StructInitDot. - - const scratch_top = p.scratch.items.len; - defer p.scratch.shrinkRetainingCapacity(scratch_top); - const field_init = try p.parseFieldInit(); - if (field_init != 0) { - try p.scratch.append(p.gpa, field_init); - while (true) { - switch (p.token_tags[p.tok_i]) { - .comma => p.tok_i += 1, - .r_brace => { - p.tok_i += 1; - break; - }, - .colon, .r_paren, .r_bracket => return p.failExpected(.r_brace), - // Likely just a missing comma; give error but continue parsing. - else => try p.warn(.expected_comma_after_initializer), - } - if (p.eatToken(.r_brace)) |_| break; - const next = try p.expectFieldInit(); - try p.scratch.append(p.gpa, next); - } - const comma = (p.token_tags[p.tok_i - 2] == .comma); - const inits = p.scratch.items[scratch_top..]; - switch (inits.len) { - 0 => unreachable, - 1 => return p.addNode(.{ - .tag = if (comma) .struct_init_dot_two_comma else .struct_init_dot_two, - .main_token = lbrace, - .data = .{ - .lhs = inits[0], - .rhs = 0, - }, - }), - 2 => return p.addNode(.{ - .tag = if (comma) .struct_init_dot_two_comma else .struct_init_dot_two, - .main_token = lbrace, - .data = .{ - .lhs = inits[0], - .rhs = inits[1], - }, - }), - else => { - const span = try p.listToSpan(inits); - return p.addNode(.{ - .tag = if (comma) .struct_init_dot_comma else .struct_init_dot, - .main_token = lbrace, - .data = .{ - .lhs = span.start, - .rhs = span.end, - }, - }); - }, - } - } - - while (true) { - if (p.eatToken(.r_brace)) |_| break; - const elem_init = try p.expectExpr(); - try p.scratch.append(p.gpa, elem_init); - switch (p.token_tags[p.tok_i]) { - .comma => p.tok_i += 1, - .r_brace => { - p.tok_i += 1; - break; - }, - .colon, .r_paren, .r_bracket => return p.failExpected(.r_brace), - // Likely just a missing comma; give error but continue parsing. - else => try p.warn(.expected_comma_after_initializer), - } - } - const comma = (p.token_tags[p.tok_i - 2] == .comma); - const inits = p.scratch.items[scratch_top..]; - switch (inits.len) { - 0 => return p.addNode(.{ - .tag = .struct_init_dot_two, - .main_token = lbrace, - .data = .{ - .lhs = 0, - .rhs = 0, - }, - }), - 1 => return p.addNode(.{ - .tag = if (comma) .array_init_dot_two_comma else .array_init_dot_two, - .main_token = lbrace, - .data = .{ - .lhs = inits[0], - .rhs = 0, - }, - }), - 2 => return p.addNode(.{ - .tag = if (comma) .array_init_dot_two_comma else .array_init_dot_two, - .main_token = lbrace, - .data = .{ - .lhs = inits[0], - .rhs = inits[1], - }, - }), - else => { - const span = try p.listToSpan(inits); - return p.addNode(.{ - .tag = if (comma) .array_init_dot_comma else .array_init_dot, - .main_token = lbrace, - .data = .{ - .lhs = span.start, - .rhs = span.end, - }, - }); - }, - } - }, - else => return null_node, - }, - .keyword_error => switch (p.token_tags[p.tok_i + 1]) { - .l_brace => { - const error_token = p.tok_i; - p.tok_i += 2; - while (true) { - if (p.eatToken(.r_brace)) |_| break; - _ = try p.eatDocComments(); - _ = try p.expectToken(.identifier); - switch (p.token_tags[p.tok_i]) { - .comma => p.tok_i += 1, - .r_brace => { - p.tok_i += 1; - break; - }, - .colon, .r_paren, .r_bracket => return p.failExpected(.r_brace), - // Likely just a missing comma; give error but continue parsing. - else => try p.warn(.expected_comma_after_field), - } - } - return p.addNode(.{ - .tag = .error_set_decl, - .main_token = error_token, - .data = .{ - .lhs = undefined, - .rhs = p.tok_i - 1, // rbrace - }, - }); - }, - else => { - const main_token = p.nextToken(); - const period = p.eatToken(.period); - if (period == null) try p.warnExpected(.period); - const identifier = p.eatToken(.identifier); - if (identifier == null) try p.warnExpected(.identifier); - return p.addNode(.{ - .tag = .error_value, - .main_token = main_token, - .data = .{ - .lhs = period orelse 0, - .rhs = identifier orelse 0, - }, - }); - }, - }, - .l_paren => return p.addNode(.{ - .tag = .grouped_expression, - .main_token = p.nextToken(), - .data = .{ - .lhs = try p.expectExpr(), - .rhs = try p.expectToken(.r_paren), - }, - }), - else => return null_node, - } - } - - fn expectPrimaryTypeExpr(p: *Parser) !Node.Index { - const node = try p.parsePrimaryTypeExpr(); - if (node == 0) { - return p.fail(.expected_primary_type_expr); - } - return node; - } - - /// ForPrefix <- KEYWORD_for LPAREN Expr RPAREN PtrIndexPayload - /// - /// ForTypeExpr <- ForPrefix TypeExpr (KEYWORD_else TypeExpr)? - fn parseForTypeExpr(p: *Parser) !Node.Index { - const for_token = p.eatToken(.keyword_for) orelse return null_node; - _ = try p.expectToken(.l_paren); - const array_expr = try p.expectExpr(); - _ = try p.expectToken(.r_paren); - const found_payload = try p.parsePtrIndexPayload(); - if (found_payload == 0) try p.warn(.expected_loop_payload); - - const then_expr = try p.expectTypeExpr(); - _ = p.eatToken(.keyword_else) orelse { - return p.addNode(.{ - .tag = .for_simple, - .main_token = for_token, - .data = .{ - .lhs = array_expr, - .rhs = then_expr, - }, - }); - }; - const else_expr = try p.expectTypeExpr(); - return p.addNode(.{ - .tag = .@"for", - .main_token = for_token, - .data = .{ - .lhs = array_expr, - .rhs = try p.addExtra(Node.If{ - .then_expr = then_expr, - .else_expr = else_expr, - }), - }, - }); - } - - /// WhilePrefix <- KEYWORD_while LPAREN Expr RPAREN PtrPayload? WhileContinueExpr? - /// - /// WhileTypeExpr <- WhilePrefix TypeExpr (KEYWORD_else Payload? TypeExpr)? - fn parseWhileTypeExpr(p: *Parser) !Node.Index { - const while_token = p.eatToken(.keyword_while) orelse return null_node; - _ = try p.expectToken(.l_paren); - const condition = try p.expectExpr(); - _ = try p.expectToken(.r_paren); - _ = try p.parsePtrPayload(); - const cont_expr = try p.parseWhileContinueExpr(); - - const then_expr = try p.expectTypeExpr(); - _ = p.eatToken(.keyword_else) orelse { - if (cont_expr == 0) { - return p.addNode(.{ - .tag = .while_simple, - .main_token = while_token, - .data = .{ - .lhs = condition, - .rhs = then_expr, - }, - }); - } else { - return p.addNode(.{ - .tag = .while_cont, - .main_token = while_token, - .data = .{ - .lhs = condition, - .rhs = try p.addExtra(Node.WhileCont{ - .cont_expr = cont_expr, - .then_expr = then_expr, - }), - }, - }); - } - }; - _ = try p.parsePayload(); - const else_expr = try p.expectTypeExpr(); - return p.addNode(.{ - .tag = .@"while", - .main_token = while_token, - .data = .{ - .lhs = condition, - .rhs = try p.addExtra(Node.While{ - .cont_expr = cont_expr, - .then_expr = then_expr, - .else_expr = else_expr, - }), - }, - }); - } - - /// SwitchExpr <- KEYWORD_switch LPAREN Expr RPAREN LBRACE SwitchProngList RBRACE - fn expectSwitchExpr(p: *Parser) !Node.Index { - const switch_token = p.assertToken(.keyword_switch); - _ = try p.expectToken(.l_paren); - const expr_node = try p.expectExpr(); - _ = try p.expectToken(.r_paren); - _ = try p.expectToken(.l_brace); - const cases = try p.parseSwitchProngList(); - const trailing_comma = p.token_tags[p.tok_i - 1] == .comma; - _ = try p.expectToken(.r_brace); - - return p.addNode(.{ - .tag = if (trailing_comma) .switch_comma else .@"switch", - .main_token = switch_token, - .data = .{ - .lhs = expr_node, - .rhs = try p.addExtra(Node.SubRange{ - .start = cases.start, - .end = cases.end, - }), - }, - }); - } - - /// AsmExpr <- KEYWORD_asm KEYWORD_volatile? LPAREN Expr AsmOutput? RPAREN - /// - /// AsmOutput <- COLON AsmOutputList AsmInput? - /// - /// AsmInput <- COLON AsmInputList AsmClobbers? - /// - /// AsmClobbers <- COLON StringList - /// - /// StringList <- (STRINGLITERAL COMMA)* STRINGLITERAL? - /// - /// AsmOutputList <- (AsmOutputItem COMMA)* AsmOutputItem? - /// - /// AsmInputList <- (AsmInputItem COMMA)* AsmInputItem? - fn expectAsmExpr(p: *Parser) !Node.Index { - const asm_token = p.assertToken(.keyword_asm); - _ = p.eatToken(.keyword_volatile); - _ = try p.expectToken(.l_paren); - const template = try p.expectExpr(); - - if (p.eatToken(.r_paren)) |rparen| { - return p.addNode(.{ - .tag = .asm_simple, - .main_token = asm_token, - .data = .{ - .lhs = template, - .rhs = rparen, - }, - }); - } - - _ = try p.expectToken(.colon); - - const scratch_top = p.scratch.items.len; - defer p.scratch.shrinkRetainingCapacity(scratch_top); - - while (true) { - const output_item = try p.parseAsmOutputItem(); - if (output_item == 0) break; - try p.scratch.append(p.gpa, output_item); - switch (p.token_tags[p.tok_i]) { - .comma => p.tok_i += 1, - // All possible delimiters. - .colon, .r_paren, .r_brace, .r_bracket => break, - // Likely just a missing comma; give error but continue parsing. - else => try p.warnExpected(.comma), - } - } - if (p.eatToken(.colon)) |_| { - while (true) { - const input_item = try p.parseAsmInputItem(); - if (input_item == 0) break; - try p.scratch.append(p.gpa, input_item); - switch (p.token_tags[p.tok_i]) { - .comma => p.tok_i += 1, - // All possible delimiters. - .colon, .r_paren, .r_brace, .r_bracket => break, - // Likely just a missing comma; give error but continue parsing. - else => try p.warnExpected(.comma), - } - } - if (p.eatToken(.colon)) |_| { - while (p.eatToken(.string_literal)) |_| { - switch (p.token_tags[p.tok_i]) { - .comma => p.tok_i += 1, - .colon, .r_paren, .r_brace, .r_bracket => break, - // Likely just a missing comma; give error but continue parsing. - else => try p.warnExpected(.comma), - } - } - } - } - const rparen = try p.expectToken(.r_paren); - const span = try p.listToSpan(p.scratch.items[scratch_top..]); - return p.addNode(.{ - .tag = .@"asm", - .main_token = asm_token, - .data = .{ - .lhs = template, - .rhs = try p.addExtra(Node.Asm{ - .items_start = span.start, - .items_end = span.end, - .rparen = rparen, - }), - }, - }); - } - - /// AsmOutputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN (MINUSRARROW TypeExpr / IDENTIFIER) RPAREN - fn parseAsmOutputItem(p: *Parser) !Node.Index { - _ = p.eatToken(.l_bracket) orelse return null_node; - const identifier = try p.expectToken(.identifier); - _ = try p.expectToken(.r_bracket); - _ = try p.expectToken(.string_literal); - _ = try p.expectToken(.l_paren); - const type_expr: Node.Index = blk: { - if (p.eatToken(.arrow)) |_| { - break :blk try p.expectTypeExpr(); - } else { - _ = try p.expectToken(.identifier); - break :blk null_node; - } - }; - const rparen = try p.expectToken(.r_paren); - return p.addNode(.{ - .tag = .asm_output, - .main_token = identifier, - .data = .{ - .lhs = type_expr, - .rhs = rparen, - }, - }); - } - - /// AsmInputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN Expr RPAREN - fn parseAsmInputItem(p: *Parser) !Node.Index { - _ = p.eatToken(.l_bracket) orelse return null_node; - const identifier = try p.expectToken(.identifier); - _ = try p.expectToken(.r_bracket); - _ = try p.expectToken(.string_literal); - _ = try p.expectToken(.l_paren); - const expr = try p.expectExpr(); - const rparen = try p.expectToken(.r_paren); - return p.addNode(.{ - .tag = .asm_input, - .main_token = identifier, - .data = .{ - .lhs = expr, - .rhs = rparen, - }, - }); - } - - /// BreakLabel <- COLON IDENTIFIER - fn parseBreakLabel(p: *Parser) !TokenIndex { - _ = p.eatToken(.colon) orelse return @as(TokenIndex, 0); - return p.expectToken(.identifier); - } - - /// BlockLabel <- IDENTIFIER COLON - fn parseBlockLabel(p: *Parser) TokenIndex { - if (p.token_tags[p.tok_i] == .identifier and - p.token_tags[p.tok_i + 1] == .colon) - { - const identifier = p.tok_i; - p.tok_i += 2; - return identifier; - } - return null_node; - } - - /// FieldInit <- DOT IDENTIFIER EQUAL Expr - fn parseFieldInit(p: *Parser) !Node.Index { - if (p.token_tags[p.tok_i + 0] == .period and - p.token_tags[p.tok_i + 1] == .identifier and - p.token_tags[p.tok_i + 2] == .equal) - { - p.tok_i += 3; - return p.expectExpr(); - } else { - return null_node; - } - } - - fn expectFieldInit(p: *Parser) !Node.Index { - if (p.token_tags[p.tok_i] != .period or - p.token_tags[p.tok_i + 1] != .identifier or - p.token_tags[p.tok_i + 2] != .equal) - return p.fail(.expected_initializer); - - p.tok_i += 3; - return p.expectExpr(); - } - - /// WhileContinueExpr <- COLON LPAREN AssignExpr RPAREN - fn parseWhileContinueExpr(p: *Parser) !Node.Index { - _ = p.eatToken(.colon) orelse { - if (p.token_tags[p.tok_i] == .l_paren and - p.tokensOnSameLine(p.tok_i - 1, p.tok_i)) - return p.fail(.expected_continue_expr); - return null_node; - }; - _ = try p.expectToken(.l_paren); - const node = try p.parseAssignExpr(); - if (node == 0) return p.fail(.expected_expr_or_assignment); - _ = try p.expectToken(.r_paren); - return node; - } - - /// LinkSection <- KEYWORD_linksection LPAREN Expr RPAREN - fn parseLinkSection(p: *Parser) !Node.Index { - _ = p.eatToken(.keyword_linksection) orelse return null_node; - _ = try p.expectToken(.l_paren); - const expr_node = try p.expectExpr(); - _ = try p.expectToken(.r_paren); - return expr_node; - } - - /// CallConv <- KEYWORD_callconv LPAREN Expr RPAREN - fn parseCallconv(p: *Parser) !Node.Index { - _ = p.eatToken(.keyword_callconv) orelse return null_node; - _ = try p.expectToken(.l_paren); - const expr_node = try p.expectExpr(); - _ = try p.expectToken(.r_paren); - return expr_node; - } - - /// AddrSpace <- KEYWORD_addrspace LPAREN Expr RPAREN - fn parseAddrSpace(p: *Parser) !Node.Index { - _ = p.eatToken(.keyword_addrspace) orelse return null_node; - _ = try p.expectToken(.l_paren); - const expr_node = try p.expectExpr(); - _ = try p.expectToken(.r_paren); - return expr_node; - } - - /// This function can return null nodes and then still return nodes afterwards, - /// such as in the case of anytype and `...`. Caller must look for rparen to find - /// out when there are no more param decls left. - /// - /// ParamDecl - /// <- doc_comment? (KEYWORD_noalias / KEYWORD_comptime)? (IDENTIFIER COLON)? ParamType - /// / DOT3 - /// - /// ParamType - /// <- KEYWORD_anytype - /// / TypeExpr - fn expectParamDecl(p: *Parser) !Node.Index { - _ = try p.eatDocComments(); - switch (p.token_tags[p.tok_i]) { - .keyword_noalias, .keyword_comptime => p.tok_i += 1, - .ellipsis3 => { - p.tok_i += 1; - return null_node; - }, - else => {}, - } - if (p.token_tags[p.tok_i] == .identifier and - p.token_tags[p.tok_i + 1] == .colon) - { - p.tok_i += 2; - } - switch (p.token_tags[p.tok_i]) { - .keyword_anytype => { - p.tok_i += 1; - return null_node; - }, - else => return p.expectTypeExpr(), - } - } - - /// Payload <- PIPE IDENTIFIER PIPE - fn parsePayload(p: *Parser) !TokenIndex { - _ = p.eatToken(.pipe) orelse return @as(TokenIndex, 0); - const identifier = try p.expectToken(.identifier); - _ = try p.expectToken(.pipe); - return identifier; - } - - /// PtrPayload <- PIPE ASTERISK? IDENTIFIER PIPE - fn parsePtrPayload(p: *Parser) !TokenIndex { - _ = p.eatToken(.pipe) orelse return @as(TokenIndex, 0); - _ = p.eatToken(.asterisk); - const identifier = try p.expectToken(.identifier); - _ = try p.expectToken(.pipe); - return identifier; - } - - /// Returns the first identifier token, if any. - /// - /// PtrIndexPayload <- PIPE ASTERISK? IDENTIFIER (COMMA IDENTIFIER)? PIPE - fn parsePtrIndexPayload(p: *Parser) !TokenIndex { - _ = p.eatToken(.pipe) orelse return @as(TokenIndex, 0); - _ = p.eatToken(.asterisk); - const identifier = try p.expectToken(.identifier); - if (p.eatToken(.comma) != null) { - _ = try p.expectToken(.identifier); - } - _ = try p.expectToken(.pipe); - return identifier; - } - - /// SwitchProng <- KEYWORD_inline? SwitchCase EQUALRARROW PtrIndexPayload? AssignExpr - /// - /// SwitchCase - /// <- SwitchItem (COMMA SwitchItem)* COMMA? - /// / KEYWORD_else - fn parseSwitchProng(p: *Parser) !Node.Index { - const scratch_top = p.scratch.items.len; - defer p.scratch.shrinkRetainingCapacity(scratch_top); - - const is_inline = p.eatToken(.keyword_inline) != null; - - if (p.eatToken(.keyword_else) == null) { - while (true) { - const item = try p.parseSwitchItem(); - if (item == 0) break; - try p.scratch.append(p.gpa, item); - if (p.eatToken(.comma) == null) break; - } - if (scratch_top == p.scratch.items.len) { - if (is_inline) p.tok_i -= 1; - return null_node; - } - } - const arrow_token = try p.expectToken(.equal_angle_bracket_right); - _ = try p.parsePtrIndexPayload(); - - const items = p.scratch.items[scratch_top..]; - switch (items.len) { - 0 => return p.addNode(.{ - .tag = if (is_inline) .switch_case_inline_one else .switch_case_one, - .main_token = arrow_token, - .data = .{ - .lhs = 0, - .rhs = try p.expectAssignExpr(), - }, - }), - 1 => return p.addNode(.{ - .tag = if (is_inline) .switch_case_inline_one else .switch_case_one, - .main_token = arrow_token, - .data = .{ - .lhs = items[0], - .rhs = try p.expectAssignExpr(), - }, - }), - else => return p.addNode(.{ - .tag = if (is_inline) .switch_case_inline else .switch_case, - .main_token = arrow_token, - .data = .{ - .lhs = try p.addExtra(try p.listToSpan(items)), - .rhs = try p.expectAssignExpr(), - }, - }), - } - } - - /// SwitchItem <- Expr (DOT3 Expr)? - fn parseSwitchItem(p: *Parser) !Node.Index { - const expr = try p.parseExpr(); - if (expr == 0) return null_node; - - if (p.eatToken(.ellipsis3)) |token| { - return p.addNode(.{ - .tag = .switch_range, - .main_token = token, - .data = .{ - .lhs = expr, - .rhs = try p.expectExpr(), - }, - }); - } - return expr; - } - - const PtrModifiers = struct { - align_node: Node.Index, - addrspace_node: Node.Index, - bit_range_start: Node.Index, - bit_range_end: Node.Index, - }; - - fn parsePtrModifiers(p: *Parser) !PtrModifiers { - var result: PtrModifiers = .{ - .align_node = 0, - .addrspace_node = 0, - .bit_range_start = 0, - .bit_range_end = 0, - }; - var saw_const = false; - var saw_volatile = false; - var saw_allowzero = false; - var saw_addrspace = false; - while (true) { - switch (p.token_tags[p.tok_i]) { - .keyword_align => { - if (result.align_node != 0) { - try p.warn(.extra_align_qualifier); - } - p.tok_i += 1; - _ = try p.expectToken(.l_paren); - result.align_node = try p.expectExpr(); - - if (p.eatToken(.colon)) |_| { - result.bit_range_start = try p.expectExpr(); - _ = try p.expectToken(.colon); - result.bit_range_end = try p.expectExpr(); - } - - _ = try p.expectToken(.r_paren); - }, - .keyword_const => { - if (saw_const) { - try p.warn(.extra_const_qualifier); - } - p.tok_i += 1; - saw_const = true; - }, - .keyword_volatile => { - if (saw_volatile) { - try p.warn(.extra_volatile_qualifier); - } - p.tok_i += 1; - saw_volatile = true; - }, - .keyword_allowzero => { - if (saw_allowzero) { - try p.warn(.extra_allowzero_qualifier); - } - p.tok_i += 1; - saw_allowzero = true; - }, - .keyword_addrspace => { - if (saw_addrspace) { - try p.warn(.extra_addrspace_qualifier); - } - result.addrspace_node = try p.parseAddrSpace(); - }, - else => return result, - } - } - } - - /// SuffixOp - /// <- LBRACKET Expr (DOT2 (Expr? (COLON Expr)?)?)? RBRACKET - /// / DOT IDENTIFIER - /// / DOTASTERISK - /// / DOTQUESTIONMARK - fn parseSuffixOp(p: *Parser, lhs: Node.Index) !Node.Index { - switch (p.token_tags[p.tok_i]) { - .l_bracket => { - const lbracket = p.nextToken(); - const index_expr = try p.expectExpr(); - - if (p.eatToken(.ellipsis2)) |_| { - const end_expr = try p.parseExpr(); - if (p.eatToken(.colon)) |_| { - const sentinel = try p.expectExpr(); - _ = try p.expectToken(.r_bracket); - return p.addNode(.{ - .tag = .slice_sentinel, - .main_token = lbracket, - .data = .{ - .lhs = lhs, - .rhs = try p.addExtra(Node.SliceSentinel{ - .start = index_expr, - .end = end_expr, - .sentinel = sentinel, - }), - }, - }); - } - _ = try p.expectToken(.r_bracket); - if (end_expr == 0) { - return p.addNode(.{ - .tag = .slice_open, - .main_token = lbracket, - .data = .{ - .lhs = lhs, - .rhs = index_expr, - }, - }); - } - return p.addNode(.{ - .tag = .slice, - .main_token = lbracket, - .data = .{ - .lhs = lhs, - .rhs = try p.addExtra(Node.Slice{ - .start = index_expr, - .end = end_expr, - }), - }, - }); - } - _ = try p.expectToken(.r_bracket); - return p.addNode(.{ - .tag = .array_access, - .main_token = lbracket, - .data = .{ - .lhs = lhs, - .rhs = index_expr, - }, - }); - }, - .period_asterisk => return p.addNode(.{ - .tag = .deref, - .main_token = p.nextToken(), - .data = .{ - .lhs = lhs, - .rhs = undefined, - }, - }), - .invalid_periodasterisks => { - try p.warn(.asterisk_after_ptr_deref); - return p.addNode(.{ - .tag = .deref, - .main_token = p.nextToken(), - .data = .{ - .lhs = lhs, - .rhs = undefined, - }, - }); - }, - .period => switch (p.token_tags[p.tok_i + 1]) { - .identifier => return p.addNode(.{ - .tag = .field_access, - .main_token = p.nextToken(), - .data = .{ - .lhs = lhs, - .rhs = p.nextToken(), - }, - }), - .question_mark => return p.addNode(.{ - .tag = .unwrap_optional, - .main_token = p.nextToken(), - .data = .{ - .lhs = lhs, - .rhs = p.nextToken(), - }, - }), - .l_brace => { - // this a misplaced `.{`, handle the error somewhere else - return null_node; - }, - else => { - p.tok_i += 1; - try p.warn(.expected_suffix_op); - return null_node; - }, - }, - else => return null_node, - } - } - - /// Caller must have already verified the first token. - /// - /// ContainerDeclAuto <- ContainerDeclType LBRACE container_doc_comment? ContainerMembers RBRACE - /// - /// ContainerDeclType - /// <- KEYWORD_struct (LPAREN Expr RPAREN)? - /// / KEYWORD_opaque - /// / KEYWORD_enum (LPAREN Expr RPAREN)? - /// / KEYWORD_union (LPAREN (KEYWORD_enum (LPAREN Expr RPAREN)? / Expr) RPAREN)? - fn parseContainerDeclAuto(p: *Parser) !Node.Index { - const main_token = p.nextToken(); - const arg_expr = switch (p.token_tags[main_token]) { - .keyword_opaque => null_node, - .keyword_struct, .keyword_enum => blk: { - if (p.eatToken(.l_paren)) |_| { - const expr = try p.expectExpr(); - _ = try p.expectToken(.r_paren); - break :blk expr; - } else { - break :blk null_node; - } - }, - .keyword_union => blk: { - if (p.eatToken(.l_paren)) |_| { - if (p.eatToken(.keyword_enum)) |_| { - if (p.eatToken(.l_paren)) |_| { - const enum_tag_expr = try p.expectExpr(); - _ = try p.expectToken(.r_paren); - _ = try p.expectToken(.r_paren); - - _ = try p.expectToken(.l_brace); - const members = try p.parseContainerMembers(); - const members_span = try members.toSpan(p); - _ = try p.expectToken(.r_brace); - return p.addNode(.{ - .tag = switch (members.trailing) { - true => .tagged_union_enum_tag_trailing, - false => .tagged_union_enum_tag, - }, - .main_token = main_token, - .data = .{ - .lhs = enum_tag_expr, - .rhs = try p.addExtra(members_span), - }, - }); - } else { - _ = try p.expectToken(.r_paren); - - _ = try p.expectToken(.l_brace); - const members = try p.parseContainerMembers(); - _ = try p.expectToken(.r_brace); - if (members.len <= 2) { - return p.addNode(.{ - .tag = switch (members.trailing) { - true => .tagged_union_two_trailing, - false => .tagged_union_two, - }, - .main_token = main_token, - .data = .{ - .lhs = members.lhs, - .rhs = members.rhs, - }, - }); - } else { - const span = try members.toSpan(p); - return p.addNode(.{ - .tag = switch (members.trailing) { - true => .tagged_union_trailing, - false => .tagged_union, - }, - .main_token = main_token, - .data = .{ - .lhs = span.start, - .rhs = span.end, - }, - }); - } - } - } else { - const expr = try p.expectExpr(); - _ = try p.expectToken(.r_paren); - break :blk expr; - } - } else { - break :blk null_node; - } - }, - else => { - p.tok_i -= 1; - return p.fail(.expected_container); - }, - }; - _ = try p.expectToken(.l_brace); - const members = try p.parseContainerMembers(); - _ = try p.expectToken(.r_brace); - if (arg_expr == 0) { - if (members.len <= 2) { - return p.addNode(.{ - .tag = switch (members.trailing) { - true => .container_decl_two_trailing, - false => .container_decl_two, - }, - .main_token = main_token, - .data = .{ - .lhs = members.lhs, - .rhs = members.rhs, - }, - }); - } else { - const span = try members.toSpan(p); - return p.addNode(.{ - .tag = switch (members.trailing) { - true => .container_decl_trailing, - false => .container_decl, - }, - .main_token = main_token, - .data = .{ - .lhs = span.start, - .rhs = span.end, - }, - }); - } - } else { - const span = try members.toSpan(p); - return p.addNode(.{ - .tag = switch (members.trailing) { - true => .container_decl_arg_trailing, - false => .container_decl_arg, - }, - .main_token = main_token, - .data = .{ - .lhs = arg_expr, - .rhs = try p.addExtra(Node.SubRange{ - .start = span.start, - .end = span.end, - }), - }, - }); - } - } - - /// Give a helpful error message for those transitioning from - /// C's 'struct Foo {};' to Zig's 'const Foo = struct {};'. - fn parseCStyleContainer(p: *Parser) Error!bool { - const main_token = p.tok_i; - switch (p.token_tags[p.tok_i]) { - .keyword_enum, .keyword_union, .keyword_struct => {}, - else => return false, - } - const identifier = p.tok_i + 1; - if (p.token_tags[identifier] != .identifier) return false; - p.tok_i += 2; - - try p.warnMsg(.{ - .tag = .c_style_container, - .token = identifier, - .extra = .{ .expected_tag = p.token_tags[main_token] }, - }); - try p.warnMsg(.{ - .tag = .zig_style_container, - .is_note = true, - .token = identifier, - .extra = .{ .expected_tag = p.token_tags[main_token] }, - }); - - _ = try p.expectToken(.l_brace); - _ = try p.parseContainerMembers(); - _ = try p.expectToken(.r_brace); - try p.expectSemicolon(.expected_semi_after_decl, true); - return true; - } - - /// Holds temporary data until we are ready to construct the full ContainerDecl AST node. - /// - /// ByteAlign <- KEYWORD_align LPAREN Expr RPAREN - fn parseByteAlign(p: *Parser) !Node.Index { - _ = p.eatToken(.keyword_align) orelse return null_node; - _ = try p.expectToken(.l_paren); - const expr = try p.expectExpr(); - _ = try p.expectToken(.r_paren); - return expr; - } - - /// SwitchProngList <- (SwitchProng COMMA)* SwitchProng? - fn parseSwitchProngList(p: *Parser) !Node.SubRange { - const scratch_top = p.scratch.items.len; - defer p.scratch.shrinkRetainingCapacity(scratch_top); - - while (true) { - const item = try parseSwitchProng(p); - if (item == 0) break; - - try p.scratch.append(p.gpa, item); - - switch (p.token_tags[p.tok_i]) { - .comma => p.tok_i += 1, - // All possible delimiters. - .colon, .r_paren, .r_brace, .r_bracket => break, - // Likely just a missing comma; give error but continue parsing. - else => try p.warn(.expected_comma_after_switch_prong), - } - } - return p.listToSpan(p.scratch.items[scratch_top..]); - } - - /// ParamDeclList <- (ParamDecl COMMA)* ParamDecl? - fn parseParamDeclList(p: *Parser) !SmallSpan { - _ = try p.expectToken(.l_paren); - const scratch_top = p.scratch.items.len; - defer p.scratch.shrinkRetainingCapacity(scratch_top); - var varargs: union(enum) { none, seen, nonfinal: TokenIndex } = .none; - while (true) { - if (p.eatToken(.r_paren)) |_| break; - if (varargs == .seen) varargs = .{ .nonfinal = p.tok_i }; - const param = try p.expectParamDecl(); - if (param != 0) { - try p.scratch.append(p.gpa, param); - } else if (p.token_tags[p.tok_i - 1] == .ellipsis3) { - if (varargs == .none) varargs = .seen; - } - switch (p.token_tags[p.tok_i]) { - .comma => p.tok_i += 1, - .r_paren => { - p.tok_i += 1; - break; - }, - .colon, .r_brace, .r_bracket => return p.failExpected(.r_paren), - // Likely just a missing comma; give error but continue parsing. - else => try p.warn(.expected_comma_after_param), - } - } - if (varargs == .nonfinal) { - try p.warnMsg(.{ .tag = .varargs_nonfinal, .token = varargs.nonfinal }); - } - const params = p.scratch.items[scratch_top..]; - return switch (params.len) { - 0 => SmallSpan{ .zero_or_one = 0 }, - 1 => SmallSpan{ .zero_or_one = params[0] }, - else => SmallSpan{ .multi = try p.listToSpan(params) }, - }; - } - - /// FnCallArguments <- LPAREN ExprList RPAREN - /// - /// ExprList <- (Expr COMMA)* Expr? - fn parseBuiltinCall(p: *Parser) !Node.Index { - const builtin_token = p.assertToken(.builtin); - if (p.token_tags[p.nextToken()] != .l_paren) { - p.tok_i -= 1; - try p.warn(.expected_param_list); - // Pretend this was an identifier so we can continue parsing. - return p.addNode(.{ - .tag = .identifier, - .main_token = builtin_token, - .data = .{ - .lhs = undefined, - .rhs = undefined, - }, - }); - } - const scratch_top = p.scratch.items.len; - defer p.scratch.shrinkRetainingCapacity(scratch_top); - while (true) { - if (p.eatToken(.r_paren)) |_| break; - const param = try p.expectExpr(); - try p.scratch.append(p.gpa, param); - switch (p.token_tags[p.tok_i]) { - .comma => p.tok_i += 1, - .r_paren => { - p.tok_i += 1; - break; - }, - // Likely just a missing comma; give error but continue parsing. - else => try p.warn(.expected_comma_after_arg), - } - } - const comma = (p.token_tags[p.tok_i - 2] == .comma); - const params = p.scratch.items[scratch_top..]; - switch (params.len) { - 0 => return p.addNode(.{ - .tag = .builtin_call_two, - .main_token = builtin_token, - .data = .{ - .lhs = 0, - .rhs = 0, - }, - }), - 1 => return p.addNode(.{ - .tag = if (comma) .builtin_call_two_comma else .builtin_call_two, - .main_token = builtin_token, - .data = .{ - .lhs = params[0], - .rhs = 0, - }, - }), - 2 => return p.addNode(.{ - .tag = if (comma) .builtin_call_two_comma else .builtin_call_two, - .main_token = builtin_token, - .data = .{ - .lhs = params[0], - .rhs = params[1], - }, - }), - else => { - const span = try p.listToSpan(params); - return p.addNode(.{ - .tag = if (comma) .builtin_call_comma else .builtin_call, - .main_token = builtin_token, - .data = .{ - .lhs = span.start, - .rhs = span.end, - }, - }); - }, - } - } - - /// IfPrefix <- KEYWORD_if LPAREN Expr RPAREN PtrPayload? - fn parseIf(p: *Parser, comptime bodyParseFn: fn (p: *Parser) Error!Node.Index) !Node.Index { - const if_token = p.eatToken(.keyword_if) orelse return null_node; - _ = try p.expectToken(.l_paren); - const condition = try p.expectExpr(); - _ = try p.expectToken(.r_paren); - _ = try p.parsePtrPayload(); - - const then_expr = try bodyParseFn(p); - assert(then_expr != 0); - - _ = p.eatToken(.keyword_else) orelse return p.addNode(.{ - .tag = .if_simple, - .main_token = if_token, - .data = .{ - .lhs = condition, - .rhs = then_expr, - }, - }); - _ = try p.parsePayload(); - const else_expr = try bodyParseFn(p); - assert(then_expr != 0); - - return p.addNode(.{ - .tag = .@"if", - .main_token = if_token, - .data = .{ - .lhs = condition, - .rhs = try p.addExtra(Node.If{ - .then_expr = then_expr, - .else_expr = else_expr, - }), - }, - }); - } - - /// Skips over doc comment tokens. Returns the first one, if any. - fn eatDocComments(p: *Parser) !?TokenIndex { - if (p.eatToken(.doc_comment)) |tok| { - var first_line = tok; - if (tok > 0 and tokensOnSameLine(p, tok - 1, tok)) { - try p.warnMsg(.{ - .tag = .same_line_doc_comment, - .token = tok, - }); - first_line = p.eatToken(.doc_comment) orelse return null; - } - while (p.eatToken(.doc_comment)) |_| {} - return first_line; - } - return null; - } - - fn tokensOnSameLine(p: *Parser, token1: TokenIndex, token2: TokenIndex) bool { - return std.mem.indexOfScalar(u8, p.source[p.token_starts[token1]..p.token_starts[token2]], '\n') == null; - } - - fn eatToken(p: *Parser, tag: Token.Tag) ?TokenIndex { - return if (p.token_tags[p.tok_i] == tag) p.nextToken() else null; - } - - fn assertToken(p: *Parser, tag: Token.Tag) TokenIndex { - const token = p.nextToken(); - assert(p.token_tags[token] == tag); - return token; - } - - fn expectToken(p: *Parser, tag: Token.Tag) Error!TokenIndex { - if (p.token_tags[p.tok_i] != tag) { - return p.failMsg(.{ - .tag = .expected_token, - .token = p.tok_i, - .extra = .{ .expected_tag = tag }, - }); - } - return p.nextToken(); - } - - fn expectSemicolon(p: *Parser, error_tag: AstError.Tag, recoverable: bool) Error!void { - if (p.token_tags[p.tok_i] == .semicolon) { - _ = p.nextToken(); - return; - } - try p.warn(error_tag); - if (!recoverable) return error.ParseError; - } - - fn nextToken(p: *Parser) TokenIndex { - const result = p.tok_i; - p.tok_i += 1; - return result; - } -}; - -test { - _ = @import("parser_test.zig"); -} diff --git a/lib/std/zig/parser_test.zig b/lib/std/zig/parser_test.zig index 49b0715695502a6cf50314504a03fa7f9b2c593a..3c44322ccc7f8d47472fe711a265d0af9f9c04b0 100644 --- a/lib/std/zig/parser_test.zig +++ b/lib/std/zig/parser_test.zig @@ -6073,7 +6073,7 @@ var fixed_buffer_mem: [100 * 1024]u8 = undefined; fn testParse(source: [:0]const u8, allocator: mem.Allocator, anything_changed: *bool) ![]u8 { const stderr = io.getStdErr().writer(); - var tree = try std.zig.parse(allocator, source); + var tree = try std.zig.Ast.parse(allocator, source, .zig); defer tree.deinit(allocator); for (tree.errors) |parse_error| { @@ -6124,7 +6124,7 @@ fn testCanonical(source: [:0]const u8) !void { const Error = std.zig.Ast.Error.Tag; fn testError(source: [:0]const u8, expected_errors: []const Error) !void { - var tree = try std.zig.parse(std.testing.allocator, source); + var tree = try std.zig.Ast.parse(std.testing.allocator, source, .zig); defer tree.deinit(std.testing.allocator); std.testing.expectEqual(expected_errors.len, tree.errors.len) catch |err| { diff --git a/lib/std/zig/perf_test.zig b/lib/std/zig/perf_test.zig index d3fc90eaeaaef76b980a6dfc768f55a979a469c7..58f7a67694ad802d35ce184a6fac3fa4026fdffd 100644 --- a/lib/std/zig/perf_test.zig +++ b/lib/std/zig/perf_test.zig @@ -1,7 +1,6 @@ const std = @import("std"); const mem = std.mem; const Tokenizer = std.zig.Tokenizer; -const Parser = std.zig.Parser; const io = std.io; const fmtIntSizeBin = std.fmt.fmtIntSizeBin; @@ -34,6 +33,6 @@ pub fn main() !void { fn testOnce() usize { var fixed_buf_alloc = std.heap.FixedBufferAllocator.init(fixed_buffer_mem[0..]); var allocator = fixed_buf_alloc.allocator(); - _ = std.zig.parse(allocator, source) catch @panic("parse failure"); + _ = std.zig.Ast.parse(allocator, source, .zig) catch @panic("parse failure"); return fixed_buf_alloc.end_index; } diff --git a/src/Module.zig b/src/Module.zig index b395c0a9502392a562405223fd972d88b38cf4c3..3bb15e78c336a2cc00ffeff42c382d21385c319e 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -2057,7 +2057,7 @@ pub const File = struct { if (file.tree_loaded) return &file.tree; const source = try file.getSource(gpa); - file.tree = try std.zig.parse(gpa, source.bytes); + file.tree = try Ast.parse(gpa, source.bytes, .zig); file.tree_loaded = true; return &file.tree; } @@ -3662,7 +3662,7 @@ pub fn astGenFile(mod: *Module, file: *File) !void { file.source = source; file.source_loaded = true; - file.tree = try std.zig.parse(gpa, source); + file.tree = try Ast.parse(gpa, source, .zig); defer if (!file.tree_loaded) file.tree.deinit(gpa); if (file.tree.errors.len != 0) { @@ -3977,7 +3977,7 @@ pub fn populateBuiltinFile(mod: *Module) !void { else => |e| return e, } - file.tree = try std.zig.parse(gpa, file.source); + file.tree = try Ast.parse(gpa, file.source, .zig); file.tree_loaded = true; assert(file.tree.errors.len == 0); // builtin.zig must parse diff --git a/src/main.zig b/src/main.zig index 72e7e094e63fe7c2fda7f10d644d01517039c88a..06c36bad87865cbc29839351075275578cf3191d 100644 --- a/src/main.zig +++ b/src/main.zig @@ -4361,7 +4361,7 @@ pub fn cmdFmt(gpa: Allocator, arena: Allocator, args: []const []const u8) !void }; defer gpa.free(source_code); - var tree = std.zig.parse(gpa, source_code) catch |err| { + var tree = Ast.parse(gpa, source_code, .zig) catch |err| { fatal("error parsing stdin: {}", .{err}); }; defer tree.deinit(gpa); @@ -4566,7 +4566,7 @@ fn fmtPathFile( // Add to set after no longer possible to get error.IsDir. if (try fmt.seen.fetchPut(stat.inode, {})) |_| return; - var tree = try std.zig.parse(fmt.gpa, source_code); + var tree = try Ast.parse(fmt.gpa, source_code, .zig); defer tree.deinit(fmt.gpa); try printErrsMsgToStdErr(fmt.gpa, fmt.arena, tree.errors, tree, file_path, fmt.color); @@ -5312,7 +5312,7 @@ pub fn cmdAstCheck( file.pkg = try Package.create(gpa, "root", null, file.sub_file_path); defer file.pkg.destroy(gpa); - file.tree = try std.zig.parse(gpa, file.source); + file.tree = try Ast.parse(gpa, file.source, .zig); file.tree_loaded = true; defer file.tree.deinit(gpa); @@ -5438,7 +5438,7 @@ pub fn cmdChangelist( file.source = source; file.source_loaded = true; - file.tree = try std.zig.parse(gpa, file.source); + file.tree = try Ast.parse(gpa, file.source, .zig); file.tree_loaded = true; defer file.tree.deinit(gpa); @@ -5476,7 +5476,7 @@ pub fn cmdChangelist( if (new_amt != new_stat.size) return error.UnexpectedEndOfFile; - var new_tree = try std.zig.parse(gpa, new_source); + var new_tree = try Ast.parse(gpa, new_source, .zig); defer new_tree.deinit(gpa); try printErrsMsgToStdErr(gpa, arena, new_tree.errors, new_tree, new_source_file, .auto); -- 2.54.0 From 81c27c74bc8ccc8087b75c5d4eb1b350ad907cd0 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 2 Feb 2023 23:45:23 -0700 Subject: [PATCH 81/84] use build.zig.zon instead of build.zig.ini for the manifest file * improve error message when build manifest file is missing * update std.zig.Ast to support ZON * Compilation.AllErrors.Message: make the notes field a const slice * move build manifest parsing logic into src/Manifest.zig and add more checks, and make the checks integrate into the standard error reporting code so that reported errors look sexy closes #14290 --- lib/std/Build.zig | 4 +- lib/std/array_hash_map.zig | 3 +- lib/std/zig/Ast.zig | 4 + lib/std/zig/Parse.zig | 13 +- src/Compilation.zig | 2 +- src/Manifest.zig | 499 +++++++++++++++++++++++++++++++++++++ src/Package.zig | 351 ++++++++++---------------- src/main.zig | 17 +- 8 files changed, 667 insertions(+), 226 deletions(-) create mode 100644 src/Manifest.zig diff --git a/lib/std/Build.zig b/lib/std/Build.zig index d695637fc336414b606425734eb12a0974f2a0e0..6846007443189c8a684bd9ba5b66b068e7da5fdd 100644 --- a/lib/std/Build.zig +++ b/lib/std/Build.zig @@ -1496,8 +1496,8 @@ pub fn dependency(b: *Build, name: []const u8, args: anytype) *Dependency { } } - const full_path = b.pathFromRoot("build.zig.ini"); - std.debug.print("no dependency named '{s}' in '{s}'\n", .{ name, full_path }); + const full_path = b.pathFromRoot("build.zig.zon"); + std.debug.print("no dependency named '{s}' in '{s}'. All packages used in build.zig must be declared in this file.\n", .{ name, full_path }); std.process.exit(1); } diff --git a/lib/std/array_hash_map.zig b/lib/std/array_hash_map.zig index cf04a54116b029c9836e40fa9cdc4f400671b77a..57821d1b51c9c1810379b5c112f2db8d1c7dbfb0 100644 --- a/lib/std/array_hash_map.zig +++ b/lib/std/array_hash_map.zig @@ -1145,7 +1145,8 @@ pub fn ArrayHashMapUnmanaged( } /// Create a copy of the hash map which can be modified separately. - /// The copy uses the same context and allocator as this instance. + /// The copy uses the same context as this instance, but is allocated + /// with the provided allocator. pub fn clone(self: Self, allocator: Allocator) !Self { if (@sizeOf(ByIndexContext) != 0) @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call cloneContext instead."); diff --git a/lib/std/zig/Ast.zig b/lib/std/zig/Ast.zig index a9a02606ebfd3992ae280ee06c20dc7e353f2770..80dda052abed49151914720f105158819c3ce4e4 100644 --- a/lib/std/zig/Ast.zig +++ b/lib/std/zig/Ast.zig @@ -1,4 +1,8 @@ //! Abstract Syntax Tree for Zig source code. +//! For Zig syntax, the root node is at nodes[0] and contains the list of +//! sub-nodes. +//! For Zon syntax, the root node is at nodes[0] and contains lhs as the node +//! index of the main expression. /// Reference to externally-owned data. source: [:0]const u8, diff --git a/lib/std/zig/Parse.zig b/lib/std/zig/Parse.zig index f599a08f55259efb914a069e6d27c1741698a268..d498366b34de82c010796a037a55643e2050732d 100644 --- a/lib/std/zig/Parse.zig +++ b/lib/std/zig/Parse.zig @@ -181,17 +181,26 @@ pub fn parseRoot(p: *Parse) !void { /// TODO: set a flag in Parse struct, and honor that flag /// by emitting compilation errors when non-zon nodes are encountered. pub fn parseZon(p: *Parse) !void { - const node_index = p.parseExpr() catch |err| switch (err) { + // We must use index 0 so that 0 can be used as null elsewhere. + p.nodes.appendAssumeCapacity(.{ + .tag = .root, + .main_token = 0, + .data = undefined, + }); + const node_index = p.expectExpr() catch |err| switch (err) { error.ParseError => { assert(p.errors.items.len > 0); return; }, else => |e| return e, }; - assert(node_index == 0); if (p.token_tags[p.tok_i] != .eof) { try p.warnExpected(.eof); } + p.nodes.items(.data)[0] = .{ + .lhs = node_index, + .rhs = undefined, + }; } /// ContainerMembers <- ContainerDeclarations (ContainerField COMMA)* (ContainerField / ContainerDeclarations) diff --git a/src/Compilation.zig b/src/Compilation.zig index 7d42d3b610f2a5b8efc02d1b2f0dfc239c3be62a..e09b8f18abe0652043301349ece259daec0c6241 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -385,7 +385,7 @@ pub const AllErrors = struct { count: u32 = 1, /// Does not include the trailing newline. source_line: ?[]const u8, - notes: []Message = &.{}, + notes: []const Message = &.{}, reference_trace: []Message = &.{}, /// Splits the error message up into lines to properly indent them diff --git a/src/Manifest.zig b/src/Manifest.zig new file mode 100644 index 0000000000000000000000000000000000000000..c3f77aec98dd1ba28c80f6e87ecc40ba78f14836 --- /dev/null +++ b/src/Manifest.zig @@ -0,0 +1,499 @@ +pub const basename = "build.zig.zon"; +pub const Hash = std.crypto.hash.sha2.Sha256; + +pub const Dependency = struct { + url: []const u8, + url_tok: Ast.TokenIndex, + hash: ?[]const u8, + hash_tok: Ast.TokenIndex, +}; + +pub const ErrorMessage = struct { + msg: []const u8, + tok: Ast.TokenIndex, + off: u32, +}; + +pub const MultihashFunction = enum(u16) { + identity = 0x00, + sha1 = 0x11, + @"sha2-256" = 0x12, + @"sha2-512" = 0x13, + @"sha3-512" = 0x14, + @"sha3-384" = 0x15, + @"sha3-256" = 0x16, + @"sha3-224" = 0x17, + @"sha2-384" = 0x20, + @"sha2-256-trunc254-padded" = 0x1012, + @"sha2-224" = 0x1013, + @"sha2-512-224" = 0x1014, + @"sha2-512-256" = 0x1015, + @"blake2b-256" = 0xb220, + _, +}; + +pub const multihash_function: MultihashFunction = switch (Hash) { + std.crypto.hash.sha2.Sha256 => .@"sha2-256", + else => @compileError("unreachable"), +}; +comptime { + // We avoid unnecessary uleb128 code in hexDigest by asserting here the + // values are small enough to be contained in the one-byte encoding. + assert(@enumToInt(multihash_function) < 127); + assert(Hash.digest_length < 127); +} +pub const multihash_len = 1 + 1 + Hash.digest_length; + +name: []const u8, +version: std.SemanticVersion, +dependencies: std.StringArrayHashMapUnmanaged(Dependency), + +errors: []ErrorMessage, +arena_state: std.heap.ArenaAllocator.State, + +pub const Error = Allocator.Error; + +pub fn parse(gpa: Allocator, ast: std.zig.Ast) Error!Manifest { + const node_tags = ast.nodes.items(.tag); + const node_datas = ast.nodes.items(.data); + assert(node_tags[0] == .root); + const main_node_index = node_datas[0].lhs; + + var arena_instance = std.heap.ArenaAllocator.init(gpa); + errdefer arena_instance.deinit(); + + var p: Parse = .{ + .gpa = gpa, + .ast = ast, + .arena = arena_instance.allocator(), + .errors = .{}, + + .name = undefined, + .version = undefined, + .dependencies = .{}, + .buf = .{}, + }; + defer p.buf.deinit(gpa); + defer p.errors.deinit(gpa); + defer p.dependencies.deinit(gpa); + + p.parseRoot(main_node_index) catch |err| switch (err) { + error.ParseFailure => assert(p.errors.items.len > 0), + else => |e| return e, + }; + + return .{ + .name = p.name, + .version = p.version, + .dependencies = try p.dependencies.clone(p.arena), + .errors = try p.arena.dupe(ErrorMessage, p.errors.items), + .arena_state = arena_instance.state, + }; +} + +pub fn deinit(man: *Manifest, gpa: Allocator) void { + man.arena_state.promote(gpa).deinit(); + man.* = undefined; +} + +const hex_charset = "0123456789abcdef"; + +pub fn hex64(x: u64) [16]u8 { + var result: [16]u8 = undefined; + var i: usize = 0; + while (i < 8) : (i += 1) { + const byte = @truncate(u8, x >> @intCast(u6, 8 * i)); + result[i * 2 + 0] = hex_charset[byte >> 4]; + result[i * 2 + 1] = hex_charset[byte & 15]; + } + return result; +} + +test hex64 { + const s = "[" ++ hex64(0x12345678_abcdef00) ++ "]"; + try std.testing.expectEqualStrings("[00efcdab78563412]", s); +} + +pub fn hexDigest(digest: [Hash.digest_length]u8) [multihash_len * 2]u8 { + var result: [multihash_len * 2]u8 = undefined; + + result[0] = hex_charset[@enumToInt(multihash_function) >> 4]; + result[1] = hex_charset[@enumToInt(multihash_function) & 15]; + + result[2] = hex_charset[Hash.digest_length >> 4]; + result[3] = hex_charset[Hash.digest_length & 15]; + + for (digest) |byte, i| { + result[4 + i * 2] = hex_charset[byte >> 4]; + result[5 + i * 2] = hex_charset[byte & 15]; + } + return result; +} + +const Parse = struct { + gpa: Allocator, + ast: std.zig.Ast, + arena: Allocator, + buf: std.ArrayListUnmanaged(u8), + errors: std.ArrayListUnmanaged(ErrorMessage), + + name: []const u8, + version: std.SemanticVersion, + dependencies: std.StringArrayHashMapUnmanaged(Dependency), + + const InnerError = error{ ParseFailure, OutOfMemory }; + + fn parseRoot(p: *Parse, node: Ast.Node.Index) !void { + const ast = p.ast; + const main_tokens = ast.nodes.items(.main_token); + const main_token = main_tokens[node]; + + var buf: [2]Ast.Node.Index = undefined; + const struct_init = ast.fullStructInit(&buf, node) orelse { + return fail(p, main_token, "expected top level expression to be a struct", .{}); + }; + + var have_name = false; + var have_version = false; + + for (struct_init.ast.fields) |field_init| { + const name_token = ast.firstToken(field_init) - 2; + const field_name = try identifierTokenString(p, name_token); + // We could get fancy with reflection and comptime logic here but doing + // things manually provides an opportunity to do any additional verification + // that is desirable on a per-field basis. + if (mem.eql(u8, field_name, "dependencies")) { + try parseDependencies(p, field_init); + } else if (mem.eql(u8, field_name, "name")) { + p.name = try parseString(p, field_init); + have_name = true; + } else if (mem.eql(u8, field_name, "version")) { + const version_text = try parseString(p, field_init); + p.version = std.SemanticVersion.parse(version_text) catch |err| v: { + try appendError(p, main_tokens[field_init], "unable to parse semantic version: {s}", .{@errorName(err)}); + break :v undefined; + }; + have_version = true; + } else { + // Ignore unknown fields so that we can add fields in future zig + // versions without breaking older zig versions. + } + } + + if (!have_name) { + try appendError(p, main_token, "missing top-level 'name' field", .{}); + } + + if (!have_version) { + try appendError(p, main_token, "missing top-level 'version' field", .{}); + } + } + + fn parseDependencies(p: *Parse, node: Ast.Node.Index) !void { + const ast = p.ast; + const main_tokens = ast.nodes.items(.main_token); + + var buf: [2]Ast.Node.Index = undefined; + const struct_init = ast.fullStructInit(&buf, node) orelse { + const tok = main_tokens[node]; + return fail(p, tok, "expected dependencies expression to be a struct", .{}); + }; + + for (struct_init.ast.fields) |field_init| { + const name_token = ast.firstToken(field_init) - 2; + const dep_name = try identifierTokenString(p, name_token); + const dep = try parseDependency(p, field_init); + try p.dependencies.put(p.gpa, dep_name, dep); + } + } + + fn parseDependency(p: *Parse, node: Ast.Node.Index) !Dependency { + const ast = p.ast; + const main_tokens = ast.nodes.items(.main_token); + + var buf: [2]Ast.Node.Index = undefined; + const struct_init = ast.fullStructInit(&buf, node) orelse { + const tok = main_tokens[node]; + return fail(p, tok, "expected dependency expression to be a struct", .{}); + }; + + var dep: Dependency = .{ + .url = undefined, + .url_tok = undefined, + .hash = null, + .hash_tok = undefined, + }; + var have_url = false; + + for (struct_init.ast.fields) |field_init| { + const name_token = ast.firstToken(field_init) - 2; + const field_name = try identifierTokenString(p, name_token); + // We could get fancy with reflection and comptime logic here but doing + // things manually provides an opportunity to do any additional verification + // that is desirable on a per-field basis. + if (mem.eql(u8, field_name, "url")) { + dep.url = parseString(p, field_init) catch |err| switch (err) { + error.ParseFailure => continue, + else => |e| return e, + }; + dep.url_tok = main_tokens[field_init]; + have_url = true; + } else if (mem.eql(u8, field_name, "hash")) { + dep.hash = parseHash(p, field_init) catch |err| switch (err) { + error.ParseFailure => continue, + else => |e| return e, + }; + dep.hash_tok = main_tokens[field_init]; + } else { + // Ignore unknown fields so that we can add fields in future zig + // versions without breaking older zig versions. + } + } + + if (!have_url) { + try appendError(p, main_tokens[node], "dependency is missing 'url' field", .{}); + } + + return dep; + } + + fn parseString(p: *Parse, node: Ast.Node.Index) ![]const u8 { + const ast = p.ast; + const node_tags = ast.nodes.items(.tag); + const main_tokens = ast.nodes.items(.main_token); + if (node_tags[node] != .string_literal) { + return fail(p, main_tokens[node], "expected string literal", .{}); + } + const str_lit_token = main_tokens[node]; + const token_bytes = ast.tokenSlice(str_lit_token); + p.buf.clearRetainingCapacity(); + try parseStrLit(p, str_lit_token, &p.buf, token_bytes, 0); + const duped = try p.arena.dupe(u8, p.buf.items); + return duped; + } + + fn parseHash(p: *Parse, node: Ast.Node.Index) ![]const u8 { + const ast = p.ast; + const main_tokens = ast.nodes.items(.main_token); + const tok = main_tokens[node]; + const h = try parseString(p, node); + + if (h.len >= 2) { + const their_multihash_func = std.fmt.parseInt(u8, h[0..2], 16) catch |err| { + return fail(p, tok, "invalid multihash value: unable to parse hash function: {s}", .{ + @errorName(err), + }); + }; + if (@intToEnum(MultihashFunction, their_multihash_func) != multihash_function) { + return fail(p, tok, "unsupported hash function: only sha2-256 is supported", .{}); + } + } + + const hex_multihash_len = 2 * Manifest.multihash_len; + if (h.len != hex_multihash_len) { + return fail(p, tok, "wrong hash size. expected: {d}, found: {d}", .{ + hex_multihash_len, h.len, + }); + } + + return h; + } + + /// TODO: try to DRY this with AstGen.identifierTokenString + fn identifierTokenString(p: *Parse, token: Ast.TokenIndex) InnerError![]const u8 { + const ast = p.ast; + const token_tags = ast.tokens.items(.tag); + assert(token_tags[token] == .identifier); + const ident_name = ast.tokenSlice(token); + if (!mem.startsWith(u8, ident_name, "@")) { + return ident_name; + } + p.buf.clearRetainingCapacity(); + try parseStrLit(p, token, &p.buf, ident_name, 1); + const duped = try p.arena.dupe(u8, p.buf.items); + return duped; + } + + /// TODO: try to DRY this with AstGen.parseStrLit + fn parseStrLit( + p: *Parse, + token: Ast.TokenIndex, + buf: *std.ArrayListUnmanaged(u8), + bytes: []const u8, + offset: u32, + ) InnerError!void { + const raw_string = bytes[offset..]; + var buf_managed = buf.toManaged(p.gpa); + const result = std.zig.string_literal.parseWrite(buf_managed.writer(), raw_string); + buf.* = buf_managed.moveToUnmanaged(); + switch (try result) { + .success => {}, + .failure => |err| try p.appendStrLitError(err, token, bytes, offset), + } + } + + /// TODO: try to DRY this with AstGen.failWithStrLitError + fn appendStrLitError( + p: *Parse, + err: std.zig.string_literal.Error, + token: Ast.TokenIndex, + bytes: []const u8, + offset: u32, + ) Allocator.Error!void { + const raw_string = bytes[offset..]; + switch (err) { + .invalid_escape_character => |bad_index| { + try p.appendErrorOff( + token, + offset + @intCast(u32, bad_index), + "invalid escape character: '{c}'", + .{raw_string[bad_index]}, + ); + }, + .expected_hex_digit => |bad_index| { + try p.appendErrorOff( + token, + offset + @intCast(u32, bad_index), + "expected hex digit, found '{c}'", + .{raw_string[bad_index]}, + ); + }, + .empty_unicode_escape_sequence => |bad_index| { + try p.appendErrorOff( + token, + offset + @intCast(u32, bad_index), + "empty unicode escape sequence", + .{}, + ); + }, + .expected_hex_digit_or_rbrace => |bad_index| { + try p.appendErrorOff( + token, + offset + @intCast(u32, bad_index), + "expected hex digit or '}}', found '{c}'", + .{raw_string[bad_index]}, + ); + }, + .invalid_unicode_codepoint => |bad_index| { + try p.appendErrorOff( + token, + offset + @intCast(u32, bad_index), + "unicode escape does not correspond to a valid codepoint", + .{}, + ); + }, + .expected_lbrace => |bad_index| { + try p.appendErrorOff( + token, + offset + @intCast(u32, bad_index), + "expected '{{', found '{c}", + .{raw_string[bad_index]}, + ); + }, + .expected_rbrace => |bad_index| { + try p.appendErrorOff( + token, + offset + @intCast(u32, bad_index), + "expected '}}', found '{c}", + .{raw_string[bad_index]}, + ); + }, + .expected_single_quote => |bad_index| { + try p.appendErrorOff( + token, + offset + @intCast(u32, bad_index), + "expected single quote ('), found '{c}", + .{raw_string[bad_index]}, + ); + }, + .invalid_character => |bad_index| { + try p.appendErrorOff( + token, + offset + @intCast(u32, bad_index), + "invalid byte in string or character literal: '{c}'", + .{raw_string[bad_index]}, + ); + }, + } + } + + fn fail( + p: *Parse, + tok: Ast.TokenIndex, + comptime fmt: []const u8, + args: anytype, + ) InnerError { + try appendError(p, tok, fmt, args); + return error.ParseFailure; + } + + fn appendError(p: *Parse, tok: Ast.TokenIndex, comptime fmt: []const u8, args: anytype) !void { + return appendErrorOff(p, tok, 0, fmt, args); + } + + fn appendErrorOff( + p: *Parse, + tok: Ast.TokenIndex, + byte_offset: u32, + comptime fmt: []const u8, + args: anytype, + ) Allocator.Error!void { + try p.errors.append(p.gpa, .{ + .msg = try std.fmt.allocPrint(p.arena, fmt, args), + .tok = tok, + .off = byte_offset, + }); + } +}; + +const Manifest = @This(); +const std = @import("std"); +const mem = std.mem; +const Allocator = std.mem.Allocator; +const assert = std.debug.assert; +const Ast = std.zig.Ast; +const testing = std.testing; + +test "basic" { + const gpa = testing.allocator; + + const example = + \\.{ + \\ .name = "foo", + \\ .version = "3.2.1", + \\ .dependencies = .{ + \\ .bar = .{ + \\ .url = "https://example.com/baz.tar.gz", + \\ .hash = "1220f1b680b6065fcfc94fe777f22e73bcb7e2767e5f4d99d4255fe76ded69c7a35f", + \\ }, + \\ }, + \\} + ; + + var ast = try std.zig.Ast.parse(gpa, example, .zon); + defer ast.deinit(gpa); + + try testing.expect(ast.errors.len == 0); + + var manifest = try Manifest.parse(gpa, ast); + defer manifest.deinit(gpa); + + try testing.expectEqualStrings("foo", manifest.name); + + try testing.expectEqual(@as(std.SemanticVersion, .{ + .major = 3, + .minor = 2, + .patch = 1, + }), manifest.version); + + try testing.expect(manifest.dependencies.count() == 1); + try testing.expectEqualStrings("bar", manifest.dependencies.keys()[0]); + try testing.expectEqualStrings( + "https://example.com/baz.tar.gz", + manifest.dependencies.values()[0].url, + ); + try testing.expectEqualStrings( + "1220f1b680b6065fcfc94fe777f22e73bcb7e2767e5f4d99d4255fe76ded69c7a35f", + manifest.dependencies.values()[0].hash orelse return error.TestFailed, + ); +} diff --git a/src/Package.zig b/src/Package.zig index 35b1ff505627803018051aef8b8351c4e299717b..401eef2121cc00b218d19d125e72fb8f9b682c34 100644 --- a/src/Package.zig +++ b/src/Package.zig @@ -6,8 +6,8 @@ const fs = std.fs; const mem = std.mem; const Allocator = mem.Allocator; const assert = std.debug.assert; -const Hash = std.crypto.hash.sha2.Sha256; const log = std.log.scoped(.package); +const main = @import("main.zig"); const Compilation = @import("Compilation.zig"); const Module = @import("Module.zig"); @@ -15,6 +15,7 @@ const ThreadPool = @import("ThreadPool.zig"); const WaitGroup = @import("WaitGroup.zig"); const Cache = @import("Cache.zig"); const build_options = @import("build_options"); +const Manifest = @import("Manifest.zig"); pub const Table = std.StringHashMapUnmanaged(*Package); @@ -141,10 +142,10 @@ pub fn addAndAdopt(parent: *Package, gpa: Allocator, child: *Package) !void { } pub const build_zig_basename = "build.zig"; -pub const ini_basename = build_zig_basename ++ ".ini"; pub fn fetchAndAddDependencies( pkg: *Package, + arena: Allocator, thread_pool: *ThreadPool, http_client: *std.http.Client, directory: Compilation.Directory, @@ -153,89 +154,77 @@ pub fn fetchAndAddDependencies( dependencies_source: *std.ArrayList(u8), build_roots_source: *std.ArrayList(u8), name_prefix: []const u8, + color: main.Color, ) !void { const max_bytes = 10 * 1024 * 1024; const gpa = thread_pool.allocator; - const build_zig_ini = directory.handle.readFileAlloc(gpa, ini_basename, max_bytes) catch |err| switch (err) { + const build_zig_zon_bytes = directory.handle.readFileAllocOptions( + arena, + Manifest.basename, + max_bytes, + null, + 1, + 0, + ) catch |err| switch (err) { error.FileNotFound => { // Handle the same as no dependencies. return; }, else => |e| return e, }; - defer gpa.free(build_zig_ini); - const ini: std.Ini = .{ .bytes = build_zig_ini }; + var ast = try std.zig.Ast.parse(gpa, build_zig_zon_bytes, .zon); + defer ast.deinit(gpa); + + if (ast.errors.len > 0) { + const file_path = try directory.join(arena, &.{Manifest.basename}); + try main.printErrsMsgToStdErr(gpa, arena, ast, file_path, color); + return error.PackageFetchFailed; + } + + var manifest = try Manifest.parse(gpa, ast); + defer manifest.deinit(gpa); + + if (manifest.errors.len > 0) { + const ttyconf: std.debug.TTY.Config = switch (color) { + .auto => std.debug.detectTTYConfig(std.io.getStdErr()), + .on => .escape_codes, + .off => .no_color, + }; + const file_path = try directory.join(arena, &.{Manifest.basename}); + for (manifest.errors) |msg| { + Report.renderErrorMessage(ast, file_path, ttyconf, msg, &.{}); + } + return error.PackageFetchFailed; + } + + const report: Report = .{ + .ast = &ast, + .directory = directory, + .color = color, + .arena = arena, + }; + var any_error = false; - var it = ini.iterateSection("\n[dependency]\n"); - while (it.next()) |dep| { - var line_it = mem.split(u8, dep, "\n"); - var opt_name: ?[]const u8 = null; - var opt_url: ?[]const u8 = null; - var expected_hash: ?[]const u8 = null; - while (line_it.next()) |kv| { - const eq_pos = mem.indexOfScalar(u8, kv, '=') orelse continue; - const key = kv[0..eq_pos]; - const value = kv[eq_pos + 1 ..]; - if (mem.eql(u8, key, "name")) { - opt_name = value; - } else if (mem.eql(u8, key, "url")) { - opt_url = value; - } else if (mem.eql(u8, key, "hash")) { - expected_hash = value; - } else { - const loc = std.zig.findLineColumn(ini.bytes, @ptrToInt(key.ptr) - @ptrToInt(ini.bytes.ptr)); - std.log.warn("{s}/{s}:{d}:{d} unrecognized key: '{s}'", .{ - directory.path orelse ".", - "build.zig.ini", - loc.line, - loc.column, - key, - }); - } - } + const deps_list = manifest.dependencies.values(); + for (manifest.dependencies.keys()) |name, i| { + const dep = deps_list[i]; - const name = opt_name orelse { - const loc = std.zig.findLineColumn(ini.bytes, @ptrToInt(dep.ptr) - @ptrToInt(ini.bytes.ptr)); - std.log.err("{s}/{s}:{d}:{d} missing key: 'name'", .{ - directory.path orelse ".", - "build.zig.ini", - loc.line, - loc.column, - }); - any_error = true; - continue; - }; - - const url = opt_url orelse { - const loc = std.zig.findLineColumn(ini.bytes, @ptrToInt(dep.ptr) - @ptrToInt(ini.bytes.ptr)); - std.log.err("{s}/{s}:{d}:{d} missing key: 'name'", .{ - directory.path orelse ".", - "build.zig.ini", - loc.line, - loc.column, - }); - any_error = true; - continue; - }; - - const sub_prefix = try std.fmt.allocPrint(gpa, "{s}{s}.", .{ name_prefix, name }); - defer gpa.free(sub_prefix); + const sub_prefix = try std.fmt.allocPrint(arena, "{s}{s}.", .{ name_prefix, name }); const fqn = sub_prefix[0 .. sub_prefix.len - 1]; const sub_pkg = try fetchAndUnpack( thread_pool, http_client, global_cache_directory, - url, - expected_hash, - ini, - directory, + dep, + report, build_roots_source, fqn, ); try pkg.fetchAndAddDependencies( + arena, thread_pool, http_client, sub_pkg.root_src_directory, @@ -244,6 +233,7 @@ pub fn fetchAndAddDependencies( dependencies_source, build_roots_source, sub_prefix, + color, ); try addAndAdopt(pkg, gpa, sub_pkg); @@ -253,7 +243,7 @@ pub fn fetchAndAddDependencies( }); } - if (any_error) return error.InvalidBuildZigIniFile; + if (any_error) return error.InvalidBuildManifestFile; } pub fn createFilePkg( @@ -264,7 +254,7 @@ pub fn createFilePkg( contents: []const u8, ) !*Package { const rand_int = std.crypto.random.int(u64); - const tmp_dir_sub_path = "tmp" ++ fs.path.sep_str ++ hex64(rand_int); + const tmp_dir_sub_path = "tmp" ++ fs.path.sep_str ++ Manifest.hex64(rand_int); { var tmp_dir = try cache_directory.handle.makeOpenPath(tmp_dir_sub_path, .{}); defer tmp_dir.close(); @@ -282,14 +272,73 @@ pub fn createFilePkg( return createWithDir(gpa, name, cache_directory, o_dir_sub_path, basename); } +const Report = struct { + ast: *const std.zig.Ast, + directory: Compilation.Directory, + color: main.Color, + arena: Allocator, + + fn fail( + report: Report, + tok: std.zig.Ast.TokenIndex, + comptime fmt_string: []const u8, + fmt_args: anytype, + ) error{ PackageFetchFailed, OutOfMemory } { + return failWithNotes(report, &.{}, tok, fmt_string, fmt_args); + } + + fn failWithNotes( + report: Report, + notes: []const Compilation.AllErrors.Message, + tok: std.zig.Ast.TokenIndex, + comptime fmt_string: []const u8, + fmt_args: anytype, + ) error{ PackageFetchFailed, OutOfMemory } { + const ttyconf: std.debug.TTY.Config = switch (report.color) { + .auto => std.debug.detectTTYConfig(std.io.getStdErr()), + .on => .escape_codes, + .off => .no_color, + }; + const file_path = try report.directory.join(report.arena, &.{Manifest.basename}); + renderErrorMessage(report.ast.*, file_path, ttyconf, .{ + .tok = tok, + .off = 0, + .msg = try std.fmt.allocPrint(report.arena, fmt_string, fmt_args), + }, notes); + return error.PackageFetchFailed; + } + + fn renderErrorMessage( + ast: std.zig.Ast, + file_path: []const u8, + ttyconf: std.debug.TTY.Config, + msg: Manifest.ErrorMessage, + notes: []const Compilation.AllErrors.Message, + ) void { + const token_starts = ast.tokens.items(.start); + const start_loc = ast.tokenLocation(0, msg.tok); + Compilation.AllErrors.Message.renderToStdErr(.{ .src = .{ + .msg = msg.msg, + .src_path = file_path, + .line = @intCast(u32, start_loc.line), + .column = @intCast(u32, start_loc.column), + .span = .{ + .start = token_starts[msg.tok], + .end = @intCast(u32, token_starts[msg.tok] + ast.tokenSlice(msg.tok).len), + .main = token_starts[msg.tok] + msg.off, + }, + .source_line = ast.source[start_loc.line_start..start_loc.line_end], + .notes = notes, + } }, ttyconf); + } +}; + fn fetchAndUnpack( thread_pool: *ThreadPool, http_client: *std.http.Client, global_cache_directory: Compilation.Directory, - url: []const u8, - expected_hash: ?[]const u8, - ini: std.Ini, - comp_directory: Compilation.Directory, + dep: Manifest.Dependency, + report: Report, build_roots_source: *std.ArrayList(u8), fqn: []const u8, ) !*Package { @@ -298,37 +347,8 @@ fn fetchAndUnpack( // Check if the expected_hash is already present in the global package // cache, and thereby avoid both fetching and unpacking. - if (expected_hash) |h| cached: { - const hex_multihash_len = 2 * multihash_len; - if (h.len >= 2) { - const their_multihash_func = std.fmt.parseInt(u8, h[0..2], 16) catch |err| { - return reportError( - ini, - comp_directory, - h.ptr, - "invalid multihash value: unable to parse hash function: {s}", - .{@errorName(err)}, - ); - }; - if (@intToEnum(MultihashFunction, their_multihash_func) != multihash_function) { - return reportError( - ini, - comp_directory, - h.ptr, - "unsupported hash function: only sha2-256 is supported", - .{}, - ); - } - } - if (h.len != hex_multihash_len) { - return reportError( - ini, - comp_directory, - h.ptr, - "wrong hash size. expected: {d}, found: {d}", - .{ hex_multihash_len, h.len }, - ); - } + if (dep.hash) |h| cached: { + const hex_multihash_len = 2 * Manifest.multihash_len; const hex_digest = h[0..hex_multihash_len]; const pkg_dir_sub_path = "p" ++ s ++ hex_digest; var pkg_dir = global_cache_directory.handle.openDir(pkg_dir_sub_path, .{}) catch |err| switch (err) { @@ -366,10 +386,10 @@ fn fetchAndUnpack( return ptr; } - const uri = try std.Uri.parse(url); + const uri = try std.Uri.parse(dep.url); const rand_int = std.crypto.random.int(u64); - const tmp_dir_sub_path = "tmp" ++ s ++ hex64(rand_int); + const tmp_dir_sub_path = "tmp" ++ s ++ Manifest.hex64(rand_int); const actual_hash = a: { var tmp_directory: Compilation.Directory = d: { @@ -398,13 +418,9 @@ fn fetchAndUnpack( // by default, so the same logic applies for buffering the reader as for gzip. try unpackTarball(gpa, &req, tmp_directory.handle, std.compress.xz); } else { - return reportError( - ini, - comp_directory, - uri.path.ptr, - "unknown file extension for path '{s}'", - .{uri.path}, - ); + return report.fail(dep.url_tok, "unknown file extension for path '{s}'", .{ + uri.path, + }); } // TODO: delete files not included in the package prior to computing the package hash. @@ -415,28 +431,21 @@ fn fetchAndUnpack( break :a try computePackageHash(thread_pool, .{ .dir = tmp_directory.handle }); }; - const pkg_dir_sub_path = "p" ++ s ++ hexDigest(actual_hash); + const pkg_dir_sub_path = "p" ++ s ++ Manifest.hexDigest(actual_hash); try renameTmpIntoCache(global_cache_directory.handle, tmp_dir_sub_path, pkg_dir_sub_path); - const actual_hex = hexDigest(actual_hash); - if (expected_hash) |h| { + const actual_hex = Manifest.hexDigest(actual_hash); + if (dep.hash) |h| { if (!mem.eql(u8, h, &actual_hex)) { - return reportError( - ini, - comp_directory, - h.ptr, - "hash mismatch: expected: {s}, found: {s}", - .{ h, actual_hex }, - ); + return report.fail(dep.hash_tok, "hash mismatch: expected: {s}, found: {s}", .{ + h, actual_hex, + }); } } else { - return reportError( - ini, - comp_directory, - url.ptr, - "url field is missing corresponding hash field: hash={s}", - .{&actual_hex}, - ); + const notes: [1]Compilation.AllErrors.Message = .{.{ .plain = .{ + .msg = try std.fmt.allocPrint(report.arena, "expected .hash = \"{s}\",", .{&actual_hex}), + } }}; + return report.failWithNotes(¬es, dep.url_tok, "url field is missing corresponding hash field", .{}); } const build_root = try global_cache_directory.join(gpa, &.{pkg_dir_sub_path}); @@ -471,29 +480,9 @@ fn unpackTarball( }); } -fn reportError( - ini: std.Ini, - comp_directory: Compilation.Directory, - src_ptr: [*]const u8, - comptime fmt_string: []const u8, - fmt_args: anytype, -) error{PackageFetchFailed} { - const loc = std.zig.findLineColumn(ini.bytes, @ptrToInt(src_ptr) - @ptrToInt(ini.bytes.ptr)); - if (comp_directory.path) |p| { - std.debug.print("{s}{c}{s}:{d}:{d}: error: " ++ fmt_string ++ "\n", .{ - p, fs.path.sep, ini_basename, loc.line + 1, loc.column + 1, - } ++ fmt_args); - } else { - std.debug.print("{s}:{d}:{d}: error: " ++ fmt_string ++ "\n", .{ - ini_basename, loc.line + 1, loc.column + 1, - } ++ fmt_args); - } - return error.PackageFetchFailed; -} - const HashedFile = struct { path: []const u8, - hash: [Hash.digest_length]u8, + hash: [Manifest.Hash.digest_length]u8, failure: Error!void, const Error = fs.File.OpenError || fs.File.ReadError || fs.File.StatError; @@ -507,7 +496,7 @@ const HashedFile = struct { fn computePackageHash( thread_pool: *ThreadPool, pkg_dir: fs.IterableDir, -) ![Hash.digest_length]u8 { +) ![Manifest.Hash.digest_length]u8 { const gpa = thread_pool.allocator; // We'll use an arena allocator for the path name strings since they all @@ -550,7 +539,7 @@ fn computePackageHash( std.sort.sort(*HashedFile, all_files.items, {}, HashedFile.lessThan); - var hasher = Hash.init(.{}); + var hasher = Manifest.Hash.init(.{}); var any_failures = false; for (all_files.items) |hashed_file| { hashed_file.failure catch |err| { @@ -571,7 +560,7 @@ fn workerHashFile(dir: fs.Dir, hashed_file: *HashedFile, wg: *WaitGroup) void { fn hashFileFallible(dir: fs.Dir, hashed_file: *HashedFile) HashedFile.Error!void { var buf: [8000]u8 = undefined; var file = try dir.openFile(hashed_file.path, .{}); - var hasher = Hash.init(.{}); + var hasher = Manifest.Hash.init(.{}); hasher.update(hashed_file.path); hasher.update(&.{ 0, @boolToInt(try isExecutable(file)) }); while (true) { @@ -595,52 +584,6 @@ fn isExecutable(file: fs.File) !bool { } } -const hex_charset = "0123456789abcdef"; - -fn hex64(x: u64) [16]u8 { - var result: [16]u8 = undefined; - var i: usize = 0; - while (i < 8) : (i += 1) { - const byte = @truncate(u8, x >> @intCast(u6, 8 * i)); - result[i * 2 + 0] = hex_charset[byte >> 4]; - result[i * 2 + 1] = hex_charset[byte & 15]; - } - return result; -} - -test hex64 { - const s = "[" ++ hex64(0x12345678_abcdef00) ++ "]"; - try std.testing.expectEqualStrings("[00efcdab78563412]", s); -} - -const multihash_function: MultihashFunction = switch (Hash) { - std.crypto.hash.sha2.Sha256 => .@"sha2-256", - else => @compileError("unreachable"), -}; -comptime { - // We avoid unnecessary uleb128 code in hexDigest by asserting here the - // values are small enough to be contained in the one-byte encoding. - assert(@enumToInt(multihash_function) < 127); - assert(Hash.digest_length < 127); -} -const multihash_len = 1 + 1 + Hash.digest_length; - -fn hexDigest(digest: [Hash.digest_length]u8) [multihash_len * 2]u8 { - var result: [multihash_len * 2]u8 = undefined; - - result[0] = hex_charset[@enumToInt(multihash_function) >> 4]; - result[1] = hex_charset[@enumToInt(multihash_function) & 15]; - - result[2] = hex_charset[Hash.digest_length >> 4]; - result[3] = hex_charset[Hash.digest_length & 15]; - - for (digest) |byte, i| { - result[4 + i * 2] = hex_charset[byte >> 4]; - result[5 + i * 2] = hex_charset[byte & 15]; - } - return result; -} - fn renameTmpIntoCache( cache_dir: fs.Dir, tmp_dir_sub_path: []const u8, @@ -669,21 +612,3 @@ fn renameTmpIntoCache( break; } } - -const MultihashFunction = enum(u16) { - identity = 0x00, - sha1 = 0x11, - @"sha2-256" = 0x12, - @"sha2-512" = 0x13, - @"sha3-512" = 0x14, - @"sha3-384" = 0x15, - @"sha3-256" = 0x16, - @"sha3-224" = 0x17, - @"sha2-384" = 0x20, - @"sha2-256-trunc254-padded" = 0x1012, - @"sha2-224" = 0x1013, - @"sha2-512-224" = 0x1014, - @"sha2-512-256" = 0x1015, - @"blake2b-256" = 0xb220, - _, -}; diff --git a/src/main.zig b/src/main.zig index 06c36bad87865cbc29839351075275578cf3191d..f634c259ff9eeefb15cc458d50238f2859d9cf40 100644 --- a/src/main.zig +++ b/src/main.zig @@ -3915,6 +3915,7 @@ pub const usage_build = ; pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { + var color: Color = .auto; var prominent_compile_errors: bool = false; // We want to release all the locks before executing the child process, so we make a nice @@ -4117,6 +4118,7 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi // Here we borrow main package's table and will replace it with a fresh // one after this process completes. main_pkg.fetchAndAddDependencies( + arena, &thread_pool, &http_client, build_directory, @@ -4125,6 +4127,7 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi &dependencies_source, &build_roots_source, "", + color, ) catch |err| switch (err) { error.PackageFetchFailed => process.exit(1), else => |e| return e, @@ -4366,7 +4369,7 @@ pub fn cmdFmt(gpa: Allocator, arena: Allocator, args: []const []const u8) !void }; defer tree.deinit(gpa); - try printErrsMsgToStdErr(gpa, arena, tree.errors, tree, "", color); + try printErrsMsgToStdErr(gpa, arena, tree, "", color); var has_ast_error = false; if (check_ast_flag) { const Module = @import("Module.zig"); @@ -4569,7 +4572,7 @@ fn fmtPathFile( var tree = try Ast.parse(fmt.gpa, source_code, .zig); defer tree.deinit(fmt.gpa); - try printErrsMsgToStdErr(fmt.gpa, fmt.arena, tree.errors, tree, file_path, fmt.color); + try printErrsMsgToStdErr(fmt.gpa, fmt.arena, tree, file_path, fmt.color); if (tree.errors.len != 0) { fmt.any_error = true; return; @@ -4649,14 +4652,14 @@ fn fmtPathFile( } } -fn printErrsMsgToStdErr( +pub fn printErrsMsgToStdErr( gpa: mem.Allocator, arena: mem.Allocator, - parse_errors: []const Ast.Error, tree: Ast, path: []const u8, color: Color, ) !void { + const parse_errors: []const Ast.Error = tree.errors; var i: usize = 0; while (i < parse_errors.len) : (i += 1) { const parse_error = parse_errors[i]; @@ -5316,7 +5319,7 @@ pub fn cmdAstCheck( file.tree_loaded = true; defer file.tree.deinit(gpa); - try printErrsMsgToStdErr(gpa, arena, file.tree.errors, file.tree, file.sub_file_path, color); + try printErrsMsgToStdErr(gpa, arena, file.tree, file.sub_file_path, color); if (file.tree.errors.len != 0) { process.exit(1); } @@ -5442,7 +5445,7 @@ pub fn cmdChangelist( file.tree_loaded = true; defer file.tree.deinit(gpa); - try printErrsMsgToStdErr(gpa, arena, file.tree.errors, file.tree, old_source_file, .auto); + try printErrsMsgToStdErr(gpa, arena, file.tree, old_source_file, .auto); if (file.tree.errors.len != 0) { process.exit(1); } @@ -5479,7 +5482,7 @@ pub fn cmdChangelist( var new_tree = try Ast.parse(gpa, new_source, .zig); defer new_tree.deinit(gpa); - try printErrsMsgToStdErr(gpa, arena, new_tree.errors, new_tree, new_source_file, .auto); + try printErrsMsgToStdErr(gpa, arena, new_tree, new_source_file, .auto); if (new_tree.errors.len != 0) { process.exit(1); } -- 2.54.0 From 9db084f43d6f253f36484b9e3b76ea483917a893 Mon Sep 17 00:00:00 2001 From: Ryan Liptak Date: Thu, 2 Feb 2023 00:54:07 -0800 Subject: [PATCH 82/84] Add test for optional error set return types Closes #5820 --- test/behavior/error.zig | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/test/behavior/error.zig b/test/behavior/error.zig index b2a6cc5a5052659f3264b80a86551bcb77e81f19..f30290eb918bcd5280e93a9867f6a7b0f2fd6743 100644 --- a/test/behavior/error.zig +++ b/test/behavior/error.zig @@ -896,3 +896,18 @@ test "optional error union return type" { }; try expect(1234 == try S.foo().?); } + +test "optional error set return type" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + + const E = error{ A, B }; + const S = struct { + fn foo(return_null: bool) ?E { + return if (return_null) null else E.A; + } + }; + + try expect(null == S.foo(true)); + try expect(E.A == S.foo(false).?); +} -- 2.54.0 From c181ba102234756f39207402d4932303449f1c41 Mon Sep 17 00:00:00 2001 From: Manlio Perillo Date: Thu, 2 Feb 2023 15:11:13 +0100 Subject: [PATCH 83/84] langref: remove link to closed issue #4026 In the math builtin functions documentation, remove the link to issue https://github.com/ziglang/zig/issues/4026, since it was closed by https://github.com/ziglang/zig/pull/11532. --- doc/langref.html.in | 42 ++++++++++++++---------------------------- 1 file changed, 14 insertions(+), 28 deletions(-) diff --git a/doc/langref.html.in b/doc/langref.html.in index a6a46979c4ba8bd54bcd6a92f4606ea6c3a3dd3c..36711e555aa04b42478a9525ce9f32d3e9542059 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -9206,8 +9206,7 @@ fn doTheTest() !void { when available.

- Supports {#link|Floats#} and {#link|Vectors#} of floats, with the caveat that - some float operations are not yet implemented for all float types. + Supports {#link|Floats#} and {#link|Vectors#} of floats.

{#header_close#} {#header_open|@sin#} @@ -9217,8 +9216,7 @@ fn doTheTest() !void { when available.

- Supports {#link|Floats#} and {#link|Vectors#} of floats, with the caveat that - some float operations are not yet implemented for all float types. + Supports {#link|Floats#} and {#link|Vectors#} of floats.

{#header_close#} @@ -9229,8 +9227,7 @@ fn doTheTest() !void { when available.

- Supports {#link|Floats#} and {#link|Vectors#} of floats, with the caveat that - some float operations are not yet implemented for all float types. + Supports {#link|Floats#} and {#link|Vectors#} of floats.

{#header_close#} @@ -9241,8 +9238,7 @@ fn doTheTest() !void { Uses a dedicated hardware instruction when available.

- Supports {#link|Floats#} and {#link|Vectors#} of floats, with the caveat that - some float operations are not yet implemented for all float types. + Supports {#link|Floats#} and {#link|Vectors#} of floats.

{#header_close#} @@ -9253,8 +9249,7 @@ fn doTheTest() !void { when available.

- Supports {#link|Floats#} and {#link|Vectors#} of floats, with the caveat that - some float operations are not yet implemented for all float types. + Supports {#link|Floats#} and {#link|Vectors#} of floats.

{#header_close#} {#header_open|@exp2#} @@ -9264,8 +9259,7 @@ fn doTheTest() !void { when available.

- Supports {#link|Floats#} and {#link|Vectors#} of floats, with the caveat that - some float operations are not yet implemented for all float types. + Supports {#link|Floats#} and {#link|Vectors#} of floats.

{#header_close#} {#header_open|@log#} @@ -9275,8 +9269,7 @@ fn doTheTest() !void { when available.

- Supports {#link|Floats#} and {#link|Vectors#} of floats, with the caveat that - some float operations are not yet implemented for all float types. + Supports {#link|Floats#} and {#link|Vectors#} of floats.

{#header_close#} {#header_open|@log2#} @@ -9286,8 +9279,7 @@ fn doTheTest() !void { when available.

- Supports {#link|Floats#} and {#link|Vectors#} of floats, with the caveat that - some float operations are not yet implemented for all float types. + Supports {#link|Floats#} and {#link|Vectors#} of floats.

{#header_close#} {#header_open|@log10#} @@ -9297,8 +9289,7 @@ fn doTheTest() !void { when available.

- Supports {#link|Floats#} and {#link|Vectors#} of floats, with the caveat that - some float operations are not yet implemented for all float types. + Supports {#link|Floats#} and {#link|Vectors#} of floats.

{#header_close#} {#header_open|@fabs#} @@ -9308,8 +9299,7 @@ fn doTheTest() !void { when available.

- Supports {#link|Floats#} and {#link|Vectors#} of floats, with the caveat that - some float operations are not yet implemented for all float types. + Supports {#link|Floats#} and {#link|Vectors#} of floats.

{#header_close#} {#header_open|@floor#} @@ -9319,8 +9309,7 @@ fn doTheTest() !void { Uses a dedicated hardware instruction when available.

- Supports {#link|Floats#} and {#link|Vectors#} of floats, with the caveat that - some float operations are not yet implemented for all float types. + Supports {#link|Floats#} and {#link|Vectors#} of floats.

{#header_close#} {#header_open|@ceil#} @@ -9330,8 +9319,7 @@ fn doTheTest() !void { Uses a dedicated hardware instruction when available.

- Supports {#link|Floats#} and {#link|Vectors#} of floats, with the caveat that - some float operations are not yet implemented for all float types. + Supports {#link|Floats#} and {#link|Vectors#} of floats.

{#header_close#} {#header_open|@trunc#} @@ -9341,8 +9329,7 @@ fn doTheTest() !void { Uses a dedicated hardware instruction when available.

- Supports {#link|Floats#} and {#link|Vectors#} of floats, with the caveat that - some float operations are not yet implemented for all float types. + Supports {#link|Floats#} and {#link|Vectors#} of floats.

{#header_close#} {#header_open|@round#} @@ -9352,8 +9339,7 @@ fn doTheTest() !void { when available.

- Supports {#link|Floats#} and {#link|Vectors#} of floats, with the caveat that - some float operations are not yet implemented for all float types. + Supports {#link|Floats#} and {#link|Vectors#} of floats.

{#header_close#} -- 2.54.0 From 4c7f8286d53bf3df22b1a4596cfdd38d3736240e Mon Sep 17 00:00:00 2001 From: Loris Cro Date: Fri, 3 Feb 2023 18:05:07 +0100 Subject: [PATCH 84/84] autodoc: fix search regression --- lib/docs/main.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/docs/main.js b/lib/docs/main.js index 62af5866b64290b0985ec4bdad302718dfd1995b..fae39c5fbaeb9abfe47dcc42b2b91e00b8ba0be1 100644 --- a/lib/docs/main.js +++ b/lib/docs/main.js @@ -3162,7 +3162,6 @@ const NAV_MODES = { canonTypeDecls = new Array(zigAnalysis.types.length); for (let pkgI = 0; pkgI < zigAnalysis.packages.length; pkgI += 1) { - if (pkgI === zigAnalysis.rootPkg && rootIsStd) continue; let pkg = zigAnalysis.packages[pkgI]; let pkgNames = canonPkgPaths[pkgI]; if (pkgNames === undefined) continue; -- 2.54.0

2HB)JX7z{D9fJ~Ek^I1w0Qrx{aONrL4G%()?lDCe3I7|5z-u|Y{1}-n>w`VKU zfH;%qD9b&=al(_fmVwLUsa%_@Y=wMl;L4lOsE**EYm+&gq|`=I$dzr-+%21jc|Xh> zf1vayk#X?{N^8Q~-#$>9=^cvX&F6zJy1*yT7w>&JU&#)cNf<;oas6TG3W$tcpv0K6 zb+meu$4^wE_-6~0uA$C)ZU8!~msgDs#P$@ga|D{(A0;zQ+ld^?5>51fko>X0<+(WMFTBW|Ha4xnl+@O4O ztpZCs&fm*^=ySd^TN#YUb=N61JYRS1b|cm)gJW@+5B{Ifk6g;)48czzBeoJT2E%%V zLSOK5>y-q(Ztf%NzPKLfzm%_Buf(b_r+_VOqLlALP(&DMvA_Pf9xMu4yN*_I5)+;S z4lWZ4e=H-EzLKMq3(16SXp&c|FT?=>>G?TOTAbx?Zcxf0;Ty1$0GAMkk9KUNwA z-9^mvF0R^dehg&hyxvA7mG2d;SsVi5t$@D~`TyM#cW+_;G65b|J+4;TIP3kE*EmUKSr zGo@3gx?E#rB6 zl>w&ZW}ANvLmnKhA5a)?{*5xnS#-l$bm<#qwkb>0%7N#0s90m_yYt6nX0v-anuW!nLGx2OyuKVo*L+bS%hM=25opcOtv}J4K@GuJ0k_Ep>D| zq_j0g=tu5Q+reR|P;%FVi2%G7E#;pVfU-V9JdLEv zX;6wKeBx<*Gm~#Rt)w8S_bc{8DDMaSs*Ldc1vlI*@TmQ(at6j6U;lZoH~k`O+|lzx=y$0m-u$01jNwxPbY- z!RuXAJ~rHR6kP=0XSn02dI>}oTVj_#lrEK1&158=V?=y5n5wLW=SfOe83PlnAnP6m z&AjtT9Koa%`vvlAe<;JGDNu-CR$iy{=w;}}yfH`5!Y2EN)V9P)sH2c0zHUohhJ zUA&@v4v!71uVQ1r%q`ad_U-(}HD$TsmSf>{C5(jCO*b%xn~q^O6`Ud6;bU)MEsWze zZYy2D@{PR>#lW{b><(myExhm!(C9Mnc2`KdEANuD`;p_|pUNkaVS!_!fekPizI7B! zEP`6{HL|W)Mm>z|J*sxphkc4_Jj29Z2Oj@vVxye+70OcrnGc`q&vufYr&j=Lh=npY zfZawbGXtp=ekPE`m0JZ%Mr|>fGhQikTK$-|@GBJJ2s@JxK4Pt6f*NZ#w9#;j8pO(j zF-{3$iPH4nc<~YIAm0Pz`9kHr3anM}s7)}dNsqoPux`e8mXg(LTQi~`FXHc+nQ)ms z-^`jjvwAEngJmG(C85XIE0KkJV7#Oib884|XFszXcXz#mpfdD9;qEO^V|r7FPRdOq z?Ws3{2I2apq%FdYBIKYl^ha*fLFj(HgP<~`XA|LQ3^}L_{gB&!T;!lKG$EIw=b$l! z5h02g>ofP-*vbYO z0}tT@+7)Z8e<*w3Tl#V>|0RNrG#(2KY=u*>m~wnqoJ^l+KG{F9&-ZFXFf@Fq%a{ZB;3nbqy^zK3Vk9=G!iq&JVCS{46<+ z8PTksw;{*zbsS6aQ$MAR3cDrlnuy_$EbQPtE3uV`m*Nx1ua0L5k56RndDjUnflp6l z)nN3sIgvGmwd2i1_AcDr53kI2;Bc@}71kO_N)=Ys_c)@J6@E;8i2mrsxwVGgfnm1*an>Qn(8cuA}8;y&LVw9@J=uOXEhc&w+2=y z+&q*J7h-oNvyy$k4F8d(OO}~1b(76Ye=rJ zriB?B`yN5O<)B#JIn)@-i^Gh8Jf)8Qslae!jAKI`Hq=1hSP)@s;J0b+Y>S2$k46|9 z!++kQdaNH{bgv%UB;88opVZg8(>V%#yjGum3Tl|$fK_zA_G1Iqm>@Jg+SrQsXvmUj zM9pK2@w})ZUd4!l8ZnB~(WVhwiS{oxViWcLMe6;V-HgNpEugXVG?;@BFA||DS&uGs)Lwg4Vv1rmf;1|J&O)+eGMY|oaICy zzfj#+EB04->d=gqKByA{%(6i*noDan*OIJ(CT(oXhPsw-A+9ir<-4_p@j2gbsadl= z>g;x6)Zeya{i=-{Uv{yQ4K=Cb^YON%;q;p*kxh!C@$#PSnN9j7mA~Jfg`1rVnm&VP zj;!|VC4>GM1dkx#COs`a)A4Ec8m*`=pJs7E9<2rPk#&r5rUOJR0x`!+>lnjBopyYJ z^k`?iT8r-jv~`RX`8VyEnH%dG+Yzuk*EM$IYA4nX^VY8u8%|}(^^6txoldN(bQ}SF zk--T-$IfiBRJex^u5XNz3ij|R^^Ga~oh~fYUvx#xVwDEKjodD5k7+9*Bq3Z(LkwW$ zGdlh0*bo?B@C=xeZ~5J4SiCeJXVzVH5_7bn(Z&aK1@*-g^=M?=$VWcQLNWgt&$72k zgSEJ^aWIhxa}!YcqkP+QY@y*t-n$!nQu-0Ycmdl~r=~`K=_p=rYOKv~bYlfrxCftS zN|4xGeYAN|$?&IM@;rjE{>a0-v#|mIFR(D)_Hm=acXemQRMM`Qu@|@YU=^K@72duF zTSB~D4+j6;haHW3v8N0~>7t*&fLHWpPg7C5siPmO0(ICg{n$>xVO4*23N5F< z$QtV87mBEFUSyBMU?^Y!+l7;sg98N3J3D|itx)J9p1~$yx4yM!GT>t-OV(UVlb?Ia z7>zauzQmeIg@L?nTg?0ZmskapyT+on#%_^W_YqLKR~QAp-|`Aefn8#=S6To2gIw=;m9@J+$aU>x*6yJ}t}~NaxBG)! zqpbYHgIq_8iTAP)SA{cGNZO%7(nc0xuh$L2X0wH#8N@1tBjUB7pt#{Ks0uA!FAL}$ z1-%8=^7w0rFulpl`@LvxZgNJu-pIdrjrDc~yWYs-UuRKOox!d*nq6^4gC7;_dLtkB zI!l0&{bamna)!Fz$g?TujC8$`=fBR9OwK^p8@bP5Ru?j3ke$YV3TAH7$3-jn|~rBfL()na6H%(GB4Qy~wN(;hI}u|PDz=hEcG1fc^2hJ4N8Tyf-Bf-|VBReB@ zu#->r(ROV0jO+|=_?_Nm<*0$0+Z5^={xjK0JB)AFM*!N5@i>(cjpPSM)TxBAH%z`@aooMb+;jaThJ6TrV zE)C(F(YaUC%u%MCooE;lnfTN+a~zefOEX7u-}hOS@God1p~zEZmcrMi@tE;Z&F8dkXzL$<7{+$iI(z-~u@iz|Vqcly>$aHu{z+Y%u0`V+!kr zBybGa^pE))V;IGUUOGn5w9m${XbKa3WDFpBn6t5>&d9N>*#q323%~LSrJ`Z?eqpR= zf)I>HjANb9c=9+F9ihjLE@cb#7pY&O>c^-W`?1-@G?D^VC!+`_jjhC+!b#gw*%QQ0 zy_Cw@;A|>8m8CpFplUImtpb9aAJ1MzGB}aNJKmbWo-=?a-anC5@Xw~JAHkO2C0_H3 z=xAtG!_!y=NaT;FvBZEen~4e0zc^(0>;b0@J{(uF|&n%NwKZJ_fc zv^NJH;4r^vFK2Uf3^Y-TsB{*bhl#Ju4Kc?^;}`RDD21VbWiqSie_;_&B9vYk8iFv) zCwXrwolXt;Q0bRc`UPK$Qk)TdKN&M|kz1y)^7QRqTcV@ z2&`ZpZ%<)K(&TZxN;<12{W6C4OGl`~JA6?(i<8d4&|_`@`VCIZB zw#L*?>1GMa7AP)#LN5`Ff@CBUcm3HT`ozYM8F*8{MnuX72LKMMd8D?SmoZ+#v zAOMx{H)gT#{GDt8=A`4-(T`K5DYIDzY4>>k<7~Zu_ae-lP`gv4xg}4Z1Lf5zesT_L zkEHrs)`mtfItqb!_wwwySkcISi)`%I#4dV5lmeI2AqZ_0=mKZ;?DQk6HlL#3{aQ0Wj$z{P;re!DccmH^rN4Lacx-eDFf-gje|oNc@k^ z73>25vpL?}8Fswp1ao)kQXub}AKjR5T*R1k3N$u9I*u1PGbi(-lTfkRV#rm%UcQ($ zk}gi*-z^5m2$FJZF_d<9C-Cx1ST+AW1Rq~?oi{IUE-%d<$L&j49sg9au@;Lwv%Fcw zTpe73Da6YGnJfuiYnX`%DCSc$Sxx_$lSv_?1j5UGQOrOb*;QZ4HU=)A?d*4gFAx4b zIEMQ#gLdF|K57|O_g0>}4E*Iqetj8R2F>UE%FyU&;TRhh(t~I1|atVjNIu z_#rzcU4^`$MD(FF=WRnI`Y>Y!rXATaEW#!&lli*QhKiKN*YJy>^5!-CD&l;>sz#Kj zV(mRc4BlF|lAQ=DAgn!vKTzHB;=`;iZ=P`*?NwN|FW;|4@O@|Zyv3vkSY6Wwe~>202s z&DxoSJSJIg^Xu7|;MgF!xh%c-tMHeac>-_ycS+gRR;`-gFBvE6ve!3mfl;1J7S}vijhW zBX+T#NZ#7T-T|q(xC_f~ha>1~HqKy}*BMd|v6j;AoqX>hEP?Ud@&kDJ*}UlwY@6?XGfvj_bMM3K6=}~-{`z51dQogXqZmamuf#Bzgkc?YwEKw-r|?L5KeK62^>i#`Ee(Z^ z*@bM7WJh;s86cd4Z#%;(Lx4JehAlG9qgd1w9Xg{33aCxEW5M2zJ&iMMdfnp_{_x-fo>qLK z?^%4}Ce@Mf;;gf5GP)Rh4gwhb0i9z{m>d`Ji~>m)o)?Wq6*C)ebsih!PyEI6tUBt= zJkMG`tlnd&(!H3?Hk@)?C}uIskq(r+!ri=MJtORg?ZBz+sW6uL&HE4-Yot!q) zef=H22_}SG1q+_%OM!VbFa3YZuQ(1ut(6px#L(F5syME%FTvp$jL=}D?_~5X3CN_0 zhlx_%`qCX(8YN0l_~5l2mSn^u7p9S!;-|Nl9mVsUzwxsKdL3c(2TT3ZQs`Xp9{Ix{ z|7AB2+k~3gjE|7Fnkyo0Vz@@B)Y$6=eH@)gM@p|{Q28M=>=74TJSe~eJB|dLcA)#H z-aMct)KDSx_X^%Qgr_!tiY*P;EHovUup0q3=@v+J_SV5T3JH{&ORh4B%FxY3Kmdcb zNg}5=hX^+&%WtH{CoMmG&BH**N3-Koi2fX)ZS%5Zi;wK{PcYFX2lrRn1P9_X&Rzvr z&X}D}%{_bKssr>gT8c1{+6^3dqY2TD(Q=lGa)RiKDS^q(0M(FQD#Jo4pn>-)a58wb z3KwzD!O9A+(VIwvguxx!xx?d{sFk?oGJ7EegExr5>jUK@FSA&<6L1>v_3o!d z)0s2NGyvYVLE5o29FE8z!S8L2*V0<9ernUD_WQ1nKg^W1j zHxN4h6J)gi18hVW{^Q694FB8M_}9n?JY4e#JoG2qOczc$QHsC@l(UzjRauNNk@bd- z>yN}LXB~=(ejj3qSqXYHV!81u4&V5Ph=p#^3gV-$u`2c=tVK@(RU85W1=LNHib7z< z_(%fvA>3_HsH#l>nTWDMDMUj{LI6|?l)-5>2-I4b_7Q=i6>=pg*+ro8#ZR3;?RNe~ zjf`NbL8M5VSNbzE*hRL8Kw&ir0#%HZ2+}HY{NdHautKDby|Soh=K9iRy`Fa-)k{Sa z_YcY^da7H@KK$nI(f447M>avA{F%12I)-Z9x%ngH^U? zzzFWBi+l)!3~~l0E)!UO@F++0O*7n-XmBJaj_%9DVg~UP6HK;%L0Ei?K`WBH(#=38 zDvlRMPr{vNF`f{ti-?*OLH0g$2U}Qq+5!=Xp(ULIpfZ8@5SF_QQ7H0h*@NQmqdcjI zDAoI42)hFcxqu3=i^X41Ov^_+^d^wvfe+oJ580d_`cHf(2sG|j2=hW47KIQIAZ)aU z2^iX4z#>BqLdDHg9kd_2JFc$=(MVw4pxJ4XDQKv0f8&P*yamOHQcZvoNnKn+%GYH+ zVsi>aAP*uOUv`3y~PB_Jcx#Pi$%UHAn2==Pu77*(9-7L z1ysTbD!NvWWU0Rke$1f@{Fq5M_&eWYVK4sc;gV4t4aNc7hNnTJYvcTvZ(>6-#s_*g z=k|BiFuR|ZL6W?^ePQz@Y0-lca5*^K7T5-t)3J@zmuSbv1%E&!#&QA+n1EWIG>!W( z5tOkJH?kY?IVwrTBuuNYiMzNEVH%EbSmSbkSD}D&Ack%!Rtd?j+ ziTfSoBB@Yn;O)lt*~Bk~cpxEOb0a&Lw3P`a zUil6Sw!2`40X~RaaQEwDOL|;d1>+jQzmi*7P+V)WrPzEQ4%7Rt#z0ygYz&NF88E|7 zkW1&5KqBB<0GFA% zd?5I?f{=d!U(Do#@C6$Olbk`ICPX&qoSfjDI0&maiyYxq!y}@thXQbzP7UPqIk#Dr zeuCT)>JrS0youiwcaW?FCf;a#J1;!CIEsJr5+;)eB zM!9f9khHQ?jCa1nSWnT9vR(L`x}f~4E&x0JWf!)g3orad7l_x!XsSOhr2@Ew^C?04 z22{G5OScgLBcg%ZXP|=&QdF(GtW(DnIF-Pm29TDdRss`&>!G_5Q4Rv1z8n1oIdsD< z;K4cP(x0rH{RXyEqK3a?3D+>BfP>LlG1q7xxov>)Hq-tJs)&OH>darzFWPh;N~G*M zm2#uaPlW(UZ0WXujl`4cxely|=;aG+e+bbNm_+csM~y*(b?q@Ey10p+zQb29-Qt}% z_^*NLUX{Sq2N#m=n$#(M`e<3fAnHN_McuVQLh8gfol>fJ-zk>5Wl;}4-zAG;xTO-R zT`QG3J!R2S3DqTw{#_ZAfFfkpN6Dh4oE}8c?qIEYV#;Zuf}u}9#HpUh1d{-cM-3sH zBdJSb6Af9guQ|b>(WvhhT!Wp0>!x6VaU$AWPd?+UTH&GKMOXz7Vb*k?Fl#C!%;p4p z3bTdyvO&9Z2KyiVv0M;{e%kZ1)K6VS6e=vrD;F+QmqcDe=;_!6qIf z-)^*A6zy)d>LT*r7!MlB2uvnYNZ33t(8Z@~t4d2ZqcmkK_G2A$z0-)ygaElH1@TOw z)Zbw6Qj9c;)(Z|7`#>hExKp|3Ipgs5~UPhr_KOQ%I|BY_M@ADFos);o@#`@ z2S+k|aS4GWsG|em3lb%!3xSzJbF$mlQ@bGL`8M#LhZ6ww8=93zDHkAuK`=7{zFxd? z6E((HgNtGt{Bs!9r=X`AZd7f2&RLZ~m4NTLMusVH6NaDw(hx(&vf)c9xYb5I-57*2 zsH&oozylPzU~utn!r{3%1BLN4X{5YJCkbZEK-ScvfVhqn5#|$Z1MFzjPRhG1{4iSf z5K}&Z#F8Yh_4o#1*H|H?I1I_qZRjO`qOOm&wX_7}-z(eD#E?p~9KS!o?-b|nFYz0f zQ_|XAbO(R^=b_i^M@A3o3t>-cp2kK^4ejDS8cvLGDnTEtF6fXBvC3h#4D5*kv9;e zrw#F8lolG|qX-@ahWI4PA2P%P&|pstkie1dGYIufJ^&!lHqVd{?PUEANeO;1eW1!x zd zY&@>b7~>=Gg|*(a;Au6}VV`U5<5`eq)z;?y%HRBs?{5=}Ms`jwCfP1%d+ z2e9`ykv8@^O)2>9JM;|<^#-NTWn7`uM?3C~?XHA=W8{J-Lw}2qr;CxUL8iHXQb`K6 zxJeW_$s8>DQM3bcT0|FJoI%evQ&}O*;GEzoa5tjmyMI!9yN$Mxct6c6-im(&^b#TP z;Z_e+d;zvV-ruBFx09NshT)1a!B6LR?s$`!O!Oc4fI$IE-6Iui`--H?(HINdp@J!K zSGXdP|9dJm##aPEG2xDpE!?FH^wE|G;)o^aUVJNk?6mr@234euNTjY_WIL+GM;m=+4hp(Nqc2j}_P;-V~Tjd>J%~l!I2^6jh60EjxT!6t;75KR}{&3poG1K{eu8kh3 zUfFv$+(vlW%DafPp278UPmL@svQ%`yhG5ibNa;iANU3}kmB&JvOeq#`rk@QDh6$)hzaa+NfIPr{ha`dPD zTzP+bA-QiRkeQLvsxu6}^^^d%j7ER@64c%h$@1ugyu z9cuD#EO6dBM2%NVM1OR(FrcHU8Uw#LIz)}IgWy=M2sFO(54!Yk^oXL-*XSFB7qYw$I0A2OE;< zEIf_Eh0foF_zj_{EXBj8%1}H!7ZeZU(5CuR7X+ax5MoS@zl+|1(utB){({~KDfo($ zuwnclT|}Oc9H);5g6&00h;kaKU@P!p3U{4KDJa_w{keA<<dkK#ErH6ER`6H1i!;Ss$ot#Dr_|B6TUz|SIq z9Ae@T^N$ddW;_k5XKaIo0i}qNLKXvBL4X@ksBR(636S`>m?m9g>Ox|nH3bd}B{NWg zw2VSyir@LLD!74n%Iw<6d*ZO2=%qknI$!uQKu2QYypYWbaPPhe;DVi-==X7V9L**cYnH&^v{mInnz@fc`rr2$+QOGU$!&2=uN_^9iO@Xve^mLWQFJF8U@&^da;_ zU^M0*Wby`@(Qb?0-3xS+NkZuz^kGPTc~k=^z1f)-QaMolG^N!Wco!fg7!*;SocTBQ zx{jYjU9VA*j?q`?Cop**rNHF7f%Ya|H;KeDefH-G^B^6K(+&WQnG=l{2D#8U9nP}c z@;hKvN}JN@Y$g%N>`}pm=Z`{=f0O?G1)k3f5;R0N9w2S2j^`U(q=%o zLpCV15XdHl7J@L4aV`X5L4$>mL(iNGfoxppcTO<@M#T z5yi*hMGwPJ0%d&g%_YJ_?E_e%YnfZUdGW89IB#)&LCG zO-MwI|2IhK#>t0JXCqm}=$0f=I*0AzpMeVx3IcFngxy3;rIT?Zs-ifl%D!M1RnZmt z9zz!+xBu@AUF=Jx@V}4mdgNGfYb}^q8glD_zc^=c(w+7~d!ywGP@q_BuR%_-a|m#7 zYIn*2f|RGF^mQ|7v~Ym-A0@z#B1{4Y>;e=2iZDHb0Bd_FGBy~9_$Zq-N~q#WB_`tZ z9)9$iD>OAFZc2sSF-H^?fmC@=Dl+G#t$DJnHxbahL+?G}-bMD+!<`%EWOqurY6QEQ#>B$X&RyZnk>4)B)?_Xj6&lZ?|Zuhsf3V$Kk+z2MFN^3rd#tjpkbwZh(D7Dmg_7vDz zhzDYYS)3~@)fZY+RPa3b{$GQ|b7CF;+pvhk@dsh6mM=`z3;Fc~wLVz`O4pbEz4lS6LitW9WS?)9HfLibnasd1rvr8Buz@EJWMLmC>2W*3NZaQHb5xAoaF)dovHtZ+zB0+ z{u>$;=)mw>D-cVX_y>!ym2?_T9LJLW|B<$N&I(4StJrCF5~Tt&os#$_d8HZR1E@gU zApxJ|OEZ*4C;MQ`aU=|VYEPWILt76cz@|7|)J=nAw`mXAS&bsoiunKSEuzEUSjqs2i{E?%>jBfkb8=M!Y zv;JF9^V!aFqUIU;@7?~@kV)4wf}E$}x3*hnS3u6ODVSYmaQi~|iOOo^f5o(E{|rwb zvSRs9Nou5dcZf^tNm|p9{+HqJ$hWY!EAP! zI2I75!qArfG}TQUOLXK7DP!VT5YnK6cM&e4(ISCJ@`wwRrzLKq8+hI(;~+`GKd^h+Y++57V8!+=V4cBh)KMdz zf-N_l+2Fn%8An13DefQXsxwW$>qDZyzm`fjmHk}GHMcc^>$0xIYn@Y-PU7MT6jgrE z%izQGk51b*d$vlU3k1uKR@3OL)zxa2`>eHWt4}&x&Ge5K7?J1M8eMX6wU!IpaI|(C zJ4_A3A@}K6+1BbfTgwlK$Dx9^EtD+%BxrJx;J({1qzPek0~n~3DT#~aS$s}iwXz*{ z#4e33>8D8pr|rE5@i*~4jV(>0=e?CA%$D?@pRT#THnr z==ltU)qz4!)WxYST^t2ku9cz!Ep%E?!+=``_l-nvK2fwo3JWo3Il%&v>58eq3k}xn z_$q8s`Ih>s?V+<+KzjFz_st^B8hx3TqBxrXKO<1!KQW8mVir5V=v2r|@xHW7#e{Cs zv0HLZsayNzukE14BDsXC2cTgTP4*FSi7}(W3C<>baq2;f&>PmLNQr`w`3G6dlTXfg zVSnzv5CL;NUz^qW5!{5h59E5kO-^IkT;92%8v686P!OV%IFS=Vq&T?`&`<6Odg3yV zZmCJcM4SOzh#!Q#tJ@aPg){mW?9MNw_|ohK&_M_h?7L3W8&_ozY7%6HCL4%Y27rWC zF4IvWVF2A4fk?Q{;8KaZ+7WxUs~s5c_`+4KYJK@(D}M2O*X<^!>7@A1{kQ@~_iy70 z-*7fU0fxFRu(Z|<+FjidcdpHiy(ZCaNEW!1;(Ou%87~$1U;{%Lseb7K2|c5OWV%a? zzdFR}lv0QIY>ZxCajwA&AXfGK9K!PWxY)~dUFP%XoxbesVx@}a#dQxI8f9CCQlWHu zFpuaB&MtyoJdn8fn<%|QwMOea5H5J27Ot6jIFW$uIZhDa>J?95jpt;6rfOJ3?rzX;VLD7M4#=Dr59j&D8@N?d zm4_bEr4zA$GZxp4G;v5rBwuJeK^)3xJh9sT_95K^YTL%{LpnMndT>*4=_>@B%UV|Q zsK->BoC)hqI_1>HA!s$YBdv&ccnsIGUV+^l2Kripx8+;mGX&4XVPpajH^qIZD5cV& zqJDjuFe+0VET&oA$GvpEkz&PRs8zq&rOm@B=7tM^si3AhPT<3E#)H>WaBKJ&&`Gm9 zy=&s!;ZZH(I1?KpTKkb&^C57%TN5Z==13G!7s_c69dVeNfo4g81+wP6^_*dK-g>51 z?B0lSPWbqs)fQR;qe+^x`_APAz{}3H~NJFezW{CFz>>t2u z8oBim7bYJKFFO&;e+{te;+nYL%zqGG)gNypZNlu(9ormVVmlJ`%csK0gXk7OnhTWD zXHZL}Gln>^;`lND&0{7RWTXAT&XA98jd_JOux)okh>ph{?fQR*$o=|JchlR%4X!FCJ z3aDNs%Mt$36KX5?)xY?J`WU=FC$&_kz+dubE!BEb@kU)F3!W8`Vy&h32!{l{Wu-JNn|>_9&U4 zf3SIb(T8U|ie~9WE845&UA4~WMYlYPnsg8^KHZ_Tt!aAE($XTOpV(euHV@Zo8m_b& zE%*49(&xPH)1s9&PnWhbQ7@YBQS_r;^t-#LI>yz!W9d679Yr(So>djTqN8eY_4|9h z{NON@-}ET2*h$oH)Ty+Ik$O>jC-pHt>^YV36P?s5^h@E9oz)09yRO?=t%{_to}}wZ zuAZFM6H6CSrKz60q9?PvsMYY^Ha+*doxhkY|}BH&q|>YaSB<|r^ah0k;&A3978|#Q4H)Y8>zwNE(X|AI!lyOfUzOZO^M#c7H?nywFms=hc_74%a@f z)-nA=JZ^P3H7FjbR_Awms8R48SF5{P9dYdYc2}caP0s7Cj*OkU0F{Lo7~Pu3G`1Ti6N9^Xm@%9m_Q{le1tMyb{S0V*4{J&Te ze1q%biz$jgeuMSh(rDV=tA! zG`N@AU78lcV|%GJ%alIF`}fAXQ}|oG0oF14dj7b#+8izcFZWjGnLb&A9>PCR8GxPW zqdsZ6Py$LwP67>bXbiveF3`PqU)2OBe$)L!*^t z9@T(pk+j_~lJaPY95djo&oaZ^HuxMZkJ0JRCHQEwnVgrlcCdIqU1fl2#lt_G4|!&P zwYuWjHD`nTWPdfX+Bh*m;$e)vt(PCtaW^Dr(-BwX!aUoR~c?tjkbi<+p_eX0faPR9FH6Vb?Zw^qC@X1Oq zsYyZ9Nqzn-7kJ;7u<+;dkuQlZEq@6c!8pGACDjJc|7TxPV=XubfxD*CLGw5LWsRe@;WBE50U%;j~$55j^oV+ zsv{87wq{T$$W<2De#R%1YGG+Xx-`*>!(-M5G9Mi<)XRZ6+v_7CWDSH;7Q49#Xv!MQEUV$ z?wyR)JVRfdYm>3S5Aw6g>S}m_-|~i<$Tttdc6E>MAEZ`@DATG=$%Sqpi;sCtjS0x~ z!3j9Lj9M1(+OMgP>tAsa{86u|wL|pJI@Khbd~|C6-D@gyec$_a@%`qntDif+Z>1QG z6eQ4J+XpF_Mp<_-HkF5Tg}*jfjPQfO>XZ7n$%i3ESUgy*Z`L;(=eG}u4)YE}R3$_J zH^lkixU*B^hm>~e(;=c$mxri(^-eVeJg&c?R?vB!(oF}SN*b!xGwI9sinFPdp@P6H z8j59lkLM3nD};G=UUX4FF`d6LObz4ZhN&tlHW~(Ux`rnYQ|kb|77r6|gHd=~->yvf zSlF9tRg-9oa&6yKt3@rK2{6FnQv#f-)YUyWkgv~%mKl7;o7jrR>09UbZ>sDsD+_Kf zb~tcw9IrK8e0;!gwI1TH&DWFs;bQUK(w~8+Qh4(bY7DyEdjzVF<1>)NVlOd3OY99R zx)g&AOfx)b(Y4N?3W3_fz5L_|btK%~_IOKehy)yn!dJefw$P*5FG7f6wVvyDmABQk zrTfB9Z>!||HT)e_Gp(35Ti@vVy(2b)8}FzM5WKJENcBayW1c+{OK=Hyj8v0MhiSus zj~&`@p2C(<|6O%yX`4U4E84^kqw?yb)M}>F)G*Z4y#FZCaP@7N9?NJo5v?~Gt+vA; z$B$O)`|93R__ooQ=xqMeXi%+89`v4C0iUn^p7{K;@8R=T>GSdW=d1JF_XLA*=sk6? zK8aZ1`Zhc8eRa5L3`Lis%GP_ z2?W)At+bmmI_uQKQW=}`e&azipG#9)W9ckPQ(s3Mz`#jrUE~BC*JF}82OzmL2}rw! zM@@#lE?+&-xSbenh(ZWI0`LdM5>QZq)VwDdyLK->flV8u3FKLX46GK z`b~$JvYg)sz-WBx_;f6Z5A}Y9W~h<+@A|GUj?Yk=nNkQ(p!nkZG6WipSr2Zn$_%wA z%EJw#uGcS82{z_z%SxU!6Px}T-esnk$=Q_L=7(p3jx6ILv(TS4yv{7NcMuV$)!Cri z@@#c%V961}JbhPKG8>!!st_JC7g%*|wp!kuX*frXkv?)hd2-YJ+i%ZBH&^k6b6syEh|^p(!udSPVdiR6$u#~7*xd+#pvwn> z1oc}CZe{5QAVEv$NflZ|3)RIg5g=_o=>Aj+@@>JBFXoGPiWaF2OpB=y&JKCq1+Io_ z0TP)D)Q-UZk_A{yd#ObT9{jO|t}4-d)4>v%@k6yg z5WmX`faEqGy+R$0PnELe%PA$?cGe_EwhmGX;t;78cUPdT)Y)W#Ah z#OO6@0iT|&*5c#Ws^i;$vTkCIZ4J1YSmGY5=HhfBbyCvNv{dCobH;(*!E+Du#e@<$*C8_YeAg#VHA;Zn?< z=ngU5&-Cl1a?ELu3U+|@r(;bs8^W(x-gO>0#)L)TeS(j4m_ILqi8j|fwJ7||82=d% z43^dL3=~hg-O67rU>1(a08-5fEiw&{g%8NSy#`kpJo~iy>M>yLVl#R%4DF6h7!X;| z*^9-{Zde>XvD>!^OWbe$%|lB>(|KVDjM>Lb=F;$aIZH){n-wyjE)VxNvzB6A9yi}E z1yMfvm^0mRj|&nU&=?+LnjVLu_y)fWM!)edIALBI+7M<#0u*5T-1tC9f-hUSB^z1Dt<1j61heayC z@}=r|C^?^h2A;V$zMT5JFhNls7d#KnedVpFLtS&@^P)UTotZC$N10KNhBMRo1p;rR znf#onf%v>PxW*wbh7aj++Y(e=$-%k=Qe-ZA39B^EY!ozDKIhXhoYjFNKHn zn*TWl2JzqpfO5)Xe;G<=t0x_ly%Wkezj*}!T4etA z3f5u1X?!KzKSx6U8n=1C#NRX7i&?|C(RDQ-i$sSV^X zdL`8N`R4SM;olTLPP8I<<qs|7%iP`&#e~>QkCb^d zw&-oBYir&JA6%4B2CF&v&G0XGv6}yQGki=C2FUwwhJPEx9ngoo6&|0zNSNOZ@IXPQ z-?Sde(|q&TTd?QeH(TCaqa0&90JyeNP{Ay&k!0-mwt zj4~LNQmk{%#_;ihRgF(=48I+4-6 )C!Fw>`}CehcJi# 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