aboutsummaryrefslogtreecommitdiff
path: root/Variables.zig
diff options
context:
space:
mode:
authorNguyễn Gia Phong <cnx@loang.net>2025-10-17 06:19:22 +0900
committerNguyễn Gia Phong <cnx@loang.net>2025-10-17 06:19:22 +0900
commit663ea12374e958fa83ac7e1b439dd6ab22bb59ed (patch)
tree8bee2d3ae37acd62d78dd68de2798a0e6687516b /Variables.zig
parentd8090bb73f404a9abff5b7cc9cfdd8cdb1ee4d5f (diff)
downloadtaosc-663ea12374e958fa83ac7e1b439dd6ab22bb59ed.tar.gz
Implement ERM
Diffstat (limited to 'Variables.zig')
-rw-r--r--Variables.zig121
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]);
+}