Merge pull request #25430 from jacobly0/x86_64-win

Coff2: create a new linker from scratch
This commit is contained in:
Jacob Young 2025-10-03 05:03:44 -04:00 committed by GitHub
commit 12ed0ff1ef
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
64 changed files with 9074 additions and 13924 deletions

View file

@ -561,7 +561,6 @@ set(ZIG_STAGE2_SOURCES
src/libs/libunwind.zig
src/link.zig
src/link/C.zig
src/link/Coff.zig
src/link/Dwarf.zig
src/link/Elf.zig
src/link/Elf/Archive.zig

View file

@ -168,7 +168,7 @@ pub fn parseNameOrOrdinal(allocator: Allocator, reader: *std.Io.Reader) !NameOrO
}
pub const CoffOptions = struct {
target: std.coff.MachineType = .X64,
target: std.coff.IMAGE.FILE.MACHINE = .AMD64,
/// If true, zeroes will be written to all timestamp fields
reproducible: bool = true,
/// If true, the MEM_WRITE flag will not be set in the .rsrc section header
@ -210,19 +210,19 @@ pub fn writeCoff(allocator: Allocator, writer: *std.Io.Writer, resources: []cons
const lengths = resource_tree.dataLengths();
const byte_size_of_relocation = 10;
const relocations_len: u32 = @intCast(byte_size_of_relocation * resources.len);
const pointer_to_rsrc01_data = @sizeOf(std.coff.CoffHeader) + (@sizeOf(std.coff.SectionHeader) * 2);
const pointer_to_rsrc01_data = @sizeOf(std.coff.Header) + (@sizeOf(std.coff.SectionHeader) * 2);
const pointer_to_relocations = pointer_to_rsrc01_data + lengths.rsrc01;
const pointer_to_rsrc02_data = pointer_to_relocations + relocations_len;
const pointer_to_symbol_table = pointer_to_rsrc02_data + lengths.rsrc02;
const timestamp: i64 = if (options.reproducible) 0 else std.time.timestamp();
const size_of_optional_header = 0;
const machine_type: std.coff.MachineType = options.target;
const flags = std.coff.CoffHeaderFlags{
.@"32BIT_MACHINE" = 1,
const machine_type: std.coff.IMAGE.FILE.MACHINE = options.target;
const flags = std.coff.Header.Flags{
.@"32BIT_MACHINE" = true,
};
const number_of_symbols = 5 + @as(u32, @intCast(resources.len)) + @intFromBool(options.define_external_symbol != null);
const coff_header = std.coff.CoffHeader{
const coff_header = std.coff.Header{
.machine = machine_type,
.number_of_sections = 2,
.time_date_stamp = @as(u32, @truncate(@as(u64, @bitCast(timestamp)))),
@ -245,9 +245,9 @@ pub fn writeCoff(allocator: Allocator, writer: *std.Io.Writer, resources: []cons
.number_of_relocations = @intCast(resources.len),
.number_of_linenumbers = 0,
.flags = .{
.CNT_INITIALIZED_DATA = 1,
.MEM_WRITE = @intFromBool(!options.read_only),
.MEM_READ = 1,
.CNT_INITIALIZED_DATA = true,
.MEM_WRITE = !options.read_only,
.MEM_READ = true,
},
};
try writer.writeStruct(rsrc01_header, .little);
@ -263,9 +263,9 @@ pub fn writeCoff(allocator: Allocator, writer: *std.Io.Writer, resources: []cons
.number_of_relocations = 0,
.number_of_linenumbers = 0,
.flags = .{
.CNT_INITIALIZED_DATA = 1,
.MEM_WRITE = @intFromBool(!options.read_only),
.MEM_READ = 1,
.CNT_INITIALIZED_DATA = true,
.MEM_WRITE = !options.read_only,
.MEM_READ = true,
},
};
try writer.writeStruct(rsrc02_header, .little);
@ -1005,9 +1005,9 @@ pub const supported_targets = struct {
x86_64,
aarch64,
pub fn toCoffMachineType(arch: Arch) std.coff.MachineType {
pub fn toCoffMachineType(arch: Arch) std.coff.IMAGE.FILE.MACHINE {
return switch (arch) {
.x64, .amd64, .x86_64 => .X64,
.x64, .amd64, .x86_64 => .AMD64,
.x86, .i386 => .I386,
.arm, .armnt => .ARMNT,
.arm64, .aarch64 => .ARM64,
@ -1079,26 +1079,26 @@ pub const supported_targets = struct {
};
// https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#type-indicators
pub fn rvaRelocationTypeIndicator(target: std.coff.MachineType) ?u16 {
pub fn rvaRelocationTypeIndicator(target: std.coff.IMAGE.FILE.MACHINE) ?u16 {
return switch (target) {
.X64 => 0x3, // IMAGE_REL_AMD64_ADDR32NB
.I386 => 0x7, // IMAGE_REL_I386_DIR32NB
.ARMNT => 0x2, // IMAGE_REL_ARM_ADDR32NB
.ARM64, .ARM64EC, .ARM64X => 0x2, // IMAGE_REL_ARM64_ADDR32NB
.IA64 => 0x10, // IMAGE_REL_IA64_DIR32NB
.AMD64 => @intFromEnum(std.coff.IMAGE.REL.AMD64.ADDR32NB),
.I386 => @intFromEnum(std.coff.IMAGE.REL.I386.DIR32NB),
.ARMNT => @intFromEnum(std.coff.IMAGE.REL.ARM.ADDR32NB),
.ARM64, .ARM64EC, .ARM64X => @intFromEnum(std.coff.IMAGE.REL.ARM64.ADDR32NB),
.IA64 => @intFromEnum(std.coff.IMAGE.REL.IA64.DIR32NB),
.EBC => 0x1, // This is what cvtres.exe writes for this target, unsure where it comes from
else => null,
};
}
pub fn isSupported(target: std.coff.MachineType) bool {
pub fn isSupported(target: std.coff.IMAGE.FILE.MACHINE) bool {
return rvaRelocationTypeIndicator(target) != null;
}
comptime {
// Enforce two things:
// 1. Arch enum field names are all lowercase (necessary for how fromStringIgnoreCase is implemented)
// 2. All enum fields in Arch have an associated RVA relocation type when converted to a coff.MachineType
// 2. All enum fields in Arch have an associated RVA relocation type when converted to a coff.IMAGE.FILE.MACHINE
for (@typeInfo(Arch).@"enum".fields) |enum_field| {
const all_lower = all_lower: for (enum_field.name) |c| {
if (std.ascii.isUpper(c)) break :all_lower false;

View file

@ -527,7 +527,7 @@ const LazyIncludePaths = struct {
arena: std.mem.Allocator,
auto_includes_option: cli.Options.AutoIncludes,
zig_lib_dir: []const u8,
target_machine_type: std.coff.MachineType,
target_machine_type: std.coff.IMAGE.FILE.MACHINE,
resolved_include_paths: ?[]const []const u8 = null,
pub fn get(self: *LazyIncludePaths, error_handler: *ErrorHandler) ![]const []const u8 {
@ -555,11 +555,11 @@ const LazyIncludePaths = struct {
}
};
fn getIncludePaths(arena: std.mem.Allocator, auto_includes_option: cli.Options.AutoIncludes, zig_lib_dir: []const u8, target_machine_type: std.coff.MachineType) ![]const []const u8 {
fn getIncludePaths(arena: std.mem.Allocator, auto_includes_option: cli.Options.AutoIncludes, zig_lib_dir: []const u8, target_machine_type: std.coff.IMAGE.FILE.MACHINE) ![]const []const u8 {
if (auto_includes_option == .none) return &[_][]const u8{};
const includes_arch: std.Target.Cpu.Arch = switch (target_machine_type) {
.X64 => .x86_64,
.AMD64 => .x86_64,
.I386 => .x86,
.ARMNT => .thumb,
.ARM64 => .aarch64,

View file

@ -1082,7 +1082,7 @@ pub fn toElfMachine(target: *const Target) std.elf.EM {
};
}
pub fn toCoffMachine(target: *const Target) std.coff.MachineType {
pub fn toCoffMachine(target: *const Target) std.coff.IMAGE.FILE.MACHINE {
return switch (target.cpu.arch) {
.arm => .ARM,
.thumb => .ARMNT,
@ -1092,7 +1092,7 @@ pub fn toCoffMachine(target: *const Target) std.coff.MachineType {
.riscv32 => .RISCV32,
.riscv64 => .RISCV64,
.x86 => .I386,
.x86_64 => .X64,
.x86_64 => .AMD64,
.amdgcn,
.arc,

View file

@ -50,7 +50,7 @@ pub fn eqlString(a: []const u8, b: []const u8) bool {
}
pub fn hashString(s: []const u8) u32 {
return @as(u32, @truncate(std.hash.Wyhash.hash(0, s)));
return @truncate(std.hash.Wyhash.hash(0, s));
}
/// Deprecated in favor of `ArrayHashMapWithAllocator` (no code changes needed)

File diff suppressed because it is too large Load diff

View file

@ -78,13 +78,15 @@ pub fn defaultQueryPageSize() usize {
};
var size = global.cached_result.load(.unordered);
if (size > 0) return size;
size = switch (builtin.os.tag) {
.linux => if (builtin.link_libc) @intCast(std.c.sysconf(@intFromEnum(std.c._SC.PAGESIZE))) else std.os.linux.getauxval(std.elf.AT_PAGESZ),
.driverkit, .ios, .macos, .tvos, .visionos, .watchos => blk: {
size = size: switch (builtin.os.tag) {
.linux => if (builtin.link_libc)
@max(std.c.sysconf(@intFromEnum(std.c._SC.PAGESIZE)), 0)
else
std.os.linux.getauxval(std.elf.AT_PAGESZ),
.driverkit, .ios, .macos, .tvos, .visionos, .watchos => {
const task_port = std.c.mach_task_self();
// mach_task_self may fail "if there are any resource failures or other errors".
if (task_port == std.c.TASK.NULL)
break :blk 0;
if (task_port == std.c.TASK.NULL) break :size 0;
var info_count = std.c.TASK.VM.INFO_COUNT;
var vm_info: std.c.task_vm_info_data_t = undefined;
vm_info.page_size = 0;
@ -94,21 +96,28 @@ pub fn defaultQueryPageSize() usize {
@as(std.c.task_info_t, @ptrCast(&vm_info)),
&info_count,
);
assert(vm_info.page_size != 0);
break :blk @intCast(vm_info.page_size);
break :size @intCast(vm_info.page_size);
},
.windows => blk: {
var info: std.os.windows.SYSTEM_INFO = undefined;
std.os.windows.kernel32.GetSystemInfo(&info);
break :blk info.dwPageSize;
.windows => {
var sbi: windows.SYSTEM_BASIC_INFORMATION = undefined;
switch (windows.ntdll.NtQuerySystemInformation(
.SystemBasicInformation,
&sbi,
@sizeOf(windows.SYSTEM_BASIC_INFORMATION),
null,
)) {
.SUCCESS => break :size sbi.PageSize,
else => break :size 0,
}
},
else => if (builtin.link_libc)
@intCast(std.c.sysconf(@intFromEnum(std.c._SC.PAGESIZE)))
@max(std.c.sysconf(@intFromEnum(std.c._SC.PAGESIZE)), 0)
else if (builtin.os.tag == .freestanding or builtin.os.tag == .other)
@compileError("unsupported target: freestanding/other")
else
@compileError("pageSize on " ++ @tagName(builtin.cpu.arch) ++ "-" ++ @tagName(builtin.os.tag) ++ " is not supported without linking libc, using the default implementation"),
};
if (size == 0) size = page_size_max;
assert(size >= page_size_min);
assert(size <= page_size_max);

View file

@ -256,8 +256,8 @@ test_filters: []const []const u8,
link_task_wait_group: WaitGroup = .{},
link_prog_node: std.Progress.Node = .none,
link_uav_prog_node: std.Progress.Node = .none,
link_lazy_prog_node: std.Progress.Node = .none,
link_const_prog_node: std.Progress.Node = .none,
link_synth_prog_node: std.Progress.Node = .none,
llvm_opt_bisect_limit: c_int,
@ -1982,13 +1982,13 @@ pub fn create(gpa: Allocator, arena: Allocator, diag: *CreateDiagnostic, options
};
if (have_zcu and (!need_llvm or use_llvm)) {
if (output_mode == .Obj) break :s .zcu;
if (options.config.use_new_linker) break :s .zcu;
switch (target_util.zigBackend(target, use_llvm)) {
else => {},
.stage2_aarch64, .stage2_x86_64 => if (target.ofmt == .coff) {
break :s if (is_exe_or_dyn_lib) .dyn_lib else .zcu;
},
}
if (options.config.use_new_linker) break :s .zcu;
}
if (need_llvm and !build_options.have_llvm) break :s .none; // impossible to build without llvm
if (is_exe_or_dyn_lib) break :s .lib;
@ -3081,22 +3081,30 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE
comp.link_prog_node = main_progress_node.start("Linking", 0);
if (lf.cast(.elf2)) |elf| {
comp.link_prog_node.increaseEstimatedTotalItems(3);
comp.link_uav_prog_node = comp.link_prog_node.start("Constants", 0);
comp.link_lazy_prog_node = comp.link_prog_node.start("Synthetics", 0);
comp.link_const_prog_node = comp.link_prog_node.start("Constants", 0);
comp.link_synth_prog_node = comp.link_prog_node.start("Synthetics", 0);
elf.mf.update_prog_node = comp.link_prog_node.start("Relocations", elf.mf.updates.items.len);
} else if (lf.cast(.coff2)) |coff| {
comp.link_prog_node.increaseEstimatedTotalItems(3);
comp.link_const_prog_node = comp.link_prog_node.start("Constants", 0);
comp.link_synth_prog_node = comp.link_prog_node.start("Synthetics", 0);
coff.mf.update_prog_node = comp.link_prog_node.start("Relocations", coff.mf.updates.items.len);
}
}
defer {
comp.link_prog_node.end();
comp.link_prog_node = .none;
comp.link_uav_prog_node.end();
comp.link_uav_prog_node = .none;
comp.link_lazy_prog_node.end();
comp.link_lazy_prog_node = .none;
comp.link_const_prog_node.end();
comp.link_const_prog_node = .none;
comp.link_synth_prog_node.end();
comp.link_synth_prog_node = .none;
if (comp.bin_file) |lf| {
if (lf.cast(.elf2)) |elf| {
elf.mf.update_prog_node.end();
elf.mf.update_prog_node = .none;
} else if (lf.cast(.coff2)) |coff| {
coff.mf.update_prog_node.end();
coff.mf.update_prog_node = .none;
}
}
}
@ -3218,7 +3226,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE
.root_dir = comp.dirs.local_cache,
.sub_path = try fs.path.join(arena, &.{ o_sub_path, comp.emit_bin.? }),
};
const result: link.File.OpenError!void = switch (need_writable_dance) {
const result: (link.File.OpenError || error{HotSwapUnavailableOnHostOperatingSystem})!void = switch (need_writable_dance) {
.no => {},
.lf_only => lf.makeWritable(),
.lf_and_debug => res: {

View file

@ -11919,10 +11919,10 @@ pub fn getString(ip: *InternPool, key: []const u8) OptionalNullTerminatedString
var map_index = hash;
while (true) : (map_index += 1) {
map_index &= map_mask;
const entry = map.at(map_index);
const index = entry.acquire().unwrap() orelse return null;
const entry = &map.entries[map_index];
const index = entry.value.unwrap() orelse return .none;
if (entry.hash != hash) continue;
if (index.eqlSlice(key, ip)) return index;
if (index.eqlSlice(key, ip)) return index.toOptional();
}
}

View file

@ -978,21 +978,8 @@ pub fn genNavRef(
},
.link_once => unreachable,
}
} else if (lf.cast(.coff)) |coff_file| {
// TODO audit this
switch (linkage) {
.internal => {
const atom_index = try coff_file.getOrCreateAtomForNav(nav_index);
const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?;
return .{ .sym_index = sym_index };
},
.strong, .weak => {
const global_index = try coff_file.getGlobalSymbol(nav.name.toSlice(ip), lib_name.toSlice(ip));
try coff_file.need_got_table.put(zcu.gpa, global_index, {}); // needs GOT
return .{ .sym_index = global_index };
},
.link_once => unreachable,
}
} else if (lf.cast(.coff2)) |coff| {
return .{ .sym_index = @intFromEnum(try coff.navSymbol(zcu, nav_index)) };
} else {
const msg = try ErrorMsg.create(zcu.gpa, src_loc, "TODO genNavRef for target {}", .{target});
return .{ .fail = msg };

View file

@ -135,11 +135,6 @@ pub fn emit(
else if (lf.cast(.macho)) |mf|
mf.getZigObject().?.getOrCreateMetadataForLazySymbol(mf, pt, lazy_reloc.symbol) catch |err|
return zcu.codegenFail(func.owner_nav, "{s} creating lazy symbol", .{@errorName(err)})
else if (lf.cast(.coff)) |cf|
if (cf.getOrCreateAtomForLazySymbol(pt, lazy_reloc.symbol)) |atom|
cf.getAtom(atom).getSymbolIndex().?
else |err|
return zcu.codegenFail(func.owner_nav, "{s} creating lazy symbol", .{@errorName(err)})
else
return zcu.codegenFail(func.owner_nav, "external symbols unimplemented for {s}", .{@tagName(lf.tag)}),
mir.body[lazy_reloc.reloc.label],
@ -154,8 +149,6 @@ pub fn emit(
try ef.getGlobalSymbol(std.mem.span(global_reloc.name), null)
else if (lf.cast(.macho)) |mf|
try mf.getGlobalSymbol(std.mem.span(global_reloc.name), null)
else if (lf.cast(.coff)) |cf|
try cf.getGlobalSymbol(std.mem.span(global_reloc.name), "compiler_rt")
else
return zcu.codegenFail(func.owner_nav, "external symbols unimplemented for {s}", .{@tagName(lf.tag)}),
mir.body[global_reloc.reloc.label],

View file

@ -12103,7 +12103,7 @@ fn firstParamSRet(fn_info: InternPool.Key.FuncType, zcu: *Zcu, target: *const st
return switch (fn_info.cc) {
.auto => returnTypeByRef(zcu, target, return_type),
.x86_64_sysv => firstParamSRetSystemV(return_type, zcu, target),
.x86_64_win => x86_64_abi.classifyWindows(return_type, zcu, target) == .memory,
.x86_64_win => x86_64_abi.classifyWindows(return_type, zcu, target, .ret) == .memory,
.x86_sysv, .x86_win => isByRef(return_type, zcu),
.x86_stdcall => !isScalar(zcu, return_type),
.wasm_mvp => wasm_c_abi.classifyType(return_type, zcu) == .indirect,
@ -12205,7 +12205,7 @@ fn lowerFnRetTy(o: *Object, pt: Zcu.PerThread, fn_info: InternPool.Key.FuncType)
fn lowerWin64FnRetTy(o: *Object, pt: Zcu.PerThread, fn_info: InternPool.Key.FuncType) Allocator.Error!Builder.Type {
const zcu = pt.zcu;
const return_type = Type.fromInterned(fn_info.return_type);
switch (x86_64_abi.classifyWindows(return_type, zcu, zcu.getTarget())) {
switch (x86_64_abi.classifyWindows(return_type, zcu, zcu.getTarget(), .ret)) {
.integer => {
if (isScalar(zcu, return_type)) {
return o.lowerType(pt, return_type);
@ -12476,7 +12476,7 @@ const ParamTypeIterator = struct {
fn nextWin64(it: *ParamTypeIterator, ty: Type) ?Lowering {
const zcu = it.pt.zcu;
switch (x86_64_abi.classifyWindows(ty, zcu, zcu.getTarget())) {
switch (x86_64_abi.classifyWindows(ty, zcu, zcu.getTarget(), .arg)) {
.integer => {
if (isScalar(zcu, ty)) {
it.zig_index += 1;

File diff suppressed because it is too large Load diff

View file

@ -89,6 +89,7 @@ pub fn emitMir(emit: *Emit) Error!void {
}
var reloc_info_buf: [2]RelocInfo = undefined;
var reloc_info_index: usize = 0;
const ip = &emit.pt.zcu.intern_pool;
while (lowered_relocs.len > 0 and
lowered_relocs[0].lowered_inst_index == lowered_index) : ({
lowered_relocs = lowered_relocs[1..];
@ -114,7 +115,6 @@ pub fn emitMir(emit: *Emit) Error!void {
return error.EmitFail;
},
};
const ip = &emit.pt.zcu.intern_pool;
break :target switch (ip.getNav(nav).status) {
.unresolved => unreachable,
.type_resolved => |type_resolved| .{
@ -170,11 +170,8 @@ pub fn emitMir(emit: *Emit) Error!void {
else if (emit.bin_file.cast(.macho)) |macho_file|
macho_file.getZigObject().?.getOrCreateMetadataForLazySymbol(macho_file, emit.pt, lazy_sym) catch |err|
return emit.fail("{s} creating lazy symbol", .{@errorName(err)})
else if (emit.bin_file.cast(.coff)) |coff_file|
if (coff_file.getOrCreateAtomForLazySymbol(emit.pt, lazy_sym)) |atom|
coff_file.getAtom(atom).getSymbolIndex().?
else |err|
return emit.fail("{s} creating lazy symbol", .{@errorName(err)})
else if (emit.bin_file.cast(.coff2)) |elf|
@intFromEnum(try elf.lazySymbol(lazy_sym))
else
return emit.fail("lazy symbols unimplemented for {s}", .{@tagName(emit.bin_file.tag)}),
.is_extern = false,
@ -188,10 +185,13 @@ pub fn emitMir(emit: *Emit) Error!void {
.type = .FUNC,
})) else if (emit.bin_file.cast(.macho)) |macho_file|
try macho_file.getGlobalSymbol(extern_func.toSlice(&emit.lower.mir).?, null)
else if (emit.bin_file.cast(.coff)) |coff_file|
try coff_file.getGlobalSymbol(extern_func.toSlice(&emit.lower.mir).?, "compiler_rt")
else
return emit.fail("external symbol unimplemented for {s}", .{@tagName(emit.bin_file.tag)}),
else if (emit.bin_file.cast(.coff2)) |coff| @intFromEnum(try coff.globalSymbol(
extern_func.toSlice(&emit.lower.mir).?,
switch (comp.compiler_rt_strat) {
.none, .lib, .obj, .zcu => null,
.dyn_lib => "compiler_rt",
},
)) else return emit.fail("external symbol unimplemented for {s}", .{@tagName(emit.bin_file.tag)}),
.is_extern = true,
.type = .symbol,
},
@ -204,9 +204,7 @@ pub fn emitMir(emit: *Emit) Error!void {
switch (lowered_inst.encoding.mnemonic) {
.call => {
reloc.target.type = .branch;
if (emit.bin_file.cast(.coff)) |_| try emit.encodeInst(try .new(.none, .call, &.{
.{ .mem = .initRip(.ptr, 0) },
}, emit.lower.target), reloc_info) else try emit.encodeInst(lowered_inst, reloc_info);
try emit.encodeInst(lowered_inst, reloc_info);
continue :lowered_inst;
},
else => {},
@ -283,27 +281,8 @@ pub fn emitMir(emit: *Emit) Error!void {
}, emit.lower.target), reloc_info),
else => unreachable,
}
} else if (emit.bin_file.cast(.coff)) |_| {
if (reloc.target.is_extern) switch (lowered_inst.encoding.mnemonic) {
.lea => try emit.encodeInst(try .new(.none, .mov, &.{
lowered_inst.ops[0],
.{ .mem = .initRip(.ptr, 0) },
}, emit.lower.target), reloc_info),
.mov => {
const dst_reg = lowered_inst.ops[0].reg.to64();
try emit.encodeInst(try .new(.none, .mov, &.{
.{ .reg = dst_reg },
.{ .mem = .initRip(.ptr, 0) },
}, emit.lower.target), reloc_info);
try emit.encodeInst(try .new(.none, .mov, &.{
lowered_inst.ops[0],
.{ .mem = .initSib(lowered_inst.ops[reloc.op_index].mem.sib.ptr_size, .{ .base = .{
.reg = dst_reg,
} }) },
}, emit.lower.target), &.{});
},
else => unreachable,
} else switch (lowered_inst.encoding.mnemonic) {
} else if (emit.bin_file.cast(.coff2)) |_| {
switch (lowered_inst.encoding.mnemonic) {
.lea => try emit.encodeInst(try .new(.none, .lea, &.{
lowered_inst.ops[0],
.{ .mem = .initRip(.none, 0) },
@ -683,7 +662,7 @@ pub fn emitMir(emit: *Emit) Error!void {
table_reloc.source_offset,
@enumFromInt(emit.atom_index),
@as(i64, table_offset) + table_reloc.target_offset,
.{ .x86_64 = .@"32" },
.{ .X86_64 = .@"32" },
);
for (emit.lower.mir.table) |entry| {
try elf.addReloc(
@ -691,7 +670,7 @@ pub fn emitMir(emit: *Emit) Error!void {
table_offset,
@enumFromInt(emit.atom_index),
emit.code_offset_mapping.items[entry],
.{ .x86_64 = .@"64" },
.{ .X86_64 = .@"64" },
);
table_offset += ptr_size;
}
@ -800,23 +779,14 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI
end_offset - 4,
@enumFromInt(reloc.target.index),
reloc.off,
.{ .x86_64 = .@"32" },
) else if (emit.bin_file.cast(.coff)) |coff_file| {
const atom_index = coff_file.getAtomIndexForSymbol(
.{ .sym_index = emit.atom_index, .file = null },
).?;
try coff_file.addRelocation(atom_index, .{
.type = if (reloc.target.is_extern) .got else .direct,
.target = if (reloc.target.is_extern)
coff_file.getGlobalByIndex(reloc.target.index)
else
.{ .sym_index = reloc.target.index, .file = null },
.offset = end_offset - 4,
.addend = @intCast(reloc.off),
.pcrel = true,
.length = 2,
});
} else unreachable,
.{ .X86_64 = .@"32" },
) else if (emit.bin_file.cast(.coff2)) |coff| try coff.addReloc(
@enumFromInt(emit.atom_index),
end_offset - 4,
@enumFromInt(reloc.target.index),
reloc.off,
.{ .AMD64 = .REL32 },
) else unreachable,
.branch => if (emit.bin_file.cast(.elf)) |elf_file| {
const zo = elf_file.zigObjectPtr().?;
const atom = zo.symbol(emit.atom_index).atom(elf_file).?;
@ -831,7 +801,7 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI
end_offset - 4,
@enumFromInt(reloc.target.index),
reloc.off - 4,
.{ .x86_64 = .PC32 },
.{ .X86_64 = .PC32 },
) else if (emit.bin_file.cast(.macho)) |macho_file| {
const zo = macho_file.getZigObject().?;
const atom = zo.symbols.items[emit.atom_index].getAtom(macho_file).?;
@ -848,22 +818,13 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI
.symbolnum = @intCast(reloc.target.index),
},
});
} else if (emit.bin_file.cast(.coff)) |coff_file| {
const atom_index = coff_file.getAtomIndexForSymbol(
.{ .sym_index = emit.atom_index, .file = null },
).?;
try coff_file.addRelocation(atom_index, .{
.type = if (reloc.target.is_extern) .import else .got,
.target = if (reloc.target.is_extern)
coff_file.getGlobalByIndex(reloc.target.index)
else
.{ .sym_index = reloc.target.index, .file = null },
.offset = end_offset - 4,
.addend = @intCast(reloc.off),
.pcrel = true,
.length = 2,
});
} else return emit.fail("TODO implement {s} reloc for {s}", .{
} else if (emit.bin_file.cast(.coff2)) |coff| try coff.addReloc(
@enumFromInt(emit.atom_index),
end_offset - 4,
@enumFromInt(reloc.target.index),
reloc.off,
.{ .AMD64 = .REL32 },
) else return emit.fail("TODO implement {s} reloc for {s}", .{
@tagName(reloc.target.type), @tagName(emit.bin_file.tag),
}),
.tls => if (emit.bin_file.cast(.elf)) |elf_file| {
@ -892,7 +853,7 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI
end_offset - 4,
@enumFromInt(reloc.target.index),
reloc.off,
.{ .x86_64 = .TPOFF32 },
.{ .X86_64 = .TPOFF32 },
) else if (emit.bin_file.cast(.macho)) |macho_file| {
const zo = macho_file.getZigObject().?;
const atom = zo.symbols.items[emit.atom_index].getAtom(macho_file).?;

View file

@ -110,7 +110,9 @@ pub const Class = enum {
}
};
pub fn classifyWindows(ty: Type, zcu: *Zcu, target: *const std.Target) Class {
pub const Context = enum { ret, arg, other };
pub fn classifyWindows(ty: Type, zcu: *Zcu, target: *const std.Target, ctx: Context) Class {
// https://docs.microsoft.com/en-gb/cpp/build/x64-calling-convention?view=vs-2017
// "There's a strict one-to-one correspondence between a function call's arguments
// and the registers used for those arguments. Any argument that doesn't fit in 8
@ -148,8 +150,9 @@ pub fn classifyWindows(ty: Type, zcu: *Zcu, target: *const std.Target) Class {
},
.float => switch (ty.floatBits(target)) {
16, 32, 64, 128 => .sse,
16, 32, 64 => .sse,
80 => .memory,
128 => if (ctx == .arg) .memory else .sse,
else => unreachable,
},
.vector => .sse,
@ -166,8 +169,6 @@ pub fn classifyWindows(ty: Type, zcu: *Zcu, target: *const std.Target) Class {
};
}
pub const Context = enum { ret, arg, other };
/// There are a maximum of 8 possible return slots. Returned values are in
/// the beginning of the array; unused slots are filled with .none.
pub fn classifySystemV(ty: Type, zcu: *Zcu, target: *const std.Target, ctx: Context) [8]Class {

View file

@ -96,6 +96,7 @@ pub const Env = enum {
.spirv_backend,
.lld_linker,
.coff_linker,
.coff2_linker,
.elf_linker,
.elf2_linker,
.macho_linker,
@ -284,6 +285,7 @@ pub const Feature = enum {
lld_linker,
coff_linker,
coff2_linker,
elf_linker,
elf2_linker,
macho_linker,

View file

@ -574,16 +574,13 @@ pub const File = struct {
const gpa = comp.gpa;
switch (base.tag) {
.lld => assert(base.file == null),
.coff, .elf, .macho, .wasm, .goff, .xcoff => {
.elf, .macho, .wasm, .goff, .xcoff => {
if (base.file != null) return;
dev.checkAny(&.{ .coff_linker, .elf_linker, .macho_linker, .plan9_linker, .wasm_linker, .goff_linker, .xcoff_linker });
const emit = base.emit;
if (base.child_pid) |pid| {
if (builtin.os.tag == .windows) {
const coff_file = base.cast(.coff).?;
coff_file.ptraceAttach(pid) catch |err| {
log.warn("attaching failed with error: {s}", .{@errorName(err)});
};
return error.HotSwapUnavailableOnHostOperatingSystem;
} else {
// If we try to open the output file in write mode while it is running,
// it will return ETXTBSY. So instead, we copy the file, atomically rename it
@ -610,27 +607,20 @@ pub const File = struct {
}
}
}
const output_mode = comp.config.output_mode;
const link_mode = comp.config.link_mode;
base.file = try emit.root_dir.handle.createFile(emit.sub_path, .{
.truncate = false,
.read = true,
.mode = determineMode(output_mode, link_mode),
});
base.file = try emit.root_dir.handle.openFile(emit.sub_path, .{ .mode = .read_write });
},
.elf2 => {
const elf = base.cast(.elf2).?;
if (base.file == null) {
elf.mf.file = try base.emit.root_dir.handle.createFile(base.emit.sub_path, .{
.truncate = false,
.read = true,
.mode = determineMode(comp.config.output_mode, comp.config.link_mode),
});
base.file = elf.mf.file;
try elf.mf.ensureTotalCapacity(
@intCast(elf.mf.nodes.items[0].location().resolve(&elf.mf)[1]),
);
}
.elf2, .coff2 => if (base.file == null) {
const mf = if (base.cast(.elf2)) |elf|
&elf.mf
else if (base.cast(.coff2)) |coff|
&coff.mf
else
unreachable;
mf.file = try base.emit.root_dir.handle.openFile(base.emit.sub_path, .{
.mode = .read_write,
});
base.file = mf.file;
try mf.ensureTotalCapacity(@intCast(mf.nodes.items[0].location().resolve(mf)[1]));
},
.c, .spirv => dev.checkAny(&.{ .c_linker, .spirv_linker }),
.plan9 => unreachable,
@ -654,12 +644,9 @@ pub const File = struct {
pub fn makeExecutable(base: *File) !void {
dev.check(.make_executable);
const comp = base.comp;
const output_mode = comp.config.output_mode;
const link_mode = comp.config.link_mode;
switch (output_mode) {
switch (comp.config.output_mode) {
.Obj => return,
.Lib => switch (link_mode) {
.Lib => switch (comp.config.link_mode) {
.static => return,
.dynamic => {},
},
@ -681,7 +668,7 @@ pub const File = struct {
}
}
},
.coff, .macho, .wasm, .goff, .xcoff => if (base.file) |f| {
.macho, .wasm, .goff, .xcoff => if (base.file) |f| {
dev.checkAny(&.{ .coff_linker, .macho_linker, .plan9_linker, .wasm_linker, .goff_linker, .xcoff_linker });
f.close();
base.file = null;
@ -694,23 +681,22 @@ pub const File = struct {
log.warn("detaching failed with error: {s}", .{@errorName(err)});
};
},
.windows => {
const coff_file = base.cast(.coff).?;
coff_file.ptraceDetach(pid);
},
else => return error.HotSwapUnavailableOnHostOperatingSystem,
}
}
},
.elf2 => {
const elf = base.cast(.elf2).?;
if (base.file) |f| {
elf.mf.unmap();
assert(elf.mf.file.handle == f.handle);
elf.mf.file = undefined;
f.close();
base.file = null;
}
.elf2, .coff2 => if (base.file) |f| {
const mf = if (base.cast(.elf2)) |elf|
&elf.mf
else if (base.cast(.coff2)) |coff|
&coff.mf
else
unreachable;
mf.unmap();
assert(mf.file.handle == f.handle);
mf.file = undefined;
f.close();
base.file = null;
},
.c, .spirv => dev.checkAny(&.{ .c_linker, .spirv_linker }),
.plan9 => unreachable,
@ -828,7 +814,7 @@ pub const File = struct {
.spirv => {},
.goff, .xcoff => {},
.plan9 => unreachable,
.elf2 => {},
.elf2, .coff2 => {},
inline else => |tag| {
dev.check(tag.devFeature());
return @as(*tag.Type(), @fieldParentPtr("base", base)).updateLineNumber(pt, ti_id);
@ -864,7 +850,7 @@ pub const File = struct {
pub fn idle(base: *File, tid: Zcu.PerThread.Id) !bool {
switch (base.tag) {
else => return false,
inline .elf2 => |tag| {
inline .elf2, .coff2 => |tag| {
dev.check(tag.devFeature());
return @as(*tag.Type(), @fieldParentPtr("base", base)).idle(tid);
},
@ -874,7 +860,7 @@ pub const File = struct {
pub fn updateErrorData(base: *File, pt: Zcu.PerThread) !void {
switch (base.tag) {
else => {},
inline .elf2 => |tag| {
inline .elf2, .coff2 => |tag| {
dev.check(tag.devFeature());
return @as(*tag.Type(), @fieldParentPtr("base", base)).updateErrorData(pt);
},
@ -1155,7 +1141,7 @@ pub const File = struct {
if (base.zcu_object_basename != null) return;
switch (base.tag) {
inline .elf2, .wasm => |tag| {
inline .elf2, .coff2, .wasm => |tag| {
dev.check(tag.devFeature());
return @as(*tag.Type(), @fieldParentPtr("base", base)).prelink(base.comp.link_prog_node);
},
@ -1164,7 +1150,7 @@ pub const File = struct {
}
pub const Tag = enum {
coff,
coff2,
elf,
elf2,
macho,
@ -1178,7 +1164,7 @@ pub const File = struct {
pub fn Type(comptime tag: Tag) type {
return switch (tag) {
.coff => Coff,
.coff2 => Coff2,
.elf => Elf,
.elf2 => Elf2,
.macho => MachO,
@ -1194,7 +1180,7 @@ pub const File = struct {
fn fromObjectFormat(ofmt: std.Target.ObjectFormat, use_new_linker: bool) Tag {
return switch (ofmt) {
.coff => .coff,
.coff => .coff2,
.elf => if (use_new_linker) .elf2 else .elf,
.macho => .macho,
.wasm => .wasm,
@ -1279,7 +1265,7 @@ pub const File = struct {
pub const Lld = @import("link/Lld.zig");
pub const C = @import("link/C.zig");
pub const Coff = @import("link/Coff.zig");
pub const Coff2 = @import("link/Coff2.zig");
pub const Elf = @import("link/Elf.zig");
pub const Elf2 = @import("link/Elf2.zig");
pub const MachO = @import("link/MachO.zig");

File diff suppressed because it is too large Load diff

2193
src/link/Coff2.zig Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -34,17 +34,28 @@ pub fn init(file: std.fs.File, gpa: std.mem.Allocator) !MappedFile {
.writers = .{},
};
errdefer mf.deinit(gpa);
const size: u64, const blksize = if (is_windows)
.{ try windows.GetFileSizeEx(file.handle), 1 }
else stat: {
const size: u64, const block_size = stat: {
if (is_windows) {
var sbi: windows.SYSTEM_BASIC_INFORMATION = undefined;
break :stat .{
try windows.GetFileSizeEx(file.handle),
switch (windows.ntdll.NtQuerySystemInformation(
.SystemBasicInformation,
&sbi,
@sizeOf(windows.SYSTEM_BASIC_INFORMATION),
null,
)) {
.SUCCESS => @max(sbi.PageSize, sbi.AllocationGranularity),
else => std.heap.page_size_max,
},
};
}
const stat = try std.posix.fstat(mf.file.handle);
if (!std.posix.S.ISREG(stat.mode)) return error.PathAlreadyExists;
break :stat .{ @bitCast(stat.size), stat.blksize };
break :stat .{ @bitCast(stat.size), @max(std.heap.pageSize(), stat.blksize) };
};
mf.flags = .{
.block_size = .fromByteUnits(
std.math.ceilPowerOfTwoAssert(usize, @max(std.heap.pageSize(), blksize)),
),
.block_size = .fromByteUnits(std.math.ceilPowerOfTwoAssert(usize, block_size)),
.copy_file_range_unsupported = false,
.fallocate_insert_range_unsupported = false,
.fallocate_punch_hole_unsupported = false,
@ -90,9 +101,11 @@ pub const Node = extern struct {
resized: bool,
/// Whether this node might contain non-zero bytes.
has_content: bool,
/// Whether a moved event on this node bubbles down to children.
bubbles_moved: bool,
unused: @Type(.{ .int = .{
.signedness = .unsigned,
.bits = 32 - @bitSizeOf(std.mem.Alignment) - 5,
.bits = 32 - @bitSizeOf(std.mem.Alignment) - 6,
} }) = 0,
};
@ -136,6 +149,25 @@ pub const Node = extern struct {
return &mf.nodes.items[@intFromEnum(ni)];
}
pub fn parent(ni: Node.Index, mf: *const MappedFile) Node.Index {
return ni.get(mf).parent;
}
pub const ChildIterator = struct {
mf: *const MappedFile,
ni: Node.Index,
pub fn next(it: *ChildIterator) ?Node.Index {
const ni = it.ni;
if (ni == .none) return null;
it.ni = ni.get(it.mf).next;
return ni;
}
};
pub fn children(ni: Node.Index, mf: *const MappedFile) ChildIterator {
return .{ .mf = mf, .ni = ni.get(mf).first };
}
pub fn childrenMoved(ni: Node.Index, gpa: std.mem.Allocator, mf: *MappedFile) !void {
var child_ni = ni.get(mf).last;
while (child_ni != .none) {
@ -147,9 +179,10 @@ pub const Node = extern struct {
pub fn hasMoved(ni: Node.Index, mf: *const MappedFile) bool {
var parent_ni = ni;
while (parent_ni != Node.Index.root) {
const parent = parent_ni.get(mf);
if (parent.flags.moved) return true;
parent_ni = parent.parent;
const parent_node = parent_ni.get(mf);
if (!parent_node.flags.bubbles_moved) break;
if (parent_node.flags.moved) return true;
parent_ni = parent_node.parent;
}
return false;
}
@ -163,12 +196,7 @@ pub const Node = extern struct {
return node_moved.*;
}
fn movedAssumeCapacity(ni: Node.Index, mf: *MappedFile) void {
var parent_ni = ni;
while (parent_ni != Node.Index.root) {
const parent_node = parent_ni.get(mf);
if (parent_node.flags.moved) return;
parent_ni = parent_node.parent;
}
if (ni.hasMoved(mf)) return;
const node = ni.get(mf);
node.flags.moved = true;
if (node.flags.resized) return;
@ -242,10 +270,10 @@ pub const Node = extern struct {
var offset, const size = ni.location(mf).resolve(mf);
var parent_ni = ni;
while (true) {
const parent = parent_ni.get(mf);
if (set_has_content) parent.flags.has_content = true;
const parent_node = parent_ni.get(mf);
if (set_has_content) parent_node.flags.has_content = true;
if (parent_ni == .none) break;
parent_ni = parent.parent;
parent_ni = parent_node.parent;
offset += parent_ni.location(mf).resolve(mf)[0];
}
return .{ .offset = offset, .size = size };
@ -449,6 +477,7 @@ fn addNode(mf: *MappedFile, gpa: std.mem.Allocator, opts: struct {
.moved = true,
.resized = true,
.has_content = false,
.bubbles_moved = opts.add_node.bubbles_moved,
},
.location_payload = location_payload,
};
@ -471,6 +500,7 @@ pub const AddNodeOptions = struct {
fixed: bool = false,
moved: bool = false,
resized: bool = false,
bubbles_moved: bool = true,
};
pub fn addOnlyChildNode(

View file

@ -233,7 +233,7 @@ pub fn hasLldSupport(ofmt: std.Target.ObjectFormat) bool {
pub fn hasNewLinkerSupport(ofmt: std.Target.ObjectFormat, backend: std.builtin.CompilerBackend) bool {
return switch (ofmt) {
.elf => switch (backend) {
.elf, .coff => switch (backend) {
.stage2_x86_64 => true,
else => false,
},

View file

@ -1650,7 +1650,6 @@ test "coerce between pointers of compatible differently-named floats" {
if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows and !builtin.link_libc) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt == .coff) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) {
@ -2883,7 +2882,6 @@ test "@intFromFloat vector boundary cases" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
const S = struct {
fn case(comptime I: type, unshifted_inputs: [2]f32, expected: [2]I) !void {

View file

@ -43,7 +43,6 @@ export fn testPackedStuff(a: *const PackedStruct, b: *const PackedUnion) void {
}
test "export function alias" {
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt == .coff) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
_ = struct {

View file

@ -16,7 +16,6 @@ export var a_mystery_symbol: i32 = 1234;
test "function extern symbol" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
const a = @extern(*const fn () callconv(.c) i32, .{ .name = "a_mystery_function" });
@ -29,7 +28,6 @@ export fn a_mystery_function() i32 {
test "function extern symbol matches extern decl" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
const S = struct {

View file

@ -158,7 +158,6 @@ test "cmp f80/c_longdouble" {
if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt == .coff) return error.SkipZigTest;
try testCmp(f80);
try comptime testCmp(f80);
@ -283,7 +282,6 @@ test "vector cmp f80/c_longdouble" {
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt == .coff) return error.SkipZigTest;
try testCmpVector(f80);
try comptime testCmpVector(f80);
@ -396,7 +394,6 @@ test "@sqrt f80/f128/c_longdouble" {
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt == .coff) return error.SkipZigTest;
if (builtin.os.tag == .freebsd) {
// TODO https://github.com/ziglang/zig/issues/10875
@ -526,7 +523,6 @@ test "@sin f80/f128/c_longdouble" {
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt == .coff) return error.SkipZigTest;
try testSin(f80);
comptime try testSin(f80);
@ -596,7 +592,6 @@ test "@cos f80/f128/c_longdouble" {
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt == .coff) return error.SkipZigTest;
try testCos(f80);
try comptime testCos(f80);
@ -666,7 +661,6 @@ test "@tan f80/f128/c_longdouble" {
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt == .coff) return error.SkipZigTest;
try testTan(f80);
try comptime testTan(f80);
@ -736,7 +730,6 @@ test "@exp f80/f128/c_longdouble" {
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt == .coff) return error.SkipZigTest;
try testExp(f80);
try comptime testExp(f80);
@ -810,7 +803,6 @@ test "@exp2 f80/f128/c_longdouble" {
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt == .coff) return error.SkipZigTest;
try testExp2(f80);
try comptime testExp2(f80);
@ -879,7 +871,6 @@ test "@log f80/f128/c_longdouble" {
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt == .coff) return error.SkipZigTest;
try testLog(f80);
try comptime testLog(f80);
@ -946,7 +937,6 @@ test "@log2 f80/f128/c_longdouble" {
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt == .coff) return error.SkipZigTest;
try testLog2(f80);
try comptime testLog2(f80);
@ -1019,7 +1009,6 @@ test "@log10 f80/f128/c_longdouble" {
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt == .coff) return error.SkipZigTest;
try testLog10(f80);
try comptime testLog10(f80);
@ -1086,7 +1075,6 @@ test "@abs f80/f128/c_longdouble" {
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt == .coff) return error.SkipZigTest;
try testFabs(f80);
try comptime testFabs(f80);
@ -1204,7 +1192,6 @@ test "@floor f80/f128/c_longdouble" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
@ -1295,7 +1282,6 @@ test "@ceil f80/f128/c_longdouble" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
@ -1388,7 +1374,6 @@ test "@trunc f80/f128/c_longdouble" {
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt == .coff) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) {
// https://github.com/ziglang/zig/issues/12602
@ -1485,7 +1470,6 @@ test "neg f80/f128/c_longdouble" {
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt == .coff) return error.SkipZigTest;
try testNeg(f80);
try comptime testNeg(f80);
@ -1741,7 +1725,6 @@ test "comptime calls are only memoized when float arguments are bit-for-bit equa
test "result location forwarded through unary float builtins" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;

View file

@ -31,7 +31,6 @@ test "import c keywords" {
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt == .coff) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
try std.testing.expect(int == .c_keyword_variable);

View file

@ -1416,7 +1416,6 @@ test "remainder division" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
@ -1425,6 +1424,8 @@ test "remainder division" {
return error.SkipZigTest;
}
if (builtin.zig_backend == .stage2_x86_64 and builtin.object_format == .coff and builtin.abi != .gnu) return error.SkipZigTest;
try comptime remdiv(f16);
try comptime remdiv(f32);
try comptime remdiv(f64);
@ -1496,9 +1497,10 @@ test "float modulo division using @mod" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.object_format == .coff and builtin.abi != .gnu) return error.SkipZigTest;
try comptime fmod(f16);
try comptime fmod(f32);
try comptime fmod(f64);
@ -1686,7 +1688,6 @@ test "signed zeros are represented properly" {
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt == .coff) return error.SkipZigTest;
const S = struct {
fn doTheTest() !void {
@ -1824,7 +1825,8 @@ test "float divide by zero" {
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.object_format == .coff and builtin.abi != .gnu) return error.SkipZigTest;
const S = struct {
fn doTheTest(comptime F: type, zero: F, one: F) !void {

View file

@ -14,7 +14,6 @@ test "call extern function defined with conflicting type" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt == .coff) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
@import("conflicting_externs/a.zig").issue529(null);

View file

@ -5172,15 +5172,6 @@ test mulSaturate {
try test_mul_saturate.testIntVectors();
}
inline fn multiply(comptime Type: type, lhs: Type, rhs: Type) Type {
return lhs * rhs;
}
test multiply {
const test_multiply = binary(multiply, .{});
try test_multiply.testFloats();
try test_multiply.testFloatVectors();
}
inline fn divide(comptime Type: type, lhs: Type, rhs: Type) Type {
return lhs / rhs;
}
@ -5264,7 +5255,8 @@ inline fn mod(comptime Type: type, lhs: Type, rhs: Type) Type {
return @mod(lhs, rhs);
}
test mod {
if (@import("builtin").object_format == .coff) return error.SkipZigTest;
const builtin = @import("builtin");
if (builtin.object_format == .coff and builtin.abi != .gnu) return error.SkipZigTest;
const test_mod = binary(mod, .{});
try test_mod.testInts();
try test_mod.testIntVectors();

View file

@ -1,4 +1,5 @@
#target=x86_64-linux-selfhosted
#target=x86_64-windows-selfhosted
#target=x86_64-linux-cbe
#target=x86_64-windows-cbe
//#target=wasm32-wasi-selfhosted

View file

@ -1,4 +1,5 @@
#target=x86_64-linux-selfhosted
#target=x86_64-windows-selfhosted
#target=x86_64-linux-cbe
#target=x86_64-windows-cbe
//#target=wasm32-wasi-selfhosted

View file

@ -1,4 +1,5 @@
#target=x86_64-linux-selfhosted
#target=x86_64-windows-selfhosted
#target=x86_64-linux-cbe
#target=x86_64-windows-cbe
#target=wasm32-wasi-selfhosted

View file

@ -1,4 +1,5 @@
#target=x86_64-linux-selfhosted
#target=x86_64-windows-selfhosted
#target=x86_64-linux-cbe
#target=x86_64-windows-cbe
#target=wasm32-wasi-selfhosted

View file

@ -1,4 +1,5 @@
#target=x86_64-linux-selfhosted
#target=x86_64-windows-selfhosted
#target=x86_64-linux-cbe
#target=x86_64-windows-cbe
#target=wasm32-wasi-selfhosted

View file

@ -1,4 +1,5 @@
#target=x86_64-linux-selfhosted
#target=x86_64-windows-selfhosted
#target=x86_64-linux-cbe
#target=x86_64-windows-cbe
#target=wasm32-wasi-selfhosted

View file

@ -1,4 +1,5 @@
#target=x86_64-linux-selfhosted
#target=x86_64-windows-selfhosted
#target=x86_64-linux-cbe
#target=x86_64-windows-cbe

View file

@ -1,4 +1,5 @@
#target=x86_64-linux-selfhosted
#target=x86_64-windows-selfhosted
#target=x86_64-linux-cbe
#target=x86_64-windows-cbe
#update=initial version

View file

@ -1,4 +1,5 @@
#target=x86_64-linux-selfhosted
#target=x86_64-windows-selfhosted
#target=wasm32-wasi-selfhosted
#update=initial version
#file=main.zig

View file

@ -1,4 +1,5 @@
#target=x86_64-linux-selfhosted
#target=x86_64-windows-selfhosted
#target=wasm32-wasi-selfhosted
#update=initial version
#file=main.zig

View file

@ -1,4 +1,5 @@
#target=x86_64-linux-selfhosted
#target=x86_64-windows-selfhosted
#target=x86_64-linux-cbe
#target=x86_64-windows-cbe
#target=wasm32-wasi-selfhosted

View file

@ -1,4 +1,5 @@
#target=x86_64-linux-selfhosted
#target=x86_64-windows-selfhosted
#target=x86_64-linux-cbe
#target=x86_64-windows-cbe
#update=initial version

View file

@ -1,4 +1,5 @@
#target=x86_64-linux-selfhosted
#target=x86_64-windows-selfhosted
#target=x86_64-linux-cbe
#target=x86_64-windows-cbe
#update=initial version

View file

@ -1,4 +1,5 @@
#target=x86_64-linux-selfhosted
#target=x86_64-windows-selfhosted
#target=x86_64-linux-cbe
#target=x86_64-windows-cbe
#target=wasm32-wasi-selfhosted

View file

@ -1,4 +1,5 @@
#target=x86_64-linux-selfhosted
#target=x86_64-windows-selfhosted
#target=x86_64-linux-cbe
#target=x86_64-windows-cbe
#target=wasm32-wasi-selfhosted

View file

@ -1,4 +1,5 @@
#target=x86_64-linux-selfhosted
#target=x86_64-windows-selfhosted
#target=x86_64-linux-cbe
#target=x86_64-windows-cbe
//#target=wasm32-wasi-selfhosted

View file

@ -1,4 +1,5 @@
#target=x86_64-linux-selfhosted
#target=x86_64-windows-selfhosted
#target=x86_64-linux-cbe
#target=x86_64-windows-cbe
//#target=wasm32-wasi-selfhosted

View file

@ -1,4 +1,5 @@
#target=x86_64-linux-selfhosted
#target=x86_64-windows-selfhosted
#target=x86_64-linux-cbe
#target=x86_64-windows-cbe
#target=wasm32-wasi-selfhosted

View file

@ -1,4 +1,5 @@
#target=x86_64-linux-selfhosted
#target=x86_64-windows-selfhosted
#target=x86_64-linux-cbe
#target=x86_64-windows-cbe
#target=wasm32-wasi-selfhosted

View file

@ -1,4 +1,5 @@
#target=x86_64-linux-selfhosted
#target=x86_64-windows-selfhosted
#target=x86_64-linux-cbe
#target=x86_64-windows-cbe
#target=wasm32-wasi-selfhosted

View file

@ -1,4 +1,5 @@
#target=x86_64-linux-selfhosted
#target=x86_64-windows-selfhosted
#target=x86_64-linux-cbe
#target=x86_64-windows-cbe
#target=wasm32-wasi-selfhosted

View file

@ -1,4 +1,5 @@
#target=x86_64-linux-selfhosted
#target=x86_64-windows-selfhosted
#target=x86_64-linux-cbe
#target=x86_64-windows-cbe
#target=wasm32-wasi-selfhosted

View file

@ -1,4 +1,5 @@
#target=x86_64-linux-selfhosted
#target=x86_64-windows-selfhosted
#target=x86_64-linux-cbe
#target=x86_64-windows-cbe
#update=non-inline version

View file

@ -1,4 +1,5 @@
#target=x86_64-linux-selfhosted
#target=x86_64-windows-selfhosted
#target=x86_64-linux-cbe
#target=x86_64-windows-cbe
#target=wasm32-wasi-selfhosted

View file

@ -1,4 +1,5 @@
#target=x86_64-linux-selfhosted
#target=x86_64-windows-selfhosted
#target=x86_64-linux-cbe
#target=x86_64-windows-cbe
#target=wasm32-wasi-selfhosted

View file

@ -1,4 +1,5 @@
#target=x86_64-linux-selfhosted
#target=x86_64-windows-selfhosted
#target=x86_64-linux-cbe
#target=x86_64-windows-cbe
#target=wasm32-wasi-selfhosted

View file

@ -1,4 +1,5 @@
#target=x86_64-linux-selfhosted
#target=x86_64-windows-selfhosted
#target=x86_64-linux-cbe
#target=x86_64-windows-cbe
#target=wasm32-wasi-selfhosted

View file

@ -1,4 +1,5 @@
#target=x86_64-linux-selfhosted
#target=x86_64-windows-selfhosted
#target=x86_64-linux-cbe
#target=x86_64-windows-cbe
//#target=wasm32-wasi-selfhosted

View file

@ -1,4 +1,5 @@
#target=x86_64-linux-selfhosted
#target=x86_64-windows-selfhosted
#target=x86_64-linux-cbe
#target=x86_64-windows-cbe
#target=wasm32-wasi-selfhosted

View file

@ -1,4 +1,5 @@
#target=x86_64-linux-selfhosted
#target=x86_64-windows-selfhosted
#target=x86_64-linux-cbe
#target=x86_64-windows-cbe
#target=wasm32-wasi-selfhosted

View file

@ -1,4 +1,5 @@
#target=x86_64-linux-selfhosted
#target=x86_64-windows-selfhosted
#target=x86_64-linux-cbe
#target=x86_64-windows-cbe
#target=wasm32-wasi-selfhosted

View file

@ -1,4 +1,5 @@
#target=x86_64-linux-selfhosted
#target=x86_64-windows-selfhosted
#target=x86_64-linux-cbe
#target=x86_64-windows-cbe
#target=wasm32-wasi-selfhosted

View file

@ -1,4 +1,5 @@
#target=x86_64-linux-selfhosted
#target=x86_64-windows-selfhosted
#target=x86_64-linux-cbe
#target=x86_64-windows-cbe
#target=wasm32-wasi-selfhosted

View file

@ -1,4 +1,5 @@
#target=x86_64-linux-selfhosted
#target=x86_64-windows-selfhosted
#target=x86_64-linux-cbe
#target=x86_64-windows-cbe
#target=wasm32-wasi-selfhosted