feat: cheaper runtime value type, float and int arithmetic rules

This commit is contained in:
Brett Broadhurst 2026-03-29 02:24:02 -06:00
parent 9b5cd4038f
commit 92e8bcd866
Failed to generate hash of commit
13 changed files with 630 additions and 448 deletions

View file

@ -20,7 +20,7 @@ const InnerError = error{
AnalysisFail,
TooManyConstants,
InvalidJump,
};
} || anyerror;
pub const ValueInfo = union(enum) {
none,
@ -34,9 +34,24 @@ pub const ValueInfo = union(enum) {
pub const Value = struct {
ip_index: InternPool.Index,
pub fn unwrap(value: Value, ip: *InternPool) u64 {
const t = ip.values.items[@intFromEnum(value.toInterned())];
return t.int;
pub const Unwrapped = union(enum) {
int: i64,
float: f64,
fn toFloat(v: Value.Unwrapped) f64 {
return switch (v) {
.int => |i| @floatFromInt(i),
.float => |f| f,
};
}
};
pub fn unwrap(value: Value, ip: *InternPool) Unwrapped {
switch (ip.values.items[@intFromEnum(value.toInterned())]) {
.int => |int| return .{ .int = int },
.float => |float| return .{ .float = @bitCast(float) },
.str => @panic("String unwrapping not implemented!"),
}
}
pub fn fromInterned(index: InternPool.Index) Value {
@ -264,12 +279,59 @@ pub const Builder = struct {
}
};
fn foldConstant(
lhs: Value.Unwrapped,
rhs: Value.Unwrapped,
op: Story.Opcode,
) !Value.Unwrapped {
if (lhs == .int and rhs == .int) {
switch (op) {
.add => return .{ .int = lhs.int +% rhs.int },
.sub => return .{ .int = lhs.int -% rhs.int },
.mul => return .{ .int = lhs.int *% rhs.int },
.div => {
if (rhs.int == 0)
return error.DivisionByZero;
return .{ .int = @divTrunc(lhs.int, rhs.int) };
},
.mod => if (rhs.int == 0)
return error.DivisionByZero
else
return .{ .int = @mod(lhs.int, rhs.int) },
else => unreachable,
}
}
const l = lhs.toFloat();
const r = rhs.toFloat();
switch (op) {
.add => return .{ .float = l + r },
.sub => return .{ .float = l - r },
.mul => return .{ .float = l * r },
.div => if (r == 0.0)
return error.DivisionByZero
else
return .{ .float = l / r },
.mod => if (r == 0.0)
return error.DivisionByZero
else
return .{ .float = @mod(l, r) },
else => unreachable,
}
}
fn irInt(sema: *Sema, inst: Ir.Inst.Index) InnerError!ValueInfo {
const value = sema.ir.instructions[@intFromEnum(inst)].data.int;
const ip_index = try sema.module.intern_pool.getOrPutInt(sema.gpa, value);
return .{ .value = ip_index };
}
fn irFloat(sema: *Sema, inst: Ir.Inst.Index) InnerError!ValueInfo {
const value = sema.ir.instructions[@intFromEnum(inst)].data.float;
const ip_index = try sema.module.intern_pool.getOrPutFloat(sema.gpa, value);
return .{ .value = ip_index };
}
fn irStr(sema: *Sema, inst: Ir.Inst.Index) InnerError!ValueInfo {
const data = sema.ir.instructions[@intFromEnum(inst)].data.str;
const ip_index = try sema.module.intern_pool.getOrPutStr(sema.gpa, data.start);
@ -282,6 +344,7 @@ fn irUnaryOp(
inst: Ir.Inst.Index,
op: Story.Opcode,
) InnerError!ValueInfo {
const gpa = sema.gpa;
const data = sema.ir.instructions[@intFromEnum(inst)].data.un;
const ip = &sema.module.intern_pool;
const lhs = sema.resolveInst(data.lhs);
@ -290,15 +353,24 @@ fn irUnaryOp(
if (sema.resolveValue(lhs)) |lhs_value| {
const lhs_unwrapped = lhs_value.unwrap(ip);
_ = lhs_unwrapped;
const new_value = switch (op) {
//.not => !lhs_unwrapped,
//.neg => -lhs_unwrapped,
else => unreachable,
};
return .{
.value = try ip.getOrPutInt(sema.gpa, new_value),
};
switch (lhs_unwrapped) {
.int => |int| {
const new_value = switch (op) {
.not => return error.TypeError,
.neg => -int,
else => unreachable,
};
return .{ .value = try ip.getOrPutInt(gpa, new_value) };
},
.float => |float| {
const new_value = switch (op) {
.not => return error.TypeError,
.neg => -float,
else => unreachable,
};
return .{ .value = try ip.getOrPutFloat(gpa, new_value) };
},
}
}
try builder.ensureLoad(lhs);
@ -323,18 +395,16 @@ fn irBinaryOp(
if (sema.resolveValue(lhs)) |lhs_value| {
if (sema.resolveValue(rhs)) |rhs_value| {
const lhs_unwrapped = lhs_value.unwrap(ip);
const rhs_unwrapped = rhs_value.unwrap(ip);
const new_value = switch (op) {
.add => lhs_unwrapped + rhs_unwrapped,
.sub => lhs_unwrapped - rhs_unwrapped,
.mul => lhs_unwrapped * rhs_unwrapped,
.div => lhs_unwrapped / rhs_unwrapped,
else => unreachable,
};
return .{
.value = try ip.getOrPutInt(sema.gpa, new_value),
};
const lhs_unwrap = lhs_value.unwrap(ip);
const rhs_unwrap = rhs_value.unwrap(ip);
switch (try foldConstant(lhs_unwrap, rhs_unwrap, op)) {
.int => |int| return .{
.value = try ip.getOrPutInt(sema.gpa, int),
},
.float => |float| return .{
.value = try ip.getOrPutFloat(sema.gpa, float),
},
}
}
}
@ -703,6 +773,7 @@ fn analyzeBodyInner(
},
.load => try irLoad(sema, builder, inst),
.int => try irInt(sema, inst),
.float => try irFloat(sema, inst),
.str => try irStr(sema, inst),
.add => try irBinaryOp(sema, builder, inst, .add),
.sub => try irBinaryOp(sema, builder, inst, .sub),