From be0173c1dced688f0eed8345e3712b5abf8d152b Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Sun, 23 Jul 2023 00:44:04 -0400 Subject: [PATCH] llvm: fix and test datalayout generation for more targets Closes #16482 --- lib/std/Build/Step.zig | 4 +- lib/std/Build/Step/Compile.zig | 7 +- lib/std/Build/Step/TranslateC.zig | 4 +- lib/std/target.zig | 10 ++- src/Compilation.zig | 1 + src/codegen/llvm.zig | 61 ++++++++++------ test/cases.zig | 1 + test/llvm_targets.zig | 117 ++++++++++++++++++++++++++++++ test/src/Cases.zig | 16 ++++ 9 files changed, 188 insertions(+), 33 deletions(-) create mode 100644 test/llvm_targets.zig diff --git a/lib/std/Build/Step.zig b/lib/std/Build/Step.zig index f21ef8bc8f7b..991283dbc526 100644 --- a/lib/std/Build/Step.zig +++ b/lib/std/Build/Step.zig @@ -294,7 +294,7 @@ pub fn evalZigProcess( s: *Step, argv: []const []const u8, prog_node: *std.Progress.Node, -) ![]const u8 { +) !?[]const u8 { assert(argv.len != 0); const b = s.owner; const arena = b.allocator; @@ -423,6 +423,8 @@ pub fn evalZigProcess( }); } + if (s.cast(Compile)) |compile| if (compile.emit_bin == .no_emit) return result; + return result orelse return s.fail( "the following command failed to communicate the compilation result:\n{s}", .{try allocPrintCmd(arena, null, argv)}, diff --git a/lib/std/Build/Step/Compile.zig b/lib/std/Build/Step/Compile.zig index 7ff82e4b7b10..6dd0bd2d11de 100644 --- a/lib/std/Build/Step/Compile.zig +++ b/lib/std/Build/Step/Compile.zig @@ -1997,7 +1997,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { try zig_args.append(resolved_args_file); } - const output_bin_path = step.evalZigProcess(zig_args.items, prog_node) catch |err| switch (err) { + const maybe_output_bin_path = step.evalZigProcess(zig_args.items, prog_node) catch |err| switch (err) { error.NeedCompileErrorCheck => { assert(self.expect_errors.len != 0); try checkCompileErrors(self); @@ -2005,10 +2005,11 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { }, else => |e| return e, }; - const output_dir = fs.path.dirname(output_bin_path).?; // Update generated files - { + if (maybe_output_bin_path) |output_bin_path| { + const output_dir = fs.path.dirname(output_bin_path).?; + self.output_dirname_source.path = output_dir; self.output_path_source.path = b.pathJoin( diff --git a/lib/std/Build/Step/TranslateC.zig b/lib/std/Build/Step/TranslateC.zig index 60e35e940b11..cfbabc2fa958 100644 --- a/lib/std/Build/Step/TranslateC.zig +++ b/lib/std/Build/Step/TranslateC.zig @@ -148,8 +148,8 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { const output_path = try step.evalZigProcess(argv_list.items, prog_node); - self.out_basename = fs.path.basename(output_path); - const output_dir = fs.path.dirname(output_path).?; + self.out_basename = fs.path.basename(output_path.?); + const output_dir = fs.path.dirname(output_path.?).?; self.output_file.path = try fs.path.join( b.allocator, diff --git a/lib/std/target.zig b/lib/std/target.zig index e00a1c15d780..015aee61ba7b 100644 --- a/lib/std/target.zig +++ b/lib/std/target.zig @@ -1912,7 +1912,7 @@ pub const Target = struct { return switch (target.cpu.arch) { .amdgcn => 4, .x86 => switch (target.os.tag) { - .windows => 4, + .windows, .uefi => 4, else => 16, }, .arm, @@ -1931,8 +1931,6 @@ pub const Target = struct { .bpfel, .mips64, .mips64el, - .powerpc64, - .powerpc64le, .riscv32, .riscv64, .sparc64, @@ -1941,6 +1939,12 @@ pub const Target = struct { .wasm32, .wasm64, => 16, + .powerpc64, + .powerpc64le, + => switch (target.os.tag) { + else => 8, + .linux => 16, + }, else => @divExact(target.ptrBitWidth(), 8), }; } diff --git a/src/Compilation.zig b/src/Compilation.zig index 65522d0fcc79..59ee16e40814 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -1053,6 +1053,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { buf.appendSliceAssumeCapacity(","); } } + if (buf.items.len == 0) break :blk ""; assert(mem.endsWith(u8, buf.items, ",")); buf.items[buf.items.len - 1] = 0; buf.shrinkAndFree(buf.items.len); diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 4f8e9503b3ba..6648e0a8e407 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -340,7 +340,6 @@ const DataLayoutBuilder = struct { _: std.fmt.FormatOptions, writer: anytype, ) @TypeOf(writer).Error!void { - const is_aarch64_windows = self.target.cpu.arch == .aarch64 and self.target.os.tag == .windows; try writer.writeByte(switch (self.target.cpu.arch.endian()) { .Little => 'e', .Big => 'E', @@ -407,7 +406,8 @@ const DataLayoutBuilder = struct { }; if (self.target.cpu.arch == .aarch64_32) continue; if (!info.force_in_data_layout and matches_default and - self.target.cpu.arch != .riscv64 and !is_aarch64_windows and + self.target.cpu.arch != .riscv64 and !(self.target.cpu.arch == .aarch64 and + (self.target.os.tag == .uefi or self.target.os.tag == .windows)) and self.target.cpu.arch != .bpfeb and self.target.cpu.arch != .bpfel) continue; try writer.writeAll("-p"); if (info.llvm != .default) try writer.print("{d}", .{@intFromEnum(info.llvm)}); @@ -423,7 +423,7 @@ const DataLayoutBuilder = struct { if (self.target.cpu.arch == .s390x) try self.typeAlignment(.integer, 1, 8, 8, false, writer); try self.typeAlignment(.integer, 8, 8, 8, false, writer); try self.typeAlignment(.integer, 16, 16, 16, false, writer); - try self.typeAlignment(.integer, 32, if (is_aarch64_windows) 0 else 32, 32, false, writer); + try self.typeAlignment(.integer, 32, 32, 32, false, writer); try self.typeAlignment(.integer, 64, 32, 64, false, writer); try self.typeAlignment(.integer, 128, 32, 64, false, writer); if (backendSupportsF16(self.target)) try self.typeAlignment(.float, 16, 16, 16, false, writer); @@ -453,8 +453,15 @@ const DataLayoutBuilder = struct { try self.typeAlignment(.vector, 128, 128, 128, true, writer); }, } - if (self.target.os.tag != .windows and self.target.cpu.arch != .avr) - try self.typeAlignment(.aggregate, 0, 0, 64, false, writer); + const swap_agg_nat = switch (self.target.cpu.arch) { + .x86, .x86_64 => switch (self.target.os.tag) { + .uefi, .windows => true, + else => false, + }, + .avr => true, + else => false, + }; + if (!swap_agg_nat) try self.typeAlignment(.aggregate, 0, 0, 64, false, writer); for (@as([]const u24, switch (self.target.cpu.arch) { .avr => &.{8}, .msp430 => &.{ 8, 16 }, @@ -498,6 +505,7 @@ const DataLayoutBuilder = struct { 0 => try writer.print("-n{d}", .{natural}), else => try writer.print(":{d}", .{natural}), }; + if (swap_agg_nat) try self.typeAlignment(.aggregate, 0, 0, 64, false, writer); if (self.target.cpu.arch == .hexagon) { try self.typeAlignment(.integer, 64, 64, 64, true, writer); try self.typeAlignment(.integer, 32, 32, 32, true, writer); @@ -506,11 +514,9 @@ const DataLayoutBuilder = struct { try self.typeAlignment(.float, 32, 32, 32, true, writer); try self.typeAlignment(.float, 64, 64, 64, true, writer); } - if (self.target.os.tag == .windows or self.target.cpu.arch == .avr) - try self.typeAlignment(.aggregate, 0, 0, 64, false, writer); const stack_abi = self.target.stackAlignment() * 8; - if (self.target.os.tag == .windows or self.target.cpu.arch == .msp430 or - stack_abi != ptr_bit_width) + if (self.target.os.tag == .uefi or self.target.os.tag == .windows or + self.target.cpu.arch == .msp430 or stack_abi != ptr_bit_width) try writer.print("-S{d}", .{stack_abi}); switch (self.target.cpu.arch) { .hexagon, .ve => { @@ -571,22 +577,21 @@ const DataLayoutBuilder = struct { .integer => { if (self.target.ptrBitWidth() <= 16 and size >= 128) return; abi = @min(abi, self.target.maxIntAlignment() * 8); - switch (self.target.os.tag) { - .linux => switch (self.target.cpu.arch) { - .aarch64, - .aarch64_be, - .aarch64_32, - .mips, - .mipsel, - => pref = @max(pref, 32), - else => {}, - }, - else => {}, - } switch (self.target.cpu.arch) { .aarch64, .aarch64_be, .aarch64_32, + => if (size == 128) { + abi = size; + pref = size; + } else switch (self.target.os.tag) { + .macos => {}, + .uefi, .windows => { + pref = size; + force_abi = size >= 32; + }, + else => pref = @max(pref, 32), + }, .bpfeb, .bpfel, .nvptx, @@ -597,6 +602,9 @@ const DataLayoutBuilder = struct { pref = size; }, .hexagon => force_abi = true, + .mips, + .mipsel, + => pref = @max(pref, 32), .mips64, .mips64el, => if (size <= 32) { @@ -617,7 +625,8 @@ const DataLayoutBuilder = struct { 128 => abi = 64, else => {}, } - } else if ((self.target.cpu.arch.isPPC64() and (size == 256 or size == 512)) or + } else if ((self.target.cpu.arch.isPPC64() and self.target.os.tag == .linux and + (size == 256 or size == 512)) or (self.target.cpu.arch.isNvptx() and (size == 16 or size == 32))) { force_abi = true; @@ -646,17 +655,21 @@ const DataLayoutBuilder = struct { .hexagon => if (size == 32 or size == 64) { force_abi = true; }, - .aarch64_32 => if (size == 128) { + .aarch64_32, .amdgcn => if (size == 128) { abi = size; pref = size; }, + .wasm32, .wasm64 => if (self.target.os.tag == .emscripten and size == 128) { + abi = 64; + pref = 64; + }, .ve => if (size == 64) { abi = size; pref = size; }, else => {}, }, - .aggregate => if (self.target.os.tag == .windows or + .aggregate => if (self.target.os.tag == .uefi or self.target.os.tag == .windows or self.target.cpu.arch.isARM() or self.target.cpu.arch.isThumb()) { pref = @min(pref, self.target.ptrBitWidth()); diff --git a/test/cases.zig b/test/cases.zig index ffe046c70ede..6c4b1c994f3a 100644 --- a/test/cases.zig +++ b/test/cases.zig @@ -4,5 +4,6 @@ const Cases = @import("src/Cases.zig"); pub fn addCases(cases: *Cases) !void { try @import("compile_errors.zig").addCases(cases); try @import("cbe.zig").addCases(cases); + try @import("llvm_targets.zig").addCases(cases); try @import("nvptx.zig").addCases(cases); } diff --git a/test/llvm_targets.zig b/test/llvm_targets.zig new file mode 100644 index 000000000000..d042ce500cfb --- /dev/null +++ b/test/llvm_targets.zig @@ -0,0 +1,117 @@ +const std = @import("std"); +const Cases = @import("src/Cases.zig"); + +const targets = [_]std.zig.CrossTarget{ + .{ .cpu_arch = .aarch64, .os_tag = .freestanding, .abi = .none }, + .{ .cpu_arch = .aarch64, .os_tag = .linux, .abi = .none }, + .{ .cpu_arch = .aarch64, .os_tag = .macos, .abi = .none }, + .{ .cpu_arch = .aarch64, .os_tag = .uefi, .abi = .none }, + .{ .cpu_arch = .aarch64, .os_tag = .windows, .abi = .gnu }, + .{ .cpu_arch = .aarch64, .os_tag = .windows, .abi = .msvc }, + .{ .cpu_arch = .aarch64_be, .os_tag = .freestanding, .abi = .none }, + .{ .cpu_arch = .aarch64_be, .os_tag = .linux, .abi = .none }, + .{ .cpu_arch = .aarch64_32, .os_tag = .freestanding, .abi = .none }, + .{ .cpu_arch = .aarch64_32, .os_tag = .linux, .abi = .none }, + .{ .cpu_arch = .amdgcn, .os_tag = .amdhsa, .abi = .none }, + .{ .cpu_arch = .amdgcn, .os_tag = .amdpal, .abi = .none }, + .{ .cpu_arch = .amdgcn, .os_tag = .linux, .abi = .none }, + //.{ .cpu_arch = .amdgcn, .os_tag = .mesa3d, .abi = .none }, + .{ .cpu_arch = .arm, .os_tag = .freestanding, .abi = .none }, + .{ .cpu_arch = .arm, .os_tag = .linux, .abi = .none }, + .{ .cpu_arch = .arm, .os_tag = .uefi, .abi = .none }, + .{ .cpu_arch = .armeb, .os_tag = .freestanding, .abi = .none }, + .{ .cpu_arch = .armeb, .os_tag = .linux, .abi = .none }, + .{ .cpu_arch = .avr, .os_tag = .freebsd, .abi = .none }, + .{ .cpu_arch = .avr, .os_tag = .freestanding, .abi = .none }, + .{ .cpu_arch = .avr, .os_tag = .linux, .abi = .none }, + .{ .cpu_arch = .bpfel, .os_tag = .linux, .abi = .gnu }, + .{ .cpu_arch = .bpfel, .os_tag = .linux, .abi = .none }, + .{ .cpu_arch = .bpfeb, .os_tag = .linux, .abi = .gnu }, + .{ .cpu_arch = .bpfeb, .os_tag = .linux, .abi = .none }, + .{ .cpu_arch = .hexagon, .os_tag = .linux, .abi = .none }, + .{ .cpu_arch = .mips, .os_tag = .linux, .abi = .gnueabihf }, + .{ .cpu_arch = .mips, .os_tag = .linux, .abi = .musl }, + .{ .cpu_arch = .mips, .os_tag = .linux, .abi = .none }, + .{ .cpu_arch = .mipsel, .os_tag = .linux, .abi = .gnueabihf }, + .{ .cpu_arch = .mipsel, .os_tag = .linux, .abi = .musl }, + .{ .cpu_arch = .mipsel, .os_tag = .linux, .abi = .none }, + .{ .cpu_arch = .mips64, .os_tag = .linux, .abi = .none }, + .{ .cpu_arch = .mips64el, .os_tag = .linux, .abi = .none }, + .{ .cpu_arch = .msp430, .os_tag = .freebsd, .abi = .none }, + .{ .cpu_arch = .msp430, .os_tag = .freestanding, .abi = .none }, + .{ .cpu_arch = .msp430, .os_tag = .linux, .abi = .none }, + //.{ .cpu_arch = .nvptx, .os_tag = .cuda, .abi = .none }, + //.{ .cpu_arch = .nvptx64, .os_tag = .cuda, .abi = .none }, + .{ .cpu_arch = .powerpc, .os_tag = .freebsd, .abi = .none }, + .{ .cpu_arch = .powerpc, .os_tag = .freestanding, .abi = .none }, + .{ .cpu_arch = .powerpc, .os_tag = .linux, .abi = .gnueabihf }, + .{ .cpu_arch = .powerpc, .os_tag = .linux, .abi = .musl }, + .{ .cpu_arch = .powerpc, .os_tag = .linux, .abi = .none }, + .{ .cpu_arch = .powerpcle, .os_tag = .freebsd, .abi = .none }, + .{ .cpu_arch = .powerpcle, .os_tag = .freestanding, .abi = .none }, + .{ .cpu_arch = .powerpcle, .os_tag = .linux, .abi = .gnu }, + .{ .cpu_arch = .powerpcle, .os_tag = .linux, .abi = .musl }, + .{ .cpu_arch = .powerpcle, .os_tag = .linux, .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 }, + .{ .cpu_arch = .powerpc64, .os_tag = .linux, .abi = .musl }, + .{ .cpu_arch = .powerpc64, .os_tag = .linux, .abi = .none }, + .{ .cpu_arch = .powerpc64le, .os_tag = .freebsd, .abi = .none }, + .{ .cpu_arch = .powerpc64le, .os_tag = .freestanding, .abi = .none }, + .{ .cpu_arch = .powerpc64le, .os_tag = .linux, .abi = .gnu }, + .{ .cpu_arch = .powerpc64le, .os_tag = .linux, .abi = .musl }, + .{ .cpu_arch = .powerpc64le, .os_tag = .linux, .abi = .none }, + //.{ .cpu_arch = .r600, .os_tag = .mesa3d, .abi = .none }, + .{ .cpu_arch = .riscv32, .os_tag = .freestanding, .abi = .none }, + .{ .cpu_arch = .riscv32, .os_tag = .linux, .abi = .none }, + .{ .cpu_arch = .riscv64, .os_tag = .freestanding, .abi = .none }, + .{ .cpu_arch = .riscv64, .os_tag = .linux, .abi = .gnu }, + .{ .cpu_arch = .riscv64, .os_tag = .linux, .abi = .musl }, + .{ .cpu_arch = .riscv64, .os_tag = .linux, .abi = .none }, + .{ .cpu_arch = .s390x, .os_tag = .freestanding, .abi = .none }, + .{ .cpu_arch = .s390x, .os_tag = .linux, .abi = .gnu }, + .{ .cpu_arch = .sparc, .os_tag = .freestanding, .abi = .none }, + .{ .cpu_arch = .sparc, .os_tag = .linux, .abi = .gnu }, + .{ .cpu_arch = .sparc, .os_tag = .linux, .abi = .none }, + .{ .cpu_arch = .sparcel, .os_tag = .freestanding, .abi = .none }, + .{ .cpu_arch = .sparcel, .os_tag = .linux, .abi = .gnu }, + .{ .cpu_arch = .sparc64, .os_tag = .freestanding, .abi = .none }, + .{ .cpu_arch = .sparc64, .os_tag = .linux, .abi = .gnu }, + //.{ .cpu_arch = .spirv32, .os_tag = .opencl, .abi = .none }, + //.{ .cpu_arch = .spirv32, .os_tag = .glsl450, .abi = .none }, + //.{ .cpu_arch = .spirv32, .os_tag = .vulkan, .abi = .none }, + //.{ .cpu_arch = .spirv64, .os_tag = .opencl, .abi = .none }, + //.{ .cpu_arch = .spirv64, .os_tag = .glsl450, .abi = .none }, + //.{ .cpu_arch = .spirv64, .os_tag = .vulkan, .abi = .none }, + .{ .cpu_arch = .thumb, .os_tag = .freestanding, .abi = .none }, + .{ .cpu_arch = .thumbeb, .os_tag = .freestanding, .abi = .none }, + .{ .cpu_arch = .ve, .os_tag = .linux, .abi = .none }, + .{ .cpu_arch = .wasm32, .os_tag = .emscripten, .abi = .none }, + .{ .cpu_arch = .wasm32, .os_tag = .freestanding, .abi = .none }, + .{ .cpu_arch = .wasm32, .os_tag = .linux, .abi = .none }, + .{ .cpu_arch = .wasm32, .os_tag = .wasi, .abi = .none }, + .{ .cpu_arch = .wasm64, .os_tag = .emscripten, .abi = .none }, + .{ .cpu_arch = .wasm64, .os_tag = .freestanding, .abi = .none }, + .{ .cpu_arch = .wasm64, .os_tag = .linux, .abi = .none }, + .{ .cpu_arch = .wasm64, .os_tag = .wasi, .abi = .none }, + .{ .cpu_arch = .x86, .os_tag = .freestanding, .abi = .none }, + .{ .cpu_arch = .x86, .os_tag = .linux, .abi = .none }, + .{ .cpu_arch = .x86, .os_tag = .uefi, .abi = .none }, + .{ .cpu_arch = .x86, .os_tag = .windows, .abi = .gnu }, + .{ .cpu_arch = .x86, .os_tag = .windows, .abi = .msvc }, + .{ .cpu_arch = .x86_64, .os_tag = .freebsd, .abi = .none }, + .{ .cpu_arch = .x86_64, .os_tag = .freestanding, .abi = .none }, + .{ .cpu_arch = .x86_64, .os_tag = .linux, .abi = .none }, + .{ .cpu_arch = .x86_64, .os_tag = .macos, .abi = .none }, + .{ .cpu_arch = .x86_64, .os_tag = .uefi, .abi = .none }, + .{ .cpu_arch = .x86_64, .os_tag = .windows, .abi = .gnu }, + .{ .cpu_arch = .x86_64, .os_tag = .windows, .abi = .msvc }, +}; + +pub fn addCases(ctx: *Cases) !void { + for (targets) |target| { + var case = ctx.noEmitUsingLlvmBackend("llvm_targets", target); + case.addCompile(""); + } +} diff --git a/test/src/Cases.zig b/test/src/Cases.zig index 92ec3cb35f96..ce080b5490f8 100644 --- a/test/src/Cases.zig +++ b/test/src/Cases.zig @@ -76,6 +76,7 @@ pub const Case = struct { output_mode: std.builtin.OutputMode, optimize_mode: std.builtin.Mode = .Debug, updates: std.ArrayList(Update), + emit_bin: bool = true, emit_h: bool = false, is_test: bool = false, expect_exact: bool = false, @@ -176,6 +177,19 @@ pub fn exeFromCompiledC(ctx: *Cases, name: []const u8, target: CrossTarget) *Cas return &ctx.cases.items[ctx.cases.items.len - 1]; } +pub fn noEmitUsingLlvmBackend(ctx: *Cases, name: []const u8, target: CrossTarget) *Case { + ctx.cases.append(Case{ + .name = name, + .target = target, + .updates = std.ArrayList(Update).init(ctx.cases.allocator), + .output_mode = .Obj, + .emit_bin = false, + .deps = std.ArrayList(DepModule).init(ctx.arena), + .backend = .llvm, + }) catch @panic("out of memory"); + return &ctx.cases.items[ctx.cases.items.len - 1]; +} + /// Adds a test case that uses the LLVM backend to emit an executable. /// Currently this implies linking libc, because only then we can generate a testable executable. pub fn exeUsingLlvmBackend(ctx: *Cases, name: []const u8, target: CrossTarget) *Case { @@ -537,6 +551,8 @@ pub fn lowerToBuildSteps( }), }; + artifact.emit_bin = if (case.emit_bin) .default else .no_emit; + if (case.link_libc) artifact.linkLibC(); switch (case.backend) {