diff options
Diffstat (limited to 'Variables.zig')
| -rw-r--r-- | Variables.zig | 121 |
1 files changed, 121 insertions, 0 deletions
diff --git a/Variables.zig b/Variables.zig new file mode 100644 index 0000000..c4c40de --- /dev/null +++ b/Variables.zig @@ -0,0 +1,121 @@ +//! Variables captured at patch location +// Copyright (C) 2025 Nguyễn Gia Phong +// +// This file is part of taosc. +// +// Taosc is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Taosc is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with taosc. If not, see <https://www.gnu.org/licenses/>. + +const Allocator = std.mem.Allocator; +const Writer = std.io.Writer; +const assert = std.debug.assert; +const bytesAsSlice = std.mem.bytesAsSlice; +const cwd = std.fs.cwd; +const divCeil = std.math.divCeil; +const fields = std.meta.fields; +const std = @import("std"); +const suggestVectorLength = std.simd.suggestVectorLength; + +pub const RegisterEnum = enum(u5) { // TODO: u4 + rflags, // TODO: remove + r15, r14, r13, r12, r11, r10, r9, r8, + rdi, rsi, rbp, rbx, rdx, rcx, rax, + rsp, // TODO: remove + rip, // TODO: remove + + pub fn format(tag: RegisterEnum, writer: *Writer) Writer.Error!void { + try writer.print("{s}", .{ @tagName(tag) }); + } +}; +const Register = i64; +const Registers = [fields(RegisterEnum).len]Register; + +pub const signed_integers = .{ i64, i32, i16, i8 }; +const len = suggestVectorLength(Register).?; +const alignment = @alignOf(@Vector(len, Register)); +comptime { + for (signed_integers) |Int| { + assert(alignment == @alignOf(@Vector(len, Int))); + assert(alignment % @sizeOf(Int) == 0); + } +} + +fn alignedSize(T: type, count: usize) !usize { + return try divCeil(usize, @sizeOf(T) * count, alignment) * alignment; +} + +fn packedSize(T: type, container_size: usize, count: usize) !usize { + return @divExact(container_size, @sizeOf(T)) * try alignedSize(T, count); +} + +const Variables = @This(); +bytes: []align(alignment) const u8, +samples: usize, + +pub fn init(allocator: Allocator, stack_size: usize, + path: []const u8) !Variables { + var dir = try cwd().openDir(path, .{ .iterate = true }); + defer dir.close(); + var entries = dir.iterate(); + var count: usize = 0; + while (try entries.next()) |entry| { + assert(entry.kind == .file); + count += 1; + } + var size = try packedSize(Register, @sizeOf(Registers), count); + inline for (signed_integers) |Int| + size += try packedSize(Int, stack_size, count); + const bytes = try allocator.alignedAlloc(u8, + .fromByteUnits(alignment), size); + errdefer allocator.free(bytes); + + const file_size = @sizeOf(Registers) + stack_size; + const buffer = try allocator.alignedAlloc(u8, + .fromByteUnits(@alignOf(Registers)), file_size); + defer allocator.free(buffer); + const registers: *Registers = @ptrCast(buffer.ptr); + entries.reset(); + for (0..count) |index| { + const entry = try entries.next(); + const file = try dir.openFile(entry.?.name, .{}); + defer file.close(); + assert(try file.getEndPos() == file_size); + assert(try file.read(buffer) == file_size); + var offset: usize = 0; + inline for (registers) |reg| { + const slice = bytesAsSlice(Register, bytes[offset..]); + slice[index] = reg; + offset += try alignedSize(Register, count); + } + inline for (signed_integers) |Int| { + const aligned_size = try alignedSize(Int, count); + for (bytesAsSlice(Int, buffer[@sizeOf(Registers)..])) |value| { + const slice = bytesAsSlice(Int, bytes[offset..]); + slice[index] = value; + offset += aligned_size; + } + } + } + return .{ .bytes = bytes, .samples = count }; +} + +pub fn deinit(variables: Variables, allocator: Allocator) void { + allocator.free(variables.bytes); +} + +pub fn register(variables: Variables, name: RegisterEnum) ![]const Register { + const aligned_size = try alignedSize(Register, variables.samples); + const offset = aligned_size * @intFromEnum(name); + const slice = bytesAsSlice(Register, variables.bytes[offset..]); + return @alignCast(slice[0..variables.samples]); +} |
