about summary refs log tree commit diff
path: root/Variables.zig
diff options
context:
space:
mode:
authorNguyễn Gia Phong <cnx@loang.net>2025-10-17 16:27:57 +0900
committerNguyễn Gia Phong <cnx@loang.net>2025-10-17 17:57:44 +0900
commitf4c491fce28223a09900aafeb6e1e83994df2bbd (patch)
treea382e169120eea5e4728348c3e9252fbae724176 /Variables.zig
parent3a2e8fd0b06ebb738d9d4677659249e05b09e7cb (diff)
downloadtaosc-f4c491fce28223a09900aafeb6e1e83994df2bbd.tar.gz
Support constants and arithmetic operations in predicates
Diffstat (limited to 'Variables.zig')
-rw-r--r--Variables.zig109
1 files changed, 92 insertions, 17 deletions
diff --git a/Variables.zig b/Variables.zig
index 99f7061..9732afa 100644
--- a/Variables.zig
+++ b/Variables.zig
@@ -20,27 +20,29 @@ const Allocator = std.mem.Allocator;
 const Writer = std.io.Writer;
 const assert = std.debug.assert;
 const bytesAsSlice = std.mem.bytesAsSlice;
+const comptimePrint = std.fmt.comptimePrint;
 const cwd = std.fs.cwd;
 const divCeil = std.math.divCeil;
-const fields = std.meta.fields;
+const eql = std.meta.eql;
+const expect = std.testing.expect;
+const maxInt = std.math.maxInt;
+const minInt = std.math.minInt;
 const std = @import("std");
+const tags = std.meta.tags;
 
 pub const RegisterEnum = enum(u4) {
     rax, rbx, rcx, rdx, rsi, rdi, rsp, rbp,
     r8, r9, r10, r11, r12, r13, r14, r15,
-
-    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 Register = i64;
+const Registers = [tags(RegisterEnum).len]Register;
 
 pub const signed_integers = .{ i64, i32, i16, i8 };
 const alignment = @alignOf(Register);
-comptime {
-    for (signed_integers) |Int|
-        assert(alignment >= @alignOf(Int));
+
+test alignment {
+    inline for (signed_integers) |Int|
+        try expect(alignment >= @alignOf(Int));
 }
 
 fn alignedSize(T: type, count: usize) !usize {
@@ -85,9 +87,9 @@ pub fn init(allocator: Allocator, stack_size: usize,
         assert(try file.getEndPos() == file_size);
         assert(try file.read(buffer) == file_size);
         var offset: usize = 0;
-        inline for (registers) |reg| {
+        inline for (registers) |register| {
             const slice = bytesAsSlice(Register, bytes[offset..]);
-            slice[index] = reg;
+            slice[index] = register;
             offset += try alignedSize(Register, count);
         }
         inline for (signed_integers) |Int| {
@@ -106,9 +108,82 @@ 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]);
+const ConstantEnum = enum(i64) {
+    max1 = maxInt(i1),
+    min2 = minInt(i2),
+    max2 = maxInt(i2),
+    min3 = minInt(i3),
+    max3 = maxInt(i3),
+    min4 = minInt(i4),
+    max4 = maxInt(i4),
+    min5 = minInt(i5),
+    max5 = maxInt(i5),
+    min6 = minInt(i6),
+    max6 = maxInt(i6),
+    min7 = minInt(i7),
+    max7 = maxInt(i7),
+    min8 = minInt(i8),
+    max8 = maxInt(i8),
+    min9 = minInt(i9),
+    min16 = minInt(i16),
+    max16 = maxInt(i16),
+    min17 = minInt(i17),
+    min32 = minInt(i32),
+    max32 = maxInt(i32),
+    min33 = minInt(i33),
+    min64 = minInt(i64),
+    max64 = maxInt(i64),
+};
+
+pub const Query = union(enum) {
+    constant: ConstantEnum,
+    register: RegisterEnum,
+    stack: usize,
+
+    pub fn all(allocator: Allocator) Allocator.Error![]Query {
+        const constants = tags(ConstantEnum);
+        const registers = tags(RegisterEnum);
+        const n = constants.len + registers.len;
+        const queries = try allocator.alloc(Query, n);
+        for (queries[0..constants.len], constants) |*dest, src|
+            dest.* = .{ .constant = src };
+        for (queries[constants.len..][0..registers.len],
+             registers) |*dest, src|
+            dest.* = .{ .register = src };
+        return queries;
+    }
+
+    pub fn skip(q: Query, r: Query, s: Query) bool {
+        return eql(q, r) or eql(r, s) or eql(s, q)
+            or q == .constant and r == .constant and s == .constant
+            or q != .constant and r != .constant and s != .constant;
+    }
+
+    pub fn format(query: Query, writer: *Writer) Writer.Error!void {
+        switch (query) {
+            inline .constant, .register => |tag|
+                try writer.print("{s}", .{ @tagName(tag) }),
+            .stack => unreachable,
+        }
+    }
+};
+
+pub fn get(variables: Variables, query: Query,
+           tmp: []Register) ![]const Register {
+    switch (query) {
+        .constant => |constant| switch (constant) {
+            inline else => |tag| {
+                for (tmp) |*register|
+                    register.* = @intFromEnum(tag);
+                return tmp;
+            },
+        },
+        .register => |tag| {
+            const aligned_size = try alignedSize(Register, variables.samples);
+            const offset = aligned_size * @intFromEnum(tag);
+            const slice = bytesAsSlice(Register, variables.bytes[offset..]);
+            return @alignCast(slice[0..variables.samples]);
+        },
+        .stack => unreachable,
+    }
 }