authorgravatar for rpkak@noreply.codeberg.orgrpkak <rpkak@noreply.codeberg.org> 2026-06-13 12:41:14+02:00
committergravatar for rpkak@noreply.codeberg.orgrpkak <rpkak@noreply.codeberg.org> 2026-07-21 09:38:18+02:00
log2c894ce206036cb6fa155dd431444fa4f35d5cde
tree73c4daa7ba13bceaf8ce4dda6347aa3da6365bb2
parent0e61c9aba3ca641d7cdade43ef239d1a2c9ab58d
signaturebadge-check Signed by SSH key SHA256:A2g6ATENrgLKQcUdthsn72P0njmQxnHSimzwnyJsZzo

compiler_rt: optimize memset


1 files changed, 72 insertions(+), 2 deletions(-)

lib/compiler_rt.zig+72-2
......@@ -649,8 +649,73 @@ inline fn negXi2(comptime T: type, a: T) T {
649649 return -a;
650650}
651651
652pub fn memset(dest: ?[*]u8, c: c_int, len: usize) callconv(.c) ?[*]u8 {
653 @setRuntimeSafety(false);
652fn memsetSmallPowerOf2(d: [*]u8, b: u8, comptime size: usize) void {
653 if (size > @sizeOf(usize)) {
654 d[0..size].* = @splat(b);
655 } else {
656 const T = @Int(.unsigned, 8 * size);
657 var splatted: T = 0; // Setting this to undefined causes a memset call and thus infinite recursion in Debug test-compiler-rt.
658 @as(*[size]u8, @ptrCast(&splatted)).* = @splat(b);
659 @as(*align(1) T, @ptrCast(d)).* = splatted;
660 }
661}
662
663fn shortMemset(
664 log_min: comptime_int,
665 log_max: comptime_int,
666 d: [*]u8,
667 b: u8,
668 len: usize,
669) void {
670 if (log_min + 1 != log_max) {
671 const mid = (log_min + log_max) / 2;
672 if (len > 1 << mid) {
673 shortMemset(mid, log_max, d, b, len);
674 } else {
675 shortMemset(log_min, mid, d, b, len);
676 }
677 } else {
678 const size = 1 << log_min;
679
680 memsetSmallPowerOf2(d, b, size);
681 memsetSmallPowerOf2(d + len - size, b, size);
682 }
683}
684
685fn fastMemset(dest: ?[*]u8, c: c_int, len: usize) callconv(.c) ?[*]u8 {
686 const b: u8 = @truncate(@as(c_uint, @bitCast(c)));
687 const n = std.simd.suggestVectorLength(u8) orelse @sizeOf(usize);
688
689 const d = dest.?;
690
691 if (len > 2 * n) {
692 memsetSmallPowerOf2(d, b, n);
693
694 const begin_aligned = std.mem.alignBackward(usize, @intFromPtr(d) + n, n);
695 const end_aligned = std.mem.alignForward(usize, @intFromPtr(d) + len - n, n);
696
697 const aligned_ptr: [*]align(n) u8 = @ptrFromInt(begin_aligned);
698
699 var i: usize = 0;
700 while (true) {
701 memsetSmallPowerOf2(aligned_ptr + n * i, b, n);
702
703 i += 1;
704 if (i == @divExact(end_aligned - begin_aligned, n))
705 break;
706 }
707
708 memsetSmallPowerOf2(d + len - n, b, n);
709 } else {
710 if (len == 0) return dest;
711
712 shortMemset(0, @ctz(@as(usize, 2 * n)), d, b, len);
713 }
714
715 return dest;
716}
717
718fn smallMemset(dest: ?[*]u8, c: c_int, len: usize) callconv(.c) ?[*]u8 {
654719 const b: u8 = @truncate(@as(c_uint, @bitCast(c)));
655720
656721 if (len != 0) {
......@@ -667,6 +732,11 @@ pub fn memset(dest: ?[*]u8, c: c_int, len: usize) callconv(.c) ?[*]u8 {
667732 return dest;
668733}
669734
735pub const memset = if (builtin.optimize == .small)
736 smallMemset
737else
738 fastMemset;
739
670740pub fn bcmp(vl: [*]allowzero const u8, vr: [*]allowzero const u8, n: usize) callconv(.c) c_int {
671741 @setRuntimeSafety(false);
672742