authorgravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2024-07-25 22:06:29+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-07-25 18:04:50-07:00
log1c35e73b614398529782f8c027366c6d8d51ac4b
tree250c777f79bd747416f105111592fc7c79a344d6
parent81a172a5064559d1f968f240204f8ce545852441

llvm: Don't emit safety memset() for stores of undef in Debug with safety off.

Before, this code: @setRuntimeSafety(false); var arr: [38]elf.Addr = undefined; would emit a call to memset() in the output code in Debug mode, while in all the release modes, LLVM optimized the memset() out as expected. Emitting the call in Debug mode is problematic in some contexts, e.g. in std.os.linux.start_pie where we are not yet ready to correctly perform calls because relocations haven't been applied yet, or in the early stages of a dynamic linker, etc.

1 files changed, 15 insertions(+), 4 deletions(-)

src/codegen/llvm.zig+15-4
......@@ -8997,6 +8997,21 @@ pub const FuncGen = struct {
89978997
89988998 const val_is_undef = if (try self.air.value(bin_op.rhs, pt)) |val| val.isUndefDeep(mod) else false;
89998999 if (val_is_undef) {
9000 const owner_mod = self.dg.ownerModule();
9001
9002 // Even if safety is disabled, we still emit a memset to undefined since it conveys
9003 // extra information to LLVM, and LLVM will optimize it out. Safety makes the difference
9004 // between using 0xaa or actual undefined for the fill byte.
9005 //
9006 // However, for Debug builds specifically, we avoid emitting the memset because LLVM
9007 // will neither use the information nor get rid of the memset, thus leaving an
9008 // unexpected call in the user's code. This is problematic if the code in question is
9009 // not ready to correctly make calls yet, such as in our early PIE startup code, or in
9010 // the early stages of a dynamic linker, etc.
9011 if (!safety and owner_mod.optimize_mode == .Debug) {
9012 return .none;
9013 }
9014
90009015 const ptr_info = ptr_ty.ptrInfo(mod);
90019016 const needs_bitmask = (ptr_info.packed_offset.host_size != 0);
90029017 if (needs_bitmask) {
......@@ -9006,9 +9021,6 @@ pub const FuncGen = struct {
90069021 return .none;
90079022 }
90089023
9009 // Even if safety is disabled, we still emit a memset to undefined since it conveys
9010 // extra information to LLVM. However, safety makes the difference between using
9011 // 0xaa or actual undefined for the fill byte.
90129024 const len = try o.builder.intValue(try o.lowerType(Type.usize), operand_ty.abiSize(pt));
90139025 _ = try self.wip.callMemSet(
90149026 dest_ptr,
......@@ -9017,7 +9029,6 @@ pub const FuncGen = struct {
90179029 len,
90189030 if (ptr_ty.isVolatilePtr(mod)) .@"volatile" else .normal,
90199031 );
9020 const owner_mod = self.dg.ownerModule();
90219032 if (safety and owner_mod.valgrind) {
90229033 try self.valgrindMarkUndef(dest_ptr, len);
90239034 }