diff --git a/lib/compiler_rt.zig b/lib/compiler_rt.zig index 0a8621ed13e8e6b4422b7b2554bf29955282f91c..f042d0076e62740c50d61b4e28b8b3ddb07012f3 100644 --- a/lib/compiler_rt.zig +++ b/lib/compiler_rt.zig @@ -302,7 +302,6 @@ comptime { _ = @import("compiler_rt/memcpy.zig"); if (!ofmt_c) { symbol(&memset, "memset"); - symbol(&__memset, "__memset"); } _ = @import("compiler_rt/memmove.zig"); symbol(&memcmp, "memcmp"); @@ -650,14 +649,80 @@ inline fn negXi2(comptime T: type, a: T) T { return -a; } -pub fn memset(dest: ?[*]u8, c: u8, len: usize) callconv(.c) ?[*]u8 { - @setRuntimeSafety(false); +fn memsetSmallPowerOf2(d: [*]u8, b: u8, comptime size: usize) void { + if (size > @sizeOf(usize)) { + d[0..size].* = @splat(b); + } else { + const T = @Int(.unsigned, 8 * size); + var splatted: T = 0; // Setting this to undefined causes a memset call and thus infinite recursion in Debug test-compiler-rt. + @as(*[size]u8, @ptrCast(&splatted)).* = @splat(b); + @as(*align(1) T, @ptrCast(d)).* = splatted; + } +} + +fn shortMemset( + log_min: comptime_int, + log_max: comptime_int, + d: [*]u8, + b: u8, + len: usize, +) void { + if (log_min + 1 != log_max) { + const mid = (log_min + log_max) / 2; + if (len > 1 << mid) { + shortMemset(mid, log_max, d, b, len); + } else { + shortMemset(log_min, mid, d, b, len); + } + } else { + const size = 1 << log_min; + + memsetSmallPowerOf2(d, b, size); + memsetSmallPowerOf2(d + len - size, b, size); + } +} + +fn fastMemset(dest: ?[*]u8, c: c_int, len: usize) callconv(.c) ?[*]u8 { + const b: u8 = @truncate(@as(c_uint, @bitCast(c))); + const n = std.simd.suggestVectorLength(u8) orelse @sizeOf(usize); + + const d = dest.?; + + if (len > 2 * n) { + memsetSmallPowerOf2(d, b, n); + + const begin_aligned = std.mem.alignBackward(usize, @intFromPtr(d) + n, n); + const end_aligned = std.mem.alignForward(usize, @intFromPtr(d) + len - n, n); + + const aligned_ptr: [*]align(n) u8 = @ptrFromInt(begin_aligned); + + var i: usize = 0; + while (true) { + memsetSmallPowerOf2(aligned_ptr + n * i, b, n); + + i += 1; + if (i == @divExact(end_aligned - begin_aligned, n)) + break; + } + + memsetSmallPowerOf2(d + len - n, b, n); + } else { + if (len == 0) return dest; + + shortMemset(0, @ctz(@as(usize, 2 * n)), d, b, len); + } + + return dest; +} + +fn smallMemset(dest: ?[*]u8, c: c_int, len: usize) callconv(.c) ?[*]u8 { + const b: u8 = @truncate(@as(c_uint, @bitCast(c))); if (len != 0) { var d = dest.?; var n = len; while (true) { - d[0] = c; + d[0] = b; n -= 1; if (n == 0) break; d += 1; @@ -667,11 +732,10 @@ pub fn memset(dest: ?[*]u8, c: u8, len: usize) callconv(.c) ?[*]u8 { return dest; } -pub fn __memset(dest: ?[*]u8, c: u8, n: usize, dest_n: usize) callconv(.c) ?[*]u8 { - if (dest_n < n) - @panic("buffer overflow"); - return memset(dest, c, n); -} +pub const memset = if (builtin.optimize == .small) + smallMemset +else + fastMemset; pub fn bcmp(vl: [*]allowzero const u8, vr: [*]allowzero const u8, n: usize) callconv(.c) c_int { @setRuntimeSafety(false); diff --git a/lib/compiler_rt/ssp.zig b/lib/compiler_rt/ssp.zig index 42d088eeb8ab714b4b3d9ac79e579634ffff11a3..20468b0c0de8eb23cc9dff83c3e1bcbf46417f57 100644 --- a/lib/compiler_rt/ssp.zig +++ b/lib/compiler_rt/ssp.zig @@ -17,7 +17,7 @@ const compiler_rt = @import("../compiler_rt.zig"); const symbol = compiler_rt.symbol; const builtin = @import("builtin"); -extern fn memset(dest: ?[*]u8, c: u8, n: usize) callconv(.c) ?[*]u8; +extern fn memset(dest: ?[*]u8, c: c_int, n: usize) callconv(.c) ?[*]u8; extern fn memcpy(noalias dest: ?[*]u8, noalias src: ?[*]const u8, n: usize) callconv(.c) ?[*]u8; extern fn memmove(dest: ?[*]u8, src: ?[*]const u8, n: usize) callconv(.c) ?[*]u8; @@ -138,7 +138,7 @@ fn __memmove_chk(dest: ?[*]u8, src: ?[*]const u8, n: usize, dest_n: usize) callc return memmove(dest, src, n); } -fn __memset_chk(dest: ?[*]u8, c: u8, n: usize, dest_n: usize) callconv(.c) ?[*]u8 { +fn __memset_chk(dest: ?[*]u8, c: c_int, n: usize, dest_n: usize) callconv(.c) ?[*]u8 { if (dest_n < n) __chk_fail(); return memset(dest, c, n); } diff --git a/test/standalone/compiler_rt_panic/main.c b/test/standalone/compiler_rt_panic/main.c index be64216ab7e794616bd77cf5e61980f5fdc381c8..a11df761aaa60fc388163ccd76e82906767d146f 100644 --- a/test/standalone/compiler_rt_panic/main.c +++ b/test/standalone/compiler_rt_panic/main.c @@ -1,11 +1,11 @@ #include -void* __memset(void* dest, char c, size_t n, size_t dest_n); +void *__memset_chk(void *dest, int c, size_t n, size_t dest_n); char foo[128]; int main() { - __memset(&foo[0], 0xff, 128, 128); + __memset_chk(&foo[0], 0xff, 128, 128); return foo[64]; }