diff --git a/CMakeLists.txt b/CMakeLists.txt index 5f22a2a6f03a..12bcec0b3a06 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -612,6 +612,7 @@ set(ZIG_STAGE2_SOURCES src/link/Elf/relocatable.zig src/link/Elf/relocation.zig src/link/Elf/synthetic_sections.zig + src/link/Goff.zig src/link/LdScript.zig src/link/MachO.zig src/link/MachO/Archive.zig @@ -652,6 +653,7 @@ set(ZIG_STAGE2_SOURCES src/link/Wasm/Archive.zig src/link/Wasm/Flush.zig src/link/Wasm/Object.zig + src/link/Xcoff.zig src/link/aarch64.zig src/link/riscv.zig src/link/table_section.zig diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 19cf05222e5a..87d3cbfbacb6 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -399,7 +399,7 @@ pub fn dataLayout(target: std.Target) []const u8 { .sparc => "E-m:e-p:32:32-i64:64-i128:128-f128:64-n32-S64", .sparc64 => "E-m:e-i64:64-i128:128-n32:64-S128", .s390x => if (target.os.tag == .zos) - "E-m:l-i1:8:16-i8:8:16-i64:64-f128:64-v128:64-a:8:16-n32:64" + "E-m:l-p1:32:32-i1:8:16-i8:8:16-i64:64-f128:64-v128:64-a:8:16-n32:64" else "E-m:e-i1:8:16-i8:8:16-i64:64-f128:64-v128:64-a:8:16-n32:64", .x86 => switch (target.os.tag) { diff --git a/src/dev.zig b/src/dev.zig index f4be5a36a905..0d902932462a 100644 --- a/src/dev.zig +++ b/src/dev.zig @@ -82,6 +82,8 @@ pub const Env = enum { .spirv_linker, .plan9_linker, .nvptx_linker, + .goff_linker, + .xcoff_linker, => true, .cc_command, .translate_c_command, @@ -228,6 +230,8 @@ pub const Feature = enum { spirv_linker, plan9_linker, nvptx_linker, + goff_linker, + xcoff_linker, }; /// Makes the code following the call to this function unreachable if `feature` is disabled. diff --git a/src/link.zig b/src/link.zig index f436106aabae..2f04751aac46 100644 --- a/src/link.zig +++ b/src/link.zig @@ -556,9 +556,9 @@ pub const File = struct { const comp = base.comp; const gpa = comp.gpa; switch (base.tag) { - .coff, .elf, .macho, .plan9, .wasm => { + .coff, .elf, .macho, .plan9, .wasm, .goff, .xcoff => { if (base.file != null) return; - dev.checkAny(&.{ .coff_linker, .elf_linker, .macho_linker, .plan9_linker, .wasm_linker }); + 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) { @@ -650,8 +650,8 @@ pub const File = struct { } } }, - .coff, .macho, .plan9, .wasm => if (base.file) |f| { - dev.checkAny(&.{ .coff_linker, .macho_linker, .plan9_linker, .wasm_linker }); + .coff, .macho, .plan9, .wasm, .goff, .xcoff => if (base.file) |f| { + dev.checkAny(&.{ .coff_linker, .macho_linker, .plan9_linker, .wasm_linker, .goff_linker, .xcoff_linker }); if (base.zcu_object_sub_path != null) { // The file we have open is not the final file that we want to // make executable, so we don't have to close it. @@ -767,6 +767,7 @@ pub const File = struct { switch (base.tag) { .spirv, .nvptx => {}, + .goff, .xcoff => {}, inline else => |tag| { dev.check(tag.devFeature()); return @as(*tag.Type(), @fieldParentPtr("base", base)).updateLineNumber(pt, ti_id); @@ -902,6 +903,7 @@ pub const File = struct { .spirv => unreachable, .nvptx => unreachable, .wasm => unreachable, + .goff, .xcoff => unreachable, inline else => |tag| { dev.check(tag.devFeature()); return @as(*tag.Type(), @fieldParentPtr("base", base)).getNavVAddr(pt, nav_index, reloc_info); @@ -921,6 +923,7 @@ pub const File = struct { .spirv => unreachable, .nvptx => unreachable, .wasm => unreachable, + .goff, .xcoff => unreachable, inline else => |tag| { dev.check(tag.devFeature()); return @as(*tag.Type(), @fieldParentPtr("base", base)).lowerUav(pt, decl_val, decl_align, src_loc); @@ -934,6 +937,7 @@ pub const File = struct { .spirv => unreachable, .nvptx => unreachable, .wasm => unreachable, + .goff, .xcoff => unreachable, inline else => |tag| { dev.check(tag.devFeature()); return @as(*tag.Type(), @fieldParentPtr("base", base)).getUavVAddr(decl_val, reloc_info); @@ -950,6 +954,8 @@ pub const File = struct { .plan9, .spirv, .nvptx, + .goff, + .xcoff, => {}, inline else => |tag| { @@ -1246,6 +1252,8 @@ pub const File = struct { spirv, plan9, nvptx, + goff, + xcoff, pub fn Type(comptime tag: Tag) type { return switch (tag) { @@ -1257,6 +1265,8 @@ pub const File = struct { .spirv => SpirV, .plan9 => Plan9, .nvptx => NvPtx, + .goff => Goff, + .xcoff => Xcoff, }; } @@ -1270,8 +1280,8 @@ pub const File = struct { .c => .c, .spirv => .spirv, .nvptx => .nvptx, - .goff => @panic("TODO implement goff object format"), - .xcoff => @panic("TODO implement xcoff object format"), + .goff => .goff, + .xcoff => .xcoff, .hex => @panic("TODO implement hex object format"), .raw => @panic("TODO implement raw object format"), }; @@ -1377,6 +1387,8 @@ pub const File = struct { pub const SpirV = @import("link/SpirV.zig"); pub const Wasm = @import("link/Wasm.zig"); pub const NvPtx = @import("link/NvPtx.zig"); + pub const Goff = @import("link/Goff.zig"); + pub const Xcoff = @import("link/Xcoff.zig"); pub const Dwarf = @import("link/Dwarf.zig"); }; diff --git a/src/link/Goff.zig b/src/link/Goff.zig new file mode 100644 index 000000000000..55d2a15e5635 --- /dev/null +++ b/src/link/Goff.zig @@ -0,0 +1,120 @@ +//! Stub linker support for GOFF based on LLVM. + +const Goff = @This(); + +const std = @import("std"); +const builtin = @import("builtin"); + +const Allocator = std.mem.Allocator; +const assert = std.debug.assert; +const log = std.log.scoped(.link); +const Path = std.Build.Cache.Path; + +const Zcu = @import("../Zcu.zig"); +const InternPool = @import("../InternPool.zig"); +const Compilation = @import("../Compilation.zig"); +const link = @import("../link.zig"); +const trace = @import("../tracy.zig").trace; +const build_options = @import("build_options"); +const Air = @import("../Air.zig"); +const Liveness = @import("../Liveness.zig"); +const LlvmObject = @import("../codegen/llvm.zig").Object; + +base: link.File, +llvm_object: LlvmObject.Ptr, + +pub fn createEmpty( + arena: Allocator, + comp: *Compilation, + emit: Path, + options: link.File.OpenOptions, +) !*Goff { + const target = comp.root_mod.resolved_target.result; + const use_lld = build_options.have_llvm and comp.config.use_lld; + const use_llvm = comp.config.use_llvm; + + assert(use_llvm); // Caught by Compilation.Config.resolve. + assert(!use_lld); // Caught by Compilation.Config.resolve. + assert(target.os.tag == .zos); // Caught by Compilation.Config.resolve. + + const llvm_object = try LlvmObject.create(arena, comp); + const goff = try arena.create(Goff); + goff.* = .{ + .base = .{ + .tag = .goff, + .comp = comp, + .emit = emit, + .zcu_object_sub_path = emit.sub_path, + .gc_sections = options.gc_sections orelse false, + .print_gc_sections = options.print_gc_sections, + .stack_size = options.stack_size orelse 0, + .allow_shlib_undefined = options.allow_shlib_undefined orelse false, + .file = null, + .disable_lld_caching = options.disable_lld_caching, + .build_id = options.build_id, + }, + .llvm_object = llvm_object, + }; + + return goff; +} + +pub fn open( + arena: Allocator, + comp: *Compilation, + emit: Path, + options: link.File.OpenOptions, +) !*Goff { + const target = comp.root_mod.resolved_target.result; + assert(target.ofmt == .goff); + return createEmpty(arena, comp, emit, options); +} + +pub fn deinit(self: *Goff) void { + self.llvm_object.deinit(); +} + +pub fn updateFunc( + self: *Goff, + pt: Zcu.PerThread, + func_index: InternPool.Index, + air: Air, + liveness: Liveness, +) link.File.UpdateNavError!void { + if (build_options.skip_non_native and builtin.object_format != .goff) + @panic("Attempted to compile for object format that was disabled by build configuration"); + + try self.llvm_object.updateFunc(pt, func_index, air, liveness); +} + +pub fn updateNav(self: *Goff, pt: Zcu.PerThread, nav: InternPool.Nav.Index) link.File.UpdateNavError!void { + if (build_options.skip_non_native and builtin.object_format != .goff) + @panic("Attempted to compile for object format that was disabled by build configuration"); + + return self.llvm_object.updateNav(pt, nav); +} + +pub fn updateExports( + self: *Goff, + pt: Zcu.PerThread, + exported: Zcu.Exported, + export_indices: []const Zcu.Export.Index, +) !void { + if (build_options.skip_non_native and builtin.object_format != .goff) + @panic("Attempted to compile for object format that was disabled by build configuration"); + + return self.llvm_object.updateExports(pt, exported, export_indices); +} + +pub fn flush(self: *Goff, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void { + return self.flushModule(arena, tid, prog_node); +} + +pub fn flushModule(self: *Goff, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void { + if (build_options.skip_non_native and builtin.object_format != .goff) + @panic("Attempted to compile for object format that was disabled by build configuration"); + + _ = tid; + + try self.base.emitLlvmObject(arena, self.llvm_object, prog_node); +} diff --git a/src/link/Xcoff.zig b/src/link/Xcoff.zig new file mode 100644 index 000000000000..e4d4caaac913 --- /dev/null +++ b/src/link/Xcoff.zig @@ -0,0 +1,120 @@ +//! Stub linker support for GOFF based on LLVM. + +const Xcoff = @This(); + +const std = @import("std"); +const builtin = @import("builtin"); + +const Allocator = std.mem.Allocator; +const assert = std.debug.assert; +const log = std.log.scoped(.link); +const Path = std.Build.Cache.Path; + +const Zcu = @import("../Zcu.zig"); +const InternPool = @import("../InternPool.zig"); +const Compilation = @import("../Compilation.zig"); +const link = @import("../link.zig"); +const trace = @import("../tracy.zig").trace; +const build_options = @import("build_options"); +const Air = @import("../Air.zig"); +const Liveness = @import("../Liveness.zig"); +const LlvmObject = @import("../codegen/llvm.zig").Object; + +base: link.File, +llvm_object: LlvmObject.Ptr, + +pub fn createEmpty( + arena: Allocator, + comp: *Compilation, + emit: Path, + options: link.File.OpenOptions, +) !*Xcoff { + const target = comp.root_mod.resolved_target.result; + const use_lld = build_options.have_llvm and comp.config.use_lld; + const use_llvm = comp.config.use_llvm; + + assert(use_llvm); // Caught by Compilation.Config.resolve. + assert(!use_lld); // Caught by Compilation.Config.resolve. + assert(target.os.tag == .aix); // Caught by Compilation.Config.resolve. + + const llvm_object = try LlvmObject.create(arena, comp); + const xcoff = try arena.create(Xcoff); + xcoff.* = .{ + .base = .{ + .tag = .xcoff, + .comp = comp, + .emit = emit, + .zcu_object_sub_path = emit.sub_path, + .gc_sections = options.gc_sections orelse false, + .print_gc_sections = options.print_gc_sections, + .stack_size = options.stack_size orelse 0, + .allow_shlib_undefined = options.allow_shlib_undefined orelse false, + .file = null, + .disable_lld_caching = options.disable_lld_caching, + .build_id = options.build_id, + }, + .llvm_object = llvm_object, + }; + + return xcoff; +} + +pub fn open( + arena: Allocator, + comp: *Compilation, + emit: Path, + options: link.File.OpenOptions, +) !*Xcoff { + const target = comp.root_mod.resolved_target.result; + assert(target.ofmt == .xcoff); + return createEmpty(arena, comp, emit, options); +} + +pub fn deinit(self: *Xcoff) void { + self.llvm_object.deinit(); +} + +pub fn updateFunc( + self: *Xcoff, + pt: Zcu.PerThread, + func_index: InternPool.Index, + air: Air, + liveness: Liveness, +) link.File.UpdateNavError!void { + if (build_options.skip_non_native and builtin.object_format != .xcoff) + @panic("Attempted to compile for object format that was disabled by build configuration"); + + try self.llvm_object.updateFunc(pt, func_index, air, liveness); +} + +pub fn updateNav(self: *Xcoff, pt: Zcu.PerThread, nav: InternPool.Nav.Index) link.File.UpdateNavError!void { + if (build_options.skip_non_native and builtin.object_format != .xcoff) + @panic("Attempted to compile for object format that was disabled by build configuration"); + + return self.llvm_object.updateNav(pt, nav); +} + +pub fn updateExports( + self: *Xcoff, + pt: Zcu.PerThread, + exported: Zcu.Exported, + export_indices: []const Zcu.Export.Index, +) !void { + if (build_options.skip_non_native and builtin.object_format != .xcoff) + @panic("Attempted to compile for object format that was disabled by build configuration"); + + return self.llvm_object.updateExports(pt, exported, export_indices); +} + +pub fn flush(self: *Xcoff, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void { + return self.flushModule(arena, tid, prog_node); +} + +pub fn flushModule(self: *Xcoff, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void { + if (build_options.skip_non_native and builtin.object_format != .xcoff) + @panic("Attempted to compile for object format that was disabled by build configuration"); + + _ = tid; + + try self.base.emitLlvmObject(arena, self.llvm_object, prog_node); +} diff --git a/test/llvm_targets.zig b/test/llvm_targets.zig index 8e9a070d931a..1f21daa882e2 100644 --- a/test/llvm_targets.zig +++ b/test/llvm_targets.zig @@ -182,7 +182,7 @@ const targets = [_]std.Target.Query{ // .{ .cpu_arch = .nvptx64, .os_tag = .cuda, .abi = .none }, // .{ .cpu_arch = .nvptx64, .os_tag = .nvcl, .abi = .none }, - // .{ .cpu_arch = .powerpc, .os_tag = .aix, .abi = .eabihf }, + .{ .cpu_arch = .powerpc, .os_tag = .aix, .abi = .eabihf }, .{ .cpu_arch = .powerpc, .os_tag = .freebsd, .abi = .eabi }, .{ .cpu_arch = .powerpc, .os_tag = .freebsd, .abi = .eabihf }, .{ .cpu_arch = .powerpc, .os_tag = .freestanding, .abi = .eabi }, @@ -205,7 +205,7 @@ const targets = [_]std.Target.Query{ .{ .cpu_arch = .powerpcle, .os_tag = .freestanding, .abi = .eabi }, .{ .cpu_arch = .powerpcle, .os_tag = .freestanding, .abi = .eabihf }, - // .{ .cpu_arch = .powerpc64, .os_tag = .aix, .abi = .none }, + .{ .cpu_arch = .powerpc64, .os_tag = .aix, .abi = .none }, .{ .cpu_arch = .powerpc64, .os_tag = .freebsd, .abi = .none }, .{ .cpu_arch = .powerpc64, .os_tag = .freestanding, .abi = .none }, .{ .cpu_arch = .powerpc64, .os_tag = .linux, .abi = .gnu },