From 496eb69273d363f21ca3923f00714b229882e42a Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 21 Apr 2022 20:28:36 -0700 Subject: [PATCH 1/8] CI: add non-LLVM backends to the test matrix We can't yet run the behavior tests with stage3, but at least we can run them with stage2, and we can use the proper test matrix. This commit also adds use_llvm and ofmt to the zig build system. --- build.zig | 12 +++ ci/zinc/linux_test.sh | 26 +++--- lib/std/build.zig | 14 ++++ test/tests.zig | 179 +++++++++++++++++++++++++++++++----------- 4 files changed, 168 insertions(+), 63 deletions(-) diff --git a/build.zig b/build.zig index 4d3cf492bd0944ab51fe2528b92a36a81c16b55e..e9f0b69400813fc05958bde839b940947f3fbfe3 100644 --- a/build.zig +++ b/build.zig @@ -445,6 +445,9 @@ pub fn build(b: *Builder) !void { false, // skip_single_threaded skip_non_native, skip_libc, + skip_stage1, + omit_stage2, + is_stage1, )); toolchain_step.dependOn(tests.addPkgTests( @@ -457,6 +460,9 @@ pub fn build(b: *Builder) !void { true, // skip_single_threaded skip_non_native, true, // skip_libc + skip_stage1, + omit_stage2 or true, // TODO get these all passing + is_stage1, )); toolchain_step.dependOn(tests.addPkgTests( @@ -469,6 +475,9 @@ pub fn build(b: *Builder) !void { true, // skip_single_threaded skip_non_native, true, // skip_libc + skip_stage1, + omit_stage2 or true, // TODO get these all passing + is_stage1, )); toolchain_step.dependOn(tests.addCompareOutputTests(b, test_filter, modes)); @@ -494,6 +503,9 @@ pub fn build(b: *Builder) !void { false, skip_non_native, skip_libc, + skip_stage1, + omit_stage2 or true, // TODO get these all passing + is_stage1, ); const test_step = b.step("test", "Run all the tests"); diff --git a/ci/zinc/linux_test.sh b/ci/zinc/linux_test.sh index 180589cc8ef8bd8fb8c038ba70d12ee8e8e33025..01aee9a502aab445d1417f3f8b1f3eee949d50df 100755 --- a/ci/zinc/linux_test.sh +++ b/ci/zinc/linux_test.sh @@ -48,25 +48,19 @@ cd $WORKSPACE $ZIG fmt --check . --exclude test/cases/ # Build stage2 standalone so that we can test stage2 against stage2 compiler-rt. -$ZIG build -p stage2 -Dstatic-llvm -Dtarget=native-native-musl --search-prefix "$DEPS_LOCAL" +$ZIG build -p stage2 -Dstatic-llvm -Dtarget=native-native-musl --search-prefix "$DEPS_LOCAL" # Ensure that stage2 can build itself. -./stage2/bin/zig build -p stage3 -Dstatic-llvm -Dtarget=native-native-musl --search-prefix "$DEPS_LOCAL" +stage2/bin/zig build -p stage3 -Dstatic-llvm -Dtarget=native-native-musl --search-prefix "$DEPS_LOCAL" +stage2/bin/zig build # test building self-hosted without LLVM +stage2/bin/zig build -Dtarget=arm-linux-musleabihf # test building self-hosted for 32-bit arm -stage2/bin/zig test test/behavior.zig -I test -fLLVM -stage2/bin/zig test test/behavior.zig -I test -fno-LLVM -stage2/bin/zig test test/behavior.zig -I test -fLLVM -target aarch64-linux --test-cmd qemu-aarch64 --test-cmd-bin -stage2/bin/zig test test/behavior.zig -I test -fno-LLVM -target aarch64-linux --test-cmd qemu-aarch64 --test-cmd-bin -stage2/bin/zig test test/behavior.zig -I test -ofmt=c -stage2/bin/zig test test/behavior.zig -I test -fno-LLVM -target wasm32-wasi --test-cmd wasmtime --test-cmd-bin -stage2/bin/zig test test/behavior.zig -I test -fLLVM -target wasm32-wasi --test-cmd wasmtime --test-cmd-bin -stage2/bin/zig test test/behavior.zig -I test -fno-LLVM -target arm-linux --test-cmd qemu-arm --test-cmd-bin -stage2/bin/zig test test/behavior.zig -I test -fLLVM -target aarch64-macos --test-no-exec -stage2/bin/zig test test/behavior.zig -I test -fno-LLVM -target aarch64-macos --test-no-exec -stage2/bin/zig test test/behavior.zig -I test -fLLVM -target x86_64-macos --test-no-exec -stage2/bin/zig test test/behavior.zig -I test -fno-LLVM -target x86_64-macos --test-no-exec +# Here we use stage2 instead of stage3 because of two bugs remaining: +# * https://github.com/ziglang/zig/issues/11367 (and corresponding workaround in compiler source) +# * https://github.com/ziglang/zig/pull/11492#issuecomment-1112871321 +stage2/bin/zig build test-behavior -fqemu -fwasmtime -$ZIG build test-behavior -fqemu -fwasmtime +$ZIG build test-behavior -fqemu -fwasmtime -Domit-stage2 $ZIG build test-compiler-rt -fqemu -fwasmtime $ZIG build test-std -fqemu -fwasmtime $ZIG build test-minilibc -fqemu -fwasmtime @@ -79,8 +73,6 @@ $ZIG build test-runtime-safety -fqemu -fwasmtime $ZIG build test-translate-c -fqemu -fwasmtime $ZIG build test-run-translated-c -fqemu -fwasmtime $ZIG build docs -fqemu -fwasmtime -$ZIG build # test building self-hosted without LLVM -$ZIG build -Dtarget=arm-linux-musleabihf # test building self-hosted for 32-bit arm $ZIG build test-fmt -fqemu -fwasmtime $ZIG build test-stage2 -fqemu -fwasmtime diff --git a/lib/std/build.zig b/lib/std/build.zig index 38744cea1eabe4c486d4ffdc0f24c30de8b5d646..b50678a0e550586364ef9da3228c764881806517 100644 --- a/lib/std/build.zig +++ b/lib/std/build.zig @@ -1590,6 +1590,8 @@ pub const LibExeObjStep = struct { want_lto: ?bool = null, use_stage1: ?bool = null, + use_llvm: ?bool = null, + ofmt: ?std.Target.ObjectFormat = null, output_path_source: GeneratedFile, output_lib_path_source: GeneratedFile, @@ -2351,6 +2353,18 @@ pub const LibExeObjStep = struct { } } + if (self.use_llvm) |use_llvm| { + if (use_llvm) { + try zig_args.append("-fLLVM"); + } else { + try zig_args.append("-fno-LLVM"); + } + } + + if (self.ofmt) |ofmt| { + try zig_args.append(try std.fmt.allocPrint(builder.allocator, "-ofmt={s}", .{@tagName(ofmt)})); + } + if (self.entry_symbol_name) |entry| { try zig_args.append("--entry"); try zig_args.append(entry); diff --git a/test/tests.zig b/test/tests.zig index ee4b92202184de9d7d0f08c0df4d4d19864e5a6f..62c437e7f73ec43f9c244c182c9750ce095a8294 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -34,6 +34,7 @@ const TestTarget = struct { link_libc: bool = false, single_threaded: bool = false, disable_native: bool = false, + backend: ?std.builtin.CompilerBackend = null, }; const test_targets = blk: { @@ -42,15 +43,73 @@ const test_targets = blk: { // lot of branches) @setEvalBranchQuota(50000); break :blk [_]TestTarget{ - TestTarget{}, - TestTarget{ + .{}, + .{ .link_libc = true, }, - TestTarget{ + .{ .single_threaded = true, }, - TestTarget{ + .{ + .link_libc = true, + .backend = .stage2_c, + }, + .{ + .target = .{ + .cpu_arch = .x86_64, + .os_tag = .linux, + .abi = .none, + }, + .backend = .stage2_x86_64, + }, + .{ + .target = .{ + .cpu_arch = .aarch64, + .os_tag = .linux, + }, + .backend = .stage2_aarch64, + }, + .{ + .target = .{ + .cpu_arch = .wasm32, + .os_tag = .wasi, + }, + .single_threaded = true, + .backend = .stage2_wasm, + }, + .{ + .target = .{ + .cpu_arch = .arm, + .os_tag = .linux, + }, + .backend = .stage2_wasm, + }, + .{ + .target = CrossTarget.parse(.{ + .arch_os_abi = "arm-linux-none", + .cpu_features = "generic+v8a", + }) catch unreachable, + .backend = .stage2_arm, + }, + .{ + .target = .{ + .cpu_arch = .aarch64, + .os_tag = .macos, + .abi = .gnu, + }, + .backend = .stage2_aarch64, + }, + .{ + .target = .{ + .cpu_arch = .x86_64, + .os_tag = .macos, + .abi = .gnu, + }, + .backend = .stage2_x86_64, + }, + + .{ .target = .{ .cpu_arch = .wasm32, .os_tag = .wasi, @@ -58,7 +117,7 @@ const test_targets = blk: { .link_libc = false, .single_threaded = true, }, - TestTarget{ + .{ .target = .{ .cpu_arch = .wasm32, .os_tag = .wasi, @@ -67,14 +126,14 @@ const test_targets = blk: { .single_threaded = true, }, - TestTarget{ + .{ .target = .{ .cpu_arch = .x86_64, .os_tag = .linux, .abi = .none, }, }, - TestTarget{ + .{ .target = .{ .cpu_arch = .x86_64, .os_tag = .linux, @@ -82,7 +141,7 @@ const test_targets = blk: { }, .link_libc = true, }, - TestTarget{ + .{ .target = .{ .cpu_arch = .x86_64, .os_tag = .linux, @@ -91,14 +150,14 @@ const test_targets = blk: { .link_libc = true, }, - TestTarget{ + .{ .target = .{ .cpu_arch = .i386, .os_tag = .linux, .abi = .none, }, }, - TestTarget{ + .{ .target = .{ .cpu_arch = .i386, .os_tag = .linux, @@ -106,7 +165,7 @@ const test_targets = blk: { }, .link_libc = true, }, - TestTarget{ + .{ .target = .{ .cpu_arch = .i386, .os_tag = .linux, @@ -115,14 +174,14 @@ const test_targets = blk: { .link_libc = true, }, - TestTarget{ + .{ .target = .{ .cpu_arch = .aarch64, .os_tag = .linux, .abi = .none, }, }, - TestTarget{ + .{ .target = .{ .cpu_arch = .aarch64, .os_tag = .linux, @@ -130,7 +189,7 @@ const test_targets = blk: { }, .link_libc = true, }, - TestTarget{ + .{ .target = .{ .cpu_arch = .aarch64, .os_tag = .linux, @@ -138,7 +197,7 @@ const test_targets = blk: { }, .link_libc = true, }, - TestTarget{ + .{ .target = .{ .cpu_arch = .aarch64, .os_tag = .windows, @@ -147,13 +206,13 @@ const test_targets = blk: { .link_libc = true, }, - TestTarget{ + .{ .target = CrossTarget.parse(.{ .arch_os_abi = "arm-linux-none", .cpu_features = "generic+v8a", }) catch unreachable, }, - TestTarget{ + .{ .target = CrossTarget.parse(.{ .arch_os_abi = "arm-linux-musleabihf", .cpu_features = "generic+v8a", @@ -161,7 +220,7 @@ const test_targets = blk: { .link_libc = true, }, // https://github.com/ziglang/zig/issues/3287 - //TestTarget{ + //.{ // .target = CrossTarget.parse(.{ // .arch_os_abi = "arm-linux-gnueabihf", // .cpu_features = "generic+v8a", @@ -169,7 +228,7 @@ const test_targets = blk: { // .link_libc = true, //}, - TestTarget{ + .{ .target = .{ .cpu_arch = .mips, .os_tag = .linux, @@ -177,7 +236,7 @@ const test_targets = blk: { }, }, - TestTarget{ + .{ .target = .{ .cpu_arch = .mips, .os_tag = .linux, @@ -187,7 +246,7 @@ const test_targets = blk: { }, // https://github.com/ziglang/zig/issues/4927 - //TestTarget{ + //.{ // .target = .{ // .cpu_arch = .mips, // .os_tag = .linux, @@ -196,7 +255,7 @@ const test_targets = blk: { // .link_libc = true, //}, - TestTarget{ + .{ .target = .{ .cpu_arch = .mipsel, .os_tag = .linux, @@ -204,7 +263,7 @@ const test_targets = blk: { }, }, - TestTarget{ + .{ .target = .{ .cpu_arch = .mipsel, .os_tag = .linux, @@ -214,7 +273,7 @@ const test_targets = blk: { }, // https://github.com/ziglang/zig/issues/4927 - //TestTarget{ + //.{ // .target = .{ // .cpu_arch = .mipsel, // .os_tag = .linux, @@ -223,14 +282,14 @@ const test_targets = blk: { // .link_libc = true, //}, - TestTarget{ + .{ .target = .{ .cpu_arch = .powerpc, .os_tag = .linux, .abi = .none, }, }, - TestTarget{ + .{ .target = .{ .cpu_arch = .powerpc, .os_tag = .linux, @@ -239,7 +298,7 @@ const test_targets = blk: { .link_libc = true, }, // https://github.com/ziglang/zig/issues/2256 - //TestTarget{ + //.{ // .target = .{ // .cpu_arch = .powerpc, // .os_tag = .linux, @@ -248,7 +307,7 @@ const test_targets = blk: { // .link_libc = true, //}, - TestTarget{ + .{ .target = .{ .cpu_arch = .riscv64, .os_tag = .linux, @@ -256,7 +315,7 @@ const test_targets = blk: { }, }, - TestTarget{ + .{ .target = .{ .cpu_arch = .riscv64, .os_tag = .linux, @@ -266,7 +325,7 @@ const test_targets = blk: { }, // https://github.com/ziglang/zig/issues/3340 - //TestTarget{ + //.{ // .target = .{ // .cpu_arch = .riscv64, // .os = .linux, @@ -275,7 +334,7 @@ const test_targets = blk: { // .link_libc = true, //}, - TestTarget{ + .{ .target = .{ .cpu_arch = .x86_64, .os_tag = .macos, @@ -283,7 +342,7 @@ const test_targets = blk: { }, }, - TestTarget{ + .{ .target = .{ .cpu_arch = .aarch64, .os_tag = .macos, @@ -291,7 +350,7 @@ const test_targets = blk: { }, }, - TestTarget{ + .{ .target = .{ .cpu_arch = .i386, .os_tag = .windows, @@ -299,7 +358,7 @@ const test_targets = blk: { }, }, - TestTarget{ + .{ .target = .{ .cpu_arch = .x86_64, .os_tag = .windows, @@ -307,7 +366,7 @@ const test_targets = blk: { }, }, - TestTarget{ + .{ .target = .{ .cpu_arch = .i386, .os_tag = .windows, @@ -316,7 +375,7 @@ const test_targets = blk: { .link_libc = true, }, - TestTarget{ + .{ .target = .{ .cpu_arch = .x86_64, .os_tag = .windows, @@ -326,38 +385,38 @@ const test_targets = blk: { }, // Do the release tests last because they take a long time - TestTarget{ + .{ .mode = .ReleaseFast, }, - TestTarget{ + .{ .link_libc = true, .mode = .ReleaseFast, }, - TestTarget{ + .{ .mode = .ReleaseFast, .single_threaded = true, }, - TestTarget{ + .{ .mode = .ReleaseSafe, }, - TestTarget{ + .{ .link_libc = true, .mode = .ReleaseSafe, }, - TestTarget{ + .{ .mode = .ReleaseSafe, .single_threaded = true, }, - TestTarget{ + .{ .mode = .ReleaseSmall, }, - TestTarget{ + .{ .link_libc = true, .mode = .ReleaseSmall, }, - TestTarget{ + .{ .mode = .ReleaseSmall, .single_threaded = true, }, @@ -524,6 +583,9 @@ pub fn addPkgTests( skip_single_threaded: bool, skip_non_native: bool, skip_libc: bool, + skip_stage1: bool, + skip_stage2: bool, + is_stage1: bool, ) *build.Step { const step = b.step(b.fmt("test-{s}", .{name}), desc); @@ -549,6 +611,11 @@ pub fn addPkgTests( continue; } + if (test_target.backend) |backend| switch (backend) { + .stage1 => if (skip_stage1) continue, + else => if (skip_stage2) continue, + } else if (is_stage1 and skip_stage1) continue; + const want_this_mode = for (modes) |m| { if (m == test_target.mode) break true; } else false; @@ -565,12 +632,14 @@ pub fn addPkgTests( const these_tests = b.addTest(root_src); const single_threaded_txt = if (test_target.single_threaded) "single" else "multi"; - these_tests.setNamePrefix(b.fmt("{s}-{s}-{s}-{s}-{s} ", .{ + const backend_txt = if (test_target.backend) |backend| @tagName(backend) else "default"; + these_tests.setNamePrefix(b.fmt("{s}-{s}-{s}-{s}-{s}-{s} ", .{ name, triple_prefix, @tagName(test_target.mode), libc_prefix, single_threaded_txt, + backend_txt, })); these_tests.single_threaded = test_target.single_threaded; these_tests.setFilter(test_filter); @@ -581,6 +650,24 @@ pub fn addPkgTests( } these_tests.overrideZigLibDir("lib"); these_tests.addIncludePath("test"); + if (test_target.backend) |backend| switch (backend) { + .stage1 => { + these_tests.use_stage1 = true; + }, + .stage2_llvm => { + these_tests.use_stage1 = false; + these_tests.use_llvm = true; + }, + .stage2_c => { + these_tests.use_stage1 = false; + these_tests.use_llvm = false; + these_tests.ofmt = .c; + }, + else => { + these_tests.use_stage1 = false; + these_tests.use_llvm = false; + }, + }; step.dependOn(&these_tests.step); } -- 2.54.0 From 413b789e06bfc98bd285f0a340bd537b1d2c9dec Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 5 May 2022 11:32:53 -0700 Subject: [PATCH 2/8] std.os.linux.arm-eabi: upgrade to new fn ptr semantics --- lib/std/os/linux/arm-eabi.zig | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/std/os/linux/arm-eabi.zig b/lib/std/os/linux/arm-eabi.zig index 613957fa25b082d175bc00f019b85c026bd5080c..7f4a7385f21b01d7f1e834134c3ecd8ba52ba2aa 100644 --- a/lib/std/os/linux/arm-eabi.zig +++ b/lib/std/os/linux/arm-eabi.zig @@ -99,7 +99,10 @@ pub fn syscall6( /// This matches the libc clone function. pub extern fn clone( - func: fn (arg: usize) callconv(.C) u8, + func: switch (@import("builtin").zig_backend) { + .stage1 => fn (arg: usize) callconv(.C) u8, + else => *const fn (arg: usize) callconv(.C) u8, + }, stack: usize, flags: u32, arg: usize, -- 2.54.0 From edb3adaa33f943d0c64071fbf9d43aadadaa1e95 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Fri, 29 Apr 2022 11:24:30 +0200 Subject: [PATCH 3/8] stage2,llvm: handle softfloats in @intToFloat and @floatToInt If the hw doesn't have support for exotic floating-point types such as `f80`, we lower the call to a compiler-rt function call instead. I've added a behavior test specifically targeting this use case which now passes on `aarch64-macos`. Additionally, this commit makes it possible to successfully build stage3 on `aarch64-macos`. We can print the compiler's help message, however, building with it needs a little bit more love still. --- src/codegen/llvm.zig | 177 ++++++++++++++++++++++++++++++++++++----- test/behavior/cast.zig | 36 +++++++++ 2 files changed, 192 insertions(+), 21 deletions(-) diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 426ef7c378f9a9fc0e707c45eb426a035772fdbe..374ae9b38e2881e08ea56f3ccbacf84157cdd0d2 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -4229,41 +4229,166 @@ pub const FuncGen = struct { return self.builder.buildInsertValue(partial, len, 1, ""); } + inline fn isPowerOfTwo(bits: u64) bool { + return bits != 0 and ((bits & (~bits + 1)) == bits); + } + + fn intTypeFromBitsAndSignRounded(self: *FuncGen, bits: u16, signed: bool) error{OutOfMemory}!Type { + const next_pow_two = math.log2_int_ceil(u16, bits); + const rounded_bits = @as(u32, 1) << next_pow_two; + return switch (rounded_bits) { + 8, 16, 32 => if (signed) Type.initTag(.i32) else Type.initTag(.u32), + 64 => if (signed) Type.initTag(.i64) else Type.initTag(.u64), + 128 => if (signed) Type.initTag(.i128) else Type.initTag(.u128), + else => |big| if (signed) + Type.Tag.int_signed.create( + self.dg.object.type_map_arena.allocator(), + @intCast(u16, big), + ) + else + Type.Tag.int_unsigned.create( + self.dg.object.type_map_arena.allocator(), + @intCast(u16, big), + ), + }; + } + fn airIntToFloat(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { if (self.liveness.isUnused(inst)) return null; + const target = self.dg.module.getTarget(); const ty_op = self.air.instructions.items(.data)[inst].ty_op; - const operand = try self.resolveInst(ty_op.operand); - const operand_ty = self.air.typeOf(ty_op.operand); - const operand_scalar_ty = operand_ty.scalarType(); - const dest_ty = self.air.typeOfIndex(inst); - const dest_llvm_ty = try self.dg.llvmType(dest_ty); - if (operand_scalar_ty.isSignedInt()) { - return self.builder.buildSIToFP(operand, dest_llvm_ty, ""); - } else { - return self.builder.buildUIToFP(operand, dest_llvm_ty, ""); + var operand = try self.resolveInst(ty_op.operand); + var operand_ty = self.air.typeOf(ty_op.operand); + var operand_scalar_ty = operand_ty.scalarType(); + + { + const operand_bits = @intCast(u16, operand_scalar_ty.bitSize(target)); + const is_signed = operand_scalar_ty.isSignedInt(); + + if (!isPowerOfTwo(operand_bits) or operand_bits < 32) { + const wider_ty = try self.intTypeFromBitsAndSignRounded(operand_bits, is_signed); + const wider_llvm_ty = try self.dg.llvmType(wider_ty); + if (is_signed) { + operand = self.builder.buildSExt(operand, wider_llvm_ty, ""); + } else { + operand = self.builder.buildZExt(operand, wider_llvm_ty, ""); + } + operand_ty = wider_ty; + operand_scalar_ty = operand_ty.scalarType(); + } } - } - fn airFloatToInt(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { - if (self.liveness.isUnused(inst)) - return null; - - const ty_op = self.air.instructions.items(.data)[inst].ty_op; - const operand = try self.resolveInst(ty_op.operand); const dest_ty = self.air.typeOfIndex(inst); const dest_scalar_ty = dest_ty.scalarType(); const dest_llvm_ty = try self.dg.llvmType(dest_ty); - // TODO set fast math flag + if (intrinsicsAllowed(dest_scalar_ty, target)) { + if (operand_scalar_ty.isSignedInt()) { + return self.builder.buildSIToFP(operand, dest_llvm_ty, ""); + } else { + return self.builder.buildUIToFP(operand, dest_llvm_ty, ""); + } + } + + const operand_bits = @intCast(u16, operand_scalar_ty.bitSize(target)); + const compiler_rt_operand_abbrev = compilerRtIntAbbrev(operand_bits); + + const dest_bits = dest_scalar_ty.floatBits(target); + const compiler_rt_dest_abbrev = compilerRtFloatAbbrev(dest_bits); + + var fn_name_buf: [64]u8 = undefined; + const fn_name = if (operand_scalar_ty.isSignedInt()) + std.fmt.bufPrintZ(&fn_name_buf, "__float{s}i{s}f", .{ + compiler_rt_operand_abbrev, + compiler_rt_dest_abbrev, + }) catch unreachable + else + std.fmt.bufPrintZ(&fn_name_buf, "__floatun{s}i{s}f", .{ + compiler_rt_operand_abbrev, + compiler_rt_dest_abbrev, + }) catch unreachable; + + const operand_llvm_ty = try self.dg.llvmType(operand_ty); + const param_types = [1]*const llvm.Type{operand_llvm_ty}; + const libc_fn = self.getLibcFunction(fn_name, ¶m_types, dest_llvm_ty); + const params = [1]*const llvm.Value{operand}; + + return self.builder.buildCall(libc_fn, ¶ms, params.len, .C, .Auto, ""); + } + + fn airFloatToInt(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { + if (self.liveness.isUnused(inst)) + return null; + + const target = self.dg.module.getTarget(); + const ty_op = self.air.instructions.items(.data)[inst].ty_op; + + const operand = try self.resolveInst(ty_op.operand); + const operand_ty = self.air.typeOf(ty_op.operand); + const operand_scalar_ty = operand_ty.scalarType(); + + var dest_ty = self.air.typeOfIndex(inst); + var dest_scalar_ty = dest_ty.scalarType(); + + if (intrinsicsAllowed(operand_scalar_ty, target)) { + // TODO set fast math flag + const dest_llvm_ty = try self.dg.llvmType(dest_ty); + if (dest_scalar_ty.isSignedInt()) { + return self.builder.buildFPToSI(operand, dest_llvm_ty, ""); + } else { + return self.builder.buildFPToUI(operand, dest_llvm_ty, ""); + } + } + + const needs_truncating = blk: { + const dest_bits = @intCast(u16, dest_scalar_ty.bitSize(target)); + + if (!isPowerOfTwo(dest_bits) or dest_bits < 32) { + dest_ty = try self.intTypeFromBitsAndSignRounded(dest_bits, dest_scalar_ty.isSignedInt()); + dest_scalar_ty = dest_ty.scalarType(); + break :blk true; + } + + break :blk false; + }; + + const dest_llvm_ty = try self.dg.llvmType(dest_ty); + + const operand_bits = operand_scalar_ty.floatBits(target); + const compiler_rt_operand_abbrev = compilerRtFloatAbbrev(operand_bits); - if (dest_scalar_ty.isSignedInt()) { - return self.builder.buildFPToSI(operand, dest_llvm_ty, ""); - } else { - return self.builder.buildFPToUI(operand, dest_llvm_ty, ""); + const dest_bits = @intCast(u16, dest_scalar_ty.bitSize(target)); + const compiler_rt_dest_abbrev = compilerRtIntAbbrev(dest_bits); + + var fn_name_buf: [64]u8 = undefined; + const fn_name = if (dest_scalar_ty.isSignedInt()) + std.fmt.bufPrintZ(&fn_name_buf, "__fix{s}f{s}i", .{ + compiler_rt_operand_abbrev, + compiler_rt_dest_abbrev, + }) catch unreachable + else + std.fmt.bufPrintZ(&fn_name_buf, "__fixun{s}f{s}i", .{ + compiler_rt_operand_abbrev, + compiler_rt_dest_abbrev, + }) catch unreachable; + + const operand_llvm_ty = try self.dg.llvmType(operand_ty); + const param_types = [1]*const llvm.Type{operand_llvm_ty}; + const libc_fn = self.getLibcFunction(fn_name, ¶m_types, dest_llvm_ty); + const params = [1]*const llvm.Value{operand}; + + const result = self.builder.buildCall(libc_fn, ¶ms, params.len, .C, .Auto, ""); + + if (needs_truncating) { + const requested_ty = self.air.typeOfIndex(inst); + const requested_llvm_ty = try self.dg.llvmType(requested_ty); + return self.builder.buildTrunc(result, requested_llvm_ty, ""); } + + return result; } fn airSliceField(self: *FuncGen, inst: Air.Inst.Index, index: c_uint) !?*const llvm.Value { @@ -5615,6 +5740,16 @@ pub const FuncGen = struct { }; } + fn compilerRtIntAbbrev(bits: u16) []const u8 { + return switch (bits) { + 16 => "h", + 32 => "s", + 64 => "d", + 128 => "t", + else => "o", // Non-standard + }; + } + /// Creates a floating point comparison by lowering to the appropriate /// hardware instruction or softfloat routine for the target fn buildFloatCmp( diff --git a/test/behavior/cast.zig b/test/behavior/cast.zig index a1bd41e7b02e6c96c1556bd5a2414664a7bd4a48..416c7914e7ec286a860e1b02aa51f05da45a1b8b 100644 --- a/test/behavior/cast.zig +++ b/test/behavior/cast.zig @@ -112,6 +112,42 @@ test "@intToFloat" { comptime try S.doTheTest(); } +test "@intToFloat(f80)" { + if (builtin.zig_backend == .stage1) return error.SkipZigTest; + + 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_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO + + const S = struct { + fn doTheTest(comptime Int: type) !void { + try testIntToFloat(Int, -2); + } + + fn testIntToFloat(comptime Int: type, k: Int) !void { + const f = @intToFloat(f80, k); + const i = @floatToInt(Int, f); + try expect(i == k); + } + }; + try S.doTheTest(i31); + try S.doTheTest(i32); + try S.doTheTest(i45); + try S.doTheTest(i64); + try S.doTheTest(i80); + try S.doTheTest(i128); + // try S.doTheTest(i256); // TODO missing compiler_rt symbols + comptime try S.doTheTest(i31); + comptime try S.doTheTest(i32); + comptime try S.doTheTest(i45); + comptime try S.doTheTest(i64); + comptime try S.doTheTest(i80); + comptime try S.doTheTest(i128); + comptime try S.doTheTest(i256); +} + test "@floatToInt" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO -- 2.54.0 From d136cd3202711bf6ad11a6f62115cfce0d6e88f1 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 5 May 2022 23:13:14 -0700 Subject: [PATCH 4/8] LLVM: rework the previous commit Idiomatic Zig, use const instead of var, simplify the logic. --- src/codegen/llvm.zig | 143 +++++++++++----------------------- src/codegen/llvm/bindings.zig | 8 ++ 2 files changed, 55 insertions(+), 96 deletions(-) diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 374ae9b38e2881e08ea56f3ccbacf84157cdd0d2..800786891e9fd7c0c4fae320ed139155ea1a552d 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -4229,61 +4229,20 @@ pub const FuncGen = struct { return self.builder.buildInsertValue(partial, len, 1, ""); } - inline fn isPowerOfTwo(bits: u64) bool { - return bits != 0 and ((bits & (~bits + 1)) == bits); - } - - fn intTypeFromBitsAndSignRounded(self: *FuncGen, bits: u16, signed: bool) error{OutOfMemory}!Type { - const next_pow_two = math.log2_int_ceil(u16, bits); - const rounded_bits = @as(u32, 1) << next_pow_two; - return switch (rounded_bits) { - 8, 16, 32 => if (signed) Type.initTag(.i32) else Type.initTag(.u32), - 64 => if (signed) Type.initTag(.i64) else Type.initTag(.u64), - 128 => if (signed) Type.initTag(.i128) else Type.initTag(.u128), - else => |big| if (signed) - Type.Tag.int_signed.create( - self.dg.object.type_map_arena.allocator(), - @intCast(u16, big), - ) - else - Type.Tag.int_unsigned.create( - self.dg.object.type_map_arena.allocator(), - @intCast(u16, big), - ), - }; - } - fn airIntToFloat(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { if (self.liveness.isUnused(inst)) return null; - const target = self.dg.module.getTarget(); const ty_op = self.air.instructions.items(.data)[inst].ty_op; - var operand = try self.resolveInst(ty_op.operand); - var operand_ty = self.air.typeOf(ty_op.operand); - var operand_scalar_ty = operand_ty.scalarType(); - - { - const operand_bits = @intCast(u16, operand_scalar_ty.bitSize(target)); - const is_signed = operand_scalar_ty.isSignedInt(); - - if (!isPowerOfTwo(operand_bits) or operand_bits < 32) { - const wider_ty = try self.intTypeFromBitsAndSignRounded(operand_bits, is_signed); - const wider_llvm_ty = try self.dg.llvmType(wider_ty); - if (is_signed) { - operand = self.builder.buildSExt(operand, wider_llvm_ty, ""); - } else { - operand = self.builder.buildZExt(operand, wider_llvm_ty, ""); - } - operand_ty = wider_ty; - operand_scalar_ty = operand_ty.scalarType(); - } - } + const operand = try self.resolveInst(ty_op.operand); + const operand_ty = self.air.typeOf(ty_op.operand); + const operand_scalar_ty = operand_ty.scalarType(); const dest_ty = self.air.typeOfIndex(inst); const dest_scalar_ty = dest_ty.scalarType(); const dest_llvm_ty = try self.dg.llvmType(dest_ty); + const target = self.dg.module.getTarget(); if (intrinsicsAllowed(dest_scalar_ty, target)) { if (operand_scalar_ty.isSignedInt()) { @@ -4294,27 +4253,28 @@ pub const FuncGen = struct { } const operand_bits = @intCast(u16, operand_scalar_ty.bitSize(target)); - const compiler_rt_operand_abbrev = compilerRtIntAbbrev(operand_bits); - + const rt_int_bits = compilerRtIntBits(operand_bits); + const rt_int_ty = self.context.intType(rt_int_bits); + const extended = e: { + if (operand_scalar_ty.isSignedInt()) { + break :e self.builder.buildSExtOrBitCast(operand, rt_int_ty, ""); + } else { + break :e self.builder.buildZExtOrBitCast(operand, rt_int_ty, ""); + } + }; const dest_bits = dest_scalar_ty.floatBits(target); + const compiler_rt_operand_abbrev = compilerRtIntAbbrev(rt_int_bits); const compiler_rt_dest_abbrev = compilerRtFloatAbbrev(dest_bits); - + const sign_prefix = if (operand_scalar_ty.isSignedInt()) "" else "un"; var fn_name_buf: [64]u8 = undefined; - const fn_name = if (operand_scalar_ty.isSignedInt()) - std.fmt.bufPrintZ(&fn_name_buf, "__float{s}i{s}f", .{ - compiler_rt_operand_abbrev, - compiler_rt_dest_abbrev, - }) catch unreachable - else - std.fmt.bufPrintZ(&fn_name_buf, "__floatun{s}i{s}f", .{ - compiler_rt_operand_abbrev, - compiler_rt_dest_abbrev, - }) catch unreachable; - - const operand_llvm_ty = try self.dg.llvmType(operand_ty); - const param_types = [1]*const llvm.Type{operand_llvm_ty}; + const fn_name = std.fmt.bufPrintZ(&fn_name_buf, "__float{s}{s}i{s}f", .{ + sign_prefix, + compiler_rt_operand_abbrev, + compiler_rt_dest_abbrev, + }) catch unreachable; + const param_types = [1]*const llvm.Type{rt_int_ty}; const libc_fn = self.getLibcFunction(fn_name, ¶m_types, dest_llvm_ty); - const params = [1]*const llvm.Value{operand}; + const params = [1]*const llvm.Value{extended}; return self.builder.buildCall(libc_fn, ¶ms, params.len, .C, .Auto, ""); } @@ -4330,12 +4290,12 @@ pub const FuncGen = struct { const operand_ty = self.air.typeOf(ty_op.operand); const operand_scalar_ty = operand_ty.scalarType(); - var dest_ty = self.air.typeOfIndex(inst); - var dest_scalar_ty = dest_ty.scalarType(); + const dest_ty = self.air.typeOfIndex(inst); + const dest_scalar_ty = dest_ty.scalarType(); + const dest_llvm_ty = try self.dg.llvmType(dest_ty); if (intrinsicsAllowed(operand_scalar_ty, target)) { // TODO set fast math flag - const dest_llvm_ty = try self.dg.llvmType(dest_ty); if (dest_scalar_ty.isSignedInt()) { return self.builder.buildFPToSI(operand, dest_llvm_ty, ""); } else { @@ -4343,52 +4303,34 @@ pub const FuncGen = struct { } } - const needs_truncating = blk: { - const dest_bits = @intCast(u16, dest_scalar_ty.bitSize(target)); - - if (!isPowerOfTwo(dest_bits) or dest_bits < 32) { - dest_ty = try self.intTypeFromBitsAndSignRounded(dest_bits, dest_scalar_ty.isSignedInt()); - dest_scalar_ty = dest_ty.scalarType(); - break :blk true; - } - - break :blk false; - }; - - const dest_llvm_ty = try self.dg.llvmType(dest_ty); + const rt_int_bits = compilerRtIntBits(@intCast(u16, dest_scalar_ty.bitSize(target))); + const libc_ret_ty = self.context.intType(rt_int_bits); const operand_bits = operand_scalar_ty.floatBits(target); const compiler_rt_operand_abbrev = compilerRtFloatAbbrev(operand_bits); - const dest_bits = @intCast(u16, dest_scalar_ty.bitSize(target)); - const compiler_rt_dest_abbrev = compilerRtIntAbbrev(dest_bits); + const compiler_rt_dest_abbrev = compilerRtIntAbbrev(rt_int_bits); + const sign_prefix = if (dest_scalar_ty.isSignedInt()) "" else "un"; var fn_name_buf: [64]u8 = undefined; - const fn_name = if (dest_scalar_ty.isSignedInt()) - std.fmt.bufPrintZ(&fn_name_buf, "__fix{s}f{s}i", .{ - compiler_rt_operand_abbrev, - compiler_rt_dest_abbrev, - }) catch unreachable - else - std.fmt.bufPrintZ(&fn_name_buf, "__fixun{s}f{s}i", .{ - compiler_rt_operand_abbrev, - compiler_rt_dest_abbrev, - }) catch unreachable; + const fn_name = std.fmt.bufPrintZ(&fn_name_buf, "__fix{s}{s}f{s}i", .{ + sign_prefix, + compiler_rt_operand_abbrev, + compiler_rt_dest_abbrev, + }) catch unreachable; const operand_llvm_ty = try self.dg.llvmType(operand_ty); const param_types = [1]*const llvm.Type{operand_llvm_ty}; - const libc_fn = self.getLibcFunction(fn_name, ¶m_types, dest_llvm_ty); + const libc_fn = self.getLibcFunction(fn_name, ¶m_types, libc_ret_ty); const params = [1]*const llvm.Value{operand}; const result = self.builder.buildCall(libc_fn, ¶ms, params.len, .C, .Auto, ""); - if (needs_truncating) { - const requested_ty = self.air.typeOfIndex(inst); - const requested_llvm_ty = try self.dg.llvmType(requested_ty); - return self.builder.buildTrunc(result, requested_llvm_ty, ""); + if (libc_ret_ty == dest_llvm_ty) { + return result; } - return result; + return self.builder.buildTrunc(result, dest_llvm_ty, ""); } fn airSliceField(self: *FuncGen, inst: Air.Inst.Index, index: c_uint) !?*const llvm.Value { @@ -8448,3 +8390,12 @@ fn needDbgVarWorkaround(dg: *DeclGen, ty: Type) bool { } return false; } + +fn compilerRtIntBits(bits: u16) u16 { + inline for (.{ 8, 16, 32, 64, 128 }) |b| { + if (bits <= b) { + return b; + } + } + return bits; +} diff --git a/src/codegen/llvm/bindings.zig b/src/codegen/llvm/bindings.zig index 4732e0dd490b72c1d8c18dd6ee5d52303955733c..c70a7d155384a8ae13f5c3cac1388e875ef71f22 100644 --- a/src/codegen/llvm/bindings.zig +++ b/src/codegen/llvm/bindings.zig @@ -476,6 +476,14 @@ pub const Builder = opaque { Name: [*:0]const u8, ) *const Value; + pub const buildSExtOrBitCast = LLVMBuildSExtOrBitCast; + extern fn LLVMBuildSExtOrBitCast( + *const Builder, + Val: *const Value, + DestTy: *const Type, + Name: [*:0]const u8, + ) *const Value; + pub const buildCall = ZigLLVMBuildCall; extern fn ZigLLVMBuildCall( *const Builder, -- 2.54.0 From 6d605ca6908e53a883eeb0aa9800e89136f83013 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 6 May 2022 15:42:52 -0700 Subject: [PATCH 5/8] CI: macos: stage2 zig build test-behavior --- ci/azure/macos_script | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/ci/azure/macos_script b/ci/azure/macos_script index b163afe3b333b9b174f5619ecfb6037c7febf59d..1df1b10dc1621f5da8cc24ad35f7498af7ed7d41 100755 --- a/ci/azure/macos_script +++ b/ci/azure/macos_script @@ -58,12 +58,23 @@ make $JOBS install # Build stage2 standalone so that we can test stage2 against stage2 compiler-rt. release/bin/zig build -p stage2 -Denable-llvm -stage2/bin/zig test ../test/behavior.zig -I../test -fLLVM -stage2/bin/zig test ../test/behavior.zig -I../test -fno-LLVM +stage2/bin/zig build test-behavior -release/bin/zig build test-toolchain -Denable-macos-sdk -release/bin/zig build test-std -release/bin/zig build docs +release/bin/zig build test-behavior -Denable-macos-sdk -Domit-stage2 +release/bin/zig build test-compiler-rt -Denable-macos-sdk +release/bin/zig build test-std -Denable-macos-sdk +release/bin/zig build test-minilibc -Denable-macos-sdk +release/bin/zig build test-compare-output -Denable-macos-sdk +release/bin/zig build test-standalone -Denable-macos-sdk +release/bin/zig build test-stack-traces -Denable-macos-sdk +release/bin/zig build test-cli -Denable-macos-sdk +release/bin/zig build test-asm-link -Denable-macos-sdk +release/bin/zig build test-runtime-safety -Denable-macos-sdk +release/bin/zig build test-translate-c -Denable-macos-sdk +release/bin/zig build test-run-translated-c -Denable-macos-sdk +release/bin/zig build docs -Denable-macos-sdk +release/bin/zig build test-fmt -Denable-macos-sdk +release/bin/zig build test-stage2 -Denable-macos-sdk if [ "${BUILD_REASON}" != "PullRequest" ]; then mv ../LICENSE release/ -- 2.54.0 From a2b8a9756f867b75e9e9dfd0ecea9de162ad5eb1 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 6 May 2022 16:26:04 -0700 Subject: [PATCH 6/8] CI: macos: disable stage2 test-behavior stage2 on macOS is not yet capable of passing these tests. Such improvements will be done in a follow-up change. --- ci/azure/macos_script | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ci/azure/macos_script b/ci/azure/macos_script index 1df1b10dc1621f5da8cc24ad35f7498af7ed7d41..d44f4dae4b902e37243f82c61a64d7f34dadc943 100755 --- a/ci/azure/macos_script +++ b/ci/azure/macos_script @@ -58,8 +58,11 @@ make $JOBS install # Build stage2 standalone so that we can test stage2 against stage2 compiler-rt. release/bin/zig build -p stage2 -Denable-llvm -stage2/bin/zig build test-behavior +# TODO: enable this +#stage2/bin/zig build test-behavior +# TODO: upgrade these to test stage2 instead of stage1 +# TODO: upgrade these to test stage3 instead of stage2 release/bin/zig build test-behavior -Denable-macos-sdk -Domit-stage2 release/bin/zig build test-compiler-rt -Denable-macos-sdk release/bin/zig build test-std -Denable-macos-sdk -- 2.54.0 From a2dbe6589ee6f33bb796ea3fd88b0bda5915e58e Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Sat, 7 May 2022 01:44:26 +0200 Subject: [PATCH 7/8] macho: share traditional codepaths with stage2+llvm backend --- ci/azure/macos_script | 3 +-- src/link/MachO.zig | 20 ++++++++++++-------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/ci/azure/macos_script b/ci/azure/macos_script index d44f4dae4b902e37243f82c61a64d7f34dadc943..e8c7c69a3387ad506cbf407d968cf8e45fd79549 100755 --- a/ci/azure/macos_script +++ b/ci/azure/macos_script @@ -58,8 +58,7 @@ make $JOBS install # Build stage2 standalone so that we can test stage2 against stage2 compiler-rt. release/bin/zig build -p stage2 -Denable-llvm -# TODO: enable this -#stage2/bin/zig build test-behavior +stage2/bin/zig build test-behavior # TODO: upgrade these to test stage2 instead of stage1 # TODO: upgrade these to test stage3 instead of stage2 diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 7caccb1fb8245aacfef88368874c182dab908c33..4b804e6fcb23cf05a91f04eceec3d5fafafd6779 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -392,8 +392,9 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*MachO { // Adhoc code signature is required when targeting aarch64-macos either directly or indirectly via the simulator // ABI such as aarch64-ios-simulator, etc. const requires_adhoc_codesig = cpu_arch == .aarch64 and (os_tag == .macos or abi == .simulator); + const use_llvm = build_options.have_llvm and options.use_llvm; const use_stage1 = build_options.is_stage1 and options.use_stage1; - const needs_prealloc = !(use_stage1 or options.cache_mode == .whole); + const needs_prealloc = !(use_stage1 or use_llvm or options.cache_mode == .whole); const self = try gpa.create(MachO); errdefer gpa.destroy(self); @@ -410,7 +411,6 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*MachO { .needs_prealloc = needs_prealloc, }; - const use_llvm = build_options.have_llvm and options.use_llvm; if (use_llvm and !use_stage1) { self.llvm_object = try LlvmObject.create(gpa, options); } @@ -571,7 +571,8 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No if (mem.eql(u8, prev_digest, &digest)) { // Hot diggity dog! The output binary is already there. - if (use_stage1) { + const use_llvm = build_options.have_llvm and self.base.options.use_llvm; + if (use_llvm or use_stage1) { log.debug("MachO Zld digest={s} match - skipping invocation", .{std.fmt.fmtSliceHexLower(&digest)}); self.base.lock = man.toOwnedLock(); return; @@ -1025,7 +1026,8 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No try self.createTentativeDefAtoms(); try self.parseObjectsIntoAtoms(); - if (use_stage1) { + const use_llvm = build_options.have_llvm and self.base.options.use_llvm; + if (use_llvm or use_stage1) { try self.sortSections(); try self.allocateTextSegment(); try self.allocateDataConstSegment(); @@ -1041,7 +1043,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No self.logSectionOrdinals(); } - if (use_stage1) { + if (use_llvm or use_stage1) { try self.writeAllAtoms(); } else { try self.writeAtoms(); @@ -4930,12 +4932,13 @@ fn allocateSegment(self: *MachO, index: u16, offset: u64) !void { var start: u64 = offset; for (seg.sections.items) |*sect, sect_id| { const is_zerofill = sect.flags == macho.S_ZEROFILL or sect.flags == macho.S_THREAD_LOCAL_ZEROFILL; + const use_llvm = build_options.have_llvm and self.base.options.use_llvm; const use_stage1 = build_options.is_stage1 and self.base.options.use_stage1; const alignment = try math.powi(u32, 2, sect.@"align"); const start_aligned = mem.alignForwardGeneric(u64, start, alignment); // TODO handle zerofill sections in stage2 - sect.offset = if (is_zerofill and use_stage1) 0 else @intCast(u32, seg.inner.fileoff + start_aligned); + sect.offset = if (is_zerofill and (use_stage1 or use_llvm)) 0 else @intCast(u32, seg.inner.fileoff + start_aligned); sect.addr = seg.inner.vmaddr + start_aligned; // Recalculate section size given the allocated start address @@ -4963,7 +4966,7 @@ fn allocateSegment(self: *MachO, index: u16, offset: u64) !void { start = start_aligned + sect.size; - if (!(is_zerofill and use_stage1)) { + if (!(is_zerofill and (use_stage1 or use_llvm))) { seg.inner.filesize = start; } seg.inner.vmsize = start; @@ -5012,10 +5015,11 @@ fn initSection( sect.addr = seg.inner.vmaddr + off - seg.inner.fileoff; const is_zerofill = opts.flags == macho.S_ZEROFILL or opts.flags == macho.S_THREAD_LOCAL_ZEROFILL; + const use_llvm = build_options.have_llvm and self.base.options.use_llvm; const use_stage1 = build_options.is_stage1 and self.base.options.use_stage1; // TODO handle zerofill in stage2 - if (!(is_zerofill and use_stage1)) { + if (!(is_zerofill and (use_stage1 or use_llvm))) { sect.offset = @intCast(u32, off); } } -- 2.54.0 From efeb031b7917f552ea73ee59c086e3d75c87cbaf Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Sat, 7 May 2022 01:52:00 +0200 Subject: [PATCH 8/8] macho: skip cache if cache_mode is .whole --- src/link/MachO.zig | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 4b804e6fcb23cf05a91f04eceec3d5fafafd6779..fa110f28cc2abcf58ff84eb923b478649337c413 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -519,7 +519,8 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No var needs_full_relink = true; cache: { - if (use_stage1 and self.base.options.disable_lld_caching) break :cache; + if ((use_stage1 and self.base.options.disable_lld_caching) or self.base.options.cache_mode == .whole) + break :cache; man = comp.cache_parent.obtain(); @@ -1099,7 +1100,8 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No } cache: { - if (use_stage1 and self.base.options.disable_lld_caching) break :cache; + if ((use_stage1 and self.base.options.disable_lld_caching) or self.base.options.cache_mode == .whole) + break :cache; // Update the file with the digest. If it fails we can continue; it only // means that the next invocation will have an unnecessary cache miss. Cache.writeSmallFile(cache_dir_handle, id_symlink_basename, &digest) catch |err| { -- 2.54.0