feat: cheaper runtime value type, float and int arithmetic rules
This commit is contained in:
parent
9b5cd4038f
commit
92e8bcd866
13 changed files with 630 additions and 448 deletions
121
src/Sema.zig
121
src/Sema.zig
|
|
@ -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),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue