authorgravatar for jahe788@gmail.comIntegratedQuantum <jahe788@gmail.com> 2023-07-06 20:41:49+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-07-06 14:41:49-04:00
log49ac816e3683def5d14d6f8415d80413ecb43e4c
treed1111a8019b7e1cb4c6a0f28158d3806126ec5d3
parent91daf1c8d8a64133f18dcec2b96e9f9f4326fe36
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Optimize Allocator functions to create less duplicate code for similar types (#16332)

* Move functionality from generic functions that doesn't depend on the type into a function that only depends on comptime alignment. This reduces comptime code duplication because e.g. `alloc(u32, )` and `alloc(i32, )` now use the same function `allocWithFoo(4, 4, )` under the hood.

1 files changed, 19 insertions(+), 12 deletions(-)

lib/std/mem/Allocator.zig+19-12
...@@ -102,8 +102,8 @@ pub inline fn rawFree(self: Allocator, buf: []u8, log2_buf_align: u8, ret_addr:...@@ -102,8 +102,8 @@ pub inline fn rawFree(self: Allocator, buf: []u8, log2_buf_align: u8, ret_addr:
102/// Call `destroy` with the result to free the memory.102/// Call `destroy` with the result to free the memory.
103pub fn create(self: Allocator, comptime T: type) Error!*T {103pub fn create(self: Allocator, comptime T: type) Error!*T {
104 if (@sizeOf(T) == 0) return @as(*T, @ptrFromInt(math.maxInt(usize)));104 if (@sizeOf(T) == 0) return @as(*T, @ptrFromInt(math.maxInt(usize)));
105 const slice = try self.allocAdvancedWithRetAddr(T, null, 1, @returnAddress());105 const ptr: *T = @ptrCast(try self.allocBytesWithAlignment(@alignOf(T), @sizeOf(T), @returnAddress()));
106 return &slice[0];106 return ptr;
107}107}
108108
109/// `ptr` should be the return value of `create`, or otherwise109/// `ptr` should be the return value of `create`, or otherwise
...@@ -113,7 +113,7 @@ pub fn destroy(self: Allocator, ptr: anytype) void {...@@ -113,7 +113,7 @@ pub fn destroy(self: Allocator, ptr: anytype) void {
113 const T = info.child;113 const T = info.child;
114 if (@sizeOf(T) == 0) return;114 if (@sizeOf(T) == 0) return;
115 const non_const_ptr = @as([*]u8, @ptrCast(@constCast(ptr)));115 const non_const_ptr = @as([*]u8, @ptrCast(@constCast(ptr)));
116 self.rawFree(non_const_ptr[0..@sizeOf(T)], math.log2(info.alignment), @returnAddress());116 self.rawFree(non_const_ptr[0..@sizeOf(T)], log2a(info.alignment), @returnAddress());
117}117}
118118
119/// Allocates an array of `n` items of type `T` and sets all the119/// Allocates an array of `n` items of type `T` and sets all the
...@@ -192,7 +192,7 @@ pub fn alignedAlloc(...@@ -192,7 +192,7 @@ pub fn alignedAlloc(
192 return self.allocAdvancedWithRetAddr(T, alignment, n, @returnAddress());192 return self.allocAdvancedWithRetAddr(T, alignment, n, @returnAddress());
193}193}
194194
195pub fn allocAdvancedWithRetAddr(195pub inline fn allocAdvancedWithRetAddr(
196 self: Allocator,196 self: Allocator,
197 comptime T: type,197 comptime T: type,
198 /// null means naturally aligned198 /// null means naturally aligned
...@@ -201,23 +201,30 @@ pub fn allocAdvancedWithRetAddr(...@@ -201,23 +201,30 @@ pub fn allocAdvancedWithRetAddr(
201 return_address: usize,201 return_address: usize,
202) Error![]align(alignment orelse @alignOf(T)) T {202) Error![]align(alignment orelse @alignOf(T)) T {
203 const a = alignment orelse @alignOf(T);203 const a = alignment orelse @alignOf(T);
204 const ptr: [*]align(a) T = @ptrCast(try self.allocWithSizeAndAlignment(@sizeOf(T), a, n, return_address));
205 return ptr[0..n];
206}
207
208fn allocWithSizeAndAlignment(self: Allocator, comptime size: usize, comptime alignment: u29, n: usize, return_address: usize) Error![*]align(alignment) u8 {
209 const byte_count = math.mul(usize, size, n) catch return Error.OutOfMemory;
210 return self.allocBytesWithAlignment(alignment, byte_count, return_address);
211}
204212
213fn allocBytesWithAlignment(self: Allocator, comptime alignment: u29, byte_count: usize, return_address: usize) Error![*]align(alignment) u8 {
205 // The Zig Allocator interface is not intended to solve alignments beyond214 // The Zig Allocator interface is not intended to solve alignments beyond
206 // the minimum OS page size. For these use cases, the caller must use OS215 // the minimum OS page size. For these use cases, the caller must use OS
207 // APIs directly.216 // APIs directly.
208 comptime assert(a <= mem.page_size);217 comptime assert(alignment <= mem.page_size);
209218
210 if (n == 0) {219 if (byte_count == 0) {
211 const ptr = comptime std.mem.alignBackward(usize, math.maxInt(usize), a);220 const ptr = comptime std.mem.alignBackward(usize, math.maxInt(usize), alignment);
212 return @as([*]align(a) T, @ptrFromInt(ptr))[0..0];221 return @as([*]align(alignment) u8, @ptrFromInt(ptr));
213 }222 }
214223
215 const byte_count = math.mul(usize, @sizeOf(T), n) catch return Error.OutOfMemory;224 const byte_ptr = self.rawAlloc(byte_count, log2a(alignment), return_address) orelse return Error.OutOfMemory;
216 const byte_ptr = self.rawAlloc(byte_count, log2a(a), return_address) orelse return Error.OutOfMemory;
217 // TODO: https://github.com/ziglang/zig/issues/4298225 // TODO: https://github.com/ziglang/zig/issues/4298
218 @memset(byte_ptr[0..byte_count], undefined);226 @memset(byte_ptr[0..byte_count], undefined);
219 const byte_slice: []align(a) u8 = @alignCast(byte_ptr[0..byte_count]);227 return @as([*]align(alignment) u8, @alignCast(byte_ptr));
220 return mem.bytesAsSlice(T, byte_slice);
221}228}
222229
223/// Requests to modify the size of an allocation. It is guaranteed to not move230/// Requests to modify the size of an allocation. It is guaranteed to not move