diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 99fb516b45..71dcbfa461 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -56,7 +56,10 @@ liveness: Liveness, bin_file: *link.File, debug_output: DebugInfoOutput, target: *const std.Target, -mod_fn: *const Module.Fn, +owner: union(enum) { + mod_fn: *const Module.Fn, + decl: Module.Decl.Index, +}, err_msg: ?*ErrorMsg, args: []MCValue, ret_mcv: InstTracking, @@ -617,7 +620,7 @@ pub fn generate( .target = &bin_file.options.target, .bin_file = bin_file, .debug_output = debug_output, - .mod_fn = module_fn, + .owner = .{ .mod_fn = module_fn }, .err_msg = null, .args = undefined, // populated after `resolveCallingConventionValues` .ret_mcv = undefined, // populated after `resolveCallingConventionValues` @@ -745,6 +748,92 @@ pub fn generate( } } +pub fn generateLazy( + bin_file: *link.File, + src_loc: Module.SrcLoc, + lazy_sym: link.File.LazySymbol, + code: *std.ArrayList(u8), + debug_output: DebugInfoOutput, +) CodeGenError!Result { + const gpa = bin_file.allocator; + var function = Self{ + .gpa = gpa, + .air = undefined, + .liveness = undefined, + .target = &bin_file.options.target, + .bin_file = bin_file, + .debug_output = debug_output, + .owner = .{ .decl = lazy_sym.ty.getOwnerDecl() }, + .err_msg = null, + .args = undefined, + .ret_mcv = undefined, + .fn_type = undefined, + .arg_index = undefined, + .src_loc = src_loc, + .end_di_line = undefined, // no debug info yet + .end_di_column = undefined, // no debug info yet + }; + defer { + function.mir_instructions.deinit(gpa); + function.mir_extra.deinit(gpa); + } + + function.genLazy(lazy_sym) catch |err| switch (err) { + 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, + }; + + var mir = Mir{ + .instructions = function.mir_instructions.toOwnedSlice(), + .extra = try function.mir_extra.toOwnedSlice(bin_file.allocator), + .frame_locs = function.frame_locs.toOwnedSlice(), + }; + defer mir.deinit(bin_file.allocator); + + var emit = Emit{ + .lower = .{ + .allocator = bin_file.allocator, + .mir = mir, + .target = &bin_file.options.target, + .src_loc = src_loc, + }, + .bin_file = bin_file, + .debug_output = debug_output, + .code = code, + .prev_di_pc = undefined, // no debug info yet + .prev_di_line = undefined, // no debug info yet + .prev_di_column = undefined, // no debug info yet + }; + defer emit.deinit(); + emit.emitMir() catch |err| switch (err) { + error.LowerFail, error.EmitFail => return Result{ .fail = emit.lower.err_msg.? }, + error.InvalidInstruction, error.CannotEncode => |e| { + const msg = switch (e) { + error.InvalidInstruction => "CodeGen failed to find a viable instruction.", + error.CannotEncode => "CodeGen failed to encode the instruction.", + }; + return Result{ + .fail = try ErrorMsg.create( + bin_file.allocator, + src_loc, + "{s} This is a bug in the Zig compiler.", + .{msg}, + ), + }; + }, + else => |e| return e, + }; + + if (function.err_msg) |em| { + return Result{ .fail = em }; + } else { + return Result.ok; + } +} + const FormatDeclData = struct { mod: *Module, decl_index: Module.Decl.Index, @@ -1545,6 +1634,103 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { verbose_tracking_log.debug("{}", .{self.fmtTracking()}); } +fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void { + switch (lazy_sym.ty.zigTypeTag()) { + .Enum => { + const enum_ty = lazy_sym.ty; + wip_mir_log.debug("{}.@tagName:", .{enum_ty.fmt(self.bin_file.options.module.?)}); + + const param_regs = abi.getCAbiIntParamRegs(self.target.*); + const param_locks = self.register_manager.lockRegsAssumeUnused(2, param_regs[0..2].*); + defer for (param_locks) |lock| self.register_manager.unlockReg(lock); + + const ret_reg = param_regs[0]; + const enum_mcv = MCValue{ .register = param_regs[1] }; + + var exitlude_jump_relocs = try self.gpa.alloc(u32, enum_ty.enumFieldCount()); + defer self.gpa.free(exitlude_jump_relocs); + + const data_reg = try self.register_manager.allocReg(null, gp); + const data_lock = self.register_manager.lockRegAssumeUnused(data_reg); + defer self.register_manager.unlockReg(data_lock); + + const data_lazy_sym = link.File.LazySymbol{ .kind = .const_data, .ty = enum_ty }; + if (self.bin_file.cast(link.File.Elf)) |elf_file| { + const atom_index = elf_file.getOrCreateAtomForLazySymbol(data_lazy_sym) catch |err| + return self.fail("{s} creating lazy symbol", .{@errorName(err)}); + const atom = elf_file.getAtom(atom_index); + _ = try atom.getOrCreateOffsetTableEntry(elf_file); + const got_addr = atom.getOffsetTableAddress(elf_file); + try self.asmRegisterMemory( + .mov, + data_reg.to64(), + Memory.sib(.qword, .{ .base = .{ .reg = .ds }, .disp = @intCast(i32, got_addr) }), + ); + } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { + const atom_index = coff_file.getOrCreateAtomForLazySymbol(data_lazy_sym) catch |err| + return self.fail("{s} creating lazy symbol", .{@errorName(err)}); + const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?; + try self.genSetReg(data_reg, Type.usize, .{ .lea_got = sym_index }); + } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { + const atom_index = macho_file.getOrCreateAtomForLazySymbol(data_lazy_sym) catch |err| + return self.fail("{s} creating lazy symbol", .{@errorName(err)}); + const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?; + try self.genSetReg(data_reg, Type.usize, .{ .lea_got = sym_index }); + } else { + return self.fail("TODO implement {s} for {}", .{ + @tagName(lazy_sym.kind), + lazy_sym.ty.fmt(self.bin_file.options.module.?), + }); + } + + var data_off: i32 = 0; + for ( + exitlude_jump_relocs, + enum_ty.enumFields().keys(), + 0.., + ) |*exitlude_jump_reloc, tag_name, index| { + var tag_pl = Value.Payload.U32{ + .base = .{ .tag = .enum_field_index }, + .data = @intCast(u32, index), + }; + const tag_val = Value.initPayload(&tag_pl.base); + const tag_mcv = try self.genTypedValue(.{ .ty = enum_ty, .val = tag_val }); + try self.genBinOpMir(.cmp, enum_ty, enum_mcv, tag_mcv); + const skip_reloc = try self.asmJccReloc(undefined, .ne); + + try self.genSetMem( + .{ .reg = ret_reg }, + 0, + Type.usize, + .{ .register_offset = .{ .reg = data_reg, .off = data_off } }, + ); + try self.genSetMem(.{ .reg = ret_reg }, 8, Type.usize, .{ .immediate = tag_name.len }); + + exitlude_jump_reloc.* = try self.asmJmpReloc(undefined); + try self.performReloc(skip_reloc); + + data_off += @intCast(i32, tag_name.len + 1); + } + + try self.airTrap(); + + for (exitlude_jump_relocs) |reloc| try self.performReloc(reloc); + try self.asmOpOnly(.ret); + }, + else => return self.fail( + "TODO implement {s} for {}", + .{ @tagName(lazy_sym.kind), lazy_sym.ty.fmt(self.bin_file.options.module.?) }, + ), + } +} + +fn getOwnerDecl(self: *const Self) Module.Decl.Index { + return switch (self.owner) { + .mod_fn => |mod_fn| mod_fn.owner_decl, + .decl => |index| index, + }; +} + fn getValue(self: *Self, value: MCValue, inst: ?Air.Inst.Index) void { const reg = value.getReg() orelse return; if (self.register_manager.isRegFree(reg)) { @@ -6020,7 +6206,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { const ty = self.air.typeOfIndex(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 name = self.owner.mod_fn.getParamName(self.bin_file.options.module.?, src_index); try self.genArgDbgInfo(ty, name, dst_mcv); break :result dst_mcv; @@ -6044,7 +6230,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.mod_fn.owner_decl, loc); + try dw.genArgDbgInfo(name, ty, self.getOwnerDecl(), loc); }, .plan9 => {}, .none => {}, @@ -6085,7 +6271,7 @@ fn genVarDbgInfo( break :blk .nop; }, }; - try dw.genVarDbgInfo(name, ty, self.mod_fn.owner_decl, is_ptr, loc); + try dw.genVarDbgInfo(name, ty, self.getOwnerDecl(), is_ptr, loc); }, .plan9 => {}, .none => {}, @@ -6243,7 +6429,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier const decl_name = mem.sliceTo(mod.declPtr(extern_fn.owner_decl).name, 0); const lib_name = mem.sliceTo(extern_fn.lib_name, 0); if (self.bin_file.cast(link.File.Coff)) |coff_file| { - const atom_index = try self.getSymbolIndexForDecl(self.mod_fn.owner_decl); + const atom_index = try self.getSymbolIndexForDecl(self.getOwnerDecl()); const sym_index = try coff_file.getGlobalSymbol(decl_name, lib_name); _ = try self.addInst(.{ .tag = .mov_linker, @@ -6257,7 +6443,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier try self.asmRegister(.call, .rax); } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { const sym_index = try macho_file.getGlobalSymbol(decl_name, lib_name); - const atom_index = try self.getSymbolIndexForDecl(self.mod_fn.owner_decl); + const atom_index = try self.getSymbolIndexForDecl(self.getOwnerDecl()); _ = try self.addInst(.{ .tag = .call_extern, .ops = undefined, @@ -6416,7 +6602,8 @@ fn airCmpLtErrorsLen(self: *Self, inst: Air.Inst.Index) !void { const mod = self.bin_file.options.module.?; const lazy_sym = link.File.LazySymbol.initDecl(.const_data, null, mod); if (self.bin_file.cast(link.File.Elf)) |elf_file| { - const atom_index = try elf_file.getOrCreateAtomForLazySymbol(lazy_sym); + const atom_index = elf_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err| + return self.fail("{s} creating lazy symbol", .{@errorName(err)}); const atom = elf_file.getAtom(atom_index); _ = try atom.getOrCreateOffsetTableEntry(elf_file); const got_addr = atom.getOffsetTableAddress(elf_file); @@ -6426,11 +6613,13 @@ fn airCmpLtErrorsLen(self: *Self, inst: Air.Inst.Index) !void { Memory.sib(.qword, .{ .base = .{ .reg = .ds }, .disp = @intCast(i32, got_addr) }), ); } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { - const atom_index = try coff_file.getOrCreateAtomForLazySymbol(lazy_sym); + const atom_index = coff_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err| + return self.fail("{s} creating lazy symbol", .{@errorName(err)}); const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?; try self.genSetReg(addr_reg, Type.usize, .{ .lea_got = sym_index }); } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { - const atom_index = try macho_file.getOrCreateAtomForLazySymbol(lazy_sym); + const atom_index = macho_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err| + return self.fail("{s} creating lazy symbol", .{@errorName(err)}); const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?; try self.genSetReg(addr_reg, Type.usize, .{ .lea_got = sym_index }); } else { @@ -7530,7 +7719,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr }), ), .load_direct => |sym_index| if (try self.movMirTag(ty) == .mov) { - const atom_index = try self.getSymbolIndexForDecl(self.mod_fn.owner_decl); + const atom_index = try self.getSymbolIndexForDecl(self.getOwnerDecl()); _ = try self.addInst(.{ .tag = .mov_linker, .ops = .direct_reloc, @@ -7557,7 +7746,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr ); }, .lea_direct, .lea_got => |sym_index| { - const atom_index = try self.getSymbolIndexForDecl(self.mod_fn.owner_decl); + const atom_index = try self.getSymbolIndexForDecl(self.getOwnerDecl()); _ = try self.addInst(.{ .tag = switch (src_mcv) { .lea_direct => .lea_linker, @@ -7577,7 +7766,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr }); }, .lea_tlv => |sym_index| { - const atom_index = try self.getSymbolIndexForDecl(self.mod_fn.owner_decl); + const atom_index = try self.getSymbolIndexForDecl(self.getOwnerDecl()); if (self.bin_file.cast(link.File.MachO)) |_| { _ = try self.addInst(.{ .tag = .lea_linker, @@ -8475,10 +8664,64 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void { fn airTagName(self: *Self, inst: Air.Inst.Index) !void { const un_op = self.air.instructions.items(.data)[inst].un_op; + const inst_ty = self.air.typeOfIndex(inst); + const enum_ty = self.air.typeOf(un_op); + + // We need a properly aligned and sized call frame to be able to call this function. + { + const needed_call_frame = FrameAlloc.init(.{ + .size = inst_ty.abiSize(self.target.*), + .alignment = inst_ty.abiAlignment(self.target.*), + }); + const frame_allocs_slice = self.frame_allocs.slice(); + const stack_frame_size = + &frame_allocs_slice.items(.abi_size)[@enumToInt(FrameIndex.call_frame)]; + stack_frame_size.* = @max(stack_frame_size.*, needed_call_frame.abi_size); + const stack_frame_align = + &frame_allocs_slice.items(.abi_align)[@enumToInt(FrameIndex.call_frame)]; + stack_frame_align.* = @max(stack_frame_align.*, needed_call_frame.abi_align); + } + + try self.spillEflagsIfOccupied(); + try self.spillRegisters(abi.getCallerPreservedRegs(self.target.*)); + + const param_regs = abi.getCAbiIntParamRegs(self.target.*); + + const dst_mcv = try self.allocRegOrMem(inst, false); + try self.genSetReg(param_regs[0], Type.usize, dst_mcv.address()); + const operand = try self.resolveInst(un_op); - _ = operand; - return self.fail("TODO implement airTagName for x86_64", .{}); - //return self.finishAir(inst, result, .{ un_op, .none, .none }); + try self.genSetReg(param_regs[1], enum_ty, operand); + + const mod = self.bin_file.options.module.?; + const lazy_sym = link.File.LazySymbol.initDecl(.code, enum_ty.getOwnerDecl(), mod); + if (self.bin_file.cast(link.File.Elf)) |elf_file| { + const atom_index = elf_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err| + return self.fail("{s} creating lazy symbol", .{@errorName(err)}); + const atom = elf_file.getAtom(atom_index); + _ = try atom.getOrCreateOffsetTableEntry(elf_file); + const got_addr = atom.getOffsetTableAddress(elf_file); + try self.asmMemory( + .call, + Memory.sib(.qword, .{ .base = .{ .reg = .ds }, .disp = @intCast(i32, got_addr) }), + ); + } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { + const atom_index = coff_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err| + return self.fail("{s} creating lazy symbol", .{@errorName(err)}); + const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?; + try self.genSetReg(.rax, Type.usize, .{ .lea_got = sym_index }); + try self.asmRegister(.call, .rax); + } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { + const atom_index = macho_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err| + return self.fail("{s} creating lazy symbol", .{@errorName(err)}); + const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?; + try self.genSetReg(.rax, Type.usize, .{ .lea_got = sym_index }); + try self.asmRegister(.call, .rax); + } else { + return self.fail("TODO implement airTagName for x86_64 {s}", .{@tagName(self.bin_file.tag)}); + } + + return self.finishAir(inst, dst_mcv, .{ un_op, .none, .none }); } fn airErrorName(self: *Self, inst: Air.Inst.Index) !void { @@ -8497,7 +8740,8 @@ fn airErrorName(self: *Self, inst: Air.Inst.Index) !void { const mod = self.bin_file.options.module.?; const lazy_sym = link.File.LazySymbol.initDecl(.const_data, null, mod); if (self.bin_file.cast(link.File.Elf)) |elf_file| { - const atom_index = try elf_file.getOrCreateAtomForLazySymbol(lazy_sym); + const atom_index = elf_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err| + return self.fail("{s} creating lazy symbol", .{@errorName(err)}); const atom = elf_file.getAtom(atom_index); _ = try atom.getOrCreateOffsetTableEntry(elf_file); const got_addr = atom.getOffsetTableAddress(elf_file); @@ -8507,11 +8751,13 @@ fn airErrorName(self: *Self, inst: Air.Inst.Index) !void { Memory.sib(.qword, .{ .base = .{ .reg = .ds }, .disp = @intCast(i32, got_addr) }), ); } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { - const atom_index = try coff_file.getOrCreateAtomForLazySymbol(lazy_sym); + const atom_index = coff_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err| + return self.fail("{s} creating lazy symbol", .{@errorName(err)}); const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?; try self.genSetReg(addr_reg, Type.usize, .{ .lea_got = sym_index }); } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { - const atom_index = try macho_file.getOrCreateAtomForLazySymbol(lazy_sym); + const atom_index = macho_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err| + return self.fail("{s} creating lazy symbol", .{@errorName(err)}); const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?; try self.genSetReg(addr_reg, Type.usize, .{ .lea_got = sym_index }); } else { @@ -8833,12 +9079,7 @@ fn limitImmediateType(self: *Self, operand: Air.Inst.Ref, comptime T: type) !MCV } fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue { - const mcv: MCValue = switch (try codegen.genTypedValue( - self.bin_file, - self.src_loc, - arg_tv, - self.mod_fn.owner_decl, - )) { + return switch (try codegen.genTypedValue(self.bin_file, self.src_loc, arg_tv, self.getOwnerDecl())) { .mcv => |mcv| switch (mcv) { .none => .none, .undef => .undef, @@ -8853,7 +9094,6 @@ fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue { return error.CodegenFail; }, }; - return mcv; } const CallMCValues = struct { diff --git a/src/codegen.zig b/src/codegen.zig index 690e96d25c..078feb409d 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -7,6 +7,7 @@ const link = @import("link.zig"); const log = std.log.scoped(.codegen); const mem = std.mem; const math = std.math; +const target_util = @import("target.zig"); const trace = @import("tracy.zig").trace; const Air = @import("Air.zig"); @@ -89,6 +90,19 @@ pub fn generateFunction( } } +pub fn generateLazyFunction( + bin_file: *link.File, + src_loc: Module.SrcLoc, + lazy_sym: link.File.LazySymbol, + code: *std.ArrayList(u8), + debug_output: DebugInfoOutput, +) CodeGenError!Result { + switch (bin_file.options.target.cpu.arch) { + .x86_64 => return @import("arch/x86_64/CodeGen.zig").generateLazy(bin_file, src_loc, lazy_sym, code, debug_output), + else => unreachable, + } +} + fn writeFloat(comptime F: type, f: F, target: Target, endian: std.builtin.Endian, code: []u8) void { _ = target; const bits = @typeInfo(F).Float.bits; @@ -101,11 +115,11 @@ pub fn generateLazySymbol( bin_file: *link.File, src_loc: Module.SrcLoc, lazy_sym: link.File.LazySymbol, + alignment: *u32, code: *std.ArrayList(u8), debug_output: DebugInfoOutput, reloc_info: RelocInfo, -) CodeGenError!struct { res: Result, alignment: u32 } { - _ = debug_output; +) CodeGenError!Result { _ = reloc_info; const tracy = trace(@src()); @@ -120,7 +134,13 @@ pub fn generateLazySymbol( lazy_sym.ty.fmt(mod), }); - if (lazy_sym.kind == .const_data and lazy_sym.ty.isAnyError()) { + if (lazy_sym.kind == .code) { + alignment.* = target_util.defaultFunctionAlignment(target); + return generateLazyFunction(bin_file, src_loc, lazy_sym, code, debug_output); + } + + if (lazy_sym.ty.isAnyError()) { + alignment.* = 4; const err_names = mod.error_name_list.items; mem.writeInt(u32, try code.addManyAsArray(4), @intCast(u32, err_names.len), endian); var offset = code.items.len; @@ -133,13 +153,21 @@ pub fn generateLazySymbol( code.appendAssumeCapacity(0); } mem.writeInt(u32, code.items[offset..][0..4], @intCast(u32, code.items.len), endian); - return .{ .res = Result.ok, .alignment = 4 }; - } else return .{ .res = .{ .fail = try ErrorMsg.create( + return Result.ok; + } else if (lazy_sym.ty.zigTypeTag() == .Enum) { + alignment.* = 1; + for (lazy_sym.ty.enumFields().keys()) |tag_name| { + try code.ensureUnusedCapacity(tag_name.len + 1); + code.appendSliceAssumeCapacity(tag_name); + code.appendAssumeCapacity(0); + } + return Result.ok; + } else return .{ .fail = try ErrorMsg.create( bin_file.allocator, src_loc, "TODO implement generateLazySymbol for {s} {}", .{ @tagName(lazy_sym.kind), lazy_sym.ty.fmt(mod) }, - ) }, .alignment = undefined }; + ) }; } pub fn generateSymbol( diff --git a/src/link/Coff.zig b/src/link/Coff.zig index deac8d1fd6..41d4617e53 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -1218,6 +1218,7 @@ fn updateLazySymbolAtom( const gpa = self.base.allocator; const mod = self.base.options.module.?; + var required_alignment: u32 = undefined; var code_buffer = std.ArrayList(u8).init(gpa); defer code_buffer.deinit(); @@ -1238,10 +1239,16 @@ fn updateLazySymbolAtom( .parent_decl_node = undefined, .lazy = .unneeded, }; - const res = try codegen.generateLazySymbol(&self.base, src, sym, &code_buffer, .none, .{ - .parent_atom_index = local_sym_index, - }); - const code = switch (res.res) { + const res = try codegen.generateLazySymbol( + &self.base, + src, + sym, + &required_alignment, + &code_buffer, + .none, + .{ .parent_atom_index = local_sym_index }, + ); + const code = switch (res) { .ok => code_buffer.items, .fail => |em| { log.err("{s}", .{em.msg}); @@ -1255,11 +1262,11 @@ fn updateLazySymbolAtom( symbol.section_number = @intToEnum(coff.SectionNumber, section_index + 1); symbol.type = .{ .complex_type = .NULL, .base_type = .NULL }; - const vaddr = try self.allocateAtom(atom_index, code_len, res.alignment); + 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}", .{ name, vaddr }); - log.debug(" (required alignment 0x{x})", .{res.alignment}); + log.debug(" (required alignment 0x{x})", .{required_alignment}); atom.size = code_len; symbol.value = vaddr; @@ -1270,14 +1277,20 @@ fn updateLazySymbolAtom( pub fn getOrCreateAtomForLazySymbol(self: *Coff, sym: link.File.LazySymbol) !Atom.Index { const gop = try self.lazy_syms.getOrPut(self.base.allocator, sym.getDecl()); - errdefer _ = self.lazy_syms.pop(); + errdefer _ = if (!gop.found_existing) self.lazy_syms.pop(); if (!gop.found_existing) gop.value_ptr.* = .{}; - const atom = switch (sym.kind) { + const atom_ptr = switch (sym.kind) { .code => &gop.value_ptr.text_atom, .const_data => &gop.value_ptr.rdata_atom, }; - if (atom.* == null) atom.* = try self.createAtom(); - return atom.*.?; + if (atom_ptr.*) |atom| return atom; + const atom = try self.createAtom(); + atom_ptr.* = atom; + try self.updateLazySymbolAtom(sym, atom, switch (sym.kind) { + .code => self.text_section_index.?, + .const_data => self.rdata_section_index.?, + }); + return atom; } pub fn getOrCreateAtomForDecl(self: *Coff, decl_index: Module.Decl.Index) !Atom.Index { diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 29ae97150e..ec113e5c8a 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -2376,14 +2376,20 @@ pub fn freeDecl(self: *Elf, decl_index: Module.Decl.Index) void { pub fn getOrCreateAtomForLazySymbol(self: *Elf, sym: File.LazySymbol) !Atom.Index { const gop = try self.lazy_syms.getOrPut(self.base.allocator, sym.getDecl()); - errdefer _ = self.lazy_syms.pop(); + errdefer _ = if (!gop.found_existing) self.lazy_syms.pop(); if (!gop.found_existing) gop.value_ptr.* = .{}; - const atom = switch (sym.kind) { + const atom_ptr = switch (sym.kind) { .code => &gop.value_ptr.text_atom, .const_data => &gop.value_ptr.rodata_atom, }; - if (atom.* == null) atom.* = try self.createAtom(); - return atom.*.?; + if (atom_ptr.*) |atom| return atom; + const atom = try self.createAtom(); + atom_ptr.* = atom; + try self.updateLazySymbolAtom(sym, atom, switch (sym.kind) { + .code => self.text_section_index.?, + .const_data => self.rodata_section_index.?, + }); + return atom; } pub fn getOrCreateAtomForDecl(self: *Elf, decl_index: Module.Decl.Index) !Atom.Index { @@ -2684,6 +2690,7 @@ fn updateLazySymbolAtom( const gpa = self.base.allocator; const mod = self.base.options.module.?; + var required_alignment: u32 = undefined; var code_buffer = std.ArrayList(u8).init(gpa); defer code_buffer.deinit(); @@ -2708,10 +2715,16 @@ fn updateLazySymbolAtom( .parent_decl_node = undefined, .lazy = .unneeded, }; - const res = try codegen.generateLazySymbol(&self.base, src, sym, &code_buffer, .none, .{ - .parent_atom_index = local_sym_index, - }); - const code = switch (res.res) { + const res = try codegen.generateLazySymbol( + &self.base, + src, + sym, + &required_alignment, + &code_buffer, + .none, + .{ .parent_atom_index = local_sym_index }, + ); + const code = switch (res) { .ok => code_buffer.items, .fail => |em| { log.err("{s}", .{em.msg}); @@ -2729,7 +2742,7 @@ fn updateLazySymbolAtom( .st_value = 0, .st_size = 0, }; - const vaddr = try self.allocateAtom(atom_index, code.len, res.alignment); + 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}", .{ name, vaddr }); diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 5136bd84a2..c14168c66b 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -2060,6 +2060,7 @@ fn updateLazySymbolAtom( const gpa = self.base.allocator; const mod = self.base.options.module.?; + var required_alignment: u32 = undefined; var code_buffer = std.ArrayList(u8).init(gpa); defer code_buffer.deinit(); @@ -2084,10 +2085,16 @@ fn updateLazySymbolAtom( .parent_decl_node = undefined, .lazy = .unneeded, }; - const res = try codegen.generateLazySymbol(&self.base, src, sym, &code_buffer, .none, .{ - .parent_atom_index = local_sym_index, - }); - const code = switch (res.res) { + const res = try codegen.generateLazySymbol( + &self.base, + src, + sym, + &required_alignment, + &code_buffer, + .none, + .{ .parent_atom_index = local_sym_index }, + ); + const code = switch (res) { .ok => code_buffer.items, .fail => |em| { log.err("{s}", .{em.msg}); @@ -2101,11 +2108,11 @@ fn updateLazySymbolAtom( symbol.n_sect = section_index + 1; symbol.n_desc = 0; - const vaddr = try self.allocateAtom(atom_index, code.len, res.alignment); + 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}", .{ name, vaddr }); - log.debug(" (required alignment 0x{x}", .{res.alignment}); + log.debug(" (required alignment 0x{x}", .{required_alignment}); atom.size = code.len; symbol.n_value = vaddr; @@ -2116,14 +2123,20 @@ fn updateLazySymbolAtom( pub fn getOrCreateAtomForLazySymbol(self: *MachO, sym: File.LazySymbol) !Atom.Index { const gop = try self.lazy_syms.getOrPut(self.base.allocator, sym.getDecl()); - errdefer _ = self.lazy_syms.pop(); + errdefer _ = if (!gop.found_existing) self.lazy_syms.pop(); if (!gop.found_existing) gop.value_ptr.* = .{}; - const atom = switch (sym.kind) { + const atom_ptr = switch (sym.kind) { .code => &gop.value_ptr.text_atom, .const_data => &gop.value_ptr.data_const_atom, }; - if (atom.* == null) atom.* = try self.createAtom(); - return atom.*.?; + if (atom_ptr.*) |atom| return atom; + const atom = try self.createAtom(); + atom_ptr.* = atom; + try self.updateLazySymbolAtom(sym, atom, switch (sym.kind) { + .code => self.text_section_index.?, + .const_data => self.data_const_section_index.?, + }); + return atom; } fn updateThreadlocalVariable(self: *MachO, module: *Module, decl_index: Module.Decl.Index) !void { diff --git a/test/behavior/enum.zig b/test/behavior/enum.zig index de5c0efb8e..26b941bcdc 100644 --- a/test/behavior/enum.zig +++ b/test/behavior/enum.zig @@ -981,7 +981,6 @@ fn test3_2(f: Test3Foo) !void { } test "@tagName" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -997,7 +996,6 @@ fn testEnumTagNameBare(n: anytype) []const u8 { const BareNumber = enum { One, Two, Three }; test "@tagName non-exhaustive enum" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -1008,7 +1006,6 @@ test "@tagName non-exhaustive enum" { const NonExhaustive = enum(u8) { A, B, _ }; test "@tagName is null-terminated" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -1023,7 +1020,6 @@ test "@tagName is null-terminated" { } test "tag name with assigned enum values" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -1113,7 +1109,6 @@ test "enum literal in array literal" { test "tag name functions are unique" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO diff --git a/test/behavior/memset.zig b/test/behavior/memset.zig index 2cc390a3c9..89e01a0e56 100644 --- a/test/behavior/memset.zig +++ b/test/behavior/memset.zig @@ -114,7 +114,6 @@ test "memset with large array element, runtime known" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; const A = [128]u64; var buf: [5]A = undefined; @@ -132,7 +131,6 @@ test "memset with large array element, comptime known" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; const A = [128]u64; var buf: [5]A = undefined; diff --git a/test/behavior/type.zig b/test/behavior/type.zig index 0d309b9a6e..695a81b1a3 100644 --- a/test/behavior/type.zig +++ b/test/behavior/type.zig @@ -258,7 +258,6 @@ test "Type.ErrorSet" { test "Type.Struct" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -383,7 +382,6 @@ test "Type.Enum" { test "Type.Union" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO diff --git a/test/behavior/union.zig b/test/behavior/union.zig index 76c5b09a89..f90a336e76 100644 --- a/test/behavior/union.zig +++ b/test/behavior/union.zig @@ -1094,7 +1094,6 @@ test "containers with single-field enums" { test "@unionInit on union with tag but no fields" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO