authorgravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2026-08-04 11:30:06+02:00
committergravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2026-08-31 23:14:46+02:00
log0a4a865644b6da11cfe99fdd794b80c08b656870
treef5c274f6e0c018efb04846979b96df4dfd9bca8f
parent9a29bf480336fa7c237a0b2bc1ca99d0762bcf24
signaturebadge-check Signed by SSH key SHA256:7B/LJ7bpR1eX8aCXSr4mtd5M45VMPKcx9zY8e95b5QM

Revert "llvm: workaround crash on large inline memset"

This reverts commit 84c2d809ec90aa3d5934adac33551f82656625ee. closes https://codeberg.org/ziglang/zig/issues/31701

2 files changed, 4 insertions(+), 43 deletions(-)

src/codegen/llvm/FuncGen.zig+4-39
...@@ -1071,7 +1071,7 @@ fn airRet(self: *FuncGen, inst: Air.Inst.Index, safety: bool) Allocator.Error!vo...@@ -1071,7 +1071,7 @@ fn airRet(self: *FuncGen, inst: Air.Inst.Index, safety: bool) Allocator.Error!vo
1071 const val_is_undef = if (un_op.toInterned()) |i| Value.fromInterned(i).isUndef(zcu) else false;1071 const val_is_undef = if (un_op.toInterned()) |i| Value.fromInterned(i).isUndef(zcu) else false;
1072 const ret_ty_align = ret_ty.abiAlignment(zcu);1072 const ret_ty_align = ret_ty.abiAlignment(zcu);
10731073
1074 if (val_is_undef and safety and !self.needMemsetWorkaround(ret_ty.abiSize(zcu))) {1074 if (val_is_undef and safety) {
1075 const rp = switch (self.ret_ptr) {1075 const rp = switch (self.ret_ptr) {
1076 .none => try self.buildZigAlloca(ret_ty, .none),1076 .none => try self.buildZigAlloca(ret_ty, .none),
1077 else => |rp| rp,1077 else => |rp| rp,
...@@ -5069,7 +5069,7 @@ fn airStore(fg: *FuncGen, inst: Air.Inst.Index, safety: bool) Allocator.Error!Bu...@@ -5069,7 +5069,7 @@ fn airStore(fg: *FuncGen, inst: Air.Inst.Index, safety: bool) Allocator.Error!Bu
5069 };5069 };
50705070
5071 const val_is_undef = if (bin_op.rhs.toInterned()) |i| Value.fromInterned(i).isUndef(zcu) else false;5071 const val_is_undef = if (bin_op.rhs.toInterned()) |i| Value.fromInterned(i).isUndef(zcu) else false;
5072 if (val_is_undef and !fg.needMemsetWorkaround(elem_ty.abiSize(zcu))) {5072 if (val_is_undef) {
5073 const owner_mod = fg.ownerModule();5073 const owner_mod = fg.ownerModule();
50745074
5075 // Even if safety is disabled, we still emit a memset to undefined since it conveys5075 // Even if safety is disabled, we still emit a memset to undefined since it conveys
...@@ -5585,11 +5585,6 @@ fn airMemset(self: *FuncGen, inst: Air.Inst.Index, safety: bool) Allocator.Error...@@ -5585,11 +5585,6 @@ fn airMemset(self: *FuncGen, inst: Air.Inst.Index, safety: bool) Allocator.Error
55855585
5586 self.maybeMarkAllowZeroAccess(ptr_ty.ptrInfo(zcu));5586 self.maybeMarkAllowZeroAccess(ptr_ty.ptrInfo(zcu));
55875587
5588 const allow_byte_memset = !self.needMemsetWorkaround(switch (ptr_ty.ptrSize(zcu)) {
5589 .one => ptr_ty.childType(zcu).abiSize(zcu),
5590 .slice => null,
5591 .many, .c => unreachable,
5592 });
5593 const len_bytes = try self.sliceOrArrayLenInBytes(dest_slice, ptr_ty);5588 const len_bytes = try self.sliceOrArrayLenInBytes(dest_slice, ptr_ty);
55945589
5595 try self.lowerMemset(5590 try self.lowerMemset(
...@@ -5600,7 +5595,6 @@ fn airMemset(self: *FuncGen, inst: Air.Inst.Index, safety: bool) Allocator.Error...@@ -5600,7 +5595,6 @@ fn airMemset(self: *FuncGen, inst: Air.Inst.Index, safety: bool) Allocator.Error
5600 len_bytes,5595 len_bytes,
5601 access_kind,5596 access_kind,
5602 safety,5597 safety,
5603 allow_byte_memset,
5604 );5598 );
5605 return .none;5599 return .none;
5606}5600}
...@@ -5614,12 +5608,11 @@ fn lowerMemset(...@@ -5614,12 +5608,11 @@ fn lowerMemset(
5614 len_bytes: Builder.Value,5608 len_bytes: Builder.Value,
5615 access_kind: Builder.MemoryAccessKind,5609 access_kind: Builder.MemoryAccessKind,
5616 safety: bool,5610 safety: bool,
5617 allow_byte_memset: bool,
5618) Allocator.Error!void {5611) Allocator.Error!void {
5619 const o = self.object;5612 const o = self.object;
5620 const zcu = o.zcu;5613 const zcu = o.zcu;
56215614
5622 if (allow_byte_memset) if (elem_ref.toInterned()) |elem_ip_index| {5615 if (elem_ref.toInterned()) |elem_ip_index| {
5623 const elem_val: Value = .fromInterned(elem_ip_index);5616 const elem_val: Value = .fromInterned(elem_ip_index);
5624 if (elem_val.isUndef(zcu)) {5617 if (elem_val.isUndef(zcu)) {
5625 // Even if safety is disabled, we still emit a memset to undefined since it conveys5618 // Even if safety is disabled, we still emit a memset to undefined since it conveys
...@@ -5660,13 +5653,12 @@ fn lowerMemset(...@@ -5660,13 +5653,12 @@ fn lowerMemset(
5660 );5653 );
5661 return;5654 return;
5662 }5655 }
5663 };5656 }
56645657
5665 const value = try self.resolveInst(elem_ref);5658 const value = try self.resolveInst(elem_ref);
5666 const elem_abi_size = elem_ty.abiSize(zcu);5659 const elem_abi_size = elem_ty.abiSize(zcu);
56675660
5668 intrinsic: {5661 intrinsic: {
5669 if (!allow_byte_memset) break :intrinsic;
5670 if (elem_abi_size != 1) break :intrinsic;5662 if (elem_abi_size != 1) break :intrinsic;
5671 // To use LLVM's intrinsic, we need to convert the operand to a raw 8-bit integer value.5663 // To use LLVM's intrinsic, we need to convert the operand to a raw 8-bit integer value.
5672 const fill_byte: Builder.Value = byte: {5664 const fill_byte: Builder.Value = byte: {
...@@ -6023,7 +6015,6 @@ fn airSplat(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value...@@ -6023,7 +6015,6 @@ fn airSplat(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value
6023 len_bytes_llvm,6015 len_bytes_llvm,
6024 .normal,6016 .normal,
6025 false,6017 false,
6026 !self.needMemsetWorkaround(len_bytes),
6027 );6018 );
60286019
6029 if (array_info.sentinel) |sent_val| {6020 if (array_info.sentinel) |sent_val| {
...@@ -8143,32 +8134,6 @@ fn llvmAllocaAddressSpace(target: *const std.Target) Builder.AddrSpace {...@@ -8143,32 +8134,6 @@ fn llvmAllocaAddressSpace(target: *const std.Target) Builder.AddrSpace {
8143 };8134 };
8144}8135}
81458136
8146/// Due to an LLVM bug, calls to `@llvm.memset.inline.*` with large constant length arguments cause
8147/// LLVM to crash. As a mitigation, this function returns `true` if we should avoid emitting a
8148/// memset call of the given length.
8149///
8150/// Most of our call sites are just setting memory to `undefined`, so can simply skip the memset
8151/// call if we return `true`.
8152///
8153/// Upstream issue: https://github.com/llvm/llvm-project/issues/189161
8154/// Zig issue: https://codeberg.org/ziglang/zig/issues/31701
8155fn needMemsetWorkaround(fg: *const FuncGen, maybe_len: ?u64) bool {
8156 if (!fg.disable_intrinsics) {
8157 // The bug is limited to `@llvm.memset.inline.*`: normal memset calls are fine.
8158 return false;
8159 }
8160 const len = maybe_len orelse {
8161 // We don't think the length is constant, but a trivial optimization on LLVM's side could
8162 // turn it into one and potentially trigger the bug. Therefore, always apply the workaround
8163 // if the length is not a known constant.
8164 return true;
8165 };
8166 // Empirically, the crash first happens at 1048561 bytes, which is 1 MiB less 15 bytes. To be
8167 // safe (just in case the limit is target-specific or something like that), let's just set the
8168 // cap at half of that, i.e. 512 KiB.
8169 return len > 1024 * 512;
8170}
8171
8172const mips_clobber_overrides = std.StaticStringMap(enum {8137const mips_clobber_overrides = std.StaticStringMap(enum {
8173 @"$msair",8138 @"$msair",
8174 @"$msacsr",8139 @"$msacsr",
test/tests.zig-4
...@@ -2895,10 +2895,6 @@ fn addOneModuleTest(...@@ -2895,10 +2895,6 @@ fn addOneModuleTest(
2895 });2895 });
2896 these_tests.linkage = test_target.linkage;2896 these_tests.linkage = test_target.linkage;
2897 these_tests.use_new_linker = test_target.new_linker;2897 these_tests.use_new_linker = test_target.new_linker;
2898 // https://codeberg.org/ziglang/zig/issues/31701
2899 if (!(mem.eql(u8, options.name, "compiler-rt") or mem.eql(u8, options.name, "libc"))) {
2900 if (options.no_builtin) these_tests.root_module.no_builtin = true;
2901 }
2902 // https://codeberg.org/ziglang/zig/issues/317022898 // https://codeberg.org/ziglang/zig/issues/31702
2903 if (mem.eql(u8, options.name, "compiler-rt") or mem.eql(u8, options.name, "libc")) {2899 if (mem.eql(u8, options.name, "compiler-rt") or mem.eql(u8, options.name, "libc")) {
2904 these_tests.root_module.stack_protector = false;2900 these_tests.root_module.stack_protector = false;