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 b333ffc666..532bfcb9bf 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 fec844a867..38cf86c758 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 2c63f171ad..71dcfef35e 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 943d21c47b..a5ae985442 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 c27639e14a..55cfc1096a 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 2ad31bf7ba..d68aa81cac 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 e8dd661684..1bb0d390e6 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 9c05114a1f..90073cf5ae 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 48e0320dc6..db84cc38f7 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 e6924a6717..252df865d0 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 5423269bf0..3a76139fe1 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 7154cd7bc1..f11a052f45 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; 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 532bfcb9bf..53841a83a8 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 38cf86c758..6a7986a7a8 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 71dcfef35e..f9ef52e8d5 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 a5ae985442..4fa1695948 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 55cfc1096a..a7d90a8bf9 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 d68aa81cac..2de358fee8 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 1bb0d390e6..c0a04765b0 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 90073cf5ae..65aee010fd 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 db84cc38f7..b0acef368a 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 252df865d0..caf9a91e1a 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 3a76139fe1..e412c78f7f 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 f11a052f45..7129722d16 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); 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 b17c140231..2d85399baf 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 53841a83a8..b509e36f3a 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 2de358fee8..635c5d8d32 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 976debb72b..1eee9cad7c 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 caf9a91e1a..1ec8ecaaf8 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 47ef974cb1..f15958b3df 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) { 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 | 189 ++++++++++++----------------------- 2 files changed, 105 insertions(+), 207 deletions(-) diff --git a/src/arch/aarch64/CodeGen.zig b/src/arch/aarch64/CodeGen.zig index b509e36f3a..93ac450bae 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, - }); - } - const sym_index = try macho_file.getGlobalSymbol(mem.sliceTo(decl_name, 0)); + } 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 635c5d8d32..4e8c20efa1 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,15 +4024,47 @@ 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.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, .{ + .linker_load = .{ + .type = .got, + .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.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 = .{ @@ -4069,53 +4080,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier }), .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); - 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, - .sym_index = sym_index, - }, - }); - // callq *%rax - _ = try self.addInst(.{ - .tag = .call, - .ops = Mir.Inst.Ops.encode(.{ - .reg1 = .rax, - .flags = 0b01, - }), - .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.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 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 | 40 ++++++++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/src/link/Elf.zig b/src/link/Elf.zig index b0acef368a..27e4602ed4 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -2289,31 +2289,43 @@ fn allocateLocalSymbol(self: *Elf) !u32 { return index; } +fn allocateGotOffset(self: *Elf) !u32 { + try self.offset_table.ensureUnusedCapacity(self.base.allocator, 1); + + 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); - if (decl.link.elf.local_sym_index != 0) return; - - try self.offset_table.ensureUnusedCapacity(self.base.allocator, 1); - try self.decls.putNoClobber(self.base.allocator, decl_index, null); + 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 { 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 27e4602ed4..e915fff423 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 0000000000..e4061f5bbc --- /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; +} 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 2d85399baf..4e1f65aff4 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 93ac450bae..8c3f3e8168 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 6a7986a7a8..49f979624d 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 e915fff423..9dbc5e846f 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(); - 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 atom = &decl.link.elf; - const decl_ptr = self.decls.getPtr(decl_index).?; - if (decl_ptr.* == null) { - decl_ptr.* = try self.getDeclPhdrIndex(decl); + if (atom.getSymbolIndex() == null) return; + + const decl_sym = atom.getSymbol(self); + try self.global_symbols.ensureUnusedCapacity(self.base.allocator, exports.len); + + 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 e4061f5bbc..caeb3bfbc5 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 1ec8ecaaf8..8fe5a1c712 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}); 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 4e1f65aff4..360dd4d1ec 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 8c3f3e8168..200bf3b8e0 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 93f1269147..df24fe5e7d 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 d64c09d199..9be5b9ca3a 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 65aee010fd..dee3c7c381 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 b1bb292c62..78824eac1d 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 9dbc5e846f..2c55e55f83 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 8fe5a1c712..543cb473d7 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) { 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 d1e5683c98..3f57b42bf5 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"); 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 b71b17243d..74c7d43dbc 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) { 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 662bd09cdb..8a9de7bdc1 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) 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 360dd4d1ec..713680c5fa 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 a7d90a8bf9..342d6b70cc 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 9be5b9ca3a..f9081499a8 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 7129722d16..31dfb87659 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(), {}); - if (code.len == 0) return; atom.size = @intCast(u32, code.len); + if (code.len == 0) return; 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 de9cefebdc..20f847e475 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 { 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 713680c5fa..dcdbeec322 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 2e57de2406..9c553a0092 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 f9081499a8..668c5b72e3 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 e412c78f7f..a8b8caafab 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; 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 8f0bcb7b96..6bb0ce4a1b 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 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 f16d70da80..92afeead90 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 2a590fdf15..0bf0797587 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 }; 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 74c7d43dbc..32463aa30e 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, 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 de3ebe15a8..57d5beae56 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 bcd0291bb2..579e25d416 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, 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 8afc9c859b..e51d4a3ca9 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; 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 200bf3b8e0..0efd34937a 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 { 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 d8c327829a..3708c4fe81 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(); 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 68c20ea49c..70c62a1faa 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}); 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 69e2f1a37a..8e2d9fe3fc 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); 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 52d95f2959..65b9fbd92a 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 6ab689ad7c..e3375ccb72 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 73bf3fa03b..4db6176dc0 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 0a81f13d46..6a3aad7a99 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 fb9698325e..0756d9f731 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 70c62a1faa..eb0ae1b1f6 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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 ZGdj}kX8LRtWnr#Te4Alux))8_07ph<5| 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 z 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˝U(JHhDAXU#|DdGLF5?LoGvELZ_F{{ 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
dkSYKSUJK{DPO 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
  • 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�W)F�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 G5()qw%~ delta 655917 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

    M10x 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 {}, + 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); 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 213c5c6559..cb37b24885 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; } 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 d27474584f..8004f94d7f 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 3d74e5e47f..7f1957d6dc 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 068fc419ac..52524c5084 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 1b00064108..244f3a38ce 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 f486356491..2fcb260c72 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 8691c5bbad..371ef8fd8d 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 0e3760526c..a452551a0a 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 fdc761ac92..72e7e094e6 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 ebca81be96..8a97b3cbcd 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; 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 6e096ee90a..cb28274f10 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; } 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 53877967c9..895a9a0973 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 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 42eb1abdde..49b0715695 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 bfee5b0599..1145007ff3 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); 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 9c553a0092..3b744a4f78 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 0000000000..cddd91384b --- /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 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 ef4487d9b9..cfe948ac02 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")); +} 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 15b3611a1e..df111906e6 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 0000000000..cde984f366 --- /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 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 fd4aa8ae76..e1521795ca 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 3b744a4f78..712a684bf8 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 9cc5ed3a42..242454e859 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' 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 712a684bf8..b4731d9509 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 762eb284f2..530e5ffb74 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 6dfe0be231..c24d517d3e 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 b8e48036de..871e948537 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 05c4373705..b318baa16c 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 d7de0aac57..d108903c82 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 f4716bc24d..95bba054b3 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 09c496211a..1b951528bb 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 cc1d2c976a..26c1a8d9cf 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 897675d448..471f9cca04 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' 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 e1521795ca..8c7781ee42 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 4a816c8318..21d7b4fe3e 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 244f3a38ce..2300ad044a 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 32463aa30e..3cee30c32d 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 e53387b27c..93e762827b 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 a050e592a2..d33c74d777 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 df111906e6..a5667ce9e8 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 b71d96c3dd..80eb739185 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 b4731d9509..d306c68e08 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 94e6a9a11a..b93422177e 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 6e8923bed9..e5fc8815ed 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 0000000000..20b223b727 --- /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 a2fea4ff11..eedef01234 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' 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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

    Tu|54{uWIQolPJ>g7`wXZi z2lod~Ot;tIbd&wTpQXg9z^K3i>TZDsiXG((9r@frwY=ku>5DWt(-<#I=hWo1=edQj z;wq>qsxrMole3ifCPMfM<8=NeUhV0sTAXTJNK-1ITAX^E;9d-i8PkpFJzAU&iJ)dT zsDS|)D1p@z;I=HJi4E#lvx3S|IaB$--5U;2%jJrg66bVA6)utKTeLZ4wBhYutQ8Ho1ppdj2lcPT!-;DasDMy=+SJ^c%XIdW_env+HrHFYT&+-=OLL>3aH{4tQ%O z&~|^&0N(UKEiO@ha5Vkk&vLwXpjE(82pm|`&+2osGeSn|I5~O2!w-;pRz?bv3qbuR zs19g=@!ptjWWafp@e-*00&Tin0XtuZ0X#^6-2>ot3*aOJ9$lC*z0QzRLl9K_u!3vr zWz3+obYuE4xuzTNvZ+lgVpN~*wVOkKx_~+7 z1SW;c(|4G2UWtbk5loH`K=;DHy6E6J=N3i<$j~t;=_s=CG=s`Xq_P8~lf@BqpNs%x zdJa5`-U4ce{ov06jT>n&&6xh$g42#2QrFy>ZeYnN#|dfzfwS`Ta7#|*dXO=YK~+`_ zrWc}0ECSoWEx14YN}&71z=gyQekC5*hy{2l1SGkE+BVa`HOCwQgyI8@MnR-$-HAZ_$)(5P$h92Xee+gT%O)*!>P=8Zu&+W&P|Nxr>EF*o|l5C zngUvHBCf%d0vYhAf|2p^^xrO=HjJ02+XZo2`kOIz za42wrkAhk;zeT`NQvfu?&#%Cx$-IMI2{ynV!QudNHK=#TuE6E^fIUlr%kc&~Y$TIQ zpYa8|62B`i({#JJTvF3-xpE4bUS?F_0u5&#V25hm0b+20&e+Ga6q-Y>ZC7;Tv}I(x zI6dB-Q;zY<^g4G=d6~S2cIg#rNQ)qMTs4B zw#+6k&QQin(>c636&Qa_*YxIG$arP?X>U#o#!J&#d^i;#4tv3hZ~d)rV7o@$&R*KAdWdSEu84*ENv40vRt)^W#(l?LE@) z<8AgXm+Kh{)?+oJ94%>AaJW5i`ajiH?SJfLz4ydsL#@y7Hwp`3|~H>UfAacb6s zM<^i07Gxy~sM`rChrk6Vyen?T1R4+pl|$fhSw<@caC=b@TrPpy@1P-I=qL~qxR(d2 zaxXJFnRYC91f7oR$OGvWywFvkdsj$ZDZ&1w&T9*Yn2M|0X04jcsI+lY^RR9;ipz#Q} zhe5`2fLatMrng6OPG`J4T|SD_mhs&5*eFg5NtCI2&^#w(uKomcMc~=#XQMb}LAw>- zL~*)KKNH2tIo&Fn(}eNz^!#W}RmRKH`GUA*r*DepRAJjRw^_hZ6f~kPsZ$N>&Vri_ z@Wv}*lIH?w#ZeWg7K4nZPq&NV1|z`%V<4W9yN5(9HNYMC3gMbnT zxcdNFfV7{32jpT$NJK9InQmsrv_J?HY(MxFg+Wc=72wY40uZUe^oM`CLM*2qD5(d; za&86{!K@$$J`sjE@D3OrR8L#sprh z2x_1TDDjvvHGpPLSj@mH7Zte7n7~5<7pAX^(uo6cuoz*!_yPi^U5)v zM2Hp$6bs0}g*Gb@%;snnQvY0U)nC_pzDarI==k%-uP8r4n)7uj`H-P$!mWiB} zj5nqiCvvJY9+*Bmk#m*-s1wGbz~rc+02zus$Ev`>4QVrh=3^0yDIjU+@buIqP6c03 zjs#7~fWo6el? zU6>9*e9L|uGK(?YHkngh_5^qpFu2FhV#ag>)Ej4k^vXf{8k0H28P80gnat_Q1MY1> zCX+;_FO=sNo6eHLDI)-CYNKRbgA`8LdQbv}lp$tJ2SCZ{fKZm>!edPWj?$n}eobc3 zq$bK(9tTe$EcJuuqCf!vo{K`H{so}aUjRz|GYCv^YN6W+E07s^PJw+7YHNe$>~~z5 z{w;;`fFvl@tANriXvkTE>5h;XL6<&@z1!EeSC07;S`Q#tj(o`%m5vpOD_ zuAj!)&kGt6V{sIKOtw##Pv=yd{xOYH5mVep1=K@ibvz)NC2$uuF$~IAs3!EMbE<$6 z)z)-QEi^+wQqu)8IQiwk7hT`sfZjgK0&3SRS3tO;Kb=!)dVB__g!UE4!fohMO%?}G zxGHU9RAk{f%mi5|fY2qM&M7zjKn5op=LLR6a4~pe`uPmb)an1LIC&WlOn1uUbYwg_ zy(N>=p7F@^Bbl7~Lh!>yA&YSwe_WoEMz$LI6+={+1-65M( z#{LXwBOW+AE3z>;fYweca6!f@K(WK9z@h*?8ydR&0$k;R3UfAamGpyu`s{2@MaCJ^ z_hxg-GR~QPJDXFX9@HiW&+dVyzCb;M3u0LU$H4Oq7x+Qdxe9oZrJMp}r6j0I04;8Z zgb{BhxIe?fvlo}PmPD>dskito)pl~6{u^$sK5sG-5tZ0_5JGmPmv%SzzfllLq7nmf2+P0tpkw5U|h(GxFmAF7-SK!5fpb`39PEF|x z{8^xhI&l39%J)K$;c%fW$Mw_eayhLTw@%-c%PAcV8vFyTF9I(bW`lHOK;B~j=>`uO zvY3Ha5JNIMNE9@|3z}8^AqqD02WYBydI#vjKbW7vlW!-c8{~1SGfti!k;e%-DPTe# zr>X#IP&MqCel(9Wnd!!z>00@mit?Z$flc5bIAel#FMzt@;4yy{ke6p|&&ubFXJT3) zFg>t{Qxv?w4;12{HJ97p6oR@j2d7Uf=Co%#F#Q^c+CN>agwvjJ-*o#@PDjQw(`S@$ z$}?V=zOa;2R2AGI2Q3Jk(b*~B$R&W}bWTU`(Zit461Ph^Wtf(BP8TTU)SDh!!s*1e ztqHWYY5Lp}PS8p+RHF_q=pta$xdqdImU8Na?Exh?u-kPN*aS|2_5%n&X1N_fO9Vix za9A~%E(n8z8#Fo!+Q`8VF20089boWG8)PU76lSa%Ojm>*&rGi^<5X7$Wj#bX1JAsG zMuuiUS7w0n-}K{UoN^qXEW_qFt#SI>GEQrWMID_2jvR<^U{qiSZ&{!2P|m3&wiYA{ zy1xl}BRL~vdzC{urzAIgNM&Qk^f~36vc90&0+gn}#rzA=EXU=bFh(*PbZs^~ltIg_ z6QG#|lyE>g;YM!ioX%FksmHi`x@iTc5o8#W4Kxf{P{HZNczOEn3Qkk-5EobnI4nS; z3IdR6C-A^QBq-Rx^MNAMH7Yrk5}>g=Llm^1i&c~Ph7i2(8U~(q;^2vd)l{Hr4jkB! zwJgY!>m0lhpqdKHq@Z*qr)E90LIPhg4)-g_&UEl(3+TpCo_+9S0EtUb5y9yQ9w5B< zs!706SKt@8eSSk&32NH~VNjt4QGG!y3v#|BymA1!NZ~T09n%>Ba|Q5xKRB81Vzgoa zWpO&=a>eb_JF7U$rrXzX@-l9j&RfkX4;mcTtLBse)l)vz zoUx3Tr?0B!G*tyP3&0T!Dy6{nI5g0~<#re-(0}kxXQ|;d<$(tH1pX|6643HDah)(& z_=5W{pcD&fvBSd`+!hQ4g)g`rtTjLXFy@kA~1~;mH|PUL6g^@KmiS1On+R*DJ21lV~BcC7Go2b4sNji;GZs9 z&*{f_V|q$GXYzD!Elyq@L8!$nW=tohKd9%_X9wB9=6Gqk-#;FCOOTVnv!S5s5>#qI z8nFU1pfkA8aDlmo0a`(Cg0yTIw@>eF;8c|dx6(nA(xRX+LEfCCzzJ%*Uu@u<%XnaV zej}&27Q*SE#S*anHlS_}uP>-p`NOX$4GP~M{M$D)a!N8X9+-ZriE};U<>^(;oTlK0 zAgDY8g&=tG%Km0fSq@OP0=azp`W8-c#(&fQG;?Y*_Dt7k;Z#hUI;T;3Eu9dP66tCKsf?56X?xH+OP6 zBk`woaXKM!r~7nqTKIvI5~#KLK_E+DAvozCK;GrUxLnbj#~sw@10{YH1!-727}URU z2Q6I$dF_kEgy{n$BK0OS@H9!HSHpn^?QU?*5FxUK03vhv3CLp_|aOh0x`SM22!7Cr!N z6F^pLf)pH>?%vDk&p2cH^j=OyL2x5dfzc6UwgRgu(~RjSdpT`1KZyO;+ypuIf(^8bMkq_5Mu8QS06=|VP)2cV1sy9O3R(~(X$$fP zIHQ3Z6rd4($O=Jt&D0>K#KCJ1au$}F|6xC;6c@Nvd_pM8@$>Y>6F7~9A;v?q8hFTX z`}CI+IDI{KfTIw!8XI)%6ssol0<`T~Ga2E_xIr}u$Wl;PT;PW;PJ95Kw7)RDZX&0x zJ~+LAqsnm#=#Xg0xWOJ!k^>DDfYJ?<<1NrNf{;}6Y9gn%326SpQ4!MYcQk-D6F_MP zRFuH>3TiUnKu+D$GbeGjGp?EbaS~@5Ls>7VunAfdae2 z<>}T_IPDqlPOqNADa{7SV$&BC$;nMCV$|CHWC|zf0=wzf)4)?A)24B@GG3l8Go5o2 zQ_G9#7p8MgWa>CGJ$VMF3DZ5^>2h;9<)`nM0Uly|JA+daG_f(0vz&3x^!k~cppnXp zmpLsNFHiqClhfI%V^O1k;{gWn^aK|;ZLw=IzYsx`#k`;vD5wQ9K@4=roJ1Drm@ly` z&{CYgoT7Y}85P(a8O)eIh=6@DaTce9GR#a!*#{nkgZ8R9VaxBQ8?NAN-yS@hQ@!I z+vagz15LOf`NQ)0*%kpuV`_Rs32G$57og!1(5M8eFQ%(6;>>2eKYj8dP8IM@w+0Sy zP#j#uSr;5>8pu z9UwtQfnv%d#Ahj|3geRLg-bcXm$0@iF3sPKH>v4 zoE;ei&T=ZS>oaytw_nF8IsN)tPI1P2)8DV<%oDoI2#Rhd2L(kwCPoI3x2NZ?15aNS zYyhX7e+M|7V>+8UUI`7+2YjLQ|c;JJ6*c23#p3pR3QOgGrTY0r3hI+6>S zCf}R>egmhdD{Ph%w2cWg9d6D{wv#5`YY}kNgVzg;JeP1fX*sHE7@tgkw}DfPnvQvL z7tJvjaXKbr`h(4!yAUqAx`or5@!536t(*#xU#>I=I7)#ND;q{6GJ>K5G(m(f5*b0- zFd~t0`u{DEs+HYwhh&!Hv+4V`avF(3t%JoXGdCy(>qeM^ypP$(;hAqG`uAPT9!2AVH*}iCSq7;%s>)2he$Ll39*W%OURN zWl#`S0J|Z5JEw{=)C~|h@bJJDY*8=^JWz}+)jrtFDb5XAKg9!FI>poOPg+Sr6>tL_QLC0W=*6v`n9{pHp=Dl)d0y#k0Mf39OgF zv&!E4IHefxPfy#&>7ja=QQ#4;5*u{%g;9Y=fmfgrbTHfmkt_jy9x>2SdzZIg-p3ir zCNrcvPqwE>niAafj`N*h}; zh&jZW$9Q@A=|h}v8INw?d6-k1k@4~LorgI~w?`f2WCtB@oOF!SjPdF8na4N}Gd|lM zdz|wUBjfY!1}8alK`oGvNR?sxbK3AvFL6V za5SKzVN!pk&}t1%f#qz9pq9@KK~TMPLNH6<{`3jw zIJLPzv*8~E71$N7Oh0;#vyk!fbmZ3EvTNWX7qo_kT44({lAwPsUI4W@QCzbL6w}lU zTnQzpkqFno=AlqyT7U<1%I*STP~goF1_fTqWzHPbz+${Q-Tw-w7?u_R(JgqTtDx{U zM5=GGJ7;?KRZa`07tk)pk*l1+s7|q(wWLwN@jP{V7cessVTB`CY`M-kiShDu_Zyt6 zv9(^AmNZYFaFbJ%qJUZgY5^-E1=InoIh36f6mK1Srf<5%S;{zPy2fqJH;m_|i{9aU z&G>gZ<6TZ0#{1Ll?s85;l$Rf8a*9ot{lUpOUGE;JdejEc)eIWo3=P`x$WCM@4ZQZB zU7xW5-st-w0dMpn_1UDL=EDM&2|f|Z3tFHrI{n){&TWh@r?0)w8OQi)I?n^nD8|>I zX062X`Ujk#qi!1>a^7ToJ3ZKN5>-*+pZ@SJr`U9}$DHDz zk_y>#GSfRBb1E^dc{F|PV@`25%w{8cx+TI>jMHl$b86^9y~E<5AOP-NO#z(@|3ExT z09Lm$bMqX9#u&n*65D&8aK2$=d=K)C{`M8mI5Qb}KJbE??SCYc*j#z1AAH3rJl)_0 zr#$1+=>ab|5A%LRl4YF!@inLTcJr5<&WudYd8co9#;LV^*(*+aM#fLmqaJZ8P3L&S zna;R)dchmcUdHC>|K4ySAEN$40@BYGXqmqCE$3Ip&(l}GOHeg`_B*)$1DNI9>k_r_^-&znq+6P-`Jx;AK#N z+8+0pQ-$&6^ya^u#vt2w{N*%~hT0BM3LfTz)h`I|N^Cd!#~BLpWygQceT;jix^wMd zyfTfE>nh{b=^g($m8Sn-!Ma!&c_{Y+e<(=RXQ6w^R+r8)Bp(C`#H zXgJ@D>4UfeyWhyjdF6h2GDIPA~>1TPk zI2o5uzs|#DE&??U=5S_ip3UI3pVHH9dAZgyZF)2P4KJ4t)8wDirTD{Cnq@Wqo56}*&AA(tqJ*S!k98E#n4;KynAAtbvkh_c%phusj95O#kQ;F^oy?mH721sp9P{x&Dd zZZjNqLrg-kyL>vkFc)ZPHXhHveAEmNcr&6LV2Z;55R(uN2;}D~o4!FYtf1JlombM-P_o*pB?WyE-S zdcOqM9LCGjbtJj4OtKbAa>>@iraA?(AO}!_54K%$95TQJiW4letGb|20}bqhCdwTz z@Pjrrf`Sd6mB4=10qF+Mt~xR(@^0f!C?j$a2Yo z)~n2x<&swh&1OO79YIrIEYQP3z$-hnKxrRz6wX~)u2`fxWrirUPN@eaCGbojC=r2Y z0->v1z)OpCATyPql_sFZ7id8;!OkoI34^?d&2dONHJE;gf>NypQ-hcy zmja6;KWJp$Nuy)A5|5)mnH2-WbiQC-(C!$+{oJzC=Y!63kXPVp1g)Q6q`;-EjZ$Ro zWaL)ZiM$YIITMc-s1RcZZF89J*v2WQb%9@j#gPTHLK77BjoNoWWdL^vI(38AN7Xw4B+LEl_%V5z)Q8*L91K9PGCGSom+{^ zn+>#taLJYFF-lyjI8IJp1~EZsHNphQYM~R;PbzWg!A$t8#AS}dgryJ@7*|ctR_3zM zK_qCaq=oN)q{!*U4~oJ&nt7OFkYViMVZSMykrZtT!bd( zEBs2FylSABzQ8~Iqac^a^t&otoNNzHHVHUtgX(H=eNG-VSfT@!dEix$AqqR`^bh}ZEmf|C#^B8? z&=rrMwQ35Cj_~`)LH^Qbgso}>Ir)Tu8PkmE|5UkDdBK?!lo~;$<8%WxE}7~7YB4tnN1g%kEGh+fT5&|uuTmVua2#yO5P96ntT!7Ee za^SBr&v>ZX}1fk|bGc9Q10kru@UxQ0d7-BL!enh!>R!&dQ z-~#P_>(}5?1+T6|EoYFurU>_%-1Ki6T>R5lp5)=f=R%q3ahhB!K@9-HhASfsXFCDf zMxy`=07aAlP(TC#*m!Qn6Vo4Sae)S0iSU9Fk}X%}Gz&N?!fcU8u|*Eu7Ji6oXwdPl zp8i3L%XfOW4wnMy-rIb)S-?@2NQ>E^s`E9uLZ?5}<fob}h z_dJ@@6O6fZTrM**)hh^UFfl0cxUx7nGAQyp)+WtSSRjnD@%*+K7q1F9<{&*= zP@!}gJiy4R&j>E2!7W8-F^#+l9cmb~oR~b_$(-vsQx~|Gt1#VZE|)kX3uxP}G$S*F z0?SAvHu^KQgGHpKgAOd>Ze`+DU{O#Jn9RfjQ6k;JEzby6Aw9jzk}F7ThXCljK+y8S z2O?Plec)xKdjzI`vg8W(Z2&EN=YpQZ2wLMO3N5cenk zB|yirfHtCl_9}tf5a6~k$f%`^Rt(@1<3QU}rVH3{siGbZ@6D~?jkIF<1^94y9?$`d z&{&70lIb(-xF&=8diGp~m2k{=_oF}+mg9 z@37~RXM8dJhCP>Ra{C^PZW8inJ7ky#T#rJ!gP=weyv;&fw`qEU1DB*2)Dh6U0a`%@ zy83f^zXO*FBaF0ng!o0L8UD4`|l~bh+n+>8g%gGfhz1yt5Ds{T6^y zJ*y`30a0_%sf&=L3AtWj#`Jx$+>+C|ow!sDK(WmPNiXaI6QKD9a)$tD{kj5^BlyA= z@a{~|apuz#oVXm2d+n>7xD*&4gJX>G1voJ=J_or~dOA3bK1E_bo?h?FrK)*>-;C)7 zxI275svI<308>MEBx^M&bWow-aHA55=y2yRQqE z5ewtx=?xxSpj{iMJ-Ff-FHhI@Wjj9*;%|Ujsfc9U3s^uH} zX5bT#z*ccP9%N8t;kg2F^i6~d4X%TZkkAL6m&xJE3u1%z)_~3i0-YZPUiJ${G{%J<~6Eak(;e?3pg^%~cQxTFom8vTcPZ;=mx#ZawfOW`r>Zz(;FBjRx&H639{z zb!34q?gfv>fP-ho^c&t>a*T7PfA{9{)&s?qr~_#r<&N3oOS~6L$41RN#6egEXbEyhKiZ~@@@RA!|(8(})!CZcf#~{Ys3g*gU zJPKyZF~iPN1$mB9ff;n#80>7LKm5}hLb#-ve(+D98^Wc^3*HdJsKM002G{v zch;bmLXr+RGk|)i5W8VRGYrr?jp+nvcLY2G17vv5BDpxGSA=oBpl={{ zgMvndm_XbJQb}SU`eP47sHG$a;>PKYVO*lDsG;_W2ecPT0Fo6ROm__7QkiZL#U&sQ z9!G$k5)R5dkop>wj9DCKew`j4#pMg`L4ykxP|gIG4$vMnc)Jz@sOGsa{X!I%3~0H) zyC^P6^kl<`c7POUp?czb4)8pcv_3cyLN;qcMr=i4BetN?7Er+g_6%~dBRhR*G*>9& z;pxAlxy;gzg32BZrVDI}EIj)dxtScm!$+Vy!@$`El;#x}6@mq3fD7^)pq0I_C#JwAPp*FrD`RhXm;6F*8e01_f<024!K;MlkRo4`c`v zbb1MB^hP*KU>mqG3LffVgrxQp)8%5hoY1aefVGJCK^ifKr%#XNvf@1q@zV*ApY}|@ z2NF625jp@8+C5!0j?0SgAVg>fNN5-M{5!?z0mr#nre`1IRsx+zEl>~M5h#FmnHlnt z)SzM$6tR#!x1da{&xjPUkgeRHN)B;g9@tOd9IVOwgWsGPG;j zvjXFE=Xfp|#u?KS;<=o`d)XlAXD4{m5zbM|UEr`_+K=WX<>_V#T*ZtBrmsril4m@y z{Zs;%3}~>xoOuJk!sY4j61ilg!R=2LO=bq9<|kyI$&Bf$NnD1Yu?0|3xng?bdoC%^ zD0@{BR~*=B;7aF*D6~BU-mlIC+wAlQ91fs!WT!JFbEz_3n68n`CChkXx?3_=EaQ#o zOOm<#aYXD+uxA+efvO6F=}{?M!i<-<=cRBtGV*~p0)md~02QK_r|(VWQZ@qZlyPK& zZpH++;K0Y?K(6+IWKYQHga<^k96`<43)2&FxI#5R?KFrqs3Qn!cyx$nLHB`zTWsKr zxh$%Ovma7(F!`#9ikQG&Zp_q zGP#NvXH4hJ;?h@`f!1*?;#Md^>b~uOw5#_HqHxxn&X&t1PMyF$H$6U&OI4Go5NBMj zSUf#8gKIZ(s2AmP`D+pt>R|1&GP&{?XH1VQ;L;aC5BXwlh2rTxSzIyGe-wa|GfyFx zA82!=IrD+(@kLznxKlAG?Lv|%sM`WQaR!=-HxzL_Q-P#Q9^C0tK#^s-V=kA1ASh|> z5P-BDmn-rrT%P{An5zkNELeUCmn4YpDnXs--B-f(4Lo81>Y9Au12slJ2!hB7f>{EG z!5INObie^At#3@fU&=KdDFnASlyOBe!V@mU1Y8OCUpZF_sB}rG;8KPpVAbhsE4a9X z(ZjNYhh=(SIhXA8=M`M()0Y=;1x}w|2@2Hd+nTr545}VvHxITeNUlP0z39`fdSI4mvgmbe@0$sO*Mhb?|&W zw9Wzf6I6mLffoAS5CQiSE>Bs(Okv?>Ixi~F5k!{&Wp0+b-HsSmzE5+y5k2ph0G9`zCV*o zZo2ejE}rR|8@ZZL2a-a$6+)3pqOIVPXnI~HmkVfTToaccBT=!p-J*rdkP$uR*rAz$ zsF({T9BEpp@fC&|Utw*K__A(Cjj!r>doJ!=A&Ka(?>4$vqTsH=Vev{t1-FpC@H zI`}X)q_K7acDd6B0Z@^AV*8&-T)B)kpk%=0D51cmz$vg4TttJfF=Yj%qywU$4d|dd z+Xc=tA(c^}DhBNOrBk?)q(JQ=CIvPH7Em<@@y_%WQ@QMr)5V9W=wr!_+zO5;MS#&XE|2LBJzRm) zPfr71K;h*1yu!21faqdbR-_D zCi4sdrK{7A%;aii+&A5878hvmW$rAlZEjaU37%hp%hA5jk=38Y0d$aFi6TE}J`hya zgF6MFmIS2D203j8T=#(k7JOI;s}sZYxH()>prM2Xf?19y_I7}eOjY1iU;}MDn>m|H zUh4};kX@iyfk%Pe5xh+bvK9z5-63ek^Z~T&>w{pHY)=V1febnh@~3&j|rV@TC9@&@=U}Opl$zr6LA(AiT#6b?3!7 zT+;FnKn{5znB@p{FkBJD-P145;ZkAxw|DyYIb6oBP)9=4fX5;BGjfA6l>!U26AC%1 z40=-;D@YD>Ql6r;!d37YW{Ug@SEuLC<;n%MLhj9lv_^i;MQx4f&f|Iusu*SFqZYI= z^SNZe=f8tWzY8K*4``S^eLmM+!yn@mX`gfP|J$=UBmI#k&?F^Z+EZY`XsnE-S7z5TP5aiqrk~bFE}N zF#X{+E^&28bqeZLgDM_YN6_I+cfr*Kc>JFUdIZsQ`R!auj2EWgTgfHK3zmUil6_(N zgmqle&@;?nH=~1l*WjxaAr}~d>aG*h`POrpB4^=)tGMDom676VE^$6^hn*EPeE^>P zird2Fc$PtdMc^{HUO_zs4P&aSBwCq44k%s${bK@1;sY>ZcYTZLIhG`TMBL>Gp+)4))m0liY090 zY8V93;JY3Y4QtmE6Ah6>M#C9g(U84?D~S&!W+SKjui=uN{$m5AEeMK_aP;_yBr-mb ztVNHHNN$D5>EG6HT^gV;NA+~n^uYC8QR<)?40M(3i6%iR2nInqG$Uw3hJu;%W6{3(b$6|2in7(!+*YZIT zJJC2}=OJ;i6HR37oWdPD(csuYF0tP4M3h(M%f_R*<^OU&Qi6=64j^U1-cyR0>7mo60@RUyRL`Djdjp&gQ&#e$Y-R{JI z7*QE*$;u;VGSxiHsB^8_^>r znOh-wdfu%8%OS{q4SWcx2sS>%UNWIp1Sv!Y_dy)NJw5*sYDIAS5uTtA&s`SWu&uz^UNm4yp)jpJ5Mf)QTXL$lyMJBe)rtE2e@|H@Y*x6+y>yMA?H; z5u_3s_DEKvhkYuyLhAIk$6P+s7rf!x&v>0Dp9 zvsU$`Wvo4w%@#<6~DI%NIU9LPne8{Tk% z4p$$rAo=u;;vjkco~R(H_<%D=rh$WGdi@)&2LqQp7EqKjstG0v9q5cc(qaD7=X~G_ z;{>lb2VW3i`<2U(@y7K0uUt-yC#L&<=aQIy>MNI+1?V7gb_F(pWy}ifkhy6kHb)M3 z1vW=P_d;Gq1s27ZzW|D8*V z@x=61-?`*sfAAyjjR%!oY>r}Xkc}v~9kUPJG4GKa!^p$Tt-zwVkCA68-8G+pu+*Hp$6)7SsvlH>*Nyns%_oS1&~7ncd++38%rx!fQJ>*%1I#{s$n&T)ZI zmgB}pEdroxZ$Z=1SkB`B?HvFgrw&?K4~hxUEd!#U;{lc<-F5)kf)Bp0i4}D2Hh5(g zXk`m%4FkSo)S3DQuB7*6Kb-YQ_AN}D9f;e7wdg^~Jer06i z;HEXrZUr5~TMY5R^g1S9v0RYdcwG#>GaCO%8<30gz<~s{0^(rax!^lH&>frkkLw;` z$L?I$B;cqInVdZ#F#UiRHxZ5nPt6kTSf~~F96Pm!JD>5u)HmGH;;_{upt`9;(2NOk zz1o54a*W)4jF+dcW#opPfHZwKGdGSXnDe?pz!7vJ3M=T86Pox6Y6a9+^U$LpfuAdR zx&kwIEi4K^j^%`>m+1jzykh*@K|2jWv*%pk#TwIpFmuZ@9-J=0!mYq~ak?dl`ZPU? zg!{#WHvkqT>(#=`Yy0 z*ZP1L335SpN-3~Iuk-{>T!AKCK^u-BcjTaKUS(XaIGd4MVK%75gzdAPLTI1ubkm<) z%F`!sa4%!LKHZ#?yOgQ-{q%L5;5gRd0;fyxEuHOL+$wCZUNs9iT7q_COX~7~mid5+ z0PwCW$QEkQawGVzQSfdb zKnvjK2uwHN;{u(=_Jt1-#{T@=di4r^Yq{|(iEoa3UCYhK<$JiYu@>c3ew=!SCG{s zLhzL*^T9hzKwCS_n9%G;3WdIMUa{#51i0TT9sq6ERA7f*y96r)!E5osMazNd8w9yC zk&YBPfpknAIMt;HaqBUzoIY8ITi5i+W7w)L(Do5c<_p4T>$R zFHF}G;Wk!+HT^+38nkc6aRKoD9XKx@y7HwqTH(bpu4hu zg7>(fth!)at_WI6wja41m`t!7$mQVH+x|<8+k#OMw5S7dkI)0qIz{ldjXR=>{2*uC z*d8pw&CiHDP>>_Zjk0fkha|T@vb>-acZ30G-3zPZ2Jm@fKLpU1T(dbcKvs%f;aB7Z zS#x3fOet<{#uL+zN^z%y!b4A*TLKau>q970A4;r7NPy%pT1FsTeu#)r-lb|eidl_ z4rs{^6~!)RGm-0$;odUThCFA6i_v@-p+xW#m?1aph&4E-1_e zx{v_jGTG^pirmr&r=3PPEg4=&<8>PN>`S7Z1~DJ%G~PMW_bYNwM+qufaO-Tkh9Yu+ zHC<{IaI^&n*z|rTUe-`hF@)Du;ASz=u7aAsO_95Ly1xxK>-6)=+yYE{o2Nfi=C)wG zJY7l!7L!<=cXe5-fTID#dGdPPtRmQ)H~pdtx2O)}qHHrJ@L?7pWmqE+Y9QP_>X6cc z)o}-3mcUW)HO$}=19C^QC}=+iD8=5GzEc%7Lq1dG&IhlFKOv-Wd3vlGx0f@h{Q#*p zA$$5C@MS5m3oHi@_JTJifH%z`Z6;B;f^-fesCK%t{goOwD8cvsB}$-16^86T&0-L};uwCGVKuikY;}CWTOy8}+9S=T|19XWV z=zv86+Y~$YqX}7Pk>(uOQ?U75E8j(ET3M z%eA<(t-+NC8)W|-sB8e8>;+g8mb%>TjF+c3>T=tHy$)%Ii-A_n z-(fp7LHFB*XLGdyfEEbpIh1)yrqE!)H1um4_5-({|~2h!ZwY$vHjSkULuvlFeX^Dey9S@LtOs)889%gGNjhjJP!wb_kd=gW~`+I0PE; zVF4XIzzW(&%m6whXnLj*w@W=Zr?Z{c@mM9OADPqFJCLCP9blK(~NGSE)j(35X(4;DHXTlpR5+ZNZfne~qysvAsg(=VWB7r5AS~l@#RH7o3I~weGu_~+D#i(*(Hzjq zPL}ECjk%qfx*ty$G2vE%-dM^BZF#~13w$~O#8u!Z(O?3n>H|Ws9jsvgg6;uE_z~28 z2m9Xf|NACT|9dAJ$n{{4g2Vp;zXlTvXpflV2_euW)hq(t%+t4;aQ84?o?c_atqSWa z@3-OR=LEG4K^wREr~CDAi}BvN+W|g515`_jOfT%=7ORIIZMs7!%kc|H7TiAu1qt$1 z@!&)ZE}=p31&TNDxd))#1CRkDa8Co=JH~%UJg9dJ8dL}MjyHgM$Ly@&PQ|V1F=pK6 z!cZ5$TF1=XJkubp<3ncLaoXUt4%&(i+UX3wBAZo%X$~Xk@Ko^NB`DY!LAP$75SXqg z#|65Lj^BzK)ae18^=u1{`3<6=T{_^FH26Me(C8P)QJ{e*kfT731Gm?Y-RXdwF#%nv zf8U&2p7GA~|K{AP$vyCZ0%dbeW*P+5bVF-yNycN-7g}(GZ&ORK=2l_6GyS#&x3MtP zdRQniar4XohY~*rB(`OkZWi zt&)5MBneI=H1>M~ir+!@w^?%=F&>%DZ^-C-`54CwqO6wgM28Z0_k@_{nK$7W1B zKs(Gp>3!>mX7C+ukkk$y-~yji0?wqk5;=I-4u2xYv;q=Uyi>uw&l zm!VJ^(gOjNtKgfcLF49-HULVE!?;|r5i+O*KD-HhY#zuH)BP>ErKhVoa(gm&qf{=d zjJXx3+ck6ZPQU5Mt*?xzVL;^%xbOnCI6wt93*`RiU(>anxTQfisW@?mfE%{pgD5~% z5vbrnR21OLQ^6YtL1n5LrsWb+rdQc^cyhGuG6L&CZqQKReTiy+P zYz-S^*b6j*4?2+-JYpsW*+o1<6nqW@vsx{sNs1FUuWZ)a|GZG=Wby4u0I z7<;xqbm2B(RED&3VDpQR;~zjl@`oSZ#+mM0!>hn}V0xq*cQ$0VFe~WJ7c56jJaFUI zRfg16FcWWp&J|$yy1%lGzkN#t3lDZKnSTz4vsF+ z!4%+Rg=jNRap&$}yfIzYgF6Gu%++oe?y%`^Jh=Zu26e!7`3C5qjwt9LST6ASx*I@; zz=F~lcr*Zd&I`EF%>rr;>=2l4>&30kxL|s!7q^b#%eF=VM^=Gi1vUi^fl5$9&|vBi zLYg`F08;=x2pYT@3w)&243NJ->5vtC-W%#RKXB0jIr@3JoHw^H3?{NBX7bBMnZ9XUk%JdgL z+`)Dz0}_6a_<@M>>1Oa`*P=}gZc=f3hWA;0{g)YLU1|90y=yVJiZ0qIS;xo7;+RN=p=v8 zPGImhMGkPU3+e^vE$^VLwgGgg0P3Lkh3R|!xKU2a|LDgJIxYX95wF~IU4L#-<|~YL z(`_BORi|h9bMr8_As1^*UEpC5#F;em(|`DLE5w4*7o?y7jkB-`Y~cXakot_^bOtS} zb_kd;fzP1_RWA_5py4S_$4h^j1RNCw=7N0<4kB=4Zw~Z$!Wq*`1Gs&J*MlaSm<4nk z84G!tz*|<&PQMbs{lpAZWr5q=pm@0>s=(s-gDFcvR)dK_;1H7%n+8*c0;47q3*_)p z@OZ!iex)nZ6AgHzSvf%`B~RxI;&u`R7k{7=SbF|<2spBVX0#k{O#jc!E9Wx>Bq9eA zK^+N&9)1p*j{r|8g6bPkqY8B7I)4^oqbs<_!w!m&3;fe_(s^a4zX{^zmOCH{3M9}- zmLt?oNcso0I2~_H7Y*iC6^2?3k#OZ@=jNF_-8Yz9hVjDmtYB_w>k|TyfwT((S)hg; zbfolz0O(kR8^WL-)6yfFPhFnHMYW-zxoA>pqHJ0SH|TDKQz6_2+^yh>5p<*z8|W4*L&i?X z!iw}zZWsPLpo4Ir2Vyy15Su=K2DjMs3!&UXrr-bvl^2k-0Lto|j@_WNpa4w^;Bpb1 z77%5kco=sSxufn(m86Qml z6UMFJv_rrV)VqNUkxjaVG0=^6q8_Nn1}Z`!vo4?t;L3E^QCBk4`@^}#7#~bu7S64w z10UCe8VZXvCT^Zy=uvxY(Cx;Tr$umgGai`U6TuxO*TSd(N~Ic1EDB5-OdJ|aEN;9l zkYH!wX@*p39iYya=JW&KI9Rs(MslBHGzEnmtK$Q~ECm)v27$%kp3)7_-P+Lp_XSA* z8x-S8R~Qx8);0z3GQbA@a-+FTqd=XS4WKd#6!aMT#=%7tY~MI|kqu}kEa;RyE;A<3 zNd*dAW=tKR_GE`pmSa<2lYpa;0O;yK4uvbz|3q`kGfnTCE*rxwUB4D2#|FA)8IlFC zOeKJ~h(lr#bm%|4?tqmBpndV63)R4r@!&BWkmC_8TTojb>?RJ7o50x$?kZ~`=l}>W z=o|${0Y^sIM&AaZEP>a|ki!7M*#ne$&6p;DJT*Zm%W-<&^iMI|%8D2Gv&@)gfJA2q zWjR8<1B+c2Zk|4H7i4-+EVlx3rBf5jEvE`{Be+!s8e(A8WL|+h4+%NO>IeVy{juC_ zOdGCDcaP&P)d5umOpfZH+Ia2Od{ra?}9n*ubyA z20d2+T=;^cafiV4ig<2Qd6bH34mjI_hYKKc0XL?fiRUh2Y=U(6+ud4{9robVs#Ae0>>bp8lSlKGzxM^jp z07#G%boD#93(F5VZ5otjCI~5AVVr($xuDqeyUE-f(V)o3-L8R7-{9!%f)2;$Fk^zB zA8_eGhkzreKry&VS@USRLkhP%4V0uD2x3MtPT9|j4VBSS^^TAE!8`CeQb8qATHD*|#S{D5p-o!QfvMmo6V&;jxhppC#1pvWhIjzfk^zm4NrOh7z#afM8SwRb!PZ7W zt%W$5x0g`?bXUv=!7PC)NCDFe9@~SIFyOSifj`R;>NbQXRt=^b&@qe){GgSSpj8Sz z&v|5~Z^+~p?qXG-`Ko#(G2zYQAse2#_Y8g&|w%C{Ea0?=rQ3rCk zW0Cplx!lLCKt-^q0xxP?98~{-PNIPv0(<~_JAArE9(RBSNwu!E3rU^x>+@t4hVsV9fe>^YeYef&J99Y z0`=3llpsrEcp0FQpkQTn1dRbt<3z}@f~Gr_*g(tbgt7$Mzzl&bC3XciN0mQZ3?Qp7 z2xoy6?0_i%wZ`DmpdR=)AxFkSD~4y_YF3xwyO5(6i2oeK2aUdi&q4zolmr@o0iQqx z+L8_$Q5EQCo_-*iQ+E1%PhK|gkjZpWP|nk5m@2Bs3mR}{Q(y&mA;1S8gSs2wb8NuF zz|aQg6)`0a&>>eEOc%s3%UNi@2Xw5%ilvPLj<(RQ1X5WF?MkptpTNY+0v?G&t5{GA zRYaNO$N(Bq1Fe$4(k#NX7@FUD!0~v2A9U9kxWoZnU&NoKz^lOSC{Qx}aXGgX2S0dJ zPJwTF;e2k9>9I?>*{8Rua`D%LvcU1=kJWVGVqB13!3}8J9DWVgtHV19Z6= z>_lZyB!QZA5NCtZEy&5r5H}-f1xFy{3^aa4X;9~L`ut2@c~#Kp1&f0Mn}W0gkAMje z3+U<#Rt+Z1Iz(E97qlLRO@YshiA8}8bYUE55sb7MlYjynWRRB4k$t*B39mvu4@e~| zsO=A`G$H+NHZ!I@0t##x(Fch+a2Dc&F5!X1IIh^cc%lQm9!mk-Il~rv^~m?p-32Kp zG5RQsy%a}KDucQcDGtEn$B^sg@J1ih$w)fEu?L?0z5p5&2X$kogDU)b0VUAY0Sasi zJPKR_CZN^Vtd5|oB0!bh9`MSS51`dT;L7d|d@SsRD0Kc8H0uT$Is+ARtf1Lo@KI=* z%rnrY`{sgYbRm8438Gn!u!Cnjpk+5`1Zsn57I<(RWEKnfatF*CPUeEU6X5O!mK4Up z2TC_=3cS;Q-QtmAf~KbFX196xr)y8(=H+byI|F)42dHTax%OeYSw8nuR?s~UeA723 zamh}9KSO|Zx>EtSsWYf6&gyuB4^n05GQ0=3n{*l8f#(=>8Q$=NPL+h7O}}2iEpH8NNwa{89Cnbh=YpX5Mtz2-f}o4!pk)#d zXxNC+oEfDqm~L3et;@vXFx`GGmy{Vdcs1q=QBbcHT-Sr<(gaG1lsFv)%9J>)7#I{- z6gaIJcoEYeml@5cZ~Vh0HNCuun}2$}0VjJsJ4&A7f>;keUYiT#LN3rHjn)ibL8ae! z(JTe9vEb$SUqDR*HZ!IVAezgJ=?!RP5t4pb1ZKc0X3!=cXpnPpD{w0CIMx>zIx-fr zIDj*@L3{lv;;W=ztE{gWMIw&8+~+b(5GCIY9Z4%aOlOf!A^R z%pz_@c`j%wVOL-UrxG4er3D&S1PwYWU7l`O#VtF1WeK-R^wQQ=0Y@cBZSz7DvHlub z_rn+6qNFP1oe7{u26)=!f*2@Sfd@mt5qx?2#VT$IrlqaZ`-{2Nrr$5;mYeRoh?jl( zf;wK&>2qwk#iyGYa|)S*>Qu}^8MKB0RMvtHIfLK$`0-bVfTKKU(1yujI%6fbcs*!9 zUV#(bUjp}EKm#?9S{B}4x&d+_cq$yjg^ZB361ePv7KoF;?UE1RYfUtmUWkISD)_W_ zPKD_ki+QE$LG61`s^x@~irlcRUN3K%?qmWI6*hxae&f4sK(=j)OehrIWZmuPSD+v?2h0|BNaFW92G$0 ztV|3FoQ@({3S4H>nM%05881)wD*>+zLqztnrd9z*S)7p#U+#xDvcb#!FoF^i*~^-y zJC$<(Vw^SIwv5}Aan|(aGH$zs27xRE8%K^Ta5RBh&J(}_5(t3~uz&zuK*0vA7S!AX zHF9~(nHPZCXq;wDEue$sLF;fJ2RDHl7W~r{%eh_Z7YJl2m?7J;0W5%I%L=dnk}YOn zTR=-OLCuRLAftB(WhwC~zzqkjw1=FqzefmM_3>~bWjoL<017;gjD@be4Abo@xUEqF z-BI8zXhPc>5#G};@^g!T7vQ0X@N~mUZc)g-B?f2#3CTZQ&0axa};&&!;6x94%0IFHo&6q&be&E^yl=0?>f(FVyK;1U|Vi=b=+Y3=g21VZKzP_B| zA-rIV89`@KDzPI~T(Atr3aY|Tox=-u4(J{NP~!*G8kr%QC4l6d=?w;)61ocPAdexp zHL(_JyFkU7^mK({Zb|S$x_TlCG;kvyBNyT-&>%LzMnn2w1sZq_^$T#p1})H7G?*k5 zrf)0e6$O`SEDj2s3S0{8NG)~3g&7Z?!i) z7J3T{kj@5p5)-^V8)>lvs9`Pw z@2!FMUxS*Wpl$;A3~Yh<;FceFA_6pZf!Zh8Apkqi7QIi>42rGkb*cKJy7LJfQ4FA=E)WK_PEjKaHfIMKF&EAfILM}WnGvGW@rPiRz(OuiCClOfx`%-w zh?jACZ56NP^bOoxtVr1#zIh0|!~}Q5fJfRFS3BOj>VbX+mL zpod#7<`zf<+ETh9gqUK1HjBZ7N1$#QTFk*q4DiMX@a#I~I{)bty11nv8<9Z!w@yuu z?&dbvhuR2fbGq`fa`SY9=Vt>z8>HDlYmzU+CQLyctm)eVxfP}x$Z>Iz5dz>5Uz8A- zGNBO`0tdh$Ag}}^A_WQ)&@HP2d2yS za;q^eneNuht%_EH8YpqIOg{+{zdZeYFSjo0ZIJVzX`IoD0hX3efbOV(o$wAC83v{0 zfIej3G)0p5D#jKDKWDTYp(`);=wNOvdm^WR1IkyywkJJU`A(zl~JkUE{ZRc`9 z2NwD#aK}o3b1ZCi0;qifDS>ZHXPL;YQx7U%L5u1jp%FF*g)gp zP)*>GZ%{G12;No#DF+1vLH7=Q87Faz3tj-vZ6S)0`O`HgaZBrgrdUBE z``~Rd>{blmWf!0|LZJ2NpeZpi@PZJC3r|chn#66WjZ(nP2NlMU;0KL+JN{~E1`T2F zWdn`t&fk7+61O@dD3D~jV1x!%K9+;jy1$Bwmgelwy#E_5Z zhZf|HI|QbuP34wz11B05h{d2YlO1^lmceHYAUi+7dmh1CH67t5p^b1&KQ)!xmGQ=O zfoa@g;^3qNs)#@_!Q{vWsy9JN%61yJj@X1VlLf$IWcrM6KrJ1Rx*z=0>!)$c)q~@n z8N6T=GFScsJlF(YG=cPkN@ym>n+%RO7!=qX84IN$HqH=$rtK>r zPlFVKYJVoj&!8?Tct##753c!{6*$1L1G>XWWjePK)4rDJ9@DuaAbl9rvlpgcoX+il zRl;cocQoUT>GNiAi+jSCkTRJuT@VJXI$?pVkWyfEWUyj*A`Bj_Wx4}OB9|G>nXU+f zTlk=v4N#*9bj=`m^!NJoe>1psK-&d%W^#uxb?lkmG?Ux1zGF|90B8e*0;_^C^oC?m zn+7zrnWX@l)?v&NI0!BnzzcOiIRF$;;3fm)oO?*^?8qRn7d+4jy1fi~vm0m~?0ydL zj2d`o51bJ%@C)n%_mxiwC|+h%gw|~PLDeZ}eH{AY((>sKO*rMISI*-8i&UaN5P>#X z3DjxemOQLPuV26|$hdd$<{5cc8^XkZKq{8w6^4 zV{3sBioK1~trv2e3q#F@RK?)Mt<9hTZu#jvOSwf+YAsdB@^{Ha+}!oBYJ&x|{T4ia zzXQC+3tTLMiVRSe0hbFPNl>=jA)v&L+y(@%l0|O&fkwkNfR{0Wt18gY4tNWS0-L~c z@G#~aaKFxR0%Mi}FL-+x$k-X80xPC(Si~&>O%FXk3xd^UaI zVs355zthhy=2m6uem(ub0&aQmo;KtRGJWD+Zb^*HQNNg5YI;8}FDK)(>G?~z%^Ckr zU%rIfSh)K&I0mtXatGte=~I_-zl3iY105R$zn|s>cslsR^jXWe4HQ7lawf-(j0)`F zL-zF>gQA zsRk+;KvVhPTAB^C_6bsWfpRx!LL9X09&{m=;|gvM#--D{R&dMXSZrSkDb((*;I@UQ z9cb)2t^uv8R27&DUK*&+ct8NuzyKBdpv8uYVxU;wA)pAlc1T|kdZObN8;-f@8d@|J#3bb~cRMwF+Quj01ixxuf*1HR`IhcM z2s&}YamIATwcL_Sb52dSS<5ZQczJsCT5izc8BJ@sTOz@2Bn4>&PJvLxD~wF_3Vfil zmCKdI0W{p@Sg*(r+9C$3sJI+ivO#jZj*Qt#V9`QuMV95DjjfE!6$KQy967QTr4&HQ z6onP8Y>!{ZoyEwwYWk`5+$xMWroUg$Ei3v!REY;P@&+0^0-LG8;kbCZ;s)*j@Nz*h z4Wf4GrbO$5|V zW(C(tpx}rES=TUKdJ}h)@G36QATD^)Sy2^a-w*!j9hmf?B92rYG*; zwqv|JeZdZHb@0k*l)%V>4yS+{q)ecgx-e}Uw?_2a2@L{{0vI8q1i2In95fh@;{ zi4CAN*m=j zLCfGz2u#0!kV9D#6kUiL)akOf{9YfGf(U9FqSHZ0sW3)CYxGVsz{J9|nUeSWE4`edb#=CpD&4r;hLShJf z*H$fPY*c!>(>`uP#?{kH_Hi3qgBH(ihaE1*3*ImTDnu9^A$z?*JMzI@G4SyN;F5MZ zG%+8-(${A^G(B=Z_a;?PDgk#?Ae|5JFdw9a1nSy@yB`8;rW+jKc5wg?KZ80Ypz#OL zzBEw53bk?u+O4z;z#U-l2p^)d*>ZqegYm-jy9c<%)gYa>Zwv}-;5Gwz$vujr7cg=w zESN5Jkh^%gw-%>>4#=UP=|ym@4?1@cG#$on#Q+uuMFqswpf&^B^t&d!l46i#APm~{ z3|i3#vXRsA(saLnJo08BZ-6?D!k}z>1+=>yBn?ToYr#E&8(6m4P4_*-odb4`0@zv^ zD+UzjAUR|D%R}7q95V!%>J?ZVk4!h*!6nKKN(Z1;5v${j=>~_n)nKmZ0C&hhOP9di zGq@{QxHXwU4FA13?d3yd4ZZ8v12t!syuq%M3m_V6(9nK(Q zT&~E%lLyJv+()?u8P`vjJ<9FEz8*Z>ac26#W86y9yN+_pux|j19D#_OKgun`xMBL6 zquefx8>br{<91=+2$o+1k)L;rTZVDd^xem}T^Kh_JIFIlpbL-WE^n-mZ@Sa1F1GF#< zIY=RS1#(Ixi@;`ZXq-UH5^dnqAi)baL4_!2U6SJlP-6pfSOfZz0&URoLr6Suf>JOj zq_<2jWaO2e-g|tzaABNfwmvr*A*O?ZUWi`kxcr$wDZp6r5?M7oOw>T}j?| zl3R`yR5fm&zVRfts5W?=EW}PoIy?qGjten4!U9>E&7g33`p1*pVL~4+PZj`emSSR1 z(0Am>a{O_5dgLi?PqvMW)(rbart4;L8jE;>Bs#847SLc~0L_?rIyPLH{{9qqx+o~u zfm8nvQP8L$D<}afO}EV#mYUvrnp;c{n9?)_Tl(LY@MNswu z&malxnC@_v+bIv!{b5mH6letZHNhj1px6R?4O%#ZsuAc$T=ZnI5L!}#lPXxb69ZH! z`sn0BMs9_L(?6W$jz%4X1&z!>Qu&SP$>+G$d3OlFy|zPO`t)<$3WhgCp^HhNMF!Mw zpi%_1m=xM~f}~^6e(oKhX)WpL%;&iiO+fXUF2e&MaGn7dQJ}kO1&)BH9O3?fElvj2 zObVB$&p6L*8jkQ3sQCzA{f+LiMbIz+C1^-}1`h-Die(Wax5A?7Di^q~F}|Pv`vUhN z#wFADUF5c9Ts8gAMebn6CDQ{gfq8wGz`REgp2B4?ujDdVZWDyZb_L9HxdN7(0pVSP z@U*Ui{8$gGE{x>)g3aXHHM=y3Va>0BMlF0V!iQV|u}&z~%@M`T`aD0HXQKn0`Q{ra!*Uy^8Vj z^u8P1`JlG!{~O$u99PaY3pg?fY??#cR!=P03q$ z71;C{U$9R1yUi^zef~{u-sy3-xHZtVEW5?6A_{TFAJBz+>}E_qSivrve*YG?ALHfe zdbhdVK-QPt=047NdAi*l?gEgPHr(O<$i9RdWXY82KkstOO+R**dm-bJ=^6L9D>+ty zCC;#eY?qwQbf3GGamn#^Lih0N2Gyz9iXA# z1Dsh3Y>sm{LCbEym%)MrcYp<_Km@Ncnlpn0FK}jod&D624NlN5Qi%8iPS8>?Fk695 zlc|Lh-1}a^363J~N8CY-tEbO<#Qm6Y+w`W#+-8hRrtf?Vc8B5ri(oV^Xi^* zcQVeO&hd;p9^|uUV8IK|xV_=A-@^-u{T5!Z(T2~t<@ok(Z9>GrjOp<&xTU6-Kj$`K z*~+WLK7Hd0ZsFVhvI7hIjb@+G$;$j~=0xsyS3;4AJ4Ao}qu?pVm08$Ja# zN6`6IY~baf+oy-T=GFtLXnD<@BM(gqAnQOW5k!LqG58hO6nNJvU7pVW29g@W-+)gH zk$TJBrGDo0WC75f#%u~anoJDl%rE#A*c?CbXDRSF@(Vzc$QOPk_URL!bBj%X_?BCf zan*M2ciei6j7z3ly$6TsqW9d3;bFQ(5E7Am(jU3gAi<~19rF(a^(SAk8F`GBI*<>_nx zaH~QS(GqdcwbN!y3qZ868Pf(3EdWYHAOCQ>i9k}?8IT~08Pf?6eRaC`U+!;=m!~`Z z@!Ed2Bq*A3LNM{M`n*M^5N1kcHtLdCvJaLTMre|>RXn^!h z;^K(|(Vw_@Qb2SBH;+2w>gf&KJUSrmI&Pi^kdRTjJbfw;4=j;inf{cAC!g`^^iW4C++P5x{-0#B>oU9#!y|8o0*+ zYAi$g8<1<*&j={7fm{L_YKoQO5l;jSK7f`SgZCC)5X*8ra=t^rQ4O>J1U#b**;zIL zvQhxf00* zu$?UM@hXr*Agixnj)3R`Pim!egH9mxvoD@>mu&6Cb}c$y54 zmHc5wMHZeI(BNDHE2zw6QV?`xbYv9R3GNoRK)S`%GCXqZ5RpIAAMWB&ntn)zM~-pl z^oKG$ZcvFg5QzX;9vQ}6({p8cT-bMk&A0=RxFyTu!V4;f3=}}FGiSD#-oP#-J-zP& zH`{cBCSI250dhQR7!Pj$E63x+C<+=pp2DcW4ed~D0WmL64^iNm20EV6fJbgRry`F= z{GNZ1O?-}witJ1d3f!8^F9ZLyje3Q{V>8PJ9pmX`Mbnkw;PzY6(1mdGbI$SgybcI%7k0x?Bto8&@N*0=Hua zW0pYE^yi8^%NXxZ?^EIto4!1Ohj04QWFFD!MaDd0pw$4#roUF=kz~9-omH798QFj$ zWu8W4{$FLDB%{lqi4AVY6O35`%ea(SSR9xf6j&5M-RA%Q845w!26XHPiz7>k5(^~O zr%zPj5l1p-`z95hSVqxiUL{^|XWNyRfm?ywaRFnNK;!hltvn)(P17yacoaojc$GMD zs%TN;@n&qDenE{#jS-?vvx%2S2xQU;CP)h6c67)VXyaAj)@MA!1ad06EuQK;&WtOj z_p0-BGB!^a*Wg(!3Lc^cH}D#g6u2E59x-GIv`jy*!4uBdK3!dt$BOaw^dwClZN|^j z`!rzzyGfHrR28!20TP#>e8vrpOXPTDoNlklqr~`nI=>c=CFAGmo?1MyP}egyP2Z!% z(+K6UH1YC?fvlCCUaZaI%YP9x#Q-{QhEIXlam}OY=e2ocMLvN9VY!}Ller^R>GCuk z9u-~%q=J$ZFxSF&ce;SN^IaH!Qy}(nV^yAT;QVLKd;nC!%;3*b;C4Ll2vi$Pv*H0S{Q+mw9f@FN)7M+_NHG4J zZfnJ3&e%J>)QZQ3v2Xe&E1sjE_E)7fkG5(*xQLs=0xjY`FlPzqV}|cZYaS(#mbV}+ z6Tn)w5YS?4!z01ecX@ia4Ns)wL|(`?K+wVLpt6KTK?zh&GBGG9fkr2o7{CYVD}j#B z07Rufw`dhbkL~LM;jhNX`boSBoC+)o?2b&1%mQ!@iz6$7!{*42;4nBcAvlbvde{&$tjKy8 zk@c`TA}M32cVt0mVn)@3qmVto0}kgeZlE3aV?7{lSbJL@dbeV{l|d_z5K>QM|zbb`r=Q9|d+tMr7j{ki(S; zSq3G!y6t|&71;RO^U=JasC$QtDPjKXs z$$_UaG%JwO0a!IGU7}clVmXRePyz-LpFB*{?0Fu1^2z!ehcXWxAFtk1FHj=>e`hGK`a_=eqK^GESVn*_B6GbTY33 zuY!RBOE%bF3hY@590HT4zXqwFI9_nOcyt*rPrv2HV<-x98arrwDjSqVvIVA2S8xXhm$f^Ol-y)q1tkRoP(=ai zif}uwfKZ??;}Dp(z1W>6oRM+*^wSPYf8IRT0X=@;2w3h1j;X7D zJeDd~7!|Sqcq0X#AmR~QxA85J}^u54$7D$;~HlTG0y zBgmcYprKTd`vul2aDsD!;^pag19%h}FHip;z@wrt4V;reu?@~MVrEP&$qL+{4XX_x z`to$=Kpthu*~c-JThr>c)1mL6~wX?*_a#@jxn-;V)`f} z$Uw&z0^p3zqQEWy2`VK84h3PbUqSvBQ(#x%$Wr1}V9Qou6PO9MMoB>ooHn5{V%Z8D z3Syv$VhrK|9hoj2#N*63b$Wadk0ImC=@Wx^E-+5qo)pXz$;dcy`koLTFQHkyN-PSz z*@|r3pu$9fUtsEViBO)qj1#AS3+3@*oIBkyj7O4j>h$O^9&HZL8j!XY#mm$C!gxT} zt*j2?QDK}m{X!TIXffgYFdk*`*}SX@+zNVTOh-VT<}zbC0HQBX*9_;8VVpDFEu3ej zz;s?Ee$diEIgnRa1g1`ZAI`Im()koM;{+#x`)DT?8>u!OO!9?Ga%g$Iy%6 zIWs*mo<{_^TObk3qbP@UfB@uW$N)%qERP$+MQX@e&&Be{LtTL^EEmV)C$kh^m!Tt$ z=ce2;wB8I_x1v5C+>2Ql&m)X%_`Y}^U1a{(c%D$CPMtKkBOUt@v^~)jd}JmIQU?{S zU(IOFjBgwXSGNv4hNK9!0@jIRgpDDw!Mon*eYi!5JSB|Fr;8`?oMl`w{b>?UF8`fp z9RiM^(FiUDVbEwqVlt0B}~k{HxLh^u&u6rkpc zr|_sT{+(`@!jp*{cpFoA4$C8_AAV3OM2m>YsXTKSe@!K65*+VFfQ`G0o)ZWxPE7a3)VKQ^%F*Mp-=JObu72 zcW3d$AO>FkX7TJo@XluQNb&BtGFbprS)X77Z8Z6k%~Qqrae96Zj}AiJ#vGn-1WzuP z=LnRi0rrF{Je*#zfkx}N9XGIMK{l^&YcM?kn=7BkQ-opel{{o~9rJl~_`$B>b>smp zEd{x!CZ9)+6D%kN;x5kT35D9t*fgE5fF~Nkt1sZmz_3EA5ZQ|9g*@^YN`4md*dk2v zDdLGh@OBmPL?L)u#XKsI(neu=eld>%LS|_(j~{}^S;AwA;Dwa%^dopbOL*K6ywFk} zR|IcEDY9c_%XpNTHh!7zR0ekg4>-KR>5_?i`oUZtMW|+7uml?@BEYHX1E|V(`~gWk zprac==?R{2rYn>qTU%YuVh;I zwQ6{*n08#5ez$=q5vzh*H9TI7J=5nj@`PZO@2Ta<#wx*8$5V_|VnQ9yTz>Gb!`0vc znjS7C&FPLUJYHB;&#dQJfK|e$fyWW#^8N-MUB-pe_crjzfw(w564;2}Bg{=aMc6Fb z-qFOP#fVL2`q5^dV^}5TwO}`Ex^gQ|D^?x5aY+QX@swlLakq`99;-xtJ5LDv8gS5F znI6!=>f(;H^;EZ_i@1_~Sk>!xeW;&EZ@o}N34#|I&Ja2AgdWB2qgvv_JjMzEn9(J~u{ zqqXPoWJ_Qv^+3fd*L40m9=Yjf=I{hyGjzNDTpm5_xxQc?b{}v5HjhUIyB6IAI6`mr z0_=Iqipb5#?yh#tm)5}@f6{zusEPK93yCil|9RmPhdUobcrQA(O6CTw45got3>e% zo=I3GBv$g=z$(GKisu?ui8rfo7&UP5^;9A-5r&H}hCRny@S& zU$t)L(PUgWef?&hNeKPnTX=F2yjxp%$`HJ?tvu-n-s7!2PY}Gj+jzp*cZ1hNoPn%~ zh}q6#jj@RS0{?Wze>^tREqC%Lg0GeUpMG>h$dSR30o+g**aKdck8SNdcw0mWWHox^ z4juzV&_Zm;1_T9G&^8y)h6G0`D+bWwbCCFq>8p0|=-Pr8R4agYZ=i39)nJ0$6b4?P z4cd#_4L&Xawz&helEz>ckDD22{SOD|&Kw2MLK*PZW`Qh1P7Q`Qb=^)L1MvPA(AKYu z-#A3TyGx*(ZW&SCg>JDa$nD@QBN|NLKmv6@2-zD1vG?RI9?+2iw|DWlFz%hMu$w20 z2ei`2v4IhEa`uerO}lxF7%xm;^`A#t?+WOKDd_SW&=r~BRsEchdlNtldEk4uKqn5J znEr1!j}+*BFR48|OBD9uk1#)oYyRxvxzD(N`klQzNsI@k+wbE^(*!MI0_{Qu-FgAv zPqy@E6Zkwx$WBP`y?>XdpWDX+I-v=4#GNN-VLfOK3)W+((T#!j{UgB9#;*w7$_8HH zbYr^zeja(o2h;QS^N8`?5mjO|W0C=#J_|aiWAc8US)es~`UiNl7|%?PI>1xL)Ny9| zr2{-hjQ^*z9^{E&JTX1)Adk2x_$n0WsWFZlgt9<3otWNrkf(?J$Ii(Djw@bImp#NI zWeZ9{ko^YWGn7Cpe@wC*S-`zZu)?EX!BD?6faLtJjx>_23{k_0z2^b0zde|^2^gF9_5kpz03$cK#;|n;Vx*W z=6%qRC-hJ|Rs~KghCBS=^Lg!6*uQ zl!UO zZ3ujz2W&HM%t;<@@J=2DaK>;v`gFSVDIU-rf~e&QE^zh(-K>6Qy4-0VO-!c? z=s^z!MR)r2`qMn3knP$aw<4Q#^fZq-(226 z2cT5a5ZAH6kEQ@0U<5js2XX===yq8Fq&purh=Pvq2W3%Eu2KT+oV+nT@H~$u__`x- zo`z*Q_|8knb}Y~p+b7}M{WyR@9EDj@)$CnoGx*R=Qa2?O3>x!pu_??#pnz;O2CPQ4RZbYkLkNK zxTP2`On1D@BUyijO94Dp3ErQl#G)Vyx}8B_KeGaCE3G;627U#IWzaoSyr9s892~>y z2=W#9d}ipjX7u|^D?mqCLyBl;RkA425NDMPLICE!^!sj59nlw=?hNs zNP^FcWxNbNs$hE0X&w$Xu*K}t^V4}Hr$=7n;b#0k{mwO>Gs2(-6zG@<$6u{&0*(ft zL$s$KR!hxEHpd1R#ji8h6pl2R{39w=$;J}Z-NpWr@-auZ}0Jl^PCU> zE$U)ZU=cXLFie{lMKjkiFpYMu9_tMc_Il4~Z&)CUC*t0ksgJdoMuOEJHTZ!)r6- zWFqsJCtU(s?t_-%GZ(sok81^;PGAjj+s?;4&5Q@8+dkn@(SmHChBUkcZop1=Wd(J_ z!QDyFnc|>Y><>Tq+C3g{sRpj-u82)vD93bV zRY)-cI=UOSuVsd)855|00-e0!I1{8&8eGn@K{s9RKgpvoeeP2p=qWl*A+X*&Nip6i03SOJ%$6E`&pI9dr5PoL<|B{IF>DGxg-iug6zx-9yvi!b5#MF7Qx49 zP5=D@JW6EplBY-$6k?1DERI(gvJ_YxZ!o|POa1{r=aUVz;YRV?^z$!y6d=*Y0Xpt? zhrslMuX)5Y_`tm&@Kx53ga>X(AP)LrgWgy*Z5y}v^nh1991`$Agdh9EslWxA^DlVC zqoV-cEde=SiVfpHAAW(7=?}#?MfKT0YepgW0wU!)P{{&6@b7_;5*w(hh3`$8?)!>| zn*(%+0jP&I-QYEkIOymf&(}N_AiDWAj}eCdq`)Z>oV70SgGWvTU>)u&{1Edsm_UaZ zLHt$^_uHRu(9Kp5zfA$vA{#{Ehdo^ogKo9DAeQC06nWDHq}WDYpFxB-!M9=D5K@Hn zEkOQMg!xl6%Mt1pXnF>n{s|6l&(}OE!ce;*a^SrLZlHs7GJP+q~+0F30DMhELhRBw>+G}P}f1^!2#|H3UKM^ ztKaji=RXI^%aH9TuDn*zyv%LMB{_Y;V-D8si$3t^Ffv}Ae*PnmDeTO9rB6I6Y@0zB zMQBZrTg;`T49f7(h9{_92hR}Tz6In2is`;{xMZiV`^3Y|xOw`nPdwhH6F|dN?XR0a z*G=34R~u7=lsI_VARWvJLZDL}KkzBAC~##dayia9H5GKz=k$kPc*Lg%e&*3&nzD0x z^=BRx5WNt@Z+|`g^k*Jf(6M%}KJzFsZD5?9@R>(^y6P7mU#7mc=_OxyTsa#5gYV?N zHT~ch9$}_AJEvd!!jmWm6+OzP09xn?x?V}25p*knD=(wtoSoA{zw-2R+UwFi(r+nwpi-44YpayFLsE?+>WTL?3$OPKz$>0dpj^Y^5_#DVFV8b{Z z_cFTiGD-2Ua62vl1>z!*6+F_8i*`$A$w8pbJN&z#~EDfAC00K$W4`3c3o;aWA7gi-Q6O=#W0pF=jIa%$Y$aB0A0x z%u?b|SP$wTtq{!;m<;MM9S{ZGe8Qn1Dli4K35!*q@yK+ipFH74H^3#?10m4xBWRH& z_`I4M;9J~5yCosFPl9eg7gS(T0F8a!n11>vkFqAH1Y}o`R^U)za}+3aWGNH44X%_X z!0QUgQE=y{i~r&&<3A5d%b@-gbD=A*B{VIAuP3 z(iv3KKQ{16PBY_GnQr@!hl?F#2OIRnEAZeWc!C0SFp>rn?93}@O^mJ41h&)!VrkA_ z9)8BV(`)|nBu@t&$3>Fe;3K23*zL$5a1k0?m|mW~@E?yU`#o^5{+XWW#H%#@|34lX z#(UFc{=5!@7kHbTI|I*@@B zr18l2LEIc%puu6s1EN`u=cc+cfr;0g@#l06 zW?qy*Nb0!!)ATRQyqW?F&|OZ7L+|$6xak#f*k_S9H3Li7?&$v zWaL)3INgPVw*Z`vAU1 zoas88yvCrz(Gxj&yTR>GP@fAtT5$uM*+EB)KH!2*M}R5_$jlLFI26+TLqA(;75Ho^ zNTvmyB?`N%5mJ=%f{XwK7?Wc=hzT-{Mc^#hqbEerPHbgz64{QH{s>mOr zh|4}eCl7%8(BQdZkSD+g)FJLu2RD(xjp-AhCX(Xx`#ii{kaM8_PM^ukYc32m9M*he z=H@X6H{S%y7ieb+tK$x#EXQ95rxyzFnlZLdUm?J2EDSXj=5Z!& z9!s#tw{r^eYBDlDnr&y6PdZQ3;fD9~dl(<0o2h{ggV0D}z1loo4X!=_rUWIy4 z&IOkq;Av(KM+s291X2MWdl7gH9zoz`0gWDmJCtB^J_u$B9AyRNQBY%umlc#}bQ$Id zz=92QS;Y#_{5+)AVRif<2r_ns5TsWNt#v??r0PsN1QgRigTAbwyK}%(c+gQ6NWzB{ zaTlg<7UtcKRuqD7F*zZ^tHStr`dblRHRM>573D3)jHLylyf%#crr#Ci)n+_4ol}fg zmFwX#3L*(|*9<6<_Dx?c#%s=aZ2Ds{USnaXp-6FL42dHbao&~CoCMCOFF>~tOgzdX zI$c1Lmy7Z8biN>N>FH*YyatSyr>9Hu>W2Nk2Xh}N6Jfn(05q=S2pMn!rD*uXT!WYr zvv| z0*-<(;RhgL&?R7Vr*uG$ECvsTeEc4at+f-X1|+J);>zOS z*fpx(sE^<$XSB?{fD>+?GmX~+>TzOu>={9gy6r2^O&dWJ{raZ4GBir1XUAr6w!Mfk>17ng6;P%N1qpajvpK^JaU zj}q9fRZtmuJzT!gK`{#5H@c{@)BE(`HaIAQZHR+VH4thRgxaADaZrvv!Z#E3arwp! z#ggd;Dqzji4B%GfsDQ2Nf=EoyH^Ai?8x)h!J!6Y1JN+KQ1_f1K8OG<+ZB==7*baaS z0|n3}B;wL+;8SkFEey26@yhgts=SE%K*7h~U!HzMl~;)kQkqP6G~^YY{$G`slMPai zfCc#Bg$tw<0SgL%i6m^%gIA0TQFct9qrt1lG_7^|ehpp)#=hwfGGFoW zc1#B@Pmed`ZB_;iz@glg$p#t-)MY@rerGzX5w8N{%js%Hyk_;68A0>M&?`VXz~@$i zo4c^<^af!^>SkR@=319~D7$aHYy9n`r7wUt-|CV)rWZoqHnfy@qdfV+&~ z(K*oaN)4t5LW*1pY~U;DuS|bv#B0oXh0%_QLxDwsV|v~%9+~Nu#=N4epkuu_Ks$7G zz{A_qTa0;?)j=hvf+%P|I5T*-&LJB#*vFrxpewK*)G7dV_d(~upEKsIwg;`b12w|n z13#cH=?n11L!d=KkPa^5z-7opCj6dKb#Om(`Z5zuW&k9=opu`4R*9RK!VB^Mm9zA%R zPz_@FG*ieZgaBlKPz=l9q^k}n;=#j#;LAQiM|{7+*@K>5XvT{AV)a z(nb*L!0Tgf2q~~QG77xL>3VR`C_{p#!h&$nAVx}ILF33k$ap1)@s*am1{iA_ki!Y; zaCkToHdzs3a)uSJ1M+|e@AS)7ydpT(At*rf$XN3#Xn>bDvsp3x0bP3y>W_lE$>3~k z#{^zYXaVZ5oS1HC!z(?#-kR4GhoSNiLtheSr~%wiXR|k4h*bdK)T{s+pMqR`hjYM2 z4s6}_6E?glj4t5R0$R)`1ifhrblD$h{KA{lZnTi z`32}+C^kp%T`p!!SEd)(@q(7M^x5&+F&>zH){a+I^oXben-+{^%)$pAcycnuJM7c-Zf{sGQHKFSJ@I&TI}cG z0o_;xK1~sv(Lo(M{w&8WrzQ(1a5!>+=1ZV=1#aP2VgZdhI9{0k(4MzK3q0or8VUoi zJO$+r&>$XYiN!YXlI}U8aP`d&yt=ZW)oh@VRM3?0N3aUeZHeF&e~uTXpLO7khy?Yi zArSyxW#@R10bKZk#|T-#B{QVg3o4sISEGW?=mw7$f`f}Inu z4CDLh(N4TBjPIu}aN-SMd^i206R!*Vd$6)I5M^=BU}e?Lyaz!ufp#vupnWNP_c;{V z_(8X8UEW^j!duKpVCki>}I0E@Ek~; z3aMcTH67Y7K?y@HctD(+e%FiFmVh6y2H`xAqqM<6IQ;=XH|XFz(3&20=rkGVR9YEc zq%}bEW>3H9%^L&{#t_ihdEj*(k?G5Pcm+Y6#4K)+>1Ta-1rV!yS`M~=CdSEJ-P3Y# zdZI7yWAGwJCPx(oHi2_s*CE!}K;}(XLt0Uw)(5E21($Zv`8D))KdTwJ6;>n9kVs(8 zkbL*!4FIh&^yl^9e;|r{A>NJY^Zj}ClpcU;8CFf^6+-6B;FtgvBaof!lLZv`9UJ#- zfA7yb2|94d1{w%lAq1UnW4t^)@Hdz2^fQ6H{0iV&3OsNNS|$M66QaOj#7%;`nnLBlrHz0hILBNNP~=j8He(qP zi}IOZpUTG!pp|3AOcs&@8Pd5zZ zl?ELvR4gUI#pTH93$EHuOwSMHm8w4>kOex~`~Uy{_Jxj&C605~vi3KJ$zmQJhl&>mjG2>>Yx@q zgBcU@5ItxTDPdTa!54KJvp#0fi2XZy1VUUx>u8`Jfoc(WL9O`jRX>jA!>5i(rfA(Z9V zyRkvQ5fn^aojCy8ze~SR5TdS57K|u3rI9mI@qaRj>zps4tp#tvINO z@e|x%T!6enWO`5xuLF|g24uzF{TvqwyzBn7@(4?Mj9nw5oT z70?~h;KmYYVivTHMj*>^$+l(z#{&%Dh4G+8gB)z2m}Z64v1kXEgQ^H{VKW1)ar%)s z-Xd`K6nqdiw0oKp&nw9IX?k5euM7Jpa5HBMq?z+Np4Yk_WvdJ5IxWy$rY1=HQ9(^$ zP+10QPs4VHz!#8%vJt50eeephKnd*m83I`Xko$N+i2^ix3F=;group;S7H-@%pl$n zR$}3u94Fiwa*Q{oe@o$&w+96@JXc-d z2h~#&pf%Et8aY{x8re#qgJQw^{Wz={K*u8Tf)+-xfVMY)_K{qk9+JwN%n02z2#Oof z&fN?RCKk}u=8g=CTngY_gQ9F)plRUC)0xwFRV+Z~2HXHSmCK9?6rhO2tN>1{3ap?@ zl?A?llhPT`&L3V-Mm#Y+K8+W2_Tq+IUPs1F(|@G#Dx~~Cxg8V~1)%#d&{sEt7UP0W z%Owz?;7e&wKm!yhJTK((Dl%@GJ};eDj~gDI=MPQ)Sja2G3M#2COrM|0E6;dix9DTK0gE9h3|2>kXL~fd`vF^7xIFtQCu#(INdc9ImX{lug&CDWQ03ze>;SDtM(CFHd)?;I*C}ki}~OI&-~*S8n?9EM8ZUeXkn? z9M7F-7EoZ31|3$^Af~`R{i7O}I6rvdD?7+dGlZ0`Fit2vdVbrBhQ*7PfRyox-a zqLW2|O@m27fo=N36kZX=8`H(|k+L>;fQk65&1J>}$=W6PyuRX~MjE)=4%(!!2i%H- zZxe>>H$-d`76$Ey12x;&!As+Lp}U5~3wS-$A!QiIt*|V`I+m+-10W$gu&WNklCzPnJ$tHF46 zdIJ-$h&m|yfhr1|85g{D85~yNjLSPczKk~*WXhH@UQfm=(--7%BSy{HrxzA+%T13c z=T+eY4+p|Fc3+y_Rn98~RnB;2`pt4)J%VMQGZqyopbMa7ri)kdN<#X^o|U}3jF+Z| zSMs_sZreVul2@Bi733-Kaw5p!)C*DAW(e@QHSp5@AK<%!)fwMS7pvygWm<4yy8Ik& zS@4<|a03gnU}VPhiF>&vA1=UAB%_N)?ojp*{gMvZ1S*G?@{zF(CiM)bVa*-v%ylmOz@PR`t9U(m%lE0s06o zs6%pj`q_G3W5%D;85?*r6!EA7kIi#}hkB>4Xy7%FL}~IO->5tNV*{_U2&hT~9lYY$ zab~iB;g5^KrLNRWL)3}^?WagK~I$U z!9TsMkyj3UDgbCrHaKg6M#n%KomYTk4c1Nu={_-iPb04^jsbEGh&T9}c#}9myH-Jy zNH?ZeHu0(`fu=4TH-cQNEbxm1)NIvf1UIq4ebNiUikGMFZ{pR0jAwwH4qD6C4YvLd z^duE^%Yr&YkoNo>0qCAQL?D1-7c^=v;JDx$_=Jv~Y{=mOTBZgYS--#! zy7&#$p8(}1(AA=#^dJBl8s8x>y}p^(9EY#jA-;ay%*~` zUii9M*jO~EoASSfcN61<>6==49Sk6W4;lc!zy}(m0K0PeyCwlgBLU>2R6q^4AN-1! zrz^GbdV^*~83dLJgCbUwnIix+)&ZKOyTTX%UMS{xk^y=H)d5h`7@WSq+kU}2nL+E& zpnK0XnbB9yb~1t&fIv$pkh?%TnSX)vBKQy#W>BF8I;mv(hc2;KlKn&kvtFj4|Owdl%py?$O(*#n?KAy5^`XU@Ds09x+u0I!nVAuzq6pZ751 zh3PI6cyl7Jf>H{L0z2r;dzQ6|*BG5ZGr-`~qi~fmkQbapK-;OnWrxCLMulsPHQ;NS z^%+}0E1|*Ts|`Y+a0Lw^C@?}5PUoD+tI5>BJ>6s?udXy`YFeLh4nzZsBV(2#xTnro zqj-6G%|u=^d9X*ot2?g|L*hRf6UPU6*Nd^P>`Bwji8%ZyH7n*=8FDhfjq`U%)A_n^i6(_JR>Dp@shgVN{( zLFkqokObp$#URLZ8z{Sof-}l~a1{X_hXW0KfKLKhFqu~wxw=0)nKux0Gr|o_=f^ZzJRH?H<#4RT%lNfFgufLEMd(Nr6k@ z%Jk|Pyc?DNa4B$UGIwx;Mq$B5HDH+KHhCvLDQaOpDGfOd!rPY+(e3p(JwU;(c$5||rO!BnTZxyK0Tg5txIsbA1v+c&0G9$t*Yr6Hc%?vNxm=DvxUw8yPp@CdYs}R9 zV)~Yayhb8ZK@K_20PXI8_jL+_+pE(>7x69^{m13VUueb9z^cII*ua{_!^jQV%6M@R zsG!;YZV|6CBjbVTLQ8mE84pa4Si<|5@%MC_rMwdve@{QRly@Iv2b2)D@NUCl*lGFi^)b{nud2cZ~gHy(3&`k<~EDj0+3j7NE3Id+e zYZb0A*1|F_lLI8{USka8WmMpD+`*9r&ykD@SEip?$*Toh)bVE}uQ4b~8Lr|rlY7Ml zirXt3N*v(01)nkrnM4NXoYqymp%8snr$1Q5s}IsAxSDq&MC|hP6{~p-L1MR8^O`cg znl8A8R}7x(^w#i3hg@M);L>3F!=cClqJMBGu`9BGui}7vh+Tmnv<^j)7u{=DAY~G0 z)R)V#gA?JQ>37$FZ4+M08>I!!99C#Gi)+(^9b^8CGxfyhi%jM~3*6}7oIzjAK44@%G zh0D_$esC#IPgu_zR1e;r25D1q3P5@~7eMVs@UaPJKm|Cs+&duvS@GZqX%2xGMu4_k zz*n_{nm$NVi=dJjR4Q?T*Ar+mgJxM6(Wm`E!{mk=cpaI3teRf3fj5q6&aUNGHt;e^ z-QL_J;3zJj$G|PfpuhmCAsm?;SsYmeW=(&$k@pc})Aoy-c;guvo2MIY;ax2P-p&tR z%r!wsfeEw+M4)B*hb_FhjIGn-w(@E-woUKa%6ozF@AT+xyg5RDI~qavoI&b0S6(K^ z+tY7uFGOpch+}+4*y|R zU;tm51?Pb7S%PywmuA5^pv#8f9MDZga1Q9=C^(1JkzD}J0o`E)=YX!Ef^!%^muA6v zpi8sh97ac0gb7TJYzPkM8YQ?gW@H)AwM|GeNCtpzXzJhw9e}{1z~p#j&yc~!?fGAU7Q2>Pqs!JW25H0{+HU+l_#owTtr;ucjT!7*Q(1lrWWsDxkUIpC? z1(yO{R|V&wgf@y-LDxZbaPzQC=iALIf$$AVETTjliU&~Kj1mGU)}uHKB@R&B!YJa% zj0h>H%b2Ij>_v7Nnk_8o8lW+NVhf7>D84}n7)W9RwIfhtI!lRRy8d2XR#SL*Lfi(m zihzOBGxzfTV{D(Ev5z;3v3>gCeY`4+ozq|J<5iGq=XPWSpYsAvSD@<{7!;T_m>2}w zrz`E}jc071-n5@Lm$7~NhyA=kjGfb+5Ab#~wogBQfH#@3eY){MUS-D4>EQ=?Z;OIW zVgcRb%Ba8qx&enFTcB&Y`ypNhkj;m9O&Pnl&pX7c#>m*S{pexdHb%zY?LJ3&1(_Io zr^g-Vm16ALUU{51n-Ojhzk-MYM>goX9gsmkPk;@QI?3D5*f)LENwA|NPVt&B_D}ac z#cL@BwqIHiRP2F<(Lo(AVS&Esb58N*Gj>nsIn8UwIAOZ?X}9jpqHp!x+SBblwhtRM+;#DmkkF^pZ)ZO`x;GxlvSJOe48 z=AGsB;P2;FVo>1EW>sM1R^Sron*Q}H?<&Uj=?l*BdPq;=Rs_wQgUYFrECn`D@GvVd zWGgWWbWLYI&l}9xK0W+A?-a)F>2J=1ovD3+SD$g>^ymw`aRNQuN{pbnYGws4kPEw} zpS-}E$T)es_C;PYE!TM?83ksDaC3tz14kBtm%`jh)AM2(mA4Dr~(g5fkI?>HUv*otX9rPPaYJtT_GlIpzeWy{^xnt3i<#z}+HUlO z_bMZ3_1K0gev$36&v>7)F)rTD@|O1}6Vr}W)BnHcwP8HH-R1)?7c*zqERo3sWKiv|;iz^Um6 zzwk;ko|=C53$G;OsqNpt@bWS;p5D&-jdvTP-IXig8&E(Ag3<8-W1-^#@aBmd$ig2O z3mqSTh3~+H9S<=&KDe^|=Xc&E%uHSLrqBP)>&)0X{qb+!2F88UQ~vOVG9H?~>ksc$ z#>3ku{N)W~V%joo`cx%$52oJJ)9)*>%QG#!HPw$#oT=x`bSY(awW+;)EgXxVv zOcP#j?_}f4W@g%XbNe?=z8prz7t@ou`HUHVOrOrpSIxL@x-bvlH^%GJxp?_h7}rkM z=jBu8c)6iNz)?sbe!4=3h%Dpn=@qP(G$rZ42>d%^f%dKVv`3ggu2>p|3l=~wvp zRG22WPyfZor_9tkZ@N4`p9h)^2YT zaO4$;pMJYb#DwwvbUOh)2gZ-n>jn5iIF4=yZ=#EzzM)&hlj%g;bTvUf9geQ%PDn5q z_K4^)J!+iZCCF#R_-Fc2LB1%EB1IuSC8h5hKPw)BA+^vYD4Oc255z z%;(4SciVIy5k3RP#_6>peCCX;)3=K788UWGe=foo#Pqp!y0s{u5!1ic>G`63=8P+* zFBjztV*Eb+mnfex)9;7V^~Lzw8E;MBF2-lfcyIb^F+OX?htt)?`4)1VXoK2%aFU1} zQ&;nJ0SUfb#{JU^CX3ik-z~v68RV$|Nj?{l+%!o(Z;lh7je{U}KAa*VGX1Y4Ul8N| z=>bxF(-;p-e>hddN+@250en#|FOLGV;|~_l;Dz2a5yR;z(tN%gr>1p4e7WJIjL7t} z(tPGj#~Y`!$?yd-F5Vs?!xzQKv*yth0R?8q8?0FZ3DXbG5Ru=0SC-F@Y5IZLBCOL5 z6!;uD-aTvutsab@UT{vvmhtiQ?FxL3)78ZJ1g3K+@)i*dZHqqCga!X z-5~1b^sS0~5sU|?^C|H~G9Bceo^V0NYWiX&K4GQ<+|$=xkddDrpv=e3#jd~%>WK&( z;GX{Qf{ZTX$LUhaeCdeTnKw_wi0OUX^u5Y_s-XP-M43;W>2KR~UKKuVrjw1+tyK85 zIHtf-Nx~%=9j2D1?Xy()nAw<)wNIa~#i!0RWzF;xT6`)@H`}Mb)8bQP2M;1HfC#ef z0xg|lnLg2!Pjq^yHs3VHL(|`A^O-RonXatEr_8o#WtV^>6GS>uhtG=f==3={d{Y>Y zO*ho#JH++|v|x*4y1gEs*mQn9J}u@e(>kWh8}La@57Xm|U_3H?y&j)3TklR#EPzyr zPk*n+=LU-8jrx2N)BW}N1ekX0pPs1C=LZ#3043+k`h04j;^4PFpCZ%7mDA-6_=0(l zazjT+LFdCv|KQ3eIeoeTUq0ip>Gf`Ws@ru8`Fa`IZh^eRK7FAvpTzX*MtsUlN9IoV zHRe;CE^Exk&avRsWC76q>eD9%^NCIG_u*q@yTFj;c(Wa(Mu`_xzBsN~gH_G@rPJpc z^93*-o&L_4uZ!{6^hy)HNsRlZ^O*7}$wH>vAoJ?n;5+u19SyP^p`il~+XPcSZN`@A zJ*IpU8IMetGvmu+JhHvljBhR@)25Zvbu9R78IMlSvf%4yJhuIp1z!mx)2+to1y+3a zOjp{cZ?xhw=J`oOP#|IGSb6fLiFikl%-PD>-4@9S0^QnU3y9Xq` z;MDYO)_iJA@0U)$XU!MPcyzjv4cH5NZTOzZEdzxZzd$@RaCsRNm>oe|@0dXs!5^Q# z-D=~wwT#E6ciQvKWO~yyUB!WKA>)zh z#~k>2nKoRR9_q*!%(Q*^^i__0p!0N(JMzi0?ONU?;K)4vp)H@tbOA>`w&^TReCCWt zr`tI3&15__{hAYBDpUX5>9)>%pJ8dx(V0(pdaXVm_w*1KJ{6{?%cfVk@RcQ;SlR{7 zok;FiV0PrlGGp4o2+CZHS&pYbO4w1o_<Kd zdHTFo0YxSrF>c3wH=98$QEo>LMP|o^?O>h=wJkG=*A@^d@#Dl$7hgec+TcH~xMcKim>&dcq{smSbjYz5d#9&X1U zx4@QgL#%xH6wKq|cH~lIcD!-|%;SW}oqq{7orBx))_JfvJH#nBA*$H8eI1!Vn$CeG zS-BnA6qy~r%xwX=ngybC(gQG$8Dd}ugvSI`xv2@Hk`dzEO;4v6c<{{u6=r;%e0}2J z@|VT&0z;NSI=CPQ4J|p|o^B8?p)tMxrEuhQ6E8k<#@o|#y!e)JK=QYM{PcrHe8SUp zz4@vcPflOy%{PZ}`gAuRzCh+9b33Q!hwzC_-{8a7!FY1Ir7z!K#=Xo4l+`z)=X~eu?Rd zA$*!lE0<6A3E@*<`nYs@UI;jc9|{4va=ULRUkoGD3GV4WRnk(7@1`FM;{zRN=@rgr z!+2nNJBT_r{Ro6&jNnV;0PO^EWEMC-Ju8AwmGSuY2@!m1ptCQwNAiKHzORvd$&62? zM@I3*GHp3EeMc0Z4&&49Powy_7#a6X{}9cm&G=%vOblNz{p zGF>*7uaWW9^!c%Tij1$PAB^SmoX(#m!o_%dy1`mGF;HsIjpOr~UW+O=CyvjDdp93A zU9dQSQUz2ocRXLj^n3Aq$Odr7^Qlg^%N8-_-it*CV*;NfsIHMo;4@>}$EU#LC@}q8 zFP{SQ%;_D|Klbv8Oz%(N1FaEWoxpdNanJP1M7}wU`=*N}@g*{zonDc|_nh(D^n_$S zN6v+y5|c^bEBEw0IU=zfKd-cc+8AG_^QZ7h>wNvz0Or986<1zP9xiSLCIx0QCItm1 zM};iMi|3jlN~UMziYPLD<(}T1D{b($dofo;hx6Pmh%MaH+44k; znZ9vPx6TvMRR0RIhnGo#NrBOdAwq%4@diVdBO_$3G83p2|IR(VJ5NLtWYe}h5kKAs zpi|kHz*+7)_jJL05zFZoX?(vK+ozkP^L=1!pRSt0m%})B`lJj#ZN_=i_hs-oF+QEn zn8~Ni_;|W%CZ7f4pXqU#d?t*4rcch~+s!zCyMGqnekRq0!aS_pjtxH;K$Cd zRq*LC&Yk|ZLQ-maas{71D7|l~;0uMwOHAkI;Afw%S;?o$ICpx$O%bW-nU#D#AVu3N z`63{S#HaVo;4@^LJN>{6z9Nv+*($y|rZtbY`&RRLGBO=*nLeY2ZyMv@>H4*N7NBZ3 zw@Acu`ledGP!NZ^Sj2OBP#s?+iAq4H*Nn^#}~)M_+xrtBVQQfis>sF`6@sv zRmw$7c^ywMf#%v@Fl7n+31td7Csra9gvn^pfQW^^skM4V$&^J`GgtQP4{W#vt`^i zy{nbajPdF8gROj3j60^=wDAQpew*Ic#%BcTMI375(_q?gW&4{pK1)Wq-`ub*yG#nK z;GV4+(*n>G`vTAvnA4p*_#Bxw9Npg5!RN{>wwz0WL4ie=L4>7F0d#0Jiw2W`z>4V) zyZOWz|4;wX&F9WIW4l8SpD82L4DRWxRM?W+|}iGcpM5o9@}qXUBM9 zdPhHB9pjhn>=XEO85zG!H=W35z&LYy+C)B6rp~tMb0_jGVf-@PX%e43qiLXxi3%3$GxUl18RA7Vp@&l6so8t$jEXT7CS_K@rrth7^r#`)5GGCA!Hq|qj z71$hSFlRZwo&I4mUncjC{gVY8K^b14b9>4ZzAsFm5r?Shd@|6qiIS|O!Id$SK!O4@ zsB}m!6(Pa*gO5_PQJ;Elcx9X z;(N$AaeMx5zDCec;m19Elh~MgE>CYg%%{NAb9wvn!+e^IOcO3|zjTD}05jwC>61_J zxij`nzkPyFi@l!*6xK4+AD-Zo+^%|(FM*N06D;Hc5)$4%{}kUrCV{Cuum%o`g95X_ zwCM$B`8*}3@_Pu*Av{J1 z@9_2M3$F6n@a%XrML?H40d*>wIq*=T6tV!RNv_ce?B?KI!RwH~6BMj%}L$>IRHCkQJsI5M~k%;!;H0F4KNP6_1@ zn8(Az2dcz5oa{T63(TJ`a*uC0EKIwD^N*`oo8Ovf>MPKqGZ53an;K7nl`T6j&TDFlPyz zp050WuZwZv^mPyT9`K&;Z4z))23JBWdZ*8R$fw5GJpIr^J{!hG)Biu@^8l5Po{#v- z7#WvNKk%5(mT~Fye~m0aTsr*{gpzy87tXkJdf8L3;Gw5{p^QtX zOFRQpdC&L~8JAAK0O6@U2lF~0)T`%wxr|GvN4x+F?t)M3k@z-FLp0B~YJ+HxXzaYHaH(=iCH()urw_wL-yan@azXi)lz60}m z-toCHE}ecE!gG5M=Jmb@$xZvf7sR-9dhiDjXZo=ZU@6{@U|z#Vu-s(`&+QYKH}ex% zj^{I99OKgI*`N9R8JAAq{Tb{_%`bdrj7zsCeBqnITtA10M}b>`(UDPL4iAq!h{XV6 z$$?m0AeJnM#R+1`fLP2RmNbaP17b;mSll3%B#0#}Fo#Eh(NRXAje|!5Bp?bAPyq>u zg9OAO0_q?EF>VD`Mn`^uInyhC@ToJ-nZDo$-(1Ey)9rrpt!11u{moB4C&oF`^?&hc zLj=XP7ybebcg~r9?>C<*WAk*8KYRs@bEb#0@=uyB{+CY%%GTlm*~9|2Nr4q)6E{eJ z6-j^#B)}ptXZnY~d=gA=)=ua82exy^Kfa}m&C}!l^GPz!*F$jD`rM0oc-TN@vI)$Y-pI&b#khF;A4dLA zMsc`qCQz0G8`RAtFn@XmGyej{Iny~=_)S2*W8n{GoHKnA3;z*_C)P90+0M?!{~lV4 zfm={Ikj9hf^gs^&KE?~vA8_#3GcK8)z{&rJap`ntF8(y8Wjxc@W=P3SKf%SHD6#Iv zWKfA?#n8g2z^=e##uTBzp};J#e7Yky|9fbLTr+(xFTW(?+UeVQ`5h%!@hC7T zFoBkmFmWreJ8D1;5Lh=|kdI%Has6~-K7J=LuqyC^6DDp24h4P%HU&74&$cjdi-EsK0kjJR{2;>b z!?=BmWH{_Uq4eBd@5q>lU+uus?n=&%)+^#Ie-@wSYbNUi#{z+Q9 zcoal<8JQd)@h7l`$C0s+mjT3MfjYxcPeDLIRABA&1R1bjH_GsfGp?I{QU)ANuVwfH zA<-lbicAhjH1Q~i2yB?XUxnXp`UF}2M3!YdN=(x~%J6%OfMXOK@9dy>U%`|muzPxl z9REVbRnx!8@t3gd;Zb4)DOH&+Bgn7LxN7RNI1^9G+97FOkgiKUZ+g=SLXMWLshQ9 zG=W8t6A=#67b=1i>uyE<07zm*n9KnU8G&`vRh0M@+1K+3Twzrb0lC^65*8w$uwa9Q zg%~6(Y^T3c;uq%saA~ptcu55)lwVw$&ZEq4!?<_4r!qL2XDai{NF!q50L&BMSl|>` zJN<$(I2IID_(d4kO*d14+b@b_zbK0Rf)M))IbOV&EZ}H@HTi76smgD~B=lOCn;$$E zsKDgN?8qU|Co)|?T*h&Gng+iRBjb+gm74sZi)v2zZ)e((T( zlor1dQ}4U!bz1yZj7z5PgbF{<;#XokGo4wRzk>1b^cro5;>FthN=z-Erytkmw_-d$ zok<5Gtf|AV#Q1Kyj}E^zGJzA9-XeM$1gAT?lWYT2sWLfrvMs4n4YA^uf+I!daEA4HPghm(+}xE zjC~0b-ZGs>pWmAC&vXxcel<{+v_PLQ8 zrPKhTWv&6g665me2SAd`rr$TF zeYYXMI>@>wAkm-G*^T(E8COnsHsaR+iRK#dD>0s(J^>_parzmk=r@q)uj!J;{ML-W zr-vFt)YcpGD=}`EzQ~y0nyKyc^!vsTgE>sVj?y;aw`Tk>J>3MNcp^x2&h#xN{I&`! zE;R`_N(#g)GVsW8D=>rF_MlxJ%%Cx4<}Ak>(*;fW<(T$eoNj2!FUz#z;`9Iz-G6C% zzA3*6Hss#9 z8#<@2wc?jy{5t)V6@Lli%IWsj{Gy;F)o0BwIX&N+pHplbS}p;tI#}~)dY?7F664|N z8?E^@B>wa@fu~zx83}YC2rFp+{zq$mC8o~)>7q9LPE3>fr$^fG+k0QT03IA?=XU(_ z1T?(vD6GiL!^Z9SZFZZ0A`@tSfQOaa@!*_h0Ul;<#|hw3d`AIAW)N>7g2%+|xN`bq z8-82HdD9hb`K3Xw-ndUzp7G%HI9q-lP^Z7gmVX`-+E zgz?Vw|K9wTOgHXK7d*u*%ygG$dSD7`=Jb`m{I=8W8rgZKUuct9v3;d4|1(C$yVEE5 z^LvA?$o1#{%ha)F`t1PzW~MEtwkHJgXE8D!n|?Zo{~~B*z`S7o45ls9wsVB=A7Ny= zvSa$WP<}h6BRjV9h4D*(1h#90^D8kjKA-L#!4Dc}DvsbUVthXRSp>hS@bB9#psk+p z)pej19D0%bM;VzqFHZj&#h(VEW25=6G2WhT62pH?^vEfAE04i(&nZZ?GtEUzV!C=P ze=OtC>8-K+^O&~sP8VPl65VbU$8XQXxMq7*0{>k`rVBjNs}uNDrq?F%oACaB*dgGk zoNk2Cm97(Y#y$m9=aY@A+@$?phK zSa@7WdiuFc{z#z@mnREoGBcPn@hC7jiex$dxIEo5i~jh5vq6DALy+nT#)|PtWIn z$+&NNV*$S&BdF;MT`%oFDv3VWc)P!MiGBJ z)OnKIgNpfi7#TlKk1yeO7kj`3+Skh9$_uSH6_^#+1wL-yQ^N1V2pZ(zD&ucr{4>3` zj6aca_w@H={OXK9r;C^KD>L4mZe7kF!nl6=gmQjy*$I~+(Z$HX!wwpGQvfY_ZQ9xd zI&J01^dsf`*&zE3EBK|ECS0EGSHWM+apZKXfFrBGk?9vJ_{%`Do|O>Uv`T&*kg6$_ z{H45q7~P7BTv;3x7#w>pPZz7=p8?7W8>;vtnHb+s=c?sj#PsFV^mVoTzG~1QSK={e z0?n1SFlITvfI15-@P{GG@xkTkigo;AOrYqf<3F#86dlZt4Ob>Z;!Hw;U4c!3S>QdW zkKlNFyKX)ILMEmyyS86w{5gF|7k@tEqv;~u{0725L5hVDE1f_&AiSGDg^BU@bU`6Ok?j|H`P&&8FHMi= z=MQAOHGNe-|3bzy(|soJhp=^=o-81+X8N)T{Hlz%rk|O>|CI5}_DvJ{A2YEX-rpi1 z@NWC;Dg3RBj1Q(OPUBA&da$`!z)=lu6{F+r=@-@ss7&8AjsG;`mFaEM`I8v0On*6@ z|1;z5>33)FuLT8Z&rJSfj7$xD(?e$SyMX9fv-z)!A%zd4CX<9BuL2_|)wa*!FJjz3 z{ns4+i%boC+t1GBPXOuNu0NmO7sQxew}3wll(C*I;O}MX+c>>+A%APaw+Aht*}OHN zoe~noQe&Ot)OjZ_EoZUV+uo03=npm|vUm z%Jij+`E42RPk+3azn1al^u#6n+Dr?+Z|_^eZ^6iU8@BX#dSaV^%=Xty`JEX-CAq`4^mqWGp5I1qR0%r>Dst zCI0>FsOy7c#D# zuDO;!oAKWCscZQc%H9(IWnB(Og)9XQM~*BdCV>tn1rA4nECnWkd((s0@#`?&pWd*J zzk~7qbk6nsK8*LKhpp$|$Gw#oI(W(AFgE;{wT|hU`Y~WXByf=Np2L2$5lGv1m0cO(B} z#*@<@ZsOPCfAFmX)ITj&0PS&I^Jx0Lt^Bf#zo!4$${#uX^d^43>GL=9bAo1^H}ji` zK@~$P8(s#Oo(tRfRfK`uCs+d9vq#$Tlu9KS59BKm0yj2El8ob0IH40 zK{lpiyiwe}?hH_G7#Fa~U~*gEoS&XfSC^-*AdwWO~3J{@ILQr@z_5 zzlZVL_LY12mxIcu!2O^K?Dq7){roD^xexMh22CIxILNQX_<#HBgZ#drb&!^a`E?i> zcWh5P!vBngarboJll*0jd!`>b$^V4$_w<#g_|GwZonCR8e>>y1=>})`r5L|Y_ddfv zkMYO!S7-RwG5(xB^DMswt zYV`F5{xwW{4@{qVkw2el?}6=Hm-rVmG9K8z?lQkWsAKl;3cohv?de)q`Q;c7PWQaZ zFDJg3TY<Y?#0gCh@Ul{t$B(*j0;CDZG!@;fuGnttdi|5?T>+b3M(pU=d&W4ggj z{zAs@(-+<3S7H1;{rFA(ON?Kq&$`9Gjq%&`z}x)djNhkc-Ud6J;||#A+wbrjGya+W z`VPN8}bh}6Vy-aH!Z9n^n|0gJ9k3Zoz zU}S8Z{^KdXCgZ;8O3(Q77#pWge8z9gxNrK=XZ(*CZ%<$GoPR0fyzPE3_$wJ1=S)BG zlHZJR&i4N=`FWTa=TGN(!>`Xcf4a>Zeoe;n)6?GY=P}Noe)SE%Hsk#1jBoip8P8Am ze#_qp5_}60e8+FXcz(LsJN|hf!FT+YjPs}Szvs7OJU`v^bYzdrB>G0vav`;p(6asKqik05>94}9d0V`7{$UH%Jr zL@@RXe-z`K={vrFjM@I?3x5S8x-M z{p~qF`L!7t?@yoci~lL({poeT`R6mX{0j<)=@?bek7mW+&>r$1&C*vzGOC6Oc>`)zsxHT%X8<| zRDmpgM$id8%+nVX$;oVw;1l3yWO{ghdc2^3BIDcX-TVSFOj9mQU&${}%J^`)ynuia z+uQRkpuOt8LIS!VsWt(D>rAuHfpxGgKi4AQs5E^7zktN_d4d9EAPEHl0Yj$c=caoK z2^cb-*XN${3$bZxt0VXI#2{uc*KVM#kII^TY+@nU-GL z-Y+ij2y~iPk)(hcSh_u3T0oGA z@!j-FS%GxMciSJz3K%dlo&7&uSY99rM3>78ypx94liWhk2Bo8#poeT9<1L@}r$NUZaM zx@%yy{>lO>Aho5+0)`;9QJMmQ+kYwxlrS>=-#I;BRUnaN$Cb$f(*-gGMOc-X9UJ#d zf2%5>%D8sAu$sU!#ueLlsR?XlRO*-T91Uki_YT+&cb(_~bnr@;gpu*JqdU}+mz-myBja^H?g7Nlr2Q2|ru{T^wtl;@O zUhsPF8H|eTj&n|JuhtS!WC5w2rzfzU@%DBFW#yk{NGJ7cvrvWL!Tz$4H=>>CEZrFO3A0JtsYF5D-`{!p#Q@=XVSO(~-Du83d+^ zaI1r4nFQ`}NP$2r()GO#z%W-V%fx5nU2 zG)VIb(r$w{(Jnq~7I5T&2*R6aERN778k@k)=_w`xnv5r>_n8P(@va562SLZxfm>*z zrUIHw%id0RFcmOEG~U21v}RKQZN^{I*Mnrvfvn(HV0E+rwcS3M3TQL+eVi_DCIBj9 z!^{NMurM9_GM&X*AQwazTMK+EX}y2~g95WAvw}Gj188BFL$(S7A^;xD=i(59>3*<2_+Ai-P;Ks;!aeA7gKpx}8?N=QIycn4dEuXIF zERf4|X!-UD&I0?G8LvDQws(37oMC0W zy*(^I-~}V&uI=_g0!tYgw{L$MED#GSZkQ z9mdE}`fR=9&Z8K6la(1vzq$3LL12L~iwgBF!QL|Z?Aw*Z6H&R~RgQxsSn zZ*BoCHB$g3_q}NXI*c!-ze*EuV7xh9J6%AB>B!6Jk?8_vd=TBB?UIb3lsp$CxApJ# z)9C`mjEvu=+h+>sFwM9(JvURJl=0j2$C(0V!ZRROBSDHGNHw@!CrjWE$j9%q1#%f5 zPLItIaA5pCeO``$9pl64cXI?X82?Xq%N6itd^mkdu7JPTP0$h?4o&6`CUYhR&=eS} z0-NL6=|6J?;-w#gG6;tz^9Dw!9ET&=Uyd8DOfSw8h-W;#{c@gw7bD}N>2d`E?-?IW z=PMMr$oOdbgF=D1jE}b06$uD3@;4sr0L_gTgAQ&24X@2B7LaCKK7CiQfHvd$>CcJ< zO2nW_ARYmqxxxlgSx_RN!nl0;)Di(>;q@R>5N&2=ZpYixb+QB$rvEMx_``ITYx>)L z0t(wD%LGap8P9F+FBcGEWSVko`r--!EygF)&s7NIfVei50w%&wZeivkaN}-Or9d<9 z#=D@QOUJ&upaG)kR#gHAnA)FD|5GI($F%nObeU>_ToAvzT0mcT?eiAU(ldy&A>lv$ zY_-4-(2~pJH3IV(S4~f=70_T@wY|Sqz>87n2V(ev#Ze>6vE$10*L4COlF*R~b0!hc zDku#m9Wy2q1r|`p+NWM1UvfRK5;IaE4N7b*jvQG6ebcYh3j{H4n6BO+(9F1T`sxOO zhm1?7_cjV>GH#!~9Yj5w{;*LXk8$brfF=P`#_iMFngoo5pIyP?|4<=?=^q@0Sf;;k z66j`}yuG?vAcv80^7I!i0zcW-PiYl!JTiTCyFfbA`YGE3+5|!w8NWJ}vmE=UOn=%bP$~vB6%x{jE?nR~39;!1x&&CKcXtVJia|}prHYTK zf6Dd?T>_`Tox3?b0!Vj!vnwzm?)c`1)c>Gv`|D1D*y%Mr0$kJmdj-JV_PkyJ@Gadd zdIiof-kx6CC-8x3)9vZ${Q}8Cn?S>wasm(sfEVgaztbOywW>Gcx?>>1Zj z-#+q%J~_Cz`W^Q69xR4KAfI@d!m3M_5Gf%J4s**AR;0I5RD|GHt5B8m1*zwy&Eiz|6!p7cvC2eY!vsGvm+c zRTiS0Y)3KW7GjoLc}6sLR77dXIpay!og0Wn6#Q`40f3V1V~nx4N< zU_Rr?>HLcXelnh(&be5?o$>Vaz{LVD7$;1(S|TuwaqjkuO9aB07|(3iST0b&$iCzB zWC6!1XQt0zA@GUuKg21URtkhLHSkWKGh0Azy4os%e~jCwtF9K%X1q8(aJ4`_FHSS23I!I&9}HQJU#8cu6_8?FJbl($0UL-}k<$&< z32-xRpKh~GK!Neg^w@O*ij0e=*RK<>!)pA6bpnoTj8~@XPZpFHyCUGoSjbYZz{m<7 zfCA-BW`RlD-M0!O-I^A}MKtAK$>1%fg zn1h6$?GP{$?tY4rFTq8e_D+ESkU6zG1%yFc7bor#Si!hwyVY(1ZAQku)6@0{EMVL> zoqeys9KO8*N*v%~f|r?xk$bw}UV%wc``}_spv{I%p!$siG$nC+dh9-dKE`L;-|Q3U zWwcoGr32I<0_9p*;}^8BPziLeIXmbG?F0pON6;RY^B{%n;7iiMb0r%O2uLvAoPO$n zK(-jv5J>6=XHt+^(>LytP!facgUfL$K(z0YkeWXCpa6&PO_0He@|_7(zDFMtQrv#? zpg=XFB-ZhNCI%kX=?fRJ3Quo1ERex?eEQ470&;Bcwl)a}ET7JMMBpjo(&_&lWz?oi z9u+WUT)N%=sDKfu2fp#OKq}*$=`W56q%%!9Gd=LQz#*n7XSR!;5C~*sS|~XE{sh4! z#)aD(-DHeG4Kc9tCDT(+3n+<976G3&;CO|>amv-J42~iK?}ew=-j%q@Hm#>sz)^B~ z#61aRwv8Y*`}D?p5)vSfzF^35+|@Jvz!`x&rfEIX4bBP}!<2a6m(UU31yXJdFE+q_ z=UvIJGJV~BiOT7&=LB{!H3&{;JTIUs)B~+T7{PTlgX4tD(=E;m$S^esZVx*zAk4@# z7wY`E(;MAn#HK&FAaDmXmUQT%fEDA;>3=T@D1x{OmjtvywC^Q>co4nrl7JQCy6G=3 z2`GcOe3u3EK(yUu0V@z)by*+;L|=gNd9Dc9fTjbyt_bKduAg3UMZg{;z4MB|JP;ju z6+-{KDxd}8t6md0sfy%sHqiMN3LwWrTBM8&kfrAnE>9P}E>I8BGUd9!G|(bSog1M1 z^LV4onre6dx<_cV!F8ER)L3pyT z0-FLGXn8uDqePZ5BZI*0>1Q4aNHRX0KJTSKtoSrx1vb!fbT&=q00lPCqJPkG`@7Sl z9tlV>UY%b0NZ<@(|8%Fv0!ob6rl&p@XkqN0{_3%S4rBLr@h1YgpfRF`^U|`Q;h9puQxyymM4^Jaw%}K;XmniLXGhwO~3p$1K<`{zia}k+FBX+*<)3 z#`+`MK{KU18QhN3c7j>ykZo1R?tpn|5Z<}_U|uSO_jVJQmjdDSTx}OnWa3GN@Qz#q z^O7LEODn;=L143u%U5~9Z?Ubfp3^%KnV zhj{P-#Djj^;GJf#K*Q-wJoUa1$(@iLZaxrR7i8y~H-vZZD%g52h<}f622Xi=LY(#j z;$IJLM?OVn$L;UI{&k0_oB`P<=LX^ZxDPhP6=LQS$o4judWdWGK=!>kLkztNo=fL( zg7A8-fh}}|?4Emh56pAmb`(-%cD&aG4pMulTnl*joE;=YCw>E4XbZ7n&V8^x8;D~L zT>|s0x$8l*@s1xiG=h?l6~q^pAv{Y6?-7J&0Ws#;3$R9Wh!u~wfzyl`H`tU*5S}Tw zqqHKk`e%^F`n{$kpHp@rR7FrhgU^bYWaS-9lJUS74UlTF{u?0|w{;Ak#~Q1sfTkPX8_}Xu>#u zx{ipTHRHeS86twlpoJ52LY(MJKVYLX0zY`B{}2|GpB^M8XwLXydY70W zc;N9-{WHJPT}oIXcdFjow!2Hx(4&R5FI2&yptn!Zj_&`5aNO_XLoxb=5ooq*zY5h+0< zM*g!PTR?X_L$!i!c`&_DT2Pbm-SpYgf_Y+4C0H$aFx^E)&`9_l$P~2ZHFy!gS{cE& zjFYC%mKD@sY@L2YR#2O9%JdJig1P_#g}(iFSO?;CPBbV8-Re0vI=ZasqJ3+f+s**tfq??34UWdGM(F4Fplx)@+@OPM#dx4 zvrPmyG9H^QYbtn>Y1y>tFH8mHnKn$D&S@st3F1#N6Ep)L>-lxHA2{m7q3L!3~&2-*vQ{o5b_8Gd9_ z5OVytJ=8`pgpp~-mF=r-1ud8uk8gisFSwkE@x=BXCqY?8z7qnVaX%3SVSy6@JdD%z zodsp4Uv?IZV?43l$VG5JNays=u7VnjC#TD}30le@76A8k*%X8|m>3jz6%-Y?9S?A2 zDR4XXaAyge++N})sL058YWp;IK_x~Ju=BVbPq1exNGfnU?qCP)ojKznsLckF5tu#w zuZN&BDnx3c5o4@Pi%V2T28Hf!W))dJ0}-WW2P!-CIzE(RAm%76Hd; zw^{@g#H5v&9XTA?Kny0xxDB`C3GOU`5(RG1>YEvY3fzt}1hX7h%$a_{M=%>SS#Rqr zsLHfr&h`{v!8Aq_GR*ou{hyy;4$LUV@6#vw3tk2-JW3A`)UhnlBgqe$WO@#bk;04Xd5SJN!ZB%!ChiV34>9SDM3+Rfzk2AG+)O#W8~7EMg6(CkueKd^Ws(IQ!0Qg+J40|e%NJfH=IMV*1jDB< z$PtX6{w7l}p7G0epDe-I%plud<_bD9GVM7yT`ym-fN9Uc?F;e+BUl;FPybmWco~v{ z!4q>=O9gE~IZC8VFqi|h3@Nit@H8{ysqLmsf{CC>_~|Wz2NY)u?^b|JTM5h--n~eH z30xL{*bBA^%m;OXDq01j86Ql)(kl4ZaKEqugElj0-jzXvi9?Z5fdRCLg;M|`E}+P% zz@Wh-p~$4b0AA}NuzxyJyI=$3r0LD=g652qw(o8i)Mk{LB&-NJugTFMO9i~xoiR%Z zbapC-z_n?ef-_9#2`eyYGJ7cUf+z<~KEVx)*QPu73%W8+*xuPM7{WL`e3D@G^oWUq{~32d6z_s6-nvB~2FoxPlL8|+ z`!fqnnw~OQ(2Via^x2aIFEBOqPS2epmqxWzGJ>%IwS9c(~|`hxgEh2*L40xf;!V9777M2PM$t-k)Z1I3kwAgFize+agpFn zCdMh#vzH3)W16#gy7n?bd8XBir~51uEC=zAE)z6jTD^Gt&t-x#pb18?6@p5PTc=yD z5Y%HlJw0QEU^(NW=?_*28ZmC2F1%9EnDO*>_mzTvj7&S1O`pC>u#jozvh7@}1?89+ zr)<|;E4ZAIX~oLzm(~g9GcsM|nVxWwPh@-e20>{?5k$YenvtmUongWJo@+>Y&Az>QocZpUXwKFf{L0ur z{oN+P1jhd9{+k6~F`k=lwMFnb-`TUx0*=fAI*yEmuDndsCvpggPj}lY7{YjO`s}TO zTNv+c57;Ki2^vO@+Af$UbbD5-0NMh@JN*KR+kbBtoB~obVW%Ky!{)u6f@O@Gr_bFh z=*Y}2uw?qfy@J})kL(iEWn47<(=Nd^QXPVd+zOlu%nFN6?h<#`Gh5 z1QQtNPrtWQP<*=0Ucm&2_0Ei7%Oe;UZMWJd$O0N8wBIinAq6)PbbueoP$lq16d?09 z?gyLqe7|56({AqRS>DWxrawI(XvMgDy5eC$(dn{>1g)nR92A@m71%C&NRXM4arbt` z!-4|f-R}r3Gtjj_1fW`GY!^H(XvxU5ar$(h6M_>NCr`h3LQsbB*!15g1n)xIYSPoc zo)l~bEdr}LB`Bo@I%rCP6;vuRg7U^+ZqVu2;FHNgQ{z00+>ngqxa7)oP(zQ06|~2V z$#DwkpzQ6BPYJ$bWL!7>(iuT*##__>oe@-Id^}y@te`q*!^v4eMW)t{>DgxmD;d{K ze|lEXoblFl*>i%%jE|=Wf~Y^!Th9p^3%7!fTV+KZ0zG|B@Dt;N>HE$L`oP@1UHyWf z3TVTZ&qYBk#+%d2FAC-`?wtPQqM(WJP0-42v?ea&8*%mNL6-z8kk`>MLf6sVxg^-i z*f#z3WkIRwHJ1hR7~8kMzAPvQ>Hu+F6-;IPGri!dU=3r-^0!w785vuqzq=-=rPXz@ zNkCwU2x38tl;gEupam_$+ydYcF-HZ*cVIQs^{)#`OD*71VA5yg0j;lK(qQ5M9cKdT zv7}rVv}e3EeaUq}6~?>MPhJ;PWc)b&^>x7<##_@PZU`DM-ksigL(quvOq%j|f2`ob52ri=@wUwA71L{83#Kxz*#79XATJ~1+UXzO2qrSFogVa7(35e= z_Bn3_otZ(aa2|dT>|^{sz2KuD=p>^R9|e~(e&6o*Nl={;w8pFavmkh_*W1s6Qj9;g zb9@mjW@J1#z2>W+9^;|utG^0nGaj5S{!P%I@!<6IZ-NFwhxkD23N)D`K=bE}+>RTk zPha^>Fp2H((G~%LCDR4J3rc|+IlA8k6`2@Yr~CgD+{-v=JMS;StBj0Owm<$YsLaUN zG@bpg;CrSSH>dyjE2zV`d%EgB!7>nc?ms~@;oVp|kEhQGs!ZqlFSv;50PpmJTO}l> zANw!3R`npS0w-t=2ee9Bfn8uRw*sf*3kJ}_eDIP=P7S66fhALC2$?XhntE2q29)Kv z8HF4f4{i5l6gtDmcyzlIvrs)FW8?N&EJ96;j2pMhvI!Y7GXB}_&n~nN+)Lo+6!K?0 zGCiJCXcyzL=~7%mE=*f?PEX(x0;OI#ZlP$##_3huLbi-Yw(sB;l41gtKv#H$EE$h) z=i?J9Vg&J<_(A;Xd-#PWGyd5gARsiCnep)Ucfvxu*%^;aUnMQHjB)q$Kp7!n#>3N7 zWrS22k4*2D5t_`nXS%$skR;>b>6WrW@{EV4N6HHAVLUutOin0;@$mF&IU#+JTh_=4 zDKZ|OeojtEhwmH+yaNEJIV{GGai|qDG%1rEiY8h zcz8Ouf{+d4;prXbmnn3N#5aT{cT4QWsmGGRPC zeXF97G2`LsFBOFh84pjFRuT$jJUqQnNytU)4`}%Xt0waVX3#DL&SoX#!>Qm_HFy?#`(JG#TSlgaS<`KFg>r=&K=n1^lvYp?^H*DF{`4q4 zp?byx({JesX{#Ls)vg~HvlKwP%Q!%(jTN+nPJt1$fR_tY<$eGy;MLX_ng&|Ht1qO> z*f{-zzR+XFbJMRF2zfCcoGx!DlnY9QeTG8ra))>oz%|kgP(XqDtKbvAK^J#1WI2AG z{@GCII^*H#r;UW9823+qW+bG^wtiNtfWU|8qQ*iW8TU?SHxW`~JULy{M5vf?@ASDQ zLdL=;n>qv>B~a^}^=3l7(+f<6k{BO>wXnSdDUzJ7XCjox_z0p8B7~xE`+75>Y!?38 zph-*v@G?dg$2E_pYg!9QYxRAF4ij-Ia6me!Jm7nAna!AfFgY?RGJ`z9l;t?%>-0Qp zp;9rZA&}q)FLMN&_0w8NMGR^dTn=L7^q5UFT=E7(dCM#&l^|XV~e8%nDvmJ$m85yrkuXhqs z;_W^SF4o_k0u}4q*EtDQfit_7i_l)if74&M2rXdTxV_U=NETEWE_V~U#JFjCmAjA{ zw~!BG&vbPkp$&|ir{C}qI?lLx`vPAfbww0qKq4-Tlou3hl{-giEWzx-(Sd*apiQ&03j#1{X1Ad_ICsbX)r#RzA-?^h;h~Q zCjmmOa0M^G3d#b7j2ItGUl}O0N(x+DuxT>y02LRYy-g2Tp%wb}+#sPMM#d-89|Q}n zV_J89`h*anY@v1Mn*|&ZtB64d$@7K^onw43{Z6P*A>)JXeqll!jEozmb43U#OfL@? zngn4hGv1!A7ajK^~qty*WxqmvPJVjZs2nj5DWeL<^ZSZrPp? zEp(HS@yv9qSfM<|Guv0j3TZR3fk!-Dr%zB96q&vuMyQkR<&h=>Q~1lRD51dV_=P3Qkg}dz(NcY)1p%$ifpQZ=r3mHp;?s`%bQ~;d{;L73v zzWPa#12jgy;MMen`9gA_OG6Ik3oQe=F|$Bu6Eox8=`tlkHjEplN0tahGHn!?9up}f zKmBrv&?d%5)7wgglo`KHUsWok&A52_wNjxn#z)hA%Y=*>zfNx~6EbF6d}VrKw2;{L zGi5@`jC?1jwhB0ceDQ+^bnoTgav?LuQ`=1{gc_L`FHYZ9B?LbHi?>=RlJV5^^lBju zrX{bYPplTwWIQ!}ceRizE9ZJj6tSrH-b$MZG@RFJiV_` zh!0|u@bnFhLT4DiO|NYdI>fZ^!F0!Fp?s!&54LY=7V>0dTsZwti;yoN?`Rwl*PS#+}=(+JqQEnHj7Obxxl*RY-CBiitwsn5PR*6H=JI zZ>mrzXsOYHsX}toji(89FfN$BXPS^YsLA(qnou2xPMt2a2(-kCbB54WMy9TJ(;v(f zI#vIFKB$Tj=0=(e*K|C&s1ZDFjwEQ~c<*)tSWpt&M*tl&=(yl&hk&D*M4B*zD0+Rx(z>n#YbA_rvCFIn(Li07jCV=#R08OWGOT!(hz~cDe zGU&u@$1|5frT_HUc|yM#pG}XPFJ#O3eEanILi3p!*G)HHEVPgD#rAKDg&s07uG@ZN znUESIt6X_`6}TKXxWXSkny5T0FZ;WrJYit%e#`tdf`^`eLLCbx5 zwg_oRgOZfM2~Nyn0Q$fxEv3#XR(5op`G6%qzW?S+ZLhyAPw8M3Tc4ohg*fj zLG-V!VEOHe+k|Yvou7p5s3xA_P-5a`Rp4?w!2vOG@piC|>8G{}ZRZAAtq8KOgLC?U ztwLhl4WP*hN1iN@-D`J1>^QaqqT}rjp}mZ6x3AtQq|C_pe){=cLOzV|x6AAnVq=uw z1|Gb1WOV0cl5*T|dNODj-*FR&X5@Ch+hQbFq7 z$*^u_p9SgGS+Jq?vnwxy0*B)P z<}3wX1r80S9n1ntrf;|;RKfUQy5?me7skcY^DYa?FfN(ieOYKCEc&~{Fr7e-=2O|D3+0F?~Uolt_c+|?Y*(x;<}I^s1e|GLns3@N_tjE zVfy78LME~kK^;-hN^TZVPn3n*5iuUJv?Q*w- zv>6#!O!vAibd2%Dbiq49vl$moUwcPLmT|)L(|3fzL1C+MS15>a$@KEOLYa&wr$4+a z6vDKLcRJr~A(`#L_k?^Im67&Pb2$oRDRG03R#oEBU}6A`>+(2uT-kp3zK}2z)1))g zZ#)#rWtwzmyZa*{aYm-~J<}5&3+007^N)oNF&^7K>4}gr6KKZc_%k6x#>dltJ`)ON z+&ZX< z*)N6qLG1;dS3=TE8y8OZd?lpDbYS81!dF7sAn|*zgj7J{EU$%(K;jm!g^WRlR;V1r_j@N~2I9B9gBY;; zozM-C#;Nax{28B2fBIhN27k|8@Q&wV1s(-XP^aO{2O&wOX?LeT{~%N?29<~!|8Lh?-g=ca3X6_R7THr@TJkSb`l;j54g zKRx)5kObq_={bLdb~CPU$!#}c61D?-Za=fI==64GVKb1_erDk!nFbzi1xZj*!J;50aE_f@LD=yC z3$&*(-IqnU8g%gfDHh=>-X%LH3pgJB)g<7kByekbAgl0Q-YGjLgDz!#!I0(HvU9pM zo3J9&ZLaA7M+HQt7qJOnV!XNCm0j3~k!i=N>6IM9vLK^oa0s7cJUu;~Q}_nsgXs=j z!dgtw@!sjJT*7&v<(^-;gd>nwpn?ZdCtRK$&n@iEcxw7`Zs8|TJ<`)x@CfTN&pX&U zUE!@j^YjZd7&)h>@Cv)vAAJH|Cu7I$czGpwx&gXs>m-C{!|iwn!m@^}z}fc6H-*abG-48prR4{VAlcfF&OBD3Ss zGvN6R6K+Qt&?)bWz&vAaM>$1i$N$aXc@87UQmdVhz#0u9i<%Bk0LvLb)(XvrEXvY{ z@OqzvSApq4c!y7edAbl@`wlQqhucvYw8&`pVlY=5B6(r@9zJ2|}NYzgDiyi6vC5%SUZ0**dl3eM+HzY{Q)~dirY~_k=b#_ z2e7r05V-|w!8{2_5I%qewm8JM^JE}P_rxHpul7O0UKHZOGt)nST(|+UhD`|K!nqKh zAjGsSr@>|mKqBNm#Jl_u7jA^406uOtIG1tR^c*2!bH>Hnmk0^lfi~?v78cfKyg8j;L|7NpfwdD6wqTU| z%dNz(!0E`~zP3h50Cc}F@Nk zZvQ1M+|0;1=hRdIZY3UpThrTQg{whc;8Wm&c!3|}1rEm!kV8OSD1qD4<>iEf;a;ee z1AAeb9M}sN<%CliXHGYl7cPN#fx~eFNGHS#d*mTrcqlJy%(#5IsDkhp#{bi~6orp7 z-kp9)QP_>~)^tfF;ZQb^djxJxFHsWC1YHk#UrAUN(9vegoPt>ZK!`#Q1IcS{-3`#&6TV>Ih#2 zwOh~V3U@Q^pB|wn3>u2<(Gv!3s`{xXJcaS%^geyz1&n8=>l+AbGTxmYX&_w1cxL() z17UOFySJJJ9JvwAWYFjxXhqj{Cqv-~(C)0+M#B9}A68A*F&3WU@L?77EE@*UbRL5v zf)83n2f9TIHhm@Lc=s@9c0z=^nV(6lp1Dq$!Epl1^uTr@we4yq!mNx;KXy#lH5EQ4 z3f<18BnfKCv4WbyjvZH~bC?M`!;U*rk}+pG0=i1O;mY<{GvULmj9;cJ+6c?>Zra}= z;3(oaXFsU#JKe`dcqQXEh|H?P9RiMGj*||9WgLGBd}rD(Fx~2xKoW=sEiv3a*-ki$ zk@3#-clN@mLU-DlK_`JgYHY|ojl7{k3e#I1g#8(BZ@=mwtjWmuWBPwbVO7Qt+f|)} zGng13Oz(3M_GkP%{ho`k8sm-WtggZzH2-laGJ#G$1)Zg(z=YZd{&%}Wz){-q;cajq zSk6t@k@5KS1UF${(9pnoH(~G)fxf%&X5QPAS_B+994}645fJ#a{k^;JW_G6eJ=2%? z3mY-r?wNkWU-%M8&zbrEF8ftVkXBHrYuLKwPZ}7BS{@ET%MjBB&=+H z1GKh?nZcZS2a^Jm(+hTUrZr3oOz`DIeCEs_Ku4Xymz@0p@lITxzBfoXi0Q@U>4L$+ z(o7F7Z`TVJ<^``NvJDXiFD1(g5jJ5uuxt8)5aFdf2X;*s03DTgfJI>c^uSPI4I!`y zvjV@sBiLrd=@&zVwYF~!6;5De`f+)>c(|}X(}&B`Gs1-}Em53*f;Gz#X-yN8;~X}W zB~eU{3}#GsSQVHYZ(N>!D_mGs4(|FbAW`_*xC0>GgUi!JBZN0IzMFnBLRgWh@200k3L6V|yl+G4JAzJCS`!I!;)Ki7`J#nW8QZ3pL<Ftu|}KgTWM!Z>OA|0LlY5Vwv;!hx}W`nqJ{m5lAvBT|Hm7~7|xP7(gZ z*f)J&s&E`%KerO20&6yCokO-j*L1BkVJoId+|%a?NJvbtOB42GY@dE6O;}N(b4IIx zz&l}Xq~WR`pp?z-_#T|Hr}L%@-(zgr{w7^mlZml)x>%O5B`7@yW(n(n==v<->F{*T z2r3_#9j~CKYi7p>OrV4@-6mVuSOK;kPQ;w~0O%MfcoH}R;+?oWy+2zx2zfyyGbpuu z$QITGrDpjYVRmq8*2opsmWTB@nOA_$KwQC+rN|GeEkFg70;j-(=|#E14?(@i&^%!$ z#-`~r@`Q`{Kx+{}3*jcPDRB$zpDvLvoX^-ay(3>(hH?M&rTM~5j7`%u3WT>Y9-V%_ zK)4*jGoId6DBR5W7$oF4-M>gUma%F2+9Kftj8CTL6$`sFKApa;SXi5}Y5JpL;RB4% zrY|lLR$_cU{aA_cB9H^JN`+k*o3^hn6=np_sB9_|wqb0V{=Q83l2{WT=$bS}(B(&< z(_fiEV@ZzhwqGw7wgug)C|W7(!PqiAu2NW?@!|BgN?~Khrs=yXh1cqR`Q8CK@enB9LF*yGr;$zIbYxTnh06raEXN5yrcbRBE)|37ffS;=3<^97Ag$9Cs)bdA zCxA|BWJIlJ!mEX+Gqz5DUoEU91a>Isa$;r;rXP$-3<7Q2wQGb`K^No()(Zb-yuIDG zPS^-EpWRR|Y{>*l9lINawL$cYM$A-l20fMBfTWV8O-QLk5?uZ1?gSKN-(&YZDd)RncPY!bOZ1w|BM+{{gvm zdwZ9#5F=y9^jY1)PW%VHP6i!020Eq$+*Ns3bfP*%ZKPX7mWF zFrEFneP54oJtO1A?RI^_&WucLkEb{H3+pg0pT41AxD3SAm>_J%xO{s21mS&*FQ>~* z6b@v3wY^}Xa4I7-ae}VvR$v$Coc?%{uq9*HblJ(mN{pS;9VQD~g9h$uCkx9!R%tMU zR0^z{zI3wiQ^rrzyQc`}GcKO~dx~%$WApT`sltmzknTd}P+)ePzyZ3B({Y;ce#Xz! z8K(;uGhUfqI$hYDv1|I;>B2^gUDF>-7e2^%b^4+i!qXYAO}CmUoCNAJ&YLOh21>`z zW(wOw93(Z}VV1Bb7VBdmos)v&t4$Bjq&|-rG>)t7`vt)TqwMg@x%1$ zMZ)gvPkBKnL^DmFy--*cCiQXp%EjPJdS;Bb7#;9kfJTK(B`d3w<@;ctx7r)Mq~_LYFPp+SepuoO9hd8`U-0@J6T zTP~~!suDgf7xrMBKHX}C@I(;z>C&e|Y+gYo6`;*G+}j4!88-zaPb3Z9L^@r-|`>unOY4Ha*V`_v$~!^Wk-^;^W_H4MVF`Jpt*-3c3cLzDAS^Hev{3=H>2><_ z?ZUE*)2DCUE}Y0XeY*G#;S9#<(;IdOPhy-tU3jOkejt(o;6vY#(i$_j0yij?DR4U; zWpD>yk&MzxVFsNS{(=j%be>s(9lXGYO`vD`$jB;3ac_M znC^K{cn{mO`ON~3=F@$T31>1*o4>v6kgy0NQ^T(5J%@!gnOb&j-+maBFwadtcm&+H zd3{8z43*(A1;$ZQ&EF@bNW)hr+##bEnUH zC~VHuv1a=9hr&leisn5MwqaykF#YypVL!$N)3u%m$1u*H-u^^bhjGF5El-3S7#B=8 zeJZRAGAHG!a4FlPoAIEHcJbl2y?x{T|l7e5!? z&(!o}y2%S+6{g8grboRHR_B-xIfAWty8Laabdc<)7s3W0S(TT<2EtHTNKpAznJ$FUs|b_8uHihm_6$9Qyl-78@k!DGTM3{a2+N~PDQuYM)0C3-?w0dgmp zBS)4dGlLU@6NA9?>91Z1?_^vveaUO#Ovc00`Q8Z6Wc)pS#T((hj8mtly%m1PICXmH zJ7F8p_KbJJix_`QH+?U>iSg(57w?6g7#aU;*ZwH125L(MeG(4RY~cef65qhW%LH0< zzJ^7S14OT2;Z_n<;BY*97QUc)df-DLx#6aKIglzIH0GIo3*m7<eUFW{AqgpdIbZpgh5;$mF;LG(-tH=EIRkk;!r0{pofB zB5FcQUQ89p0?(|mfX{c^@M3zIfXI5rHPh7uMUF6C*tPwQphz|g_Z856SJ1o0lEg&n zn3?vjnf^#pq>|+}H@EBb!dJ4&)0?D3?3AHnkO{D$MOxBe;P}6(K|tW^^v6;nflL!# zPdAemNdVC^q(#zrk){_L_e|%O5s_v*GhJOqBt-1Soi4B&71+FaLGuR+ObYA*8@5lB z5iw5Uj&m60nASYn?xQW@%E+{S_4LU)A|aA34_d*udc$tCQvijk z0+YanX}TgZj5DUo>WYXnUYKsGD^kyRar#zW5hKP+(_iR{m@{6UuAnF4$aIB!`b8lY zcgCyJSL=z$f^JSer6(fA2EM$LVfsHE5wU6dA}OF_AM{0RI2MAg76)BgD=ETa#B_~& zx~~X}JShA9(-%o#y3RfQq6mxf^kxGQaVST4`g#Kq4arSALDx15#KW8^4|V3X=^qS4 zYPB-k2U}DB{Nd;1zgk=m$fV0*k;q6XJ?%Ur|? z6hi$nEUwd|Ekv?FK5~#{QJnt5LPQDVBOXf;&^;aQmLkg;uTOt(DbfycpA^J>v#dlE zL90ouM1nyl-3wZaSTNq4?qw}vCvl4#>Ty?IMjjb%(3+VGT%hyX7FdhKF`a0eW+UPR z^2b317Uk{fHX@;nj3>75wG}xC+CWfm4^A)B?M0F#XM)leJ0jAQK;Z~VThoOcMEp4> z2)pvKIc`2TJ<~x%hw~y&Ot-nGe^h5tWNv8eoZjy&Vh@(N=qw@* zn*4p`ETY5F(AWt&q&0r}0u2@`uynMGh#gqN92b#bj$aL(piM&Y(`z(YNWP@%S$8Nhod+4q2l4e(?tl@!Jqw5E@#@|mQ z2b81s`iaQ%AeqKJz0#OPp5q*-wBQzqpT5wTMM4a;@(Hxq8C3K*K4)+P+si%uyfKT~ z^wT~feA8J>SiC`j9caQ5K3z0G#GCQ_^uz#>5|CJyDU0g#KLH}zOn11a?=fXjWxO-p zKTxEL>A}hAd1frqOgBzW?>1v;m|hViBE|`J3OE+E%vltt?+6k($*~`lAejZ?r^{Nf z$W31!3@Ly7Em&ly-v|~_VLU(mZ?K3W)2!C%3L%gp=B5RU!t|67kp!l@+|#2iSvF6v z3>6V$yf%G8s7N_z1Z$oZOCG3*;In3NXS_N6V3^1p##__l!bLooZgEc!j1m!^9$>@5 z$#j!@dbACT(exkTA~zVXOurZ*BFqD>Tv;7wNM{M$oBkm}1auguM5IU)$g_b_BI47% z>{x`SABz-u0}}DJXNjFI7%id(;(!hIi58g;YTHGN_%bqH+in#r;>idq>13Q)6sIqX z6Y&FadO;lVco8+m^V99(MP@VoZkc{N9%9OD7Z!P@6K&g75=0moneKB>Kj_LLjudha zU0L)Q?@upJ1c%L>L=h>*>C?9-ifA!*On;Opa+LAf^c6`Wj~UNT?@1Q1fE2$|&P+d@ zEMmuaVmeof$T7wT(=Vog%e8T?2Ob@uHdwH>_PCuI}qRIhRG1rSFTxtoZ6hkUNnL*hYQi$<;v&c^GNE1*PGFUS%JN5ABHL6(RL_Dim1z!A?N0BTh&0IlfY76bRRL5COYpS~_z#Da0(^yk?k zsuDA&gZqW?O3+dTwB><8;5s+>(p$#4)9rFZjG4CZO;1ebbKrp9cD;G}?i`Ug*k#w7 zrz_@)NNa!n20DRMU^5@|Xnx$6U2mSAo-3lnxOsY4u81@T^s4L4)7OG{(3`F|Prr~W zqRRoj=z8;X);tjt#x2vW@5Xs1)%9#iP4Pd1d{@*;{~QH1qRTvLX~n6C&nw& z)5}F<CbVv42=SJM@%(!EEK$VCx$N+;@K552v(pO+7{5)wP%R>^bPn!FE(KNvP*ntT;O~d6kc$0e8y~o8 zd(*~e1FD9#+WF>zO6ODUe9@}-FM&docJRrA zMAvojNlj;~6VZ~`4XQ{$H&3Bth2xN{z_h<*dUBme8~p0$4|O8otDj}+MZi}-vx2XF zW`kV)+*vPTCwT#_^k4&*9_#`ara!0`NoL$M-K9Y!kMY{{%?%>qjMt`fH;SY%Zkk@u zC}O}kbNa$YaGAEVQA7rGP4x9f5gW#9(?y!VYATyV>@iw*u=I5Sl%!-Be@=hb1U3Sc zz@|$!iv%!knx54xA|na8I~vh8gJ=Y~3#@cgvq*s4CO&8*j~6rm3)-@4#xw)8i)aQj z=sIbI77=Gqb1Jn(#GUc+^tCM_4LCYfPOTy<7^qUmT|%KxggQW?aiPb z#apIn{Cu)Zt@Eb8>J(9B{4!mjOGJ(H-P~3IM=_8S3iJkxXT>G$``Sb>!N>Jd?9S}=LKe6NTy=dyNi zEBh_e^n4*ceWuCn(`$M~jG5-NPv6)pqRX^o^7IG2BFcUeee({a&AlEaUU(fBHlWnf`8@uHP>r&h(Oddh8(? z3C70hiTxrL(ybt`G77w9f?ZQ4tibH}fhkMiCHM4mB772zozu_uiv-Jl1~v6Kkkkn& z@PICJV+O1AJ1iq1{|}^u2}KFBV*_M_O5i#7^lni;X~q@PCrl6tmiZ3J;|Oa7!N#os z88`j^1QAK5-w&rtO%#y^1(mlLU$)FGbR7a<9S6WV_DvL#WV|>1#zYZ0ruW>_xy1Qo zA#&^>#XNedwzMGyiOXT?U1G7a~WtkCi z0@^3e?D&BVH1GR@Elc1%_jDfxK2^qd)2nBTxH3MTesH#kJmdT64`+)gO&6IYA~>Bx zkRIdwRkJ z8LR1==Zc6hJ?5Ui?t+Z`^cPUh!wWLHj31}#%oE83rQYfDL@b%!w@tq^PXv5#CYJiUIth%sjiXpJ=&NO*w?pD5$==@;jVn1jkA zt_32xj9;f)ED#A{d^5dwfrtU;q%P2aj4=1T>4h(3(;44R*IOvEnS1dRsJoTert`k# zm7UJHNTiVQ?eywJA~uZsr|(!KV#oM?`u9a5ix@vopS4)T3N*-YZLx?s(}i8r`Im@H zV4O95!4i?_jGv}kEET!U^p$)19%0FN5WS(CQHt^F^oh$v+(Fz%5lIE6MMBfp)iA1o zXhnT?S&+DcKD!#@qUnO7k}4o!$67{N#;?=YEf=}Va|4uWuRLrO5cnoM{mnHIlj#mU zd~(xYt`OPExPSWml_Eim`=)wW~z(7!PlMvr2@8 ziShUJk84B>L4606wIXi9y{DT&cVU4}%;4qb2F=KvnO?hAM2+$H^d)OWyg9)AF(!fE z)4#73(PI3)U1^<&C?m&?Q=oM^0>8K0uNNs|WZXY}(*}_@jK8PP-zbvBG~xAj?oA?@ z%#6RMmu?jS?WsDrRpbiev+2{eiGX$q@7yL51-gGgWRHkC6Jz^yn|&hkj2+u!_KCEz zGj>gXbX3HQ@yK+^VeU z5q?I#H^SUJ;Fhf8TLytQ)3=-w@nJkZo$<7YDdXww=BGuNnHW2#Tb~svW;{N9{aFzc z#?#ZEoE3S^IDPwtb0PwajGfaTo);-*oW4Eug2;9z#=h;mmqp4z+ZkG}h`2DFI6D2* z6%kj)*69LQML>s?*<2Ml$aa=bfk)u%bmnU!8B8aSPS3q2V$5{v==Mb*KBOTDzH*v< zy4Fn*Rmi>54UFHnU%V;e!N~Z1y3}nEZSMKJkc+W31mrhDEM(a~E3y8TUoMS&SKr^DiCkp*6vDX@TBff00ffCcD+Zt#dEsC-y3eeqop zecAau3ZSFfA?IfZv~z$K-!VBd2+Zf=p{ zq>u5^bpHn;E{qShPkA7c&BW31ak78{v%ucz?2koK86Qs1eJoIL5p9m2AT>+^E2d9=DbmHb za=P3rkp{-Q)91euapu_mezJfg=pyL{ufc{&zY$TG?)q9pmhs;7{z3Gu}M5Zu4-u~{5h%7VD$yJO@8ud(|rHdD)i+>PFW8|J*_d&$H{s0?j8<~az zi@*~;(0=_RY)Txw+@Rg)2iO$36qp?uAW+~bp8}f#i@rR(0wMYU&IFxb_Jd!66=cjF&_ED_6~h-WZO!-%L^D}2`~X?bWX9AZ z09MC50VIA!Aj=WyUUZNF%r^uSSnC}(ynwC)Jp)oVg9Ef*@CQGL{34L$c;&@p0R>Lb z-O{Z3jB_}YI6&J5HJEw?lvo_=-FSI;xVf1em>fXi)gz$91QKHaaXJJvm{=5;+(1`1 zID(DSV4A@p@C-DJ4;tlXbv(fdvZMY7f0m=30+-`K27$Fapa?j_sl)-AEoFt-;?B#> z!vh*t1sTI7@SG2Ns5!DrU}_ZD6<7pb@PUSuxUxX*06T_7;3Y_C0}sf?2JS3PCI-+U zYpe>ani@<$xXhVX@F;*<%PV-Y1YYrhXK6v_*fDD`@qicHv1%~=nJ#ZFsyL%Do}Q2ca#CmxhQf^U;SA`tsZny8B+;JM2VB7 zUV%e_Gs}@NTbF^s@fCv`t0M!qBDV$;gCZ#JVNHx2AZs9rQGwf$5tJNBNsRR*q()jK z#(D)-1!7Yp{=}%jDX=*9sG_tYq@4mv0H83ehXodBAqOZa?g1&U zcjILTadz-1Fq$!e4yUaLMKb8pQ1CG}>E6FYq|(44$mXb$WyW*@ z6sRXSvm9sroeVn9Wd#pxloM0}5E=Y0nBl?yf*BF~f&WFslL>nlv?z{Efm2{RxWM|u z0;@O)>eOKR!J^2`>@dB)N>sd_oq>^wiJ6&=1++_6CR>R^gGoYx+ntvMRE?N1fog2f zZLGQsvI2Mc6u_l|3TUM93_FCQ0BVh#UR1}K~taFQF&c!N0#bQT(I!g;#l9}!V__~Hr@Rs~%TeOPL~wBjO1hvhf58lDZ#sgC*VPSE1RVJg2@W(?!U}3Y-{1tNJZ4bws=x&;UYVgO z4pf?=rnm>w75<2bNyE|xxc)_T`}Dv+A|f$hcQBeUAvs|e$O*!PoWMkc6Au0n5sSj( z1W;RBfmK1zj;RGyd+XXUHSjOb)A!(2GNOxPcGxLJK#heAW+tF+6UfVopyula-Yf+U1y)CR$CVe_aoxfTPI2Jd z=3=H#d?~7mHF$a0kUO&+pe6{o{|M>Ka)25ftRTmLs*Vl3$eq~-yr4$bfO)|Y*xn=j9CixpuxK(jG%Q!Cqd2oHc+=jmtj4l6$7Y&*aYG_ZfDHWWnh4a z{9^>g*nWhF0;@j5T1IQe7EqPNs?V^M(VDRV%HGRp&G?5ARQ<1E1T_ORm{u?u4cft|C;(Ehhfz@pL~mhK1XYEspo`!&7#PeLzJvN=tQrhQ8O@l!Fe-3^Mp^zc zxUo1Wa4N7kGJ{58SQLf0L3)ocDvBzwO_$mrDqAn=3R-`n!SsevQ5cl4UVu&mVbx%I z!l)X+VsD|q{Pn4 z1Xj$XsH(u~c!LR4RA?x0LI)i0Fe%kTRoq}w6hj$gybJ12vY9cx0R<708Pf|84erCU zn=yR=aX@`|B|$S#GoBsPiJk-Y>|tuk0K+yT?pjQ2n^lNG}QklQ59n7%N9ivZ>ypb^eJ%v&@)2fY^d&kUlpjs7(ec>sUZu2m7}J&ICE30c7G9un;IMh-#cKdT1FQ;2TzA7*gg{=x)O;KmC+ zCHw;uQa}0&6X^VVRt=^PEQ)Fh%nBTi4DJdNu)#o9$NAvGv55(h`IfWRgL2voRWCLrK5~zM-_|9ksDkeZ#;R~Y~!&;C^ zPBW%0AetYt+C@RZjA;*uuWQbH07OfhF`WR>;$}=|K(vS%(*+PMY{qm2MDv+3{QyN7 zgBeo;$TCJNh7OQ8y9N`3BV&D*8B+^r6v!q^Q61DFcAUVPWybV}#c|Dx$pX3z42l{G ztd0lSvlNvTSRJRZXDOXqLw3rqNoC^;}e!F zC2d7sM+QYMX7JcIv}XFjk|nT)4^+1NVO5fMVN}k9>-tfFeGXfXf>6RKmvX$fyV!FV|(5!=@w!x(Wvrz86 zLFq%6;XbpXET}d*zznI4&M+&=fnsL`v!afICa7p*P|$K>FlS&;kN_Rw&+2%C9aiy6 zfa>{rR>uqMu!>#+WYh_EP@S)WXn`{*s5o-K%W`n}2*iUEnL&v47x>r6i9t@vwv9 zOM~gh^jQL;3KBeKOdJaA3L2nBFgqw`2!JP`A56a_AgWg1zyT`31O&c;UC_Y+OHxF; z06dtDo?yVou1)|or!|-wIF!J<2UWn6ku4lb?C|-6DIE3S0dE0;@1&OdxU6Ld&uIt< z{2@2TW#6Gr;43NF^R8sF*@3@xT)Z zE0`5Qeal`>kQ2ZK%?(hvJ8s~Fm3OR;7r-JbIKkx|xFz=mTCmkacanieXYPP3=Qd+{ zzyT@Qo`41tK+Ou!2rq{jQwxaJHD~?-k!S7z@mV#Q7jT+0p8%BO;WT5q1ESf@ zm_Q?@pt=@RV}nOcc_GsppwtN(Wdscig4h?h%$a|1qSe}HX}BI#UTQF{U+jiF%XY@00%5+&>WO{Iiacd3l}`~V)X{u zzNja=3kXf#pn3Bdh;h6H2<8rMQ1+a_gGk*Qz#<(yNU6KtoOuFhn2yJcsRu-}n=yfh z{-9+vc=(Uk3^M!&ZIFV-{XogPfybPA1$Y<*sfgwQ$sAx-)B|OZGvHJWPTk@Ptd4KN zZUYz5SGcnjz$v<(71S>L0V=_NgI)KZ8(vI;lJpUfqr}aaKx2uZ#^)Z8N(M8g2Ox0) zGo~jXTF;#M24oPD`2~m%I?UgS;X7EV6~i}>5F|x^1u=Eana+S{R(*!Q-1XKBKS4#T z2qgArfX5~wMQq2p$pQ)@&}2M^2bPR`xRH`^2R9@cgX6ykwDD7eiKGNVVflwAozLI_ z4WL064}eBnA;~-h;?V_QkN)7Qhm_JB&~(0p2cFKU>rY(Sxt`In9@=jI!Hg7^q?hxc zjDWOA1-5oYfz|N^*slk85gFkDSY!upmS#QZ)I7*+4R{TT0uN}p0;FdK8o2=_V^BE{ znw3`IHDdy=pn+xt&>9y|a^Jvf&U}Lht(=Et1n^iPQbqu6Y?}*SH3QBF_2_F}K-mGj zSY|aZDEqGGMad3dKtr7(W=tPIzGX0jEU#fOW10Y3B_m+QGzCQKnlpn|&48+|86Z9+ zJ1mE;yaBDiQGjHJrMwCftcd>JACTdo!C78whLzKQN{h<|R4+7!%k zTrzWtfTJ;DvJ29VXE0+rAqZ|ZF&_YF5;kK3Yi2ZK0_lWKc7bN-p-FNDcy?olV3xp2 z9z{@lS%V2OstrvJpy{r9q=g^g8iGEF5}qcpl+G-m6)})mK50-_9MOITue?C-2(W?* zp%dV!gp?|CK&6T>v{X663oBJHybktxJ*aZr0~*NDV4}0v!Sxa%{L%6wPQPj}o!|vE zX+Xz%Ko`A1${io@=#AqAa8Rt^ffPGD&|>EbFR0jI1Z6gqfB+4iBHDiR4~Tm3qE>tb z6OIDd@g(SGY)1wKMQH^=Y4A`SqQ?YUv4ef;b%y{b&wqfIRQ0Tm8^A&@c#-OCbMSIr z1p&zNUQpK>yw(_2WrLRff~sr~4K1laQ?#Ix>H)7g^9u0n2~w3U0FpuKRe@(eRxm4y zfO;oy!OM=pMHTv#EvTddtuuD~4R+#v)RO85$a)borUM|~GMF)eXMI5xH%MIAjOhu8 z)-?w&Kn9gmFF<_I%^p?^-@#g}7`_R(f(l}AUkS9-8c|Y#mMMdVmhSReGyDXp{sB%_ zpvA$^F(L(M4*SEa#6JDtJ5hD$WG_`3f4s)nIag)a(s>pfm)UH3l_c1)w>sg^drC#Tbw$z6UHU!oX!Y#bF`u$lwl| zt8=^nUaJ0J`gbK!)huwW16n5psdyZB2xd9H`ZpPLcO87O2e`@tH!nd|6~7r1sLBF2 zFF|}_tE@p0mKj8ZCFymRgyVmPLPrkJq$!&Mm%vXxMfO4ATM}~-ay7*Rs)`jPtr#wV zmWeQ0F`Ng{4Au;1L5n7Ztr*ULXi+n!6Cj$&jOhr77BFKv0HQ(7LOuo7dIb(MrX3&w z(5w}R<~C#605-^s2{iAcAZErig%8{gV(J0OvzRe;fN1DCh!qg_3Z5)8rX>*e53VdT zrUel83C=7tra2Jy42~=_rWqi!Z-BEjsQn-SUX~19IB|z>XqIirv7!L(IelRQ$BqWm z4L;B;37alM2Xwk0yzEAiU4czO*ovV8G_%hRo)QMH3<51jWOaPOY?GzL4p|x`1Ya5? z2pXd|0aaoeOi!3VQ}~V#_&{qScp>{)grF6~lj(OfMWsPYD-;L1itr^OE3+cnn>d;t z3XBTc3cLcprmxk2EEySaf03AJarg^V$$=Jp3akP3XTS^dUhsjIQT#z$arK4|+^A+# z;D@9MuIX45yJ6!#Fbv=s+S+$Cf$E5wbLlPeBN=H0;atzgnU)gTlkqiFyTA zP`Q18A9ORjHRC>h1y)dLum?nonlbGF(M)DcTR^mc8Pf(3&11&2h96p9uK)>fnlUW_ z(cETC3qZ7(8B+_07BpjO0MQ}};-Ix{prRMFwhctXDnToTy&x5!k_J>dL)bs~L8UW< z4KB^6K-l2Yd;)}hf>S5UjHw600T<^TAU~XdG*`g$pg;Iv%izxNPrs`vDm5sg&5^Wp ziY3QRzo#oI#dm@qHvE5ue~{EwL8N&NXFD9UPFO(|PEHJB_w9djGV62}i9A;$;&C`%k~@SCeLzu*V2aeTp#bB*H@rs)cx9h4;o zqLG6lorjZ_7{K$5=p#I!c{RrlCQ#FYMc@cHD{Pp4#84D<*B+?$(r0|buLPQ(Wz}E; z@7rSqpPS95z~{)A1zjrmhXtnM2aBQzd?6rc_au0CF=V$fXvH6BDLiOpC%9+KfY|c; z2UOgE)(6(3FZV_)>~=(2?u|4OLF{U8P|pd}p9l5ZCxE)&XgiQWuI&+UR$z6!f@8}u za#!AwL6HfxjtaE=3cQ+3Nsz?>w1!)QX~J}UV^K-ZF9KPhIU8Mu9?;@QR>vLS{YT(h zp4Abu*9X+~=X7iV?Nnxmw(QQpR}=I=H|sJ@H+&^3900l}9CW-AyCM%aXoeL!+qMVU zRLBk&h^ZZ*xmK8|OW<>@sHS>AOYREw&VF^0R?t}-{AEISKzZ_ zsHPc1O}oIQ$PKzGT@19+k4b?CL~$r^7dbMxD~W@40JCZ^EnosCg(cIcnuu!FuK^9> zLb|`8@oCVuQ^!;PCkr@gppDpqA`v{Q%>)_M26cbIniV;Mf2fuGe6Cz@#J$YSlv)QaoWoT1e5t171fV3SUQo8l18qb3i$dO+ggC zG6JRq;?_t|$Ai@ow0(e$sa`=0vRJc&2_!6_AXo(9PXHZYCMXROWYu6=0opjqs>`s3 zNt#;#G+Ut0xCK6LERI2L_*n7P4yCPg+-HU*Vrj$0t9n+Y1F@XhYXE$R4&)joCX6`|u z2b#5agsjvAWmND+a)CeKT-pL(3kZu;hz<2n8yeU^vC9P-RRSFk@fW)E2BsLi^1DL- zJiEoi1j!Mw00bo~N64lIkgc2wOwj%9cUVE=b>Ja!m^t7&8)gnOw*uRAcS}*hG;nmI z<@kBCV7r^3ODDnhfR1Z}?zaY~6&4cG%JhvdC57uj4FQ;Q(7dIRJA@s2^{G;O3VW1!DogrKqn)WSj?Cj;O=E=0iCH2 z*}e=~v9bU>vDhI9pY8?CZ!`#+GtUqNZ*FFFoFSOyxbfX&0Y`9Y3P}^-{ePf62@Qf- z0=Gd+j_d!!c0F&vW#S6ZoahR{EXP|Q(^x^l4L1$Eq6}q9lo2{53OaiMq;Y~EXz3v< zXoMQN>v@78bk{S;lzQeuSLixzj4($Da-=aKaDbtPG3Z_o1y;~TJ+vUxVA23>sd2;= zUiGK}_5kEXZ4@sufm1s?z(@$MKG3l~;0==?pE4JMqaAGuxgJztf=Bc52ACdrn>fT6 zDu$Pyoh8#2&@yaYJEje6pk{{#sF?+66+x!9SwJ%k;OY=G$It?rV~_`h56kr1oMMvG z?Hxo->Nl{#_u8_f&5*;A14Wq+B_UwuJ!yQIkJnLDocO{6RAOUI&J?-dmw*Rg?g#I| zL`&G9OKCu94s_Q&s{(`LjuX>AIEqRIAr+UPF@Fuv;WsR1Oe~=Lm|*Ie!0O?}DrDzP zhX5#>pr~U2tD7Fl-D^~wmk{)8E{rIkhC|MV{i`ROKpU{l=v5T>+4gk~WL-GT_cg$wC1{-5sPkI>WL z4>smtsHpJtW&WZ9Fn3>uh+ixc6`uYRNn9-etllyJVMHZFs3$M(XpKM3Kyg;0{g zV3n>AsxTO=WFCZf3POE@P)Z?Sm3|Pa3PLS|P?thPRfWMRLJYFiQHc|DukGIHT%n>y zLVqrR&hgSCQ;clw-gQF+E@P$HFM{6GET22tthywgRsrYl5<3W|VLA=&VsL7;28YlLVT zra?1xSssz>4YTqeVR+W{FHc93{G4ZVyOC0#vr+ z)_onMMiouBPK>CVI%oh`pYe~N5*x1>Xlt%8IQfIxlRpF%SOos_fg32o(+k5z#ip;1 z5fx_aoo+ZmRCfA<7*QL>Z_{OCMGYByru)Z=f`Tb8Ry2~SkAJ#ctf&EssOR*gI8kB7 z?&)Q5qVkN5ko>$UPSk<%^7PMfqBA(QuATy(1xE?6yYZqP9Pd6%2A!w7VmhOcnC$dF zRiYx(;}S$U7`IIC=M9-R_T^P4dS4a|-O9G9S>oP3n z1NEO675EgG98a7>F$r`W4Zi}Lz(ly&pnawXL_o7Y9~l&w6*!=qwvLD>vV*$%te|LB zV08Qhm7KmHNmNf5*=dXlU<0Q=OcIsSY32tVItSLw$jwx*z^%aR$S5$0-;uEp)KzfY z06u=}GlK$)z~t%b$)ZM#lcz@|iv}`InZ71jRKsT~zaw*@BO~bWDJBNc!H*z6poIp) z#pv@@M?}E8gJCXGND&ohoHpGeMO2fqd3sWcs9_owhr>exROvvx%dEg6FpXc49n$5w zAqX1BWfFh{?kzz?;G#JUWB?>Aex``(GB!_FPZibW0XY(qRt4ToPe>J&V4OC+G8OEk z#i^nyjLp+eq>3sqPM`iVRa8!32EPIaIO3pYPY?JdDmq;!O;m*&WDqRwqtiq!nI`hX zWu*i_=>ysI5UDrmqHm47b6~XLUSrZn|8$r~+g2bo+GCQpW!220UUS z(|9&E7v-4#CS6pCaUvE`Ic_9d(B*Z~L?x#0%McY}oH_kshUjT^aM8meFbkY4 zT7;F@c=Z%m9l_}h)Z*1(Y7hqHTS$p@FH@9XcnN4w4_a6$v4P9nX<4E=jI*cfW{IkC zgG*jEP|3S@dR&&MA>%|y?p%{4YQuPO`pYcQRg71r?<)}1n7$`lRDkjS^t0Kbs*)(C zLP~P*QBq5$H|B`SaxGw0D4)+M*I+Kp~ECwSRtkTr5sTa znElMTVEY|%MR!5%7X;nW$f&@q!0C7fbRmbp|LG=qqN=DKgxZml2lnC2JW&sb-JmlJ z1@=yVlP7A%2eun_Xyg^JgQxrEiwg6D1D7A_s5?+cwdNxnwJjg)sL%PLry!29VEjM* zdx5Abq^$!DWpEfz*DVw^<$z@0FHoZz3c&@;+(K||cA-#IRUA1S!TP|V*fYJLNK|~f za*?PggzG#Pcc^)sdbJ ziU39pCLSdw4JH%F2@asMJ}m?$PM=sTs>j$2sX8wgi;Cb?3~ueom52&4HcvM!0b8C@ zB5KMwXZkD%b)f{D`F=s<7W#?`Pj@I4m1SH#J+4&Lh_QM4#8Ocsx&M3$j0!xC%!O7A z4WL8fSv8qEK-)TbRJk4JoSOcyRJ4+D?)2y~Q47YopcaVm^yOuuPLSK|=T3iLCTa>} zYn6+xLDUQP%0)qkze-eyI&v)Qn$dD9IlMUxrdPM=aKs>C>d z`u0juU5;y@3P%o7Lwho=oNiVnx)5RJ{VK4T{hVT=)Ag!FbvT}Y4Au}>F+HgoY_Q%z zQSs>lHKH1f^QK$YhJm8 zf~^m&71ibV3bI}iV!ht<9kt*F!j)RlJV+$62+V?1v*~rBB^-^@rU*EK6dyb!3UaGq zq^O7hcr>U%I7^8G+_axDJ+NL>mhs8-{CZK)9fO(;qA83Yr}s68<}qHF{vL ztzA?Gq>N4QhhUb12xzX84cvHQahRUiDk?EOtV7g|@&EL>9iq963#W5;ikiUMT+yAP zQyDKz|JW(2$+&vDbeE_jW6Si|E>RuE)ziDWz^%SjUEt;nxYf76UzC0N>n>3Z#^2LL zxL!>`1~ z3tAlyaxGvm>?=QU8z@8gmLwB^IoucWG_s7Rm)tph@7EoC2bLPro)v)Pix*bpFYr%8aY0 z8&4MXWV|@NcCzRc#w*i>rieCif4Dwb0CWmAgTUVD^QVYfGOggBE;~(BX8N}&qAGBX z#Z*yQrj<~c;;EwYjH{;qoeGP0c~BbwGbg)>EUIOc<7v_P3? zj_5pC7ocO7s5VD0=#p;%ffdtt&jRatF;~=_V;)G5Utq;_li6Uw#Cf8IjH{rB;5%Pb$ne3X$pWAQO2NAzZ@@Sk_#w^3 z9sF62A7Fx@gM40Gnm%E^s5s;D=_}@oYBKJferdj_24nN|-}6OfWhU~&P7G%O9g+cV z9yfs2ok;UQG+lDB=oH2a)7LE)HRjk33I|XP@^UdaZJ%2rDmOiFiKsTm1CWe@z>4Vz84bqm z)4wkfRgn1vcPp!cpazow_yiD8%T!We{dD7{qS}n>rpGT8?Pq*E{rytWB*x#!zd;9F=qK=GAmtIW2w?b5#>B5WY+$%**86R(V zTq$bB#Q1-D&1%sb)BD$o8cuIrBPztSk$<|v8d2Tp$JU67Ksg4}dDe;wFz%f$yH?be z=@;MhiEBl5ru(iDWoO(peZpE%6UJxLkFFKfU|c)>-C9u_#&y%R*NMuoujf(X5V*n$ zQC+o8REcrJ^ttOqCviO6It7y4-&BgqO_viAAcQceFQb77fFYv)clblb^n9 z3%I3oWQ(W+QHAN2J4I8u&rO23hDV8g zy22e%>FHU!MP(SbOnPLc$UznYE2e+kEgCR=_AXI3#+B3Uw~HE27u_wYk58}d z^dq}PRXMh8o+99A4>17LDYxG)YC3)I9#I|kz2NY<196GKUeRL4wbNVnidu-Q;{ipJ z22+6&cox1yiC19#^b31M-!uN3eqf(yI@cvW(A{f%SpvJK8}1ivVB5m4z^}kJUGu7_ zDdV2$Z}*F)iLC-vu%HkC^%P{`J%x)KL=~rZ9S{xVd;#+H4F-V~pb`nxoYFfe8p^nN zddor4IL2+$A0HGo=QubSQD}jb@E;YGnBH@tl7DFu3su*3)-HRDZhudQnzpP%HGz1W~=|0f)fN zK>nkmW{el6yB!sEih$!;kYiyPgnxR$F;N-DmDBGZ6^-F|43am3v?Ia!2QJNj zR8)NWl4GJ8LaRPc7H|{*jSxX*B6vBb$8(CQPwzbp8%7bGu6$fnhhqWAoyr0$K<>;pSbE+GQ4fyYAZw&Sx~oKGA=1JpMMW6F z12y1gH2ZXylcLHT*Fg$Fjm7+vqSM4y^1udVKqq53UI5kW0!yb$pArp|Tn9M@$%)5R}} zT5~|N3$m%w)3;v~jbL0mUEq?ar`jqW9?)b0_;yb4SO93-I2ULTuR;mDq@zZOO z`b(nk82?SryDS>Vcxn3C%c4J7SAmY|1ledS12KeGfnR|Ge5n8v=oD5i1wI8ffi2Tj zu8LYQ?wKBcRn%P)qL9_G15`ySFe^yH^Vr7Qq9W5TUln!bM^PiNbh`RA(I7mrIq90H zKhusE(;r_GO=Q~eV!GRPQEQ%!;8LPT1T@<|{oyT96~wP3)%0^WL~S^Zg3>6cE)}{7E?{GBin=kbn!fm^Xfxx#>FT#ctsq{vo4(+d zXetZHozvrQifT;fJtxY;xN5rHZBb*0N2RCt-WKHs`4+Su#Bl*=J+}h00za~EEf`l# ze|1|_o1^~`q$Hg#dk1W-{dQ5E>67n>sxq#czVnXgM2;1pLI>0_J$Oh|Z+gRBa7H(b z6cw4i;jXAQm?uzCz{+{l2Pt=bCyr>J*^I33DG>`*)oCb*Z^PZ@q-Ud*I2{v{y zhgXRWG?uBsG=mp(#uC((OpahxAUzrPMMD@bZr^)f^fn`8#6knyV*(Y9h+&kxSW(aE z(vL(98MjXNeIy#rxOMu{N1`^2TcsiK;QKnJ)fbR0-TRdoLQm`h!19VAJ#o??s~- zXH0+dUQ}Ir2WapZ(u)EWXsnJ6!dZ}E(4EuuK8Ut6ZQ!4-_*JxUy2eLQL&oOmQ6EK{ z8MjZr_ffQu@xt`nPoi3kpQbB(6^)qw;ghHr$Wb<*!G25mELsmOt+wz_Py8qvG@b9G zsO0ppFQWX6Yo@1t5w&I71#VM{Oh5HOG=>{=v+p0_ECnWkUmyd^7&lFy{#A4q2WZ+s zpYaLQj1ON$#iuX&ChEko8yr_}L?LE>cqb}7J@UKgcE&x^1%HUdm;eu}y?&X}I|Q`8pf#5bbTKmHWentt`Cs0icQ>92l@ zS~ISjuJ%h*m2v%apI@Suj2ou6{SuwcwCBZi<=>*^Lg2>74A4os3d{_7W z({KJ4_2GE9c8Y+bC`1<2IN|#*Dn7MO%$Q>-NWvN-fuc=|QOuTc`}7P(F_0UkFp9-+ zd zx4^gQ{j6d$882?vWD}bLx?5@=yO=BEmFX-TVit`5r`vLfm2jK|g^nzw&7(K{Ifoc% za*df&%nLDo7s@FH8WZg26m#U52(lE^Z@$4P25N`qbBP&%il&8JVzR*<=aDWV?GVm# zY&eh975#Az%4raW7E{7mj$h89X?X)v1?rnVIX7L9Tg-%U%5*nwF=%LN$?o&(zVJ5f|jYI+}!7~gbu9x)Bbbb&Qwe!yV*93C-2$V7tZ^tqy9d?1Cq z)9>+!$uO>){+mZkmT~=bNnWvX#x2t)@`|}L{-1u6SFDuj%8Tg%d}4Zxd#Bg)iHY%i zgN!eM=JDVYnFsj9mUG+!O{sw<6Z84O!L*WJ%#q_={}cg7C4m*wKk3V`<5{&<+pHmT2o1QBu*2A$1WCJLPG75oh z08iCL35h9jtOQvjFR)_zYhkc8cjHB+rke_jX>%L^>5&uwPxL_}PkuUB&q_@fxR@g6 zULFNT(4v!+>E~6%RHvU87mMMT4oa4$uw;p-;)SPAkPvfa+&lf6gjkpJ6;Nl41KJr| z!l%UM%F76y76c7dC@?vK^BhbCc*qbEkNk?D={pvI+0z$Gim3@+03FuA4w*`a%--CR z6q99~IQ@sDm>y#bXmCvyJV>m;w17_$bYUDwYlsw9t=&>!tt+L#S{L$(fo5~T!iRp8E0I31pwH6`=P8zS}#4;IoY!8(e zGh$>sIK4wb%u}}K22$p0xq--@Ox%vQr@vDW^I=>*-C7amKy%JR{EBQ&4BUzq(;eeP zC8lpx6x*tgHkin-z$tK;UlF`emesKXGARG~92k#G z|E(kj8d*e4d3#Quqb$~`hh{41>KBBmkme)QRBnO2Jkx)9iONjRR}tf3Tn$23)IAPMc49x*9C*Bd<8}YP6cKK7J;?fH>rtv zGm5Q+90LlSOa$E>3cB=cyRe2>G$Y?XMmJtY9&S()WD?jvy+%`P8RLQJ%35NEjQgjD zYKcWL9-O{GODvD^z;tt{SLJyu6-HsgWmKXt^WG9H-TuPYYHcwqWd zU9k$@13Zc>pvBgp+0^~hv-H4;i%DOsgbOUg%8D`4ulGF{I~%#f+!%Jf7lF+HZ~9n&XTiG_0uFPjS69*`L0^oM`hlp(4m_#AI+HlN8NW}TVJD`+^#8#0kHs=sjE|@5+KWko%=fStQ)K); zJH`U7Pdx#=sN#dsOtOyBM-_DSOG*=7MpX7KU6uDnbNT#gE$ z5!MY?rXO?>3ul}(UD8zybRDdNtC&CIujvy&ykFC|yNYQtwoZTODyGW#dpf(Dn5^~` zK5Ir6P?O;SLzW5yw=C30pp@(=?|5o*qktoufeUoQut3Xp2QRS%M#dG> z7kY~wV>~fE!$+)^@%Z#-K4OkcORh}sGZd1T?&vG#%eZ8EzpvN^#*@<>{KV22H%?#f zCl<%FfqS~HznJuNC4aGH(}e=WRHnc27gJ-LKK-P>nDTV905K`Xz0(5OR_n9dX^ zX3R8`Z+gQaMiCBBmCEe6w@-vEAoaWaW{Y9+)jAGJR5rm>5JrcKZ1+G0Ex2L&Q`W?@xalB4)>Uf4WYnSfMyr zy)?H1Gw4!`N(E-eFAQ0ZKQ2$-5-Mg0$`a2*#Z0sw@GG%GQxF44=?#V~frtD&U~M-T zvXmGE9`P%(DliBP!v2HPaYt-ztcG=1S& z4&mvE;bNwY_oq(}7c&AW4HuJQd_4VWxY%I{uu>6_O$=5H6PXm49ebF-t~wAQW(IQA zj|edvCv;bRUB5VRrn$n5DoVfUFvH{WM7N^s-1Xc@DVS=SGUz zvCTO-SwP_a^oNmRJ&gCK=S7JnFy7yOK1%F5=x*BOF=Fc(_fHRx6|-h~!asdQjF{>4 zld)nFOi%fzFNha2m@XVAmdN;QdTE?kD&w>5x8uab7+FBRnLa;OOntjdg4ix5{vVf- zYOD{Jw?9o1o5slaWO_}CSTp0(X{lmQ7@uu_nkpv6#CU&OhL|)XOxHglp*C$dv%>VMT(O-XfkHNB z$?bl5Vslvp7p!Jsvae?W-GSO5ovp;IGQGZ8T6DT#v6zB_tOA4M4@S^2=?soGp!3fe z9M>>rDVi%VI4)q!Qk0(_SS)5(zfv+wQB#50af?uvqNM_};|ifHML7j#$Bm3xib@L1 zj%$Uo6txtX9S@3RDQYV)JDw5AQq)mk2Gw|q$_mVmCnT~ItrVCY8^p5|RY7-=OJpfp zD=<4Qkj!#qDN}1SxWGYhB z2Qj6#J;zU@{eVhflw76^eX6UuVDzoJXPQ3!O&Hsm-j zS6+9Xo!|{?LJDjG&!;n$iz(GFkOZxTF=Lt`4$-B+;JD$+WB~!tW>88N4Xi|Sr7}Cu_H-ALhI9t=?BZjqy*4yo&LI940NHqbOmu9*g?Jrz*@0- zU@(i>b># z2aWr%IDkg!%$N>HfTTdFLn6zOQQ*z=jn!f*^&s~#D6k5=f5k z0(jcpz^Guw>Ac4AMffWU|8 z;&oycTt~Jx2{>{(G6=kz9$6=5$@QuSlp4VNIdx)AjPIu3hfqrOU|wpym?hVg6=_ZY0mK@X1f&KGwdMSuE_jVIRZX1ZV>Qp<#l6{15}{c>vCTpiF_Bzrb2wNM$)rn=aTUCLRV+1u`Fzo#1LZLG=e4QXZTJ z$x;wa2PCo_k+T$B+ljX6b!}o|iV$U>Vuc807o>2QwsGb3H*MH5s93w0F&n6W75FsW zzg^6d4OFfQe45?|VuOlPflt%Vg4oyZH46xQn$FW9X3h5IWV3+4=jpy3Vh)U-r}uS; z<)}i_l>#&9%)=v~h+;)6WSIosOqcHzQ}KtSFjyfAPGS9^6b4BL3oug{C>?;>APR_d z2~J^PT^k@N3{;eYtbPNv8l^yH5&7i0u9<-k&HJ!myMvnDgBPJkwz25^Q!PdZ?|Hzcwg ze}Iw&2U4;C%S?~}IfU8q1vpPE5Xur*$_%coL8h??AX*w=)gW^;!G-no6Z*R*yDI5MGH32FdAwBdB=t(H#EPynI<)DKC(5N)75$Ox$utUx=sAfW?t z*`}3U7}ha6-eAL)+o$Jsiy8B7SlR}v4gNl95D@q>eO5wql-0TNe3=}lfMj0YY7!9mI{h?Ad<{sP z*>M|4eDkdqkhoZ{mqv`(K{gK37i zB9j6$XkR+G)x+$#Kq$+M36uaq)uiLpjZFfMsshEJYkoj_HJKMo7u+i*>IG`Af|C=t ziKyVTTtFIR@&OSg9$p4en{4-oKYe4Lm?ml)rvX+@Hb5FB)4%tLsf44H_K?&K%ZuRD-44o&1RFdLKrISZU^76^eV1ZGE2p@`HV2OCbPQ3Flw?Aum^GLt zNGP#59%1ljsRxatF|aDIa68I^P8EeDJ_ZFg$DfxPK+TeG;6@j?Ky3j_qkw=H&AOAqw(A`347zY8DwAsuEsMs8t^rqLE1rq3<@+54GwHr z%9?;$oj2Em?1H3QEbZkP;^6xH0=QfSwPTS>NRU0?yo-^v;4+HfVir6s#M=x>ZxFNK z#ikIXs|u0@x0f9^t(<;fGPW3gHCfCXDW`&V%%kVjpebU?k_*6%Di%beij}t-)LRw@ zMUZ$9IQUr1m~Ox{g9=?nP*n#Rz5*)-)oh@qHVe4(0j^hAK`kDMEP>Ua-Uzb>(+epx zrU{^0aKiNOQ^Zv24}j|+aK{PMAcPbVNEIN&6_AjI)qhCUAGk}z3GNax!z1m1WR}2I zHpr$eP?hrnTsgwy0qWoy1!l(!te|#P>-70k#Y96P%HTnatV}A)5mCV)NzC8?XI9Lv z+5`@sT9AJhOjpzumj(G!fkmJV)cpZ(C4OpN-P%whpE8yA#wABsXKV{`D z12u7RZ31X1`V7^WYwdzie5;VF@ZB7 zq(2DiK!Oy4Yat0pxeDq*3Or_YWGr-Lad6~NWC2OOkWgghsQ`yQv|f0DoO>a@z*;TT zg9d7#on27P1uniI!2xhU0+GBRRT3g6LzR_-;{##@Mtqd|+ydZaAy z6fk}A3^5&5P?ZLX1W;r^TcWT!6I^hD>K#Z!G#Xr1v4V3HB*;Nk7C6YE*g z1RP&Tfcm&B0-&%2HQ!)i&I->n;39Z>_)IZ*=oke!YCjv<{1cz%Mq z2&@&9G7y1=kU?kzwe*+;L=iPIT;HaZ(;vneOOddEgQpmhA0Q4`A(18U zeY(#qF%zU506K*RR+7OQEOTdxsnmnw3|1O}64MO{XwMEyM*58c>g$CRD1brf zTME*4felC1LxyEw%>rTYqHb_uQO~0HkE-bTw1GFrI8JvDV-4|$bS|F6A#5%q4i9%vl#G?=z7Mz+aAn*e|FaQsAL{W{J!XY|A zP6QY52uWr~koixiubV3-?gdc=D!LFIF}TsUKn*}}!2#C|DpPh~t&gVj&l59Y19d_K zeoptCCuYe8>Zl0(oZbOqL&cAS*idn{`C{fAAhsiez_019ARb5+nAZa0f#nzleoa3N z;(_HrJf;O=`sSdP3UUs*Af?0#?Xf`Gs-O%BDttiM>xUS0NPWiij0IvcjL`ZL(hL9( z5JK7y3M>M%xCDNKTaTc9(%{~a0)qxq4tOie0!c?EMHU4$Q1t{FMA2v5A)>_U$RO|s zwm;gHH;r3?U6F;S6ckPb+$aIgO5hR_&5@Q1;f_qDg(FiSjw}H=5?ta;KiDBA>o4$_ zALNh););?WPYWo4E4mfpO01ye!-^aVVE!C&(B-;WN_=2Ju#P3-O45!Dek=}-FHTMt zP?Ui*ucx~#5>twXk3N8ozLkV30CgfA8zi%!wJNBu2yVxLOJ+gXnAR65C05=<(EN%Z zr~&jr3T2?~h1B$ei^R-hKXF6nHo;172qO2UpcN&^3=S)X22d9iG!PfGid^W11rb9{89clqK+wAF@&coEa4u6hs6d z4WKg;O02x;pgteCS${$T#m@&M%$X-hDex&UJ5G?w68I16!8pzUx2r`!En-o}-wdFW z^qCz&VezZ6Qy|un6JGfj@@9f!9n^>e1@;U{(CAu&0I1jg1!Q%G0<+@=u+<+>t$rb4 z&b&ej?0!g~fvjY9Tp=~Rcd3{H^NhyM=^K`c8Obc))&U(Nfd)RAUSmZiW48JajDuEffl>c{|T#2pb=IK@=2?d!{Qa7t@x$0y16LjOl_HBpAf91R4cE z205OXp0->}ykkXeIihm?W{*h(pBB@ss}Xgazh21;yTV|f)=vq7%XV7eiuB<{$VrKFIh zAflj%KM^K=0EAR@K@T7qT7)8vO-heFRHe-4LqB+f& zPC#cfcSwQr`wpor$0uzK0*;J`)CewN9bbS)BTh(W2^?XE+7CWk3t|Zm!WPF9)74gr z6*B&vK4Ybr664?LyH|=i)*~;|0=Zj(+l=W8$PMCVOdmk00CYM9v*QP`EP*BgsQJ8E z+zO()42+=63u*>m0FA3NDM%}bgR+kjtF#%@9#FnsbE`=}K~w?6-vQ!Z02Ta>JH)dD znqfxO^JYSHf$RpIk^4eifmuP=n(+a&gAOiZ9*9H7exTVROF`I?F-uVxG|w&qx~&M@ z{6#7W?tn_aOr%l@)HV4ITgbti36Hz!zgCHbGya_(v>F^FrK_<8iHI4~6_B%}&6qBL z`~eA)3*yK@lFhBa3%a6Q8d@7ND2PK#r7fVM0aOP60OzL-s71pH33KKTAj3J$m~Mc= zk+EJuR6!aZkas{99t8y?FE}7?fcQ7S0eJ&CAbCMHd=Lj^7*JjZ6*IgFtk6;p)Q}an zW(1FIgHC*ufQBDv^gtquRe_ZosS7oI%Nnr`#=p~T*NPd~EdfoPfG&Oo(VS*XKcMsu zDFtRnP@>#75j9crW`k;Ya3T0ZYWnK6V!BKlS5CjRRxG^!FSx!FP+$gKYAp;ZIz*I2 zK$%b!l%qtm1t1D|6oqve7(oHR0=}*tlFXT`7#@Iz=wz26%WS&H0{a^Z(q zmJ+Cu20k*0R6oiac3@<=gPs*ARJf;cJ59vgL zTj1~{2+8}KR!(PMFXqAcX?nnVv1-P@)6c9IQ)c`-{lj`OJL?WmX)9vJ)B~xzI-qqI z=nOFM*mxOF3bz6)3#bX(A(^EltN@y92F(gPPMDs#K}^N~R0AQG9=u7Q+6z2CC+x@| z0I7TCfD#x;;)mq)Mk8@?!4Hy7Rg4|fX%;vM zx;|EkMOu-=ar%Y^0mqj0jZiI)td8s;^CYs66&?7{AmDhVtr?_h3_ zR2_cMI=%3QmCwV(kX(BLtoYy}mDLRkVW(;sdV^AHEwY=ks&40Xix?+~-F125YFwH?o{>Jo6|0W~?G@skVkkYtv? zL-@=`E+k!m8lIq;FULEprr+Hm7H`iEo@h{H1vM9$9TZp;*s~N^K&3smB8x5q121?j zC8UGKD)1RRO`*%MM+DRk&|umjGCh!&Q@Gv@bgC*i;e(4tNHZV2lq(n1Zi4h$AsGua z9EF^*av<&kXFyI^7gjvWaUaM_;2~Y8mvR)?6}TN4vmMtwngXhvK+}8=SiwOm%3R0` zH3vLf2U=KjV%7AwJH<@6mh1w}#ekQXXzvoUN(bdB zb}I&|&6xh3)CyV&j^Pnca2$Y=3}oDm>>1O))ARR=S)o-1T%eY?BQ^bTb5R56AVUm) zxKhO*({Jn(vqSYmIQ0_K8qhid29tMO=V?8`3W?v6-I4EYo(}|$&9B2Xq8aI$BeiqmS3uq-bs96L$ z)dak#9o%(+wlF~<2wlhxX|REsF~}hZ(g|uSpoX9(b0IIZ0SB5S1+DmTYy^$qBL^W^ z>+}L~aS?8C5e|x+nJcCnDv1k={Sd(PF7txv0w=@_V5PDhIG{me#^7OdQr8kqpMOG3 zlyL!g@eq}&5dM?sRfs=V94PXrS#Z5>Y87zQ$1J$0mfv4bZ#adK-^F9OAtULaVP41( z0yRA~ySbIN)ynMV>Az27l*ZG0&WOngfu@~7c?H}71+|A5z;h7wN}%Ek)K7x0RR?vm zQ2SxfOafY#2u|iNq_ULQ!A)z(r~`PZ2RnFL1vJs6z#?!NRJMUiN)~~OumvLES$~i{ zpvh_IGz5!-0%*}AXn_}K0A4&x;5&S}4b&|G^?OmX9CINr6L_2g(zykdB~#8!1}#DQ z0AFqn(|NPK6C{CHa|n`n0nT!Wvbi3-lLO?p2Lj+>A<*P5c=i?K2T-0zE}tQbb|7}o zKyfZ8n}eKt0kqH&Jo*nUd?AbFAzH9FR|#B%fLFjFmZHG5Ldv>|b7J!8#1(IZDhP-> zKxGhm@dk4I)}0;G3+{=D$U&50_u<^-(+$pxNn&nGi99bBggP*SK1n|P#Cb6_)cO>h z5>a_+fL6mGtuF-Gk1re{ z1@Sp1q|`Vl!IVCpxmoc^FjTtpO{SW&A( z<^|IoE{cipfQ*GDw(0kOiit{rDqCd3K>h%!+O!hVhrfZ{v>g}GqYXTU2}=H;Gy&Sz zqJBwC89H4Esa+uhPT&P9koh$5QUz#;f@j7+r3z?{3w>})4OE{Ij6mpoF=)U7w7v?o z_5f6Nq15+~lmi}IfmZV11{lcK_)-t@S_DXCj~;HINC0L0)*MjN26-(4B+4PWKw~b* zp$*f8u@Zp^I-(37-bS|z6~taL{rzPzv2chrAPr~>5nwi9tV2L| z9&*bIrs?VQ{2O9oauCBoOP&y`5MWAft(ZRHikOrDqL74?k<)iw5i@0MoBrX7m^owH zbd9TGmW=JwlOWWbt773{pkf1g$P=>42GnX}azL+GL96+|OT56NHJ}s$Uh&UvhPtf^ zwBq0MnwYXLs0oBvyANLR4+=cI3w5w9vjS;?EV9u9Cnr`jCh&THcJOLL$gmJ-$PIbD zKS&QGNhaNp09AglL<#Kyu%jnHe2Zbg3mRdI!6rz6PC$pOX$0pX$0gJ2u8WB&fQEO$ z1r5s14$y)+&|0t)ZPV_FNd_Vmp{GQUBIH5`JaYg|i4a|&t_QL%kRK;Zm%AY*CJj*l zN{W~Y{BMX!vw}>ABqR%nTF@XPYC-}jdAk)hGYu;aLCr*v475m^e&L1~8)iCtc0(*n z6=gFBIEK(y`GS&0=}j?Zy9RIz1U48BZcVTV{9{#M1{G6~GzjXIVK0{;X#w1ofX60e z$Piwf;EzqvU2{^9O-3mFIP(H&wnJw#q>aOy4)Qx zSrBb|M@-oioPxlm3n)oInw(%R-oj?;oxxMsfD$%4c!e>j281V1NLz)-$@@ zL9;1{4j-hu2GNC{a6#o2xairn95NUKy0#s2WN5n6Bl?v+N{>g&9>@gbU~TA-S?-AK z;0N_OFl=HqZ$_0-e*XpCQ;)AU0IZ&Szpd_27C9RCR;) zs-A%Dp*sQHLkC;10!rU6__7@PPE8g7FMk2m>20Sb3urPjm@_}%gREu(t*%0Dv0spc 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

    Nog!$sC)A?73OE6xUexXm?mhtLz#(Cnx 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

    >R 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 z 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 From d42a93105142e3e8f1d02efeecc0c0e52457a5d9 Mon Sep 17 00:00:00 2001 From: Jakub Konka 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 dcdbeec322..8301505492 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 9c553a0092..9083cc92ab 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 0efd34937a..edbe7905a2 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 3812597789..f348fb70e3 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 d50a614206..07a8dcd858 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 df24fe5e7d..fc244e3130 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 af3ed5e053..980dbfd41e 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 668c5b72e3..2a96efe89d 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 1b65bbb04b..2595cd8ba5 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 543cb473d7..29aed25b31 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 f15958b3df..da0115d069 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 ca6bf9d681..07e5cf1aa2 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})", .{ 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 342d6b70cc..d0ff27a3e2 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' 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 4964e75852..8ae175aac8 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)); } 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 9c553a0092..7448fd149c 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 0000000000..cf01f5ea2c --- /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 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 d0ff27a3e2..c0d0c11b56 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 7c0746bfcd..dbb4c07f64 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 3e91c6807c..3a5b7b008b 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 { 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 | 1535 ++++++++++++++++++---------------- src/link/Elf/Atom.zig | 61 +- src/link/MachO.zig | 4 +- 12 files changed, 891 insertions(+), 814 deletions(-) diff --git a/src/Module.zig b/src/Module.zig index 8301505492..0695a2e98a 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 9083cc92ab..28d559f730 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 edbe7905a2..67197c35f8 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 49f979624d..c6ee960e51 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 07a8dcd858..a0af1b3cce 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 5e9326d23b..e67244167e 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 fc244e3130..23d3ca5514 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 2a96efe89d..09804add53 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 2595cd8ba5..8278377095 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 2c55e55f83..0b8128aa33 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 assert = std.debug.assert; +const elf = std.elf; +const fs = std.fs; +const log = std.log.scoped(.link); 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 log = std.log.scoped(.link); -const Atom = @import("Elf/Atom.zig"); -const Module = @import("../Module.zig"); +const codegen = @import("../codegen.zig"); +const glibc = @import("../glibc.zig"); +const link = @import("../link.zig"); +const lldMain = @import("../main.zig").lldMain; +const musl = @import("../musl.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 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 musl = @import("../musl.zig"); -const Cache = @import("../Cache.zig"); -const Air = @import("../Air.zig"); 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).?; - const phdr = &self.program_headers.items[phdr_index]; - const shdr = &self.sections.items[shdr_index]; - const new_block_ideal_capacity = padToIdeal(new_block_size); +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; +} - // We use these to indicate our intention to update metadata, placing the new block, +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)[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 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); + // } } -fn getDeclPhdrIndex(self: *Elf, decl: *Module.Decl) !u16 { +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 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().?); - } 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 }); + // TODO this write could be avoided if no fields of the symbol were changed. + try self.writeSymbol(atom.getSymbolIndex().?); + } else { + 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 caeb3bfbc5..79b699636f 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 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 const Reloc = struct { + target: u32, + offset: u64, + addend: u32, + prev_vaddr: u64, +}; 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 29aed25b31..11a1119449 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| { 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 8e2d9fe3fc..8f26aac32c 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); 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 | 466 +++++++++++++++++++---------------- 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, 352 insertions(+), 277 deletions(-) diff --git a/src/Module.zig b/src/Module.zig index 0695a2e98a..b39fd2bab2 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 28d559f730..82321ef545 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 67197c35f8..d0fba2fd0e 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 f348fb70e3..3c2a81d5d1 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 23d3ca5514..b41973ea97 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 980dbfd41e..c4f9b4eb42 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 09804add53..eb74615492 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 dee3c7c381..c062276b73 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; - - if (atom.prev) |prev| { - prev.next = atom.next; - } - if (atom.next) |next| { - next.prev = atom.prev; + { + const atom_ptr = self.getAtomPtr(atom_index); + atom_ptr.size = new_atom_size; + atom_ptr.alignment = alignment; } - if (atom_placement) |big_atom| { - atom.prev = big_atom; - atom.next = big_atom.next; - big_atom.next = atom; + if (atom.prev_index) |prev_index| { + const prev = self.getAtomPtr(prev_index); + prev.next_index = atom.next_index; + } + if (atom.next_index) |next_index| { + const next = self.getAtomPtr(next_index); + next.prev_index = atom.prev_index; + } + + 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}); - - // Remove any relocs and base relocs associated with this Atom - self.freeRelocationsForAtom(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 + Atom.freeRelocations(self, atom_index); + + 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 78824eac1d..1ee31cccaa 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 12a34b332d..1ba1d7a1c1 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 0b8128aa33..747120ac5d 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 11a1119449..42aaa3a275 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); 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 8137b76846..f1b60f1469 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 cb37b24885..b1e6f3bdac 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"); 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 | 170 +++++++++++++++++++------------- lib/std/build/LibExeObjStep.zig | 81 +++++---------- 2 files changed, 122 insertions(+), 129 deletions(-) diff --git a/lib/std/build.zig b/lib/std/build.zig index f1b60f1469..a4ad599d93 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 fn addObjectSource(builder: *Builder, name: []const u8, root_src: ?FileSource) *LibExeObjStep { - return LibExeObjStep.createObject(builder, name, root_src); - } - - pub fn addSharedLibrary( - self: *Builder, + pub const ExecutableOptions = struct { name: []const u8, - root_src: ?[]const u8, - kind: LibExeObjStep.SharedLibKind, - ) *LibExeObjStep { - return addSharedLibrarySource(self, name, convertOptionalPathToFileSource(root_src), kind); + root_source_file: ?FileSource, + version: ?std.builtin.Version = null, + target: CrossTarget, + optimize: std.builtin.Mode, + 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, + .version = options.version, + }); } - pub fn addSharedLibrarySource( - self: *Builder, + pub const ObjectOptions = struct { name: []const u8, - root_src: ?FileSource, - kind: LibExeObjStep.SharedLibKind, - ) *LibExeObjStep { - return LibExeObjStep.createSharedLibrary(self, name, root_src, kind); + root_source_file: ?FileSource, + 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 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 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 addStaticLibrarySource(self: *Builder, name: []const u8, root_src: ?FileSource) *LibExeObjStep { - return LibExeObjStep.createStaticLibrary(self, name, 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 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 addTest(self: *Builder, root_src: []const u8) *LibExeObjStep { - return LibExeObjStep.createTest(self, "test", .{ .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 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 addTestSource(self: *Builder, root_src: FileSource) *LibExeObjStep { - return LibExeObjStep.createTest(self, "test", root_src.dupe(self)); - } + pub const AssemblyOptions = struct { + name: []const u8, + source_file: FileSource, + target: CrossTarget, + optimize: std.builtin.Mode, + }; - pub fn addTestExe(self: *Builder, name: []const u8, root_src: []const u8) *LibExeObjStep { - return LibExeObjStep.createTestExe(self, name, .{ .path = root_src }); - } - - pub fn addTestExeSource(self: *Builder, name: []const u8, root_src: FileSource) *LibExeObjStep { - return LibExeObjStep.createTestExe(self, name, root_src.dupe(self)); - } - - pub fn addAssemble(self: *Builder, name: []const u8, src: []const u8) *LibExeObjStep { - return addAssembleSource(self, name, .{ .path = src }); - } - - 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 b1e6f3bdac..6ee5205b50 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"); 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 3a7468243f..98da9f31ee 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 fd4aa8ae76..c008149f41 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 29b50b5cc4..36e5feddec 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 b3876691a2..4a7b700dc2 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 a4ad599d93..4ee00a4710 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 1f9bee463c..9f45d606a1 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 4d949946d8..74c61d229b 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 4cb346aa47..81fae399ef 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 76e9bdb305..c31fa7faf5 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 2f9f892e86..068c3f9c57 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 a62d86af4f..b6dd39801c 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 bd1b6100da..50a214490d 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 751a7c4db6..a65cd60766 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 2de8c01c6a..4c1ce89261 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 25759f5619..a4c3575e45 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 efdaf191bd..0127b575fc 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 a5baf255c6..acd27a507f 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 ab016fd4bd..8b2d047371 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 0ecca14aa2..87e4d1b5da 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 0730a01d44..74efb5d580 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 9204499803..eebb31a21e 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 4315935941..33965a9272 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 a314fd2201..137239d292 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 d7fd872f77..9c38739a5c 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 767578e225..f4c88b2862 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 5a7044d960..f61aa34a93 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 e556b5bb23..db894b6ae3 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 91c44baf52..74e9a86e94 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 0ea150252c..b6baf63c11 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 031a05cedf..9b2fe952bf 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 cc00854465..dbbdbb3e51 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 314febdb20..86ff99e8b1 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 44675a15f8..f8460c4e82 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 79f67bd7df..229d965e48 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 f39f3fac2a..895cdcf316 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 7efa88999a..7401ba22dc 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 2c565f9263..69e88aefae 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 e234a3f402..6b29fd0dc3 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 283566dab3..8eab283ec2 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 181e77e296..2b9a91d728 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 ae46117f18..71bb986dff 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 88cce88d98..800c76a31c 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 f7572bd6b1..804aaf0b09 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 b50caf7264..147fb55fda 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 7557b4fa41..57ee6acd18 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 1b2cdf87ab..8f7d9e0583 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 5b67c3caa3..42971c607d 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 fbae6dc741..7fa3849083 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 538e4023f0..a885faaadf 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 0204272f97..0c54655b32 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 f0f6f30c57..ad5fbb7091 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 64f3c08583..89250ff96f 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 240d535182..6959f810d6 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 43b7bb791d..b8cbd5fc17 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 2a184dcd2e..ecdd74aa90 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 e13c0e8873..3064c6cc08 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 0038c4c298..94016b1d74 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 d636f63ebc..b0310947f6 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 02fa5e1680..27a23d5a76 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 d84160a4f4..e3c40d34c6 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 8c05e47cf6..510c7610d9 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 733b3729c1..34c555cfdb 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 8f43ae1358..8d7acc3e9a 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 ab3677370a..41a646abe8 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 ece74f0e98..59ff7ea9ab 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 03e8d04bfb..233f701661 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 677c589a84..50eefe846c 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 109c742c6f..1aca02bc71 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 c4ac18f967..baee74052e 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 68486ea18d..ad69f05ff6 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 d498e2e20a..de37265388 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 087aceff01..87a584a887 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 d008fd31c9..3f0b8b9f2f 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 7529d106f9..8dcfaeded0 100644 --- a/test/standalone/pkg_import/build.zig +++ b/test/standalone/pkg_import/build.zig @@ -1,13 +1,14 @@ const Builder = @import("std").build.Builder; pub fn build(b: *Builder) void { - const exe = b.addExecutable("test", "test.zig"); - exe.addPackagePath("my_pkg", "pkg.zig"); + const optimize = b.standardOptimizeOption(.{}); - // This is duplicated to test that you are allowed to call - // b.standardReleaseOptions() twice. - exe.setBuildMode(b.standardReleaseOptions()); - exe.setBuildMode(b.standardReleaseOptions()); + const exe = b.addExecutable(.{ + .name = "test", + .root_source_file = .{ .path = "test.zig" }, + .optimize = optimize, + }); + exe.addPackagePath("my_pkg", "pkg.zig"); const run = exe.run(); diff --git a/test/standalone/shared_library/build.zig b/test/standalone/shared_library/build.zig index 18188311c7..135be095bc 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 c64ae48dba..81b4349e20 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 738cac9783..9b02da50c1 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 da4e8bef4b..d2ca90f3ab 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 10a1132d3a..de58a602c3 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 8e972b9ba6..575550be02 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); 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 98da9f31ee..6b6c384fc4 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 c008149f41..1163ad0200 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 4df2eb1d62..189b118787 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 36e5feddec..b88515b403 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 4a7b700dc2..5ebb55373f 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 0000000000..a3c579c743 --- /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 2c06ab9279..3b8cfe5263 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 4ef350b418..7907be1787 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 400c06525e..b961227c9c 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 52ce8edfac..b7b12d791f 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 62923623f2..44a93dee66 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 537b8c8fd9..929b30e935 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 0a41e1aaef..41dbb3e35a 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 37203e64c5..8c8d8ad2d4 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 e8266dff5a..08d646ff88 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 6ee5205b50..af9d34440d 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 fd937b00f9..6d51df8cbd 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 fb06cc2179..3d26807411 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 959414e54f..f3b71dcec1 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 5183a328cd..83e4f7f66c 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 0000000000..86d6645c29 --- /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 9f45d606a1..5404747846 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 4faae8f74e..59ac568221 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 4ee00a4710..0000000000 --- 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 ba52784b45..e0318ceb43 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 c31fa7faf5..0df9c1d323 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 068c3f9c57..ee9dd94ebd 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 b6dd39801c..f6efdc784b 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 50a214490d..d8962a8e08 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 a65cd60766..662fd25c92 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 4c1ce89261..6ca1f31b86 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 a4c3575e45..b6c3002492 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 0127b575fc..f61b30ca4a 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 acd27a507f..7a1e2d862c 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 8b2d047371..586da1511b 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 87e4d1b5da..4504da9c6c 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 74efb5d580..2b3c6abb8a 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 eebb31a21e..227d4eeb63 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 33965a9272..62b70b21f1 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 137239d292..cdad94357b 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 9c38739a5c..10d293baab 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 f4c88b2862..2a3459be50 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 f61aa34a93..0a8471b919 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 db894b6ae3..eeda89446b 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 74e9a86e94..3529a134eb 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 b6baf63c11..6eabc02b5f 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 9b2fe952bf..c77588cb5d 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 dbbdbb3e51..e43c002e2e 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 86ff99e8b1..62c288f1a0 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 f8460c4e82..5be66991dd 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 229d965e48..505ab5ae96 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 895cdcf316..b6cf32d711 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 7401ba22dc..342c4c08d1 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 69e88aefae..9f57066518 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 6b29fd0dc3..1017e70a71 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 8eab283ec2..95caf42dd0 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 2b9a91d728..69c34a320e 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 71bb986dff..19913e6eca 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 800c76a31c..569d94091a 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 804aaf0b09..4c25d0d860 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 147fb55fda..d6d706a33d 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 57ee6acd18..2589b0dfcf 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 8f7d9e0583..76160e905f 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 42971c607d..95c7643880 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 7fa3849083..816b57ccab 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 a885faaadf..edd48321c9 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 0c54655b32..2103172ed6 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 ad5fbb7091..e275ee57ee 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 89250ff96f..7c32a09bef 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 6959f810d6..dce999d4a2 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 b8cbd5fc17..5345f0f538 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 ecdd74aa90..c4b4846141 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 3064c6cc08..9f79c80fcf 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 94016b1d74..b0f938a344 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 b0310947f6..c335fb73da 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 27a23d5a76..9f14c53e38 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 e3c40d34c6..9d616477a2 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 510c7610d9..258d9b7db8 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 34c555cfdb..62ac128aab 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 8d7acc3e9a..89272280d4 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 41a646abe8..dc535318cc 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 59ff7ea9ab..3089a28fd0 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 233f701661..c3303d55db 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 50eefe846c..4ca55ce999 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 1aca02bc71..44fc37893c 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 baee74052e..f9919d5ab5 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 ad69f05ff6..f2dfb2093f 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 de37265388..2708343aa5 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 87a584a887..3f1e823359 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 3f0b8b9f2f..d51ea27328 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 8dcfaeded0..5fbc8a67ae 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 135be095bc..91f7c8a06a 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 81b4349e20..9937888843 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 9b02da50c1..f073c55d4a 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 d2ca90f3ab..89e07efb22 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 de58a602c3..3ebde5a50c 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 575550be02..de25528dde 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 }; 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 6b6c384fc4..713eac6517 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", 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 189b118787..f2b2eba950 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 a3c579c743..c0152ef6f1 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 af9d34440d..67f42c1783 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 3d26807411..8e1a7ef2fc 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(); 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 1163ad0200..00a263bae2 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", 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 3edb17ffbf..b0a176d792 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 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 b88515b403..2ef5b21fe9 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 5ebb55373f..2887c170e6 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 = "$", 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 713eac6517..ecf51fe316 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 c0152ef6f1..4647baa398 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 7907be1787..bfa5338927 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 67f42c1783..5257c85a5c 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 b7b12d791f..26804b2fc8 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 929b30e935..898b9e85e7 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 08d646ff88..e7ffe78878 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 8e1a7ef2fc..94c41ce9e6 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 83e4f7f66c..9ab9ea6335 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 86d6645c29..aff8a49161 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 5404747846..c59362aeee 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 e0318ceb43..7440b49662 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 6ca1f31b86..3560b4a168 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 b6c3002492..d82c81edca 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 f61b30ca4a..8b62cec6e6 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 2b3c6abb8a..3ef17573f8 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 62b70b21f1..8b6e3dd87f 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 cdad94357b..92a73d22b7 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 eeda89446b..62757f885b 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 6eabc02b5f..408076657b 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 e43c002e2e..408f762f5d 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 62c288f1a0..6a68263fbf 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 5be66991dd..ca28458d77 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 505ab5ae96..de5aa45e30 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 de25528dde..0f36c8eb94 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 { 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 4647baa398..008ae5f4d7 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 7440b49662..40ba896569 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 {}; 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 008ae5f4d7..d695637fc3 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 3b8cfe5263..b08a797e84 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 bfa5338927..5cb096581f 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 5257c85a5c..7396a5ce66 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 26804b2fc8..5517f7f9aa 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 44a93dee66..6404d22f13 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 898b9e85e7..8ee739a41c 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 e7ffe78878..014c44f287 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 94c41ce9e6..a353737512 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 9ab9ea6335..07f2363623 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 aff8a49161..ff0ceb2a51 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 c59362aeee..d9874142d8 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 59ac568221..9e8fcdc203 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; + ); } } } 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 8ae175aac8..4429f8be2d 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 7448fd149c..87be3de7be 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 eb0ae1b1f6..2f721e1b4b 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 c528abdd7c..e19c70f322 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 c675cd225d..a13e30cb4c 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, - }, - ); - } -}; 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 b961227c9c..58a78b939d 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)), } } 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 0f36c8eb94..94030ce851 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 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 7396a5ce66..12c73bdba6 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); 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 1fee8e90a4..06880743c6 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", 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 1ee31cccaa..80c04a8fa1 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 79b699636f..24cf19432c 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 da0115d069..401d71813c 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); 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 | 228 ++++++++++++++++++++++------------- 8 files changed, 170 insertions(+), 100 deletions(-) diff --git a/src/Module.zig b/src/Module.zig index b39fd2bab2..a914dc90d8 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 82321ef545..e54bfc7bd9 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 d0fba2fd0e..aab30b73dc 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 c6ee960e51..6574501767 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 a0af1b3cce..423816c0b1 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 b41973ea97..fcae7eaabc 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 eb74615492..c0eacf88a0 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 a8b8caafab..20f540022a 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,6 +111,42 @@ const Bases = struct { const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(struct { info: DeclBlock, code: []const u8 })); +pub const PtrWidth = enum { p32, p64 }; + +pub const DeclBlock = struct { + type: aout.Sym.Type, + /// offset in the text or data sects + offset: ?u64, + /// offset into syms + sym_index: ?usize, + /// offset into got + got_index: ?usize, + + 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, @@ -127,22 +159,6 @@ fn getSymAddr(self: Plan9, s: aout.Sym) u64 { return self.getAddr(s.value, s.type); } -pub const DeclBlock = struct { - type: aout.Sym.Type, - /// offset in the text or data sects - offset: ?u64, - /// offset into syms - sym_index: ?usize, - /// offset into got - got_index: ?usize, - pub const empty = DeclBlock{ - .type = .t, - .offset = null, - .sym_index = null, - .got_index = null, - }; -}; - pub fn defaultBaseAddrs(arch: std.Target.Cpu.Arch) Bases { return switch (arch) { .x86_64 => .{ @@ -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]; +} 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 8278377095..61ddda3494 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 747120ac5d..01326fb82e 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 7c22f441cd..0a5c8b0372 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; } } 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 09c6e1c686..7d42d3b610 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 a914dc90d8..eb947a6977 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 aab30b73dc..473a62fd83 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 6574501767..57a8aed699 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 423816c0b1..8b8fca4859 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 e67244167e..418c67c580 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 342d6b70cc..8212d281e5 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 fcae7eaabc..c11ea4e63e 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 c0eacf88a0..3dd182b586 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 8b05b8b22d..02e5cadfbc 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 c062276b73..f563a617c7 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 61ddda3494..e90db2d0df 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 01326fb82e..3e0c6d2b57 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 24cf19432c..4ab304ef71 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 42aaa3a275..22eb58775b 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,9 +1803,8 @@ pub fn deinit(self: *MachO) void { } fn freeAtom(self: *MachO, atom_index: Atom.Index) void { - log.debug("freeAtom {d}", .{atom_index}); - const gpa = self.base.allocator; + log.debug("freeAtom {d}", .{atom_index}); // 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 401d71813c..5fb94b7c13 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 20f540022a..87e3ca5c22 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 31dfb87659..ee4518796e 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 20f847e475..554f98b5ca 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`. 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 eb947a6977..bfeeea51e8 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 e1af8c847f..c5a3d57d07 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 3dd182b586..450a008cea 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 7dbd3a42ce..14a29e4498 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? } 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 f563a617c7..2922e783e1 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 3e0c6d2b57..45952da6c0 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 22eb58775b..24ef275c5b 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 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 bfeeea51e8..f84d720d1f 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 e54bfc7bd9..4871961753 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 8212d281e5..8559a728e5 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 71d21d2797..a340ac5da8 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 450a008cea..0a3226f004 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 e90db2d0df..a3d0aa8a53 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 ee4518796e..b06703ed61 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 554f98b5ca..e719f8dfcc 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 8f49d68712..7d4f6a4e36 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 283566dab3..db2ca804e8 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"); 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 f84d720d1f..b395c0a950 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 4871961753..54c3c6dc38 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 8559a728e5..cf9c741513 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 0a3226f004..2b3ce51667 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 b06703ed61..17391b017a 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 }); 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 d306c68e08..4615c5b162 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 0000000000..efc3f556a9 --- /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 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 94b25c79a1..f2ee24a9e3 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 40ba896569..e02be2ebaf 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 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 47a21f5b5c..a6715d161c 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 4ecb6835f5..d2db895a5a 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) {} + \\} + }); } 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 00a263bae2..2e16c0c9e6 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#} 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 a5667ce9e8..10673a2b37 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 8a97b3cbcd..b82bfab99e 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); +} 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 a6ecc37d92..1ba4bc18fd 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 4f6a77c6ba..91772d7319 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 ebe84b8444..0f036b9ef5 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 { 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 0f036b9ef5..35b1ff5056 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, + _, +}; 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 eef5da97cc..9e75f8a275 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 e86cd76132..2c24db14d8 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 9821cf07cc..99e97b9214 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 0f1ed540c2..97f2c30833 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 */ 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 8ee739a41c..c419c85fdf 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 = {} }, }, 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 d488d018a6..62af5866b6 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 8afc9c859b..0798ec198f 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, 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 | 977 ++++++++++++++++++++------------------ 1 file changed, 520 insertions(+), 457 deletions(-) diff --git a/lib/compiler_rt/README.md b/lib/compiler_rt/README.md index b2c6a10695..8e838dfced 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. +For example the number 0.2 is not accurately representable in binary data. -All routines are TODO. +| 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 | .. | -#### Decimal float Conversion +[^options]: These numbers include options with routines for +-0 and +-Nan. -- __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 +Fixed-point fractional library routines -- __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 +TODO brief explanation + implementation -- __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 +| Done | Name | a | b | Out | Comment | +| ------ | ------------- | --------- | --------- | --------- | -------------------------- | +| | | | | | **Fixed-Point Fractional** | -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 +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 -- __dpd_fixsdsi // dec32->int -- __bid_fixsdsi // dec32->int -- __dpd_fixddsi // dec64->int -- __bid_fixddsi // dec64->int -- __dpd_fixtdsi // dec128->int -- __bid_fixtdsi // dec128->int +Future work -- __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" +Arbitrary length integer library routines 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 8a9de7bdc1..f8029fdcde 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 a353737512..c1d2c8454a 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 bce8f6ce3c..f85cf75e60 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 f312093aa3..a9a02606eb 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 0000000000..f599a08f55 --- /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 fdb122b19d..0000000000 --- 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 49b0715695..3c44322ccc 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 d3fc90eaea..58f7a67694 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 b395c0a950..3bb15e78c3 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 72e7e094e6..06c36bad87 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); 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 | 347 ++++++++++---------------- src/main.zig | 17 +- 8 files changed, 665 insertions(+), 224 deletions(-) create mode 100644 src/Manifest.zig diff --git a/lib/std/Build.zig b/lib/std/Build.zig index d695637fc3..6846007443 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 cf04a54116..57821d1b51 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 a9a02606eb..80dda052ab 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 f599a08f55..d498366b34 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 7d42d3b610..e09b8f18ab 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 0000000000..c3f77aec98 --- /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 35b1ff5056..401eef2121 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 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, - }); - } + 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 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 report: Report = .{ + .ast = &ast, + .directory = directory, + .color = color, + .arena = arena, + }; - 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; - }; + var any_error = false; + const deps_list = manifest.dependencies.values(); + for (manifest.dependencies.keys()) |name, i| { + const dep = deps_list[i]; - 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 06c36bad87..f634c259ff 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); } 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 b2a6cc5a50..f30290eb91 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).?); +} 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 a6a46979c4..36711e555a 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#} 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 62af5866b6..fae39c5fba 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;

    Snm)mo$55UdTmo_{X!t8}OJ{>j0X5D*VW^dr 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 H8@mkS|^U&$@yp&X^Rq!1J%{pbohTg8~Ql z!s+X{gvIJXC7uB2RzVKX>N3dOkbn{!FM}h4BAWuME`yLG8|Ww%R?s0*3}#FcASIyv zc#k+7nF~Ruq%bouGJr-I6<7rBf^I=%1)W;J47y@b1GHoUlr}&|oCw?#0F`JuAhQ)1 zK;yz10uz||6xl#S_~4q6jXQL@!wwPA=?=;4eA5m03&=1oneMk=AX9Pzc)^T_A~UFh z7ElB&aN@{PU2a&5=vrFjc_@b{#_DM)8`%(;1K=^ zG8qx!;3i-6AtA--HxGiVAGbpSYK+^a=N=N6%GfuZ`LIBsB-XP}m>76ir!QQ@Dm=a6 zumBh1<>}pr1?)9nv9d7NGuATJfHxdDWWi?iKn-mcGbRpjoN#0boSANZO-fPc4|Ize zBXmOn>IMQ<&;}s^@BuLbX9cD+y0eQ5g2!`MK(|q|g5vh9z;wrj{KDV`j1PKPMCuh- z98WX&v($qY6f>|Yut5%C5@29wXJTeyWn+f`Mt0EdR7UXSng|_^;NbxVN6@)Std0!a zplbp^S$Z${xJZQ|wAn;CLde==UX(iCI zI7g@?=xPW@jx0@P1|=>9P6aN34q;bb2CyL!psWU3kI$&UEbtzjr7V!oX8=j-GFT~s z7Ev=;GlFK!K&NK6@i{UUS}}m)+0h|eg#pnB)pz{1wMjr=?sVQG0)8yurcwM6fmp_U z)At?`Py^j=0NGd#I-!|cV8QhNjxuV~C65Y7GVYyj?<6D63OYAq!F2zl0u2z|0jC7Q z823$&b(c|P+&4Yon1D3nuIcmLWkeaLPv7`jz>#t9bjQ;Ipmn4#jtQhgW&@5)4?Qjb zI`^pZxPY|$K~~U)Clw`jUM9#P2%y_Gm>pRa*gyl;m#1$&F5swohy$d^2dd}1Ub^+f`F>nKG5A2phfc>3ZSKl zY>pgR0&@hX-=84pz_@q1!bCwu#yQg)-DDaeT5aUjj5ZVs=izoALDYrgH+CjQggqIVYg14+CIrq6rjKcT5+Vr zr2r0hP-_`Hi~*WLQ(y)s+~3pA3#bVpWi?P`1-b{y;=F(ijq#jgc9k z7!jNPsH%&zf$QoZYT-LqMLbM`Iln*?#Cy}MZ zt-vC1b-KYl0STt_r>1+|6UdW+ngvgo2qOjhr_bNUFD(f*0sn7Niss76zcRt>9tt7aA5&v*133p5OxVEF>(L-kzHN@t%MfBh>GI zPfb_7FEC9Md{77jC}6nT7EP`YqmU?JnI=^r{}jHbuD5a487Gkx6y0Y$Dg>;j#_ z0+)mZZcLx}LO_CX?etYI1QglUvQO<7xH3<^EaokpP3kU;g<<>_Z03P>{Enm+HPfE?rM>3d%asOzl;UE&Ms zE^sKYgSYd7hzx-~VFfnO_C+?({psMc19U(9)#*`>1f&=*OfP*T;J|ov`nE>`Hj3Xs zXTmUnr!Xr(E9D9lI6=#ZK?}|pvJ|)kzD*Z?ETG5OG2Q90fD+^B>8Xzeycmy6-|$$# zlCfp_tH%O5j4ji}pMblp9w2J}^vWj!3XGSh&w2vx>>P#go;?xJXIwa4?5ThY#u?Ka&P&TO&X~@4 zOInUeVCD4g1{o*DmDA5bD8WXV2*$b7vl?a08P87l@0Ago{^7ZRCGNP{j3sXRFym$p zv2nA7;<(ucjvL_%TnY@_pmseI=*YPS(1M%k2G<3p%=U7EuD%6dipr$Rz@@Fnv^Zv-3|&rgqdBe0C|(DeUr z1mu{mzt}GSR=}IFe#LIkNvJ#-+>XEYfLZC>pkq-TCp-Z2(jdGUkHNfD2=C%HFfRqd zyLO{pK#_?j8N%zk1?D9|cyrc*d5I9-ruAT60=FZJBD3R!V{HP8^-MhR5bpltU_;}$ z9a$Bb9cRyI0T~(#;q8L(Vz?dI6`37Roo@iiMRPlHC^9?lf$*XrDw}VD>^Mr9baw#%9J^^!iLb)Be6`37xKzJeCjy#IYj;mgS z9TN=k#ZE|A1VMP8ApQ-6@ZLgv7y#id`3v^1Kg5GaARhGNcH~rKc3c8FzkrFS-WMXd z{TA45J`mpQg{>eTdP8_euY;}kg829B<|dGwC&XzVZ-9O1!R^SW$m}@j1DNLyQF*r= zY^EE8xAqa(6jz9uk8XqITOp)qE(f2>V7TQ8=I0?~b198lqOJGy1x$7MT6qy}oY-|Mi z$qM3&UmL(YO9-zMB4+_HX7x+3MstW2$9I9#j2SoBlx+~6DYv7vBD3T4Kj6SO;Rc=g z>-e|>tk0O+kzbM7abhQ!XT@!) z?FiDh8DfPlg!lP4I4pD^DtC2)dD;-(w(DS?7Pq5_BD3TBr(m8Yx1&(KBD3S=L*Q7` zfJh!Y4Cbjr0_yu&uu?S$Z!N@nRft2IA=axvQvQ?GV13FE3!gmz>r;ZH{EwT!{#Asi zoct6VF$$ohUeD~f7Idx#6OTM3Tbw@zRw@T^%%Q_zo-8D`TOm9d2yYpLCk+Yw*N4C= zr62)(9U>ugNQ`b+1C|tpB)y-IWGMpi{iTIq zKM6y4{m;QXAxLchfmkod?I^3r?6?zRp#a3f#uH$b{16*XegfOT2e#g^e%*6$u<=5C zaq2lZXm}t#oW26Alp7+~dKk>(f;epfB-A(|0SrEkgb8%#HmKMEpH#xc!wv~<@OdUo zpi`%X6`38^LQG-hc034TnKFS&7#y? z%I|Zgi+mCAV%#@9{)>PO8Ol2dzm2 zuaRK`bze9@1dqTxPSBuKi4rG5vCj_y4Y}uR3S5pHS)iRTj!apK%sfosrZX$3zay}C z`lKHM)}Zrf&;I~*7dWPW`5~YH;*0$hkmFtV7<96_N^io!^^lw(|(xU8O>1=lF(ybg|>DwIGrN455 zrMgC5fL6?EE zWMlXotN!~a`tOsh{~n6|d-(J-?wWp;2kbp{sKMj`IyaS9Py}>@EqLrfL5U4z zR88Oy>vVZOK{JsixK_}(JS#+NCZC`k(?8bfEBORX8Bb2X&nI|}@!Rxu{DPo{@fm)> zHpYe1g9QY4Fn*iPBPf{6*gU;JP|%cnn&4VR(7dO#dY$Xv?^Kx`nWyuE12mwV<2M9x!AVCfsZ8?6cLnS zoHboXM9_qzgI$qFflJ`$^b8TfXvR&`kBA6@&K~|GBIqOoJ9`+io14k8i4ij7tN=Qj zIY3mXGlRN3>26IUQC}ODhQf>IW8)w!nk<)8&N?+eejBZ(1|mS zpko<8W9ZBRA3;YD<8Y^sn4k*dlIewFf)b1`rgw=6YC+B$X4hnX0A6Ru2-+A5+ROr; zk-sthqL`qfIDGX3c-|ho=|q7=;M{ahaX}@fMV!+WS4xOZcM=zrVLUlKUR+R__t&Ei z0Y_QK+mNEIUtCavY3I4=E5!v(88=S9FD`hIf5IK;+zNE@$$kkzY2jHQK~QIz-BAIw z(1%T+Z~9vaL2;&Scc#yg7R(ic>Vo%xp_=7o1XY-3-I=~#Qc#Sse|n6Jpp@`7kXdLW z?HASwC{7oV5(G{3HcAN|<$rq{x&{eq5ZDzBAe}s*#VU^A>Tvkw%@$_^@S;0uguIaO71vNkmKaa`^YBBaq z{~#-v&A4)UjGSP<$oGdW0s_w=`->dkGdP}N5a^r!Urta%Y7aZ8FAeSyODKQ>Qh^<` zt$|fw+jK{HK{YAx!bWyYW&_XyP4F5D@J<^RfgRHuZpQ0z3i9Euh({CsU3No&q{z^g6lCgWbilU$+ zW5f0|ML{k`#@Evel?2b~EL+$NIiZ3Zysnem@c|cjtu40#w+7P#E;FVXf(qP@GX%37 z*Dai$r7Tz}3)KM+TV##>(^Lednbs|wE~_F4+K0JKMQ{_-!k+0_s)E@d`nsy%amF{( z=c@^V4(zzCCMe4|W%^Gw!7|1P(+kuEk29{BZlNKl#CULew1!}V>6+;cpzC7bR!J#9 z-1io8+z>B=0=ELU;{={8BxfF+E}$tW&iHn^hNj?T(8^v-K|98l>Ay7vceA~m+brOy zI6Y5UFm8IRsvtMh%em9lwFRd$PME%5TQHGv+H^%7K`F*v(`|GFV>ymBH48X`4nAC{ zBlwYV*YwG{f|`tt)A#BMeqrpMzDZ9|#caEPk^p$E3NIhGf-no{fVT&b0|*>J+XxjT zHJBI#b_ghN>oY##R1yH4J|y6{b2^W{pr+_f0R?Wy4-nM~Y*3}sz4Qfj7@N13>kCe1 z;+o5(0Mg@l=k#BdbWw+M#eqUWlaUc84pb_H5Dvm zdNzIf3sXUPrVrDnbD9Zug7{O+1Pwv_<7R?OO%5H z8cZAlZ#ZDS;a1=Vomn=6OM%<5Vc+xx=7J53yQV8z2rg%QF#V*3ppNhs#G*!S#|J#% z6VEv;1r-F=fL1j!F_<$w;Q__g)#(ua|;_N?7#3Uak}y{D{wmQoGxV}s3`>w`vw8f@_i-+HU%Na!@rsY9FH&v zY?&TwBWS|7WBMc;K^2K^P+;BQ&w?Z}1x^KS#}oXZmHy{!1f3c8PZzQkv}8Oy-N#nY zj`8sHZd*Y)A+Yt_8caI`lq5l^Q((*V-L`@`>R_WT2xNf`S-_PgFo_xDvMU1M#w@=A zx8nisEPK7g4Xp@!5UfwQ8h60aD$E@K`*=brv_bf-EEql-NK=PKqh83ABMiALNyG5Mu&QmOwKz=t?H2ZsjxsCA zLJro&r=DAbX$!A{fFpBBmeTZn4uVdM2d6VS3R*E9nr`DL=%>-mq=2R!6h;vHKzoG$ z|7R{#VsqRzeUqag=;DQMj)K9A_ojO}2|6sf~Eq$z>(>WE`rL8N2aH`2+n5u!!e!7Rd5F5%IULR1;dzDT$}#cRZv54Kdf8= zPph&y?wqdUCa5XDQvkGZOo2^77<4QMuYw{d$hkntyN4T;tV`SkH5oTgpXVkh&3J6O zpqHQ|7pH=nf`%hwmcaSxcijZTWDaqFlI`S`P!+L)TTw`XQ$bNdP~hTpe|JGq zo^H@l5};hgD)4=JfxDn8H&@t|cwKo}6nGtXPQT+JC@lt3DKL#2WbYfW93xnc*Hh4#ap!bLPeB>RgVW90KnRUuwdV?00I!b>m#v^CvJP=)d0^nG4} z@{GHt-}4eIll}yn=H}LCoWi5T!UDZtgj<7Y0*}Ci>G|G*;vCceG=cZ1PVe&;bQXHT z;9kVbpdh2b2-iP?f21?(`I2a3%WJSMV%3CSF)D{l6cQi5C`3pX?7d zQ71sq5_Tegc7UL&Ihw~u4H7+3{rK130&r%3=rHU zhE%#UYBD7#>MJlh?zlRAW}sj+W6Siffr2)SN2ePF34Q_<Q;*Spx0THx>%YGaj9u5F&Vp7)9yR4~7aVbFBfF zm>sN2EYtr73u+Rlb6c381mmvh=fecWnD(+x{}C)`K#azW>D$8v%|IFOeYl{3;2{BM zF$dnb&EmLox$8eS#~sxoev&YvRa z3%ZUiE=5q4v0-{kil8}hAsCh_n9tZc{aC7C1>?c#_GyA@jHjokr3r!t;ufR{S`lMP z`t-_lL0-mn)7#UD)sT=OsKt16dUu9k9{(}W2oevdMmWGG@R((~VwRvXHv@>zBJh@1 ziFx{;5t!}O{SnRRfY3Caq|CcQ& zC3%Duy3GcfQ=c$^HUqFY?w)R#BWO&FLCMqq=Lp*1SIG{_a*j_JK$$yn`mJ0+UQjN3 znM)|B!DWKulj#Y0f@hf84o}z17c2nL3-Sd)m;Bt$7j(gIG2_wc;6%KuKyVr7bT$P+ zCkAsSh3W6}2^DL|E{>aSS|ljWcy79Hk)Sm(_RS(jQS$V!#e$;5sa#qjsKwYl{X&VL z2IJA`KTC*66A2-L$*6AlJ1w9xWwhL7W3NlL0V*=fU zB4@^QfDhEr;sZ6bCa`A-G)%Xt7M#r3y8S}6pd2GHcCtb2?5riOl1!c+S|`ZQI*$p| zbIhz0G-GU-zMxL9l(BWXSiRs(Vr=9E+sMTXY6^qu;Ew4b4MfB}IMB5kVFfx1s4Xv{ z0H#oC4Hjsv5jFi;qo4$=&B&qvYBO>*32HGOm~Pr6c$Dep^yz<^1QnT{PMXz?5iSabnMbOA&ZwD|?JWtLe1w3Y|dDG-<}yjy`0+{pql7b!5o z*$cJ_Ocxfo!K1(ox~&p&0z7!175^@NI}EoAD==s? zgH8uy&|m`Xmtg=c1L72bhzlrkf)1ybPy`(y1-b}8VEc5YcEJY5uIbI~g651}+jqAM zYBNf82`hqEK!KP1g2x?|7!+6)I0Pl6enH<9ZU1T8o5fKWx9f@-GIgcTSxnLQMF zL6n0cp8|uU0q8ghegTM#g(5#l#z0X(fdO=ohoFLxz_jUSI|U^Lb_gplfaC-~goMDH z>EAj9Z4_>Sf(0~220lpNjA;TWDn2lPwj51h$`V*TJ*Z1iopJT_sxCow>DBBC?4VUE zdv?3&CG0=uX0=@JC3T)EyQIF)hv^xSSi55@=6&-Ms{Zhm~#Bd9l> zu}83p>5;(nylz2v#>Wt;tJ7cg2+oAeeIPA+69p};b3|K+xMKRf34)+Clc05oOe+MY zpT8g=I(<@~UA(8~&4i9Zw}gQf)eD@S?%Xfv%Gf!*vtQ7T=?~}hfX#xU z)9>{QLZ@2@S-B3y%5_jHBPL?e&$w?oOCNZ;1mwKw)qR5E)3*w7ktFD{?PR18G;2M`s)m2)qXPt+ZiWJzcy1asQxVIYB64B1vb#} zZ=i#d6qp1i@qw0l?O_5>gMiP~-vPd^h8dJwz^fRQ7!}w+DVjmx0KWnoG*4tej;>c= z1J5Kf3QT1N8B+q@_6JpckRN0OJ7}?L0q8UvHgEP|$?2 zZ~DYVf|Ak`n7N^5b2>U?D{+Aiodk_caS1G$et)5$9%J`(zD0uGjNQ|t773a`b;%&> z0-a(Bnl@nrY2y}HGX2;hL375r)Bi0Jv}Ig2-Da_%596}wor?u+8Rt$vzE}{nJ^1rt zL2t&n)9sfC>M?Gfp0`ABG2_1JLQ4fB82hJZFBRO!^mXxc?PY@UOf5^M`z#YIm;4I4 zk%tGm1Q&D$i~^@4Xph<3>35b1N;9=A+5U5xpbR6^>g*xq6J#@c?s{ zBTJDIhXRj4-*o>Kf)Y$UC#Gkv5G(^Jez-!=P!g&*6y;4vbq}*er zpp{HB3uuYm4mQZbN6@*6te}ODY@qEU)90-e{Lb`X+4SkF1Pehl*J?ovgbrrVN_^1e z2}nBPRtruN0o@4$j#*B}3(TNlQ67OE(^=LCnltX0ZnH+vlyT+sqBVk%jQggaStA(3 z*gsu!t)MRB-s$0M1cI=ke$SZR zzEM!qFf^np|X9-9P%8TU<}vq?~yao_X z>3W+56&Smw`)?N9&bVPZ`xZeXj>!$pkh7*7w+PxW_DrwaA{fZ{Zu*5Sg3_X`u=D0Y z5yhkcIo4s?RzXoI@R=f@IYtH0NgmAtj?4l&j*Nw_yiC(4atMe|ciSo$!Zi8G^f_Av ziy1#m7uY6f58?)H69ip%w0@hQJmdT6=eG$;uzmzpLDK^t3Q2-A8B90bE~vuvX72Rp z?Si>NZ|1h5UnF*?UqEsC@9ly?{NPg}!CM~;vIKsyPLJ6kD8aaCdg%_q7RHs+f9(*= zHk!n)z*(aRx+I5zn*o#^!R0h7=sXHmYevw`U*Nm{__-ZnJD;Y%xg@9tn(r35Ea+lYJjjVh6zsrIK(`W7!RAc-$ z{lHG}MEAX&f<}xhrwi^9bY@&ReePaCM`m_`S<@fx71W-7WS5{WvR6rXOhS5N@r7LDnpdj-`Y z4svD$J12s1_I9g%f-H=Tv!>hc7mSdC+rbSv5iddseCln2!0PE6_k(SCzF#nkX&d+S zEN|vT)1Mv?v|`*gUGcD>=ycgbg4WXu4hl|(3T&4>B*@IjxNW=QVL<^#rpd@!CZlVC z2tc(=-Y$4tP?wPpe4n}_M;2(k(2eQSeNG4#Gd`bw;Dn$oW9RgHC&2TUzfTAn@Gb^b z=intmpb1WklY&usBpA_U`JUN~1l%N*l zj_HP{1l`#dT$>Eq15Fx zj~u5kLQb&(&HBGQC8)!Adb-$YK|{u#=^m#A6+p8~(7U6V1x~Y0&wni}J$>S7L1D(8 z=}S)wTJla}SK?J*1GR0L1tv{@eOmBY^5l+2(D_K9(=N4Bxt3=09o-5x=Wb}w6BEmoS-z*{*LK#=LE$} zUqbfXgYR%+!|oQiF&uCsGS3N0OG4cPm*#^?znnhzoS?MuE0A+pq17hzc$L%V1VJY+ zMV}XxWZW^m^t_-4W5@J;=LJn6Ya!S)nQtJkg!1GrqM)Sk zPmm#KO9L3+h^tQzx+Iup2wK7qD#}9JV^NL^rq~e%+ zMKDZ!ALvk9(6Mo#LIt$j0kqCV;Olg*tKeGE=c=GGw@CqOD;AE2+S1W7632zc2scexC9cIu76!nT52{IXqh+ ze}VRFFbWid&+&A~R$>F~gJJ=-xg9{eG{Cp+IR5=J{nT|q1*VCAr@y%_m@NU-1P^-9 z(VY(20{zqTZwN{<{rxk&>xQ5qNcG+uf}ms4Hu8$JFoKUc6X6J9WUgm&P+*w8@TRor z^c^<^`NNnU8xF7+f}F_gIFYf?Re{lw)xD6H(UFlKv}cA%-~#v<2PW-6k%+go_b3Vw4tEy7PzUn>z3e7 zrdxlfm);i46}t7eL%>lFo}NJs=ZB^8D$^zI2xc=*nBH6Wy76f|^nbIYDj2Eszcq zr{e~uEN;;LOjdzK)A{cUsxj`LZgyV~w0%77zMwqgg6VDd1&swkyEq&-FoVt+mdH|I z7Wg*()P2EF#?I*q4+LF6GmZ}gO&Ir2pY=dci*e!fqYnfP7*9_B_CU~xv1hvGLqR8D z(D{H0oQ@xuvlN&i#qpu(bq@s%6c7>u%XvXAo5G^R%*(34={SKUi(6p-^m7jdEg26^ z=XfLt+5o8kNKl*c^7QCOf=+3xs`nN}dDvSrGOFssOg4<)T+|0*OMaa)P|_rKV9XipeEzO>3&ZILFXl;KNZwwTr_?1Q$a=O zA}aCeXP*l4GM=1%`>CKZ?>W%=P#MP!kHPChxt|FdGlF;PXibluCC)LO_ka*5H|V4Z z1JKZsz>Vpx&jb}X*Rn&$a;6u~6BpqD$zNaq4dV!0oL+c9NK#<~=={JJ3|UGH3QP*1 zJ=hAYjvQH_9XgP~j_Ds3h>J6>o-Y4fP>k`ycC+V#%8ZN)rboRHG!q2hLcM?ubfQ;) zD=#zXEWj6nri`i#z7({C+*rL}ddf>d1;)qITVD#^6`6_c zEU>ayf|cx`?WD{K?9&4#2#QbVeJyCixNo}GYe8x8U7+<-pk<<*pbKFkw`#BnESO&N z8eD4ado8HUxM2FD*Mh-}OQxH>5mbegc=2xp!8=pm2uewUjR4(q0j`Y|Kn4nADewv` zo&MnsxS?$DR#1^~>GYttf}V_Xx6gSixP_7N*z~~ng7X-UP5pKMQ*4G=kR%n}GZHpe>jJyFtAL@KH6O{j{K_ znE~k3QC85xmbae;rG!3%_vQL1F@aC&5dhr^Ao)d5MQA7ZR^Sk1asMxZdi=XNKt(&~ z^m#@F4uM_Md%l1M%%>BDkG#=k%Jdf_jX*rmy}gn9aCzy7)IiS;pPdO}_~mGVYw7 z{!P$8Xcr&odP+^^2uO>^@y7J&E58Yva&&QlGL687>Ce6isWGVq&2JZPwFpIHc`j%gU7K|&Wzx^e6-Si;nYAp_^J3yNiA#E?v;E4jOKo1|N zI}Se45On1h=zKzfEP-9qfBqJ9W9*#n@JG;^v1NMAAHf{PgVSIB5tL>6D=?koub?60 zndw%41^0;U0Iji81fSv9zz8~s5j0}iH=XC7paj$HJJZ$v36?VLxHEn3KS3#d#E=H~ zh{qd@W=t;_6~KobI^G7EgH|D*J}0O$o$EiitS$R5XvVaYclyDt5)#vo{TGzxUIto5 z!2#NK)-wIge?fJ|%~M5$lo@wSwGgsa-NmcG2|8Us0W^NYE-(+Yzyq8tAy;s5f*R}d zr_K;EVO%=(tdJ_CEyAhE+<@E`VS%+p_!)&H88?I4siM>E7=`#4cTe|a6xz+WayloI zPzYn^^f)FVWybF5O-w@58TU<>Vir=eM82XB*24px$^=fL;NzJ=TfiY5a%NCU1IMP2 zz>evq%tDQftEPWv7IJ62G2Na;NQr$f_{NHy=>n`mBGYSFgk+iia7~}hB9zOxX*wsX zkP+j_={BrFy^NctpJEjXVq7&{mQ4tBJenJu5U30+U=s>rTsi$Pn~(!z=X4f!Auq=7 z)BV|n7Bg+&m>xGnKzuqkhmZ{8?&%sFLQ0G)r+ae<1u%9_pTi*(WU_}{0o2WdG@q0} zXDn!B3H)GH;N(`~RNw)xe-qdYK4&Whw4ejBXhVrp$VO@}sGkHHzXg>ApguD*RAI^V z^V~ub(HqnJ#HR;y3#oxZtD0NL zMjY%UMk|IJjNn`VDmWBC=Wm|l7E)l`JpDblP(9G?cDwu~pIujLWaV|+FJ4v&yK zn|Xy~84pfh$SY*X0q&m&3e2B=i&w~)@xXLGJ|Ppv zh0~q+go+t|OyABY^P!VJ2^mjr+*3(UegmysKuf+B;LFYGJdBLg4AWMN; zV9)e-!b0K@CDzj&MTCAZKAvtRDx}ZYIXz2M=on+?bVD&AJ;u)M31ULI%#5Ae&q)g1 zW@OwueU-G(GR7^_17(DS8TU+2l@U^9+&jHnMrgA2R$e8@{0EDJ0*?YW=mui&Ne|ot zdw3NX6u{?Fg60ww7!`N~z{wkYW;@t5k+MQnjGfc3$O<_!?wKwoClnyM8l1AXKn74@ z22HP)6Vg|K#XK8$piGGww5*cZaVMi2FX%K2s0Yu<2}y`TV*Ci2A;0B>48;C`j!0$I zWWE5(*a(+6$_uG0!&1WoSZd$^HHU71W>MfS>6RDD7KKDR{F-{G)!Yg~8loq`vAKi^ zS`k5|JQRc`Lv>wY0?#pi@;}DhkPpt^|i!1MD7qsGZVELXM)HV5uHvR67fmgj~eFLqlQ$vpM*@XsEW+ zN@0%f6P_4~jsox=>REFng~qn#Nv5X7p%G=o`* zS%Cv|Nh>_1Fylxmpq=iZMlf1R;RP+8gB@|fEU*Kd?Fy85n89^7#MRfPUBZkT>v zRS49VXH*mNfZR*yt0rU(VfCm9>51&+QDAmtDgkXA0+lch*`Oh(h!;|ik#X(%hn}8m#|E))ew>p0H<`&(E#8} z940VN|7|EFIXzZWNQAL-dXc7(C*!v1do+bq7*s1>PLN{LdH$g zlMTR?&@=-fTgDU9uNVlaGkxNizTrHdh$1U!aTjR#$`N!R9>~fL@X#|TGC+r5?VoOB z2(G1K422BXAv+;BrtiPNCkkpjTVx4rp1$5tNKJJ&D4nrtGS2{|Ur_phOh>SSLeOys zXt32(V8`@dhC&&Pr>7?y2{}O0z;YuYWyZbJPa6qIG47cD%t%O+?ZDht0fFb!MU912 z7?(`9G8Q_cvaqcKax*T-eV|I{1&0Ew0yF4BY{r*jPd34 zMl&I4;k6)*uxo6gLmunRgc=wpOiwWt%F{RolIIjCR={cSC6Efq>3SwYc}&Mp4Tng< z`=8(gjG%@am z-aMZE(^^P+x}S{@r|=GtWoYfiv(*CX)BPO;xTnvt5sH?EOphVXuVjUuzQ`u9XZqg` zA@S*&wnAErd!~oj3e_?GoPOC>$bs?qbP+ot2hl&^-bD+O5)-(tXt-yP=elVIbb-=vb!Ib6r^T~962cbgQL!e3oht-a<$XCeZ3z7J*IE zvmJ$u7*9{1=O_faS?`pi&{W0=(-WM8nSaltuo=XRZw5a=S| zYG)zPCCn6X?_? zftKk_E<&Iir*^mq=`;SE{=!8ln{m_h5LY1+##PfhU47{N$hK#$XFLx8V1e(To7gA%~J$<3O&hbOW0H1+^nVdodu+{=lfnqQC|k24Z$($x`AKXqmp- zL&%P?bNVk2Aq8QW!3|7sgQx3y3MmRebWdPX1Whr6bj5iJX)^Xs@9-3gVru1`UcZcA zW}25!BUAsZ>CIk3`5^j>m(Wwj*6Fvrg?t!Wr>px2Z4g|8wC9xtRR2wX;UlzNWerjT z3M>rj6@V)fPSBVm+1P|uVN zL+AAC{z9N-7XST)EEyL~w+s*h9mO0SfD~doSP&uB7a*kMcpG%u&9S>R=54v57&2a?_=v0=)ph5KuETADIP#XRiAY{qdKV3Ue2sEkS z8Hi-t3nbfW0)=#>z_xX;g3hsS0FfF@5+FNe1lCMH6bLrvPoPk^6u9Zfrpdem)bs<- zle0pn4yWe^36(K+PJa?4WX`x}x=gSTXxX}Ru#g?-T%};4SjPL)9|Q}nW14kg`h*an zY@t~fnvt(3WO95woi|iyF=N~GjiEwXOskGhzZ)u40HXcFgg`6yy26A&d!AN=36=6s z0C)Mot#XYlfv?kb!iBV?SAuIZea0)GMl1BdZdMJZ3ycC2rWb|_i7_6S-VrWj#kha^ z;cy{0RXoZeGwR^InR*dIF^mhQcSi`tGImdY86i~2xO{qaq>!W-bOxOf)DH&rwm2O% zvILe)?}`-qVRq{@^aLSJ#{*2DQNa#g@CpS^&?RUcyk<-@cpVuPxfD1ZXYgh@eg&y! z6eymapCuGAT_9RWTn=ggqOe9Xr=NNH{#+p`rmv@`Cq@g+V4N`hSG16{EaIR-CPpR( zkgG0$FFpe;!df!jC`L%1argA37$H^0J<~g4gf=ohn{E{=l*jmN`pQ_aDNb=h#-JNk z!H)a@K3*3zSk4J5N)bo*GLOs3|e(_bVAfi|EuBnp8>ismH>Nm(rcO*nFDFr5H9pIdE7v|5`{E*!F^6v1<>HOz~<>1NkSHk_opW& z2?en%VG}qseS4CS5kw7}0w?GM!OhdZC4t*;vdKb`ET=(gs*;5)AoFa;r|(D>(qh~_ z{c*BT82g%y9RiNO_D*+55!%Rfm2>)mR3WM9ys1JwoL50d8iOlprBtD*jMt{`%N3HI zemPZ0Lf{%FxTglH*C5RT#ylaB>HKLzZ7LI(6~UKrb3uojI2~Vr8iA0BIZnq9OrU)! zJJW=;mBC);WmI4Tdmog)85Niy>fqjBPZ!$H_F_qkfTKDjd|xb?Zk_=S-}4zl(punv z;T1T`rpN=D8H5-G8m`7PN+eSVv|rdMQ^=Wd$Mm*Lp}TBbSGNi{3V{uVv8^+NK${G6 zvW28&cY~a9mcfka0E+^rF2fcUMIHrCP@$&4EAVall58PUSb*No7BW)!#;qu!!0Gsf zCCib|kwJk+T8Ra;0EyEP7Q}`*LT4DSPXCu9q{sj29H1%QhBwm}<_pO&HN2UAFkeWXasTv(`9e;N`=_fE2sy+2 zmRlh7kMZjCoI)XWQ2NkF6^fnysZhuWmLMF8gd~`*aZcY;CS)_+Jx@q(x~{1Z`}Ffa zh4`kQED};=oG|@$kq~G~khNF{bf-{3v5+0(-s$U$g=83KPd`&EWCXe*7sR_XU8Y3H zhH=^S$P%GQrsV?DVVk+pm0s(^I=ADk8La}2pj7jNCrjYN^uOgoW{gLtn^Xva zcBIEw2pND@(sDZf-~bKsG)$jeA>_#h+IcAOX!@%PA<*?O+?7IVjK`-NRSGpTZkoQW zQb>n!$MnaQ;Ld_;m5>5s&-An^AtfQ$W^*P`SpzD3+o#W}5|U;-Gksf?5a@X5iS0#VYQGN$5mcwL>4 z2IG$D*XxA*J#KI)af8bj&>4aX&}C$hfCa5|aph$|c!C|2sKHJJ-Rcbm%hxyEyADnwQL5B(poMsc4KmBsOkiG=er=YU_1UDix?Vm2yAY>#6)pCOyG_L_# zhcG?1LC6F$hzD9?FtY(16h|6_3>lA3|JER635FaF1gr{$4 z6cS`SIQ>wg5a=B5|BXV9jEAN>HVG+7!D0xUGz1km!950M1s;Kq(`%cA4l$j4INh;X zD4*%%!|j`zg*+Lf4uZ~E<^rd7(8=bUjvc&NO3VURITgTl8l*ypR_13BYR_z>eu99YQvcQ~N=~0|&wcWTwC95E6l0$0j;ms8h&`aqjfk zP9e|<{B@l|v5eoQ-{}-GRXWY7!0gKln(|w~1YU*!?R$XMM}is_0{f;LcL{;c=8xzS z0-eo2f2t7ZZ2k+~LbB68bP4e>ewzNjOGuUR^mNs3A;baw4a`cMW=tKR(UA_!1NyVN zg}fQROh=f7c0m8{ZXwXQqzt3ZQFcq1G}fa4E1Ta0={YR$!WbrdLRIy2(T#ImZ3dgC`1^ zFn)&x!=i~o8jLrlpPneB%(!s+`-wtIGVol(>e#^oiXPBn3|7#=;{xBN>rN8VV>~oH zW|9!-=>5f$gftoVPd__J2sHctbCM8f_FZMN5NP&2Z?X{R==}wgg}`&|pix@Tj5a9N zU$8*t+W7?*O@BOD2y|Yd@Dw3?#)H#?rwD;&x2vWIfo8XtO%VdkZvUJj^3Y4tYmhWfpEg}cRTwf|+QNt|ac;Vhlq$?A9iZ+Oc%)rmHwP#u zgNk2fXt#7a?+oxTLFEjgD#lIIzswK<&0VR_6jEdSG@YMONOXGgOd%1*{^=Dnh3ptN zPv1UMNS)*SyCwlg8G$X+pUo695SR$c8Wvd!ph-2JEP+YW)n*B`)K6Fp8q*Wz7J-ed zGCOKIu3Ov)KDPr&(8lrk?FO)*Btqq7(49nPjZ6$b9E>3e4jMKg9zzuPAuKHXrB z5Fcarbo)6%W|ALxK#gJ+P{b;LlBz_O0;3~OmcXp(eRG5q86QpGFbCWUyD&${Bmvyb z0FQ!$r!zrA$dEH=SoIk}H`gP&k{JTfP9HO<`N68ekU9POVTKUYW&vRsc}< zq`5EIE0co)mp-G05)aGt>+^&J?YI@V91XG*xEvKgN9u#*43v1lEeUYwGjc0%=`t88 z@`9@g$T?#QU|ZM~I0SY~|1(cWl|>*+;L&u|`9d1?3d{m`1wifr9lyzJp}^(%f(w)< zK_hZpjuu&kZaNpb%+b0*zpUVv-4zuDKjLm_V5abb|?(V-Hi7z)5hhOu*2r%P@%vv|JA| zIRi>^^$<;912mX=m;_FNFQx+fWCql9xDo;I=p>gW^9=A!kfNaA1hucQx&MIx$o)&0 zz%>zc<{7L3GC%|Nqym?t@&eG{0%#QsmnQQHu(2ZG5)ssw;R4;euz_iM<3b@h5wI6Q zYjzRwzGHgf5+Py6UDI2a2ABRUx3=6z~y)YY#?Zr zF2cYYOt2f=L502uI3eAdF0)ifIq(4}V}h>O0(tfUSTATi4(tzs@8Ix$gW_3`ZqU$) z0!RZS2wx!i^~3ZDONB(3et>-^tJS~^jzK2mWCxu?hDJWfJY9w+=IL*j3Mq3<02R30 zpr+{b*9(QDy|^4_fQD?)(j8ojys@MtpJ+|nlOX}10>DvVFpjkfR!n-fKolA02b0< z;?Q6c0Oze641c&77(gYV22+I@(*bU9rK-rRz{LbwWXe_V2s(-9EEC95F|ehebYEe{ zbb(ueOMw|&ke&c}3)Io$0-fcdz~y*>J4*nve2z<>@d39I6EBM+1EkQo!>z~$GT{cd z61yS~vjgaeb2na4f?+XZ>fixoB_2=@i_5WtCrd#{p`H~~Yj9_QE^`29*BKx+3wS{D zb6k!yz-mBBe!!G)f&H-pq-p~X=)g8E#}z!_+pxGCckqDPLmc2e4B(&;cnHoMdw7(X zcv%&AKn~l%0~&YY0o}O4qrmDoU4DfSPyGp~n?TD!xg6o)tiTL%99I^|7;t->%kcnM zCFs07HgJ2K8*~wdusQPqW(8pKGBao~3ewdciz>;bt!J>FYNMNgG27Q;|ueI zr5KuZ878q{FH2dnKnC})K+96FM`l1xhZF=IELn)M6g<--1WL>cpo&1FugLCy40it# z7UZ%NtN}Es0}UQ3OS#beK-CfTORT%MmnZ1a%QS!Y+W#6$D2ZDEo4oG2H-#_yedL zPJjZ;@dlU#x#tJCG<|~NT|rRzynt$e1S05`URZ_n0%C;#s&_v?yz9*c9d-prE8JN> zAbLOsg9fs>96z9Vw}BP8>IK=a%h1F+edQWZ>B|af?sc$&>L!VLaH%*0d=ojU9Wz)# zZFB*!*SR2Rbpb1=JY{k~DN$EI^@8TjxEvR-f-3`tECEQ$UBe13QCF~LDYEc@+yZXW z!b;S7P;-S)kxIi7wVs$F6;xclfEAbAW=vEpQN_5j1fGEN2uhJUU2uhv6uc0f01i}m z(83GRCjyW`4cvw323E{MbOSgh1mJ}zC{93y=oauUJ8&V&4@!)zLXgbIV#ag=nrIG8 z*I6$lSAT*vO8|0l8>mXX08Idpq zas=;DfMlWL;8I`)n-VjN0K9Dv(xS^SYx?F5LONV4*q}Lz4b{QeZ{g2C&8aAd6S9A&37Cgkn%*i476{I}ln9uz~XB3O3~MKfs3EhMGQWqY#(G zA<&!_D>&#u@eXQdpI`&sHMVD?ka7J7s8tI<=3x5x1Dg^DC|Vd4I6#e1uvadCw4ep} z6*lAm2P?Y)QU;12(0w0{7mz%01MUf3CWcSb3pNR}E_8 z*g<_ss09-shJhVBg&kJY&cM*D%P@-_Qq$IhhB`pO39^;T5o~}4(-d}SO$)NgaRJnH zxDt3xyMP^381sVsxB_A|*az7B@eJ&bHSEYi%*(A{&E>cO#rPHMh=j5MY&;J**TXaY z0d`1Dv4b5{Q^?kXj@sjLJiv~egifIN800=(hEwb;4&cp1ilCbE29l+M&^B>BsKpBs zcjUgBqq!-kf2e}0^89u<`s7KSKwhHNR zegOH2+l=YObpNeFQYJs31|jFOA7FdHBPb1^T>y?BK(@d;>>W_Rg6fDHm;w914(v#f6^<`JdKI`F4}jc)5weUgusG_~^mp5ZRJeYC{KRd> z^nn9ZYD?BPaAGNLI6+a!4a%t3@%iOGtrg z1jh|fW02F&(T5q9kPi5Bj7A?PXabE{feGGo=7cu-AX{4?J!f#RgIAS+H0IH>rfY%0s zt84H&8m8%0yM@&4PatAifdyU$p8%&QR*=^itr%{At^kG%3||0Ei$cbzFK}iF+?f7g zw~!>`g6Y3@3u#y{I}18K(UH-emr2TT!P&{618f}^foMi<$0cVc3ves3=rS;Z>m5hP z@z>yzRNyG@^u9ep;;~#BOb_PIGo}q7{-S!vh4l(dx(tQV zRt!5pA_t&u+W>dl5fqEqxk1V50GA>QD8^2JJnx8fUpF}P&TuKQvN+U(?&yWN&G7=r zT*oU63M?S~C%6O_f_-rX#c=5QPA(0m3tW!u0*g46SP+XS;Qn;H0kTyAlr)$fL6a`f zKmpG}+~5Kgm7wHQ@Av>@rvkGAzk&eBI;0d7@-x63hEGuDIerU2bY54C0j$T(;U(cKoba#ClDi4$k`7xMg=n90#B9-12_1h(W?xO zuUD;NbQBeMHhuYiA<*XHH7mr8K>LaXIM=W{HZ;@~3*4Blc0fphYb|>ZsK>*=!wlM1 zEW^5veHL^-G2@2m-3Nr^*ibhQA3p$@g*YIjzW78w7#B}ZJ1peIcyjv2!$P8r8>Sxz z2|k_9b_BdQXWkJZBgXU7FCGz6VLU(m+Yuoh#zoVWj|wR>ZDgK)P@GwKdh}5tQ^u#$ zCmt0N=UvRJzyi7y7c}_2Y5LZqLODV|LF*cMK_@7HGa|FVhv~-0z`GE_j|sU;A9yoa z0Ma2~(`1$ar8*|ix?O=Rf$7tC9uv}I?4JJOn2-VEvgwk?h0Ga$P7gdTB*zBXG6Gtb zFFw8JxR5a8x#?lAVfywH zLOo0u*`^ET%F9ka-!INSJ@cfHE7Nx7>4E*?GSknT6f$L;IGyQ~kUwPgDlfAX$P=LZ znHfPhXfP-+f)-gWnVxq_NS^W4^uAL7?Ki&4MkRD2*}*;XM|j#rZG;K9)4CxhjGvJma{?%jD6FWo)uCDsX2F6 zNETxE`?Es9P}OqK$zpDh-QWoey*^pf$&^!$rL zYU+5m$b!yy0EMr>gz0-O3Q0*%W>#VW)jb^GQEE^xjadP7vId*L_30lk3OO;Jo^EnU zC{cPIw*rSQ!yaac+5^m43cLy&8caKw1?ErRa0$GE?)D`iC7}o4$`ss}g1C6{bpFdi zl8o1w%lnP`wDpfd>%5 zt1m$_00P&i%U%(3lZV*G1)79l$x`G5yNFd0wA~ssJN0#X(-omYw*AW+1spY}pSmU_ zH(mUykRQ|j<=L~@uFWKH-*7AkSGgPz|li5aP<>Fg@@Nc&S9;9U+2+>ql6!1g0>7j_w5S#h&hc2fU4{@Qx7Z zu&1?mgk%{zrk}neWWcz8I><TOlb6YfK~V@2R2ob>SQVHB_Dz2X zQra+`>znf87ED@dQV7=an1BU_k?^H*G~7m zF9bUIqu{=ff%6B@iSNt|=1dX_poI}i+zL#fvWf?M>?wl+kK+%-bsSs@yynatkW~+$ z`~}Hfho?WjFQmn|c{<+%A$i6v)Ab$*Niw!g_jn+r#@IGJ|ACM+50&EM#eSMwVnw% zNSy>Xdc{Gl8)j|=Nfrn2%0LA%fs@l)o(VZJt++P*_%k6x##_^WJ`>Vp+&NwOxsWE~ zrs=-Vg=E!l2`Dmx^)Q1pfK6h=X41sxLgFIRm_ajupdoSvVSUCGj7s8;yQc4XE)>Xk zays7&Aw|Z+(+yq-nKK@lp7BD+ka5HGSuccSt&!Zv3OessRNyDXncQ$I!H#Fal$`$Q zg^(WT{34~7LPhMeTRXu^>u0|d>IYo|pz}&dTJ+G8Rsly|fno(=(DDE!E(LCZKIZ9# z?}UVzE-sl~_(}+TW5B&vLMoC_rI3o87c|2u3|f6I&_7-JwU9JOxy5TCW8Ru;-J8y0P+ixYH;|$Hm!gs@&zU^D=}CzvM4Zs8;_u!*eE(d z0uYP5-U#Vxd|?HJ>p&R@M@3#nmcP)Ze@xOUI{mcg;Nv6~Hr$7H7R4oRTgoZVb0#r@K zM6NXBO&qCiACrs!6 zA|%NNjx$$YP%#Ng_hw&&0+{CfpWg9B$bxxpL)-MjUxbvIF0P;c;){?R)ATjdIlc0n>z6wb*?cOlG`>T*Vk2MERSCNQo$;5DBFtUP3Jl;-F8(1jllf{x=XCy` zLRnx&%}=2g9EuHo38_kfJ%*H}K`9J!w&?WyUqapv>!B;S6@)=&7=f;pXloU49JZ2@#Urz`#ulE4)8{3E2q zxM6zEAEDh*=iYR{av^Aqjj&?_OO_HB=-4Y^&|NB^iQEk=AUCpPIo<`SH3l7gqQDN> z?aC!kq5xO7gT;|iQA9!5aR*D5VwY6n!*ImI{3AMiUt-$(I5}D8#J*1%5`w9AOWzoQ+b6WF~Wap znea4t-hmV$l8nOMprb$;g*9ZskqEle2^Q1rpj}?Vpnb#wGp4U%6fVXvak?&(@D;}W z)0vosH5gA$*Jc*h)Lg*{Dv%aH&Mg4>?*u#8e;7sI^jc zfTNPY)#-t(!qC;N4%rH9;N>a;lcrB(74~90HvJB(a1d|H?#TiQ;A0USzwDZB%_gkK zbd76zz)=B_=|yb9jdG8{r?asrLJme&1nm|AEhYsY8V6b}&n|4tcxAdPyYN)T$J1}K z3(G(j)k{nl;1HH&JTqO7L)epJ1?U`uhI7-uatT{79-pqqEi5n8a1Qm*zCUND$8!t2Gaj10oLd-l_WUJoVKc}T zeQbzxB-uc#NFj|)B_82mh$GRCu7t0Joya4s!gzA}HXdPl<^@Murz^Y_Xr6vy1|#S6 z6kcKX`d`n$m;TyuJKkIgK8Y53W%YRo&xYIa5rkz8xlj1^Gw|88R*;K;&p~*W5V_|N zo&~p~m?E>|-gDsdY|XhH#TA(y5A6b*ZU*74p9eO@l)K(hN|D)dKIEcj6K+QtMP|oe zi@+L@YUg_FT@29S%7pZ*44daV!PU4I4U=|OnC z=fON(2=C%m~SJZ7qoPyEcF=)Z}&)Rb+NNvJUJE4Tvw^ zKyF`Ghsa%?3U-VdH`q(-9)dlg3Xywo8Z4&*37Nl;+sKu<9YsM`V9$UUssxd|+Xz;w z2;u#m3$|VXa_RL+h=1iFH#Bd9+$t^yky`+{$6FS{>w)lOAdZ5`eLv#q7a8Zx&XF9 z1Y+S7Nc;+OI|_oXdxu;AE(CG*L4vgBnk0xJIX6E zJN7|>low+C)@xwvd7xH6!h#!O%IB+KIWCY7nH|4Et^?m5@ML;S=J z;ckJXU^a-xg)_j8VTH)eodo8wKzLIi36U8R+%F-~#00To9V9{-Au6{|Yn@)`!6!Uj zR!}&Asd2;fd_iGn5WPiE*hu2d<0%3Pi~=PJERLY74Y)bMYtIFCP5&n-oXfaydXA8= zIpe(PON4|&8Fx?rB_tdm20rXoiOEqWOM{64)J+5p>g=ALAS@in)XhA-&{|q}`Y~Z) z&|LzLg@v^l&rRnS5tf7vpMb6}056ka9-Ww^qm2s$JWv{aN8bgUL=;h`cQ=$=|8(4-Z3AVFaN^v@!~puK-`qQViz-?)|d z6*wIk+}GA92?T)7iUu!70~fIZ7x)#}^%>tVE3xvjgUcr?4Q@Phb(4Fx^T_Se5b8^aL?sQ^v*9r-=z$fJS}9gl!lnPUjI9 zR_DLLp#;61lNG$R(MeobSp>W_j@=Qw$P9E019*2_rMR#HVt3p^abbDJ`O^=I3rlEs zGdnRT@;Nam@`E-Y2yBKM3A)<>w0w-oaVDsF!XdD5I*Wv`uG|u41y%vbUBRGD>|h@& zuqc2Isbvs&Hr-!B7<8UTm4q;8kI+mBVbC#_=Ol#Fxj=iGz^ex?O}Cd6wq#s9y;4%x zM&t*p0y}s?G{_`&#}|yCUC1XTh4qZd)Sr>oSc3^N;rbCd%C8yaGdLM&~Zx~`iy6o5IX=kG?-3+4$6it zLFWKpSis@PktMJMI+&IL+Wl3bzyV4`0+*+skrvjKKF6=X02(O3V$^gI8DVS2J<|hZ zgtZtSO|O;_Hf8LdzEMV4N^Cb9XdrA0vm$652C|-(Q((vRhai>vr}M}PyRqy6U3(BF zE3D3W=k!zoZY3Up^V8d8h5Z@lPQNBAtPM(Od61ylT3>scxk{32%oH*TF zURWQLwjh%fypXh2DlcpXNn0GC1%r?oaB$k%FAqywoB}7OKbIHQm7mWCo#EhR2aOzo zmKic>FtLC_lo@nHqOpRo730n6c_8Z0^py(2j*LsDzg7^IWBf6lOA(xMG!?-qCr(i~ zgJ%!hawR5+jhCihQWSP$JU?AhNf>lfMu3vA92+R$1kO({Q4)4!yfJ;7lCV1C@9FoH zkP`@tval^XCGu=x^IEnH7^tC#|?u_rJf7KDzW!y1cSy$MCamVx+UEw@7 z$cX#&3%bJXjJu{s=m{G$?wa1CC#=rcJAI3uunXhc=|A;^K_|!>CJ2a5x6>EqV_Z1h zS6^6xv3+`;KG>2zec=To>RHi!_3i~rom_Er+csXO| zbSooa(0NBmM#2`1Z>P^T64qqgG5x5Ka4OS-HPdyBg{L??STk7wv{i?Rfd@4C;E3RZ zE+`iOP16W~s|H6g$K^*`z-J~m^D~LnGlTXbO<61-_ zjTm=MKV~BA$ar`~!Lz*Km#=nKgBnvx`F@ii;xq+iD$ zSEqBB2|EkHZd#NvXF9^D!0Pzn>h@SO;T?>Om!^wZ2&)QrGbwN=FoLdDVs$(NTKyr= zJ>AbjSiAl(_&BsJkhRXB2DU_&5?CF&awgb@6;LY~w5DDOR41@%Fl}H~VixFTW^zzq z7g!Izh=oCc6|`(yflGl$fmz@Z*oGs_O6;Is4Vo3as7_+F6!vC3KRwV=SX=cp2k5*P z1y&8Pk3c6|2wY?ZZEn|K+QS4AKENb!ar#0_VI9Up)6ZE7XGmRSbpj1To?*yZtH9*Q z1KR%vTAR!x@Njy7m9U~4*pZw_j)dG>!KJ_m-eklqupjKy8_Y_KEDj1#mokG~2s%f- z8?+ypS)hCRb}M0Z#+}peTM5hXBf=FlGu1tv%UW301Wk}hfx+o01GHNLH5ECCAv&Y2 zg^x16pRQ;lEXVu#5adkCld*a)v={0NbGeXK*kQOxo3F|dr|Pk~&>*4#}$ z1;QBjP3Qb2AT73w6SNN&bbu=OFg8|Dm9SM{y45cM2gbeAtA7b7GHn%@9?&ZzI(@R8 za4_SB>Cf$iH5ogn3)&0cVOrQe{k^?#iqOLLW&uZWM1FxBQ=>4w)j`-wY%3e6WncrD zLtt?{1)Au0d_4WCgK#n9gz27+!dn?XPyg>ItiaZ{1GGbOx~h|KFyqSUl}^G%j0dOR zbCHml&fzR9$asFbl(VoJMJSlZYu;AkqaW%^VXVGsUq+~&*-pz~KiCo>7Wn*PQ`Sc38LbXHek6VTyS z44|9qcoaY<*n_IY>E5owOZAqqDKH59h$CwVP*3Z(3u409ZU*LPA}Nanbt5VFu|{jN36^vN|&C{=k2y3Vx<^Y*_1h$2M z36zDfDOL*=mgfN*%cQ|{fJI=}^uSPI4Slc(vjV@sZKPwn7!+_Cvm#VjUVReSA9o1a z`7TsgLArxk5j27dGm#P52by8RevFf*SA+?xVfEq0FyR!Y7gwi?hYR~NJ-9kOBV5?h z5+$xcYqpUt=w))8!-jIdFOwsK8PgqB1t!N6SEt_!7nYTSN7WXPDEzke10ddotJ6gz zgg2|~_|yg}QHmA#6_^}nuxEh|S78Ee6<@)wz~s1sJsUV6b(9GeQNa1o`$SHkHp!q?8=II7e!grYdoSn`WEiA>ja=K=;uoq+F z^pa@dAf|?M(@#VT%k!LJ1Nng=OMy|Kar)8dfpCMu2KrScj~8D@+OJfI_J z9gzlrKx3Ycf6h*?jS*JlSprHrpyR4RMy!ev1|0)=K1Mi*v2nUmtgsHxGLRJyK)W~v z8mC9a3acu&M3e2E00l=4%L8Lhpm|)V=kH-reF*Z&A z6)&vL*fd=!L3j~k)AXYW!rc;U1rnuVieR9+4tk#Mm_bbc*mN#?I;cQibFAy111X z6<9$dmaN$Vt<$yAgsqr*xu?$)kdT;OmnQ7X*fjl2ny{k6tl6ys0#Ajxk&3&OpyH0* zaRIovo6egq9LD%$dP=&m5o7!G>FL5DOnQebw3 zXNEH%-j1u&`?H0E_>u0%W(MV(581-Hph8SOM_7TeWx7L-@H0?}rI9PFEf1S&WnRIe zzzmv^Q{)Gi>7d0FoB}te7v%~+lm?$U$S$w}bd4^vKI0q6l)jV#=<4XaJYh|y-@Maj z<_SwPZkWC`PuPs{@bou%!g73IZOj@>6WElv1$IrB$QQQe-o>cM!o$lA)*6=&(b}0W zEG@Q+OMzLRaSxj!3l9&ddCQTdz$CD8`mTIoX~s#@ujLB|f^5+&5Z=nTZ~FZLVHx>W zHfWy-yg`}|G$+mr()oiiOMyXP!gQ%ZVH>C(qv>6R!p)3#h|}mYY0zm@rNYal4s(DM{b5&P;pGKo${*~Cpxa$QLEBp7?$Z!l*GbWDF!E-VSEADA6M{C2441e&K$tQ8iYu3sU{!99fu zT=psO2~3&pR3Yre_;`A6g>XC5AKvL=mBQ{!e|e|JR|=~!-kRQ4DQpZ1_}!JlYxJi4 zh8_Y4S~d$FHe+^d-~`=Y&kWikJ%Q7aQ4y4`CvavtZumWYYL#%Q7*r3u$cJd1u23zk zBD?`)9wTabA6_jyo#`L%^bgg-n!;djgBCn9YcTy_RALbL&pTbGMi_K>VtS1*=ErfnFVJUDt(TGGA5Ve1LXQ!|a=zc?*eTq_1G;#LhYb`J4g03IcL{G{oHE^}TR4`nar&%oVJH3{-zI~mg^LwH zhp)YPJpFaIuq0FK_vvgs!Zl)0NqBOEs+rLvtO8QAuSfU~D_{gESR>lWD8XnqEzB~XTC z&2l{cZ2HE2;ZiH8F1RC@ku>)+JA&>L=4DX847cOYrYB4go&`E6kp)uXonXyU0xe7G z;!@v1no9u z7ii)GmssFB26PY8PDXcLP6cL1rs)%x2rDu+PnVr6ti;$f-C?q@HB-;I>9v!EWq82* z~eET6t~valZG)ah3y3vXk5J-vI1Fz6ECty6?u8Rt#^Jw@0`a2gjG%g`JuHaZT@@D!fSa$?2&AS>Ubo6F3x@9Vc*P3H;}p?leuhF;Se#XI(V|- zRNw|FSDquR!gTicbk8}$3mAV)e>F!~kFj~W; z7aWW{pvD1880sw$wqb0Zp1nYLo6QTbK~q3=B$7cBKn5XI-8c-2T?lS0v@aC4WNe;( zaG~%{#+TEp7lGRf3l<40vESo$WGv)mnm&7>uqsT&tLZBj3o9``n0{ulu%tC2QNgT- zwhj<3Mrj?uk{&26C@c{Mt);VCB5WZJP6m7evzS5QvIfyE=v;zG1$+Xtre9bhY@#~_ zd_n>PC~Y!7`4B?;i(wL*9zsJn4?g|Hgqr0HLv-1e1V?z)x2OXbdhZmR>$ z5U@j!_+SU06-8unI^tV}r0V|7>p1yxIL&Lf0`?m$eJvGOnF|bgQs7`c4AyToo~Caym5yx2gfkc?O>fvCtSq&JO_4`|U4hArX#tl4yWb9`QnIFOfYjRaDxg61#ZWq z4DR3z0V*fp#RxOE0z3HN22iSD2Tw1u3A9e1yi-^^u#L}=vCxWv33SHqimoOB$D<4a zdJLeE3WS9q?H{;6^C80EQAx)Qhb9X+-Z(c|K;XYHH*}6f*YW)Y&>YEj{$0Y;LDLn> zcMF$t%whxG;x4dcy2>8mXaui)k8mjCtm$|62xlLZCBx7(i_s<}867te|CJ%%E{VB~Y`d zff+o5%Amj~uw(k|{RlgjOt(LP%v*dw*nqKn`jrF1Zv5avo*8kHz2-q-c>(nE6{klW z6kf~retxrnqxp2-W5StC@8?f1J0v`val&-I!@?R&e_5wn92PcXoHafFu&^}O2hb8N z&`PJx)2AF3R^SUNZIYu&@~8m+3za3!l(gzMvVh;E)wGUk18kiwS)6IxA?d z6cCj8#DG!XFDkzF9o_r5_B0T1L)9IPS8dlPS6Q^Yy#h=*Pj$V%{Xhi_bFjX##z%- zPYJ6r&YIqHN*J{5>A)%B6pq<^pxYr2Fi!t?PFQ5R!)f6NY3QN53<{i3LoYBYaDq;9 z68JiO^J!rvsGc8CJs(dCPvMvYHf948#F&L=gmW3sOy@rH97UJ238={{Nz|wA3!pIn$8CG0<$DZgL51;^9le>lv3#FTO0S%eZX% z!pp)cjMJwdyDU6`anAJcE5iDWlcu*rsO?vT+ZY?B+g%lY%GfYn<(lwz-qUOWyo?Gg zpdWiqy(7<9;pN;1~yPrd(QM-H-z_zKEK!@;3x~8 z7q$Rh*Z{d6u=l301XJ6k>C0~lmoh!SI9=|Ruq4v;fZ$1E==FeXpk*13ZI?O(9MOgo zcteF0rhjl0Vwv7`OE}vK)OQ3`*WgW!;C*8b*`ReL3ZUDaA$wzSt>V+aEv(1g$*IT= z+8hr$s5|4fusmbu^p4xY@_av771%)MC4yGd2+W(l^|r8~Bsj6M)Pt@Z0S!chi*FVM zHi6#h|8EP+F`k<)cSl%*ap83LJHo2s2*uzbXNY2fzUj?(gh3aqu7fDOen%K|-uACM z!fK5D(-rRuPh(#Sy0%2%#Pof4g{2vnZohR`*o~3#!gR&^!e1D7Ob)fMRQ?8lFU zwHdpo^FJ0A6FCP?1_Fxg3T%+$K0#^D^0Dwj#u?LZKNdEZ=;i|V2SC*hI8Z?|YYJ=v zGp1`j5q4ngo}T?gSekMA^!6vhI*c=>Z+Rk|$=E$z?y0bt$qewdm*7MKIYt$9ak&Qc zpbh9m9cZNhvg@a3JQdae-2(YkSe^0Y^qo(I71-9CXciE7HU0imVbD!!zn=;#GH#qM z`%HKx)Has>rO1y+Fx)7L*2ZVq4cyaTe%0@R@g-R1-yhhYJgnE{~VK3PCX)p0XO z73d6b&{TmEn*xfW3`a)r(%=^iS&sWb3K<28r_0}#O815u4zFCGb_gH_E^t@`*TJR$ zz7|@bf4cQcVM$@A@epa~0uFmVJ*=E!U~L<%%F{y99f#o3{DJA3$R{Y z8s>!-U%;a{5ak8z3?W+Pt#w#7q*qy&#J(t&$x$0i37BHo!ga{M}b>GQeet- z+YiE11Y6ml_gV6Cf)6U6F#XX7VQt16)A>FM%P@YQuKiJ1hjH)ph>ya`jQgk8d=$P4 z8ov$xBpj¨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�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