stage2: rework Value Payload layout

This is the same as the previous commit but for Value instead of Type.

Add `Value.castTag` and note that it is preferable to call than
`Value.cast`. This matches other abstractions in the codebase.

Added a convenience function `Value.Tag.create` which really cleans up
the callsites of creating `Value` objects.

`Value` tags can now share payload types. This is in preparation for
another improvement that I want to do.
This commit is contained in:
Andrew Kelley
2020-12-30 22:31:56 -07:00
parent 133da8692e
commit 3f7d9b5fc1
12 changed files with 573 additions and 515 deletions

View File

@@ -1092,16 +1092,12 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
tvm.deinit(self.gpa);
}
const value_payload = try decl_arena.allocator.create(Value.Payload.ExternFn);
value_payload.* = .{ .decl = decl };
const fn_val = try Value.Tag.extern_fn.create(&decl_arena.allocator, decl);
decl_arena_state.* = decl_arena.state;
decl.typed_value = .{
.most_recent = .{
.typed_value = .{
.ty = fn_type,
.val = Value.initPayload(&value_payload.base),
},
.typed_value = .{ .ty = fn_type, .val = fn_val },
.arena = decl_arena_state,
},
};
@@ -1187,7 +1183,10 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
.analysis = .{ .queued = fn_zir },
.owner_decl = decl,
};
fn_payload.* = .{ .func = new_func };
fn_payload.* = .{
.base = .{ .tag = .function },
.data = new_func,
};
var prev_type_has_bits = false;
var type_changed = true;
@@ -1375,7 +1374,6 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
}
const new_variable = try decl_arena.allocator.create(Var);
const var_payload = try decl_arena.allocator.create(Value.Payload.Variable);
new_variable.* = .{
.owner_decl = decl,
.init = var_info.val orelse undefined,
@@ -1383,14 +1381,14 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
.is_mutable = is_mutable,
.is_threadlocal = is_threadlocal,
};
var_payload.* = .{ .variable = new_variable };
const var_val = try Value.Tag.variable.create(&decl_arena.allocator, new_variable);
decl_arena_state.* = decl_arena.state;
decl.typed_value = .{
.most_recent = .{
.typed_value = .{
.ty = var_info.ty,
.val = Value.initPayload(&var_payload.base),
.val = var_val,
},
.arena = decl_arena_state,
},
@@ -2232,52 +2230,43 @@ pub fn constBool(self: *Module, scope: *Scope, src: usize, v: bool) !*Inst {
}
pub fn constIntUnsigned(self: *Module, scope: *Scope, src: usize, ty: Type, int: u64) !*Inst {
const int_payload = try scope.arena().create(Value.Payload.Int_u64);
int_payload.* = .{ .int = int };
return self.constInst(scope, src, .{
.ty = ty,
.val = Value.initPayload(&int_payload.base),
.val = try Value.Tag.int_u64.create(scope.arena(), int),
});
}
pub fn constIntSigned(self: *Module, scope: *Scope, src: usize, ty: Type, int: i64) !*Inst {
const int_payload = try scope.arena().create(Value.Payload.Int_i64);
int_payload.* = .{ .int = int };
return self.constInst(scope, src, .{
.ty = ty,
.val = Value.initPayload(&int_payload.base),
.val = try Value.Tag.int_i64.create(scope.arena(), int),
});
}
pub fn constIntBig(self: *Module, scope: *Scope, src: usize, ty: Type, big_int: BigIntConst) !*Inst {
const val_payload = if (big_int.positive) blk: {
if (big_int.positive) {
if (big_int.to(u64)) |x| {
return self.constIntUnsigned(scope, src, ty, x);
} else |err| switch (err) {
error.NegativeIntoUnsigned => unreachable,
error.TargetTooSmall => {}, // handled below
}
const big_int_payload = try scope.arena().create(Value.Payload.IntBigPositive);
big_int_payload.* = .{ .limbs = big_int.limbs };
break :blk &big_int_payload.base;
} else blk: {
return self.constInst(scope, src, .{
.ty = ty,
.val = try Value.Tag.int_big_positive.create(scope.arena(), big_int.limbs),
});
} else {
if (big_int.to(i64)) |x| {
return self.constIntSigned(scope, src, ty, x);
} else |err| switch (err) {
error.NegativeIntoUnsigned => unreachable,
error.TargetTooSmall => {}, // handled below
}
const big_int_payload = try scope.arena().create(Value.Payload.IntBigNegative);
big_int_payload.* = .{ .limbs = big_int.limbs };
break :blk &big_int_payload.base;
};
return self.constInst(scope, src, .{
.ty = ty,
.val = Value.initPayload(val_payload),
});
return self.constInst(scope, src, .{
.ty = ty,
.val = try Value.Tag.int_big_negative.create(scope.arena(), big_int.limbs),
});
}
}
pub fn createAnonymousDecl(
@@ -2346,26 +2335,20 @@ pub fn analyzeDeclRef(self: *Module, scope: *Scope, src: usize, decl: *Decl) Inn
if (decl_tv.val.tag() == .variable) {
return self.analyzeVarRef(scope, src, decl_tv);
}
const ty = try self.simplePtrType(scope, src, decl_tv.ty, false, .One);
const val_payload = try scope.arena().create(Value.Payload.DeclRef);
val_payload.* = .{ .decl = decl };
return self.constInst(scope, src, .{
.ty = ty,
.val = Value.initPayload(&val_payload.base),
.ty = try self.simplePtrType(scope, src, decl_tv.ty, false, .One),
.val = try Value.Tag.decl_ref.create(scope.arena(), decl),
});
}
fn analyzeVarRef(self: *Module, scope: *Scope, src: usize, tv: TypedValue) InnerError!*Inst {
const variable = tv.val.cast(Value.Payload.Variable).?.variable;
const variable = tv.val.castTag(.variable).?.data;
const ty = try self.simplePtrType(scope, src, tv.ty, variable.is_mutable, .One);
if (!variable.is_mutable and !variable.is_extern) {
const val_payload = try scope.arena().create(Value.Payload.RefVal);
val_payload.* = .{ .val = variable.init };
return self.constInst(scope, src, .{
.ty = ty,
.val = Value.initPayload(&val_payload.base),
.val = try Value.Tag.ref_val.create(scope.arena(), variable.init),
});
}
@@ -3107,17 +3090,11 @@ pub fn intAdd(allocator: *Allocator, lhs: Value, rhs: Value) !Value {
result_bigint.add(lhs_bigint, rhs_bigint);
const result_limbs = result_bigint.limbs[0..result_bigint.len];
const val_payload = if (result_bigint.positive) blk: {
const val_payload = try allocator.create(Value.Payload.IntBigPositive);
val_payload.* = .{ .limbs = result_limbs };
break :blk &val_payload.base;
} else blk: {
const val_payload = try allocator.create(Value.Payload.IntBigNegative);
val_payload.* = .{ .limbs = result_limbs };
break :blk &val_payload.base;
};
return Value.initPayload(val_payload);
if (result_bigint.positive) {
return Value.Tag.int_big_positive.create(allocator, result_limbs);
} else {
return Value.Tag.int_big_negative.create(allocator, result_limbs);
}
}
pub fn intSub(allocator: *Allocator, lhs: Value, rhs: Value) !Value {
@@ -3135,85 +3112,81 @@ pub fn intSub(allocator: *Allocator, lhs: Value, rhs: Value) !Value {
result_bigint.sub(lhs_bigint, rhs_bigint);
const result_limbs = result_bigint.limbs[0..result_bigint.len];
const val_payload = if (result_bigint.positive) blk: {
const val_payload = try allocator.create(Value.Payload.IntBigPositive);
val_payload.* = .{ .limbs = result_limbs };
break :blk &val_payload.base;
} else blk: {
const val_payload = try allocator.create(Value.Payload.IntBigNegative);
val_payload.* = .{ .limbs = result_limbs };
break :blk &val_payload.base;
};
return Value.initPayload(val_payload);
if (result_bigint.positive) {
return Value.Tag.int_big_positive.create(allocator, result_limbs);
} else {
return Value.Tag.int_big_negative.create(allocator, result_limbs);
}
}
pub fn floatAdd(self: *Module, scope: *Scope, float_type: Type, src: usize, lhs: Value, rhs: Value) !Value {
var bit_count = switch (float_type.tag()) {
.comptime_float => 128,
else => float_type.floatBits(self.getTarget()),
};
const allocator = scope.arena();
const val_payload = switch (bit_count) {
16 => {
return self.fail(scope, src, "TODO Implement addition for soft floats", .{});
pub fn floatAdd(
self: *Module,
scope: *Scope,
float_type: Type,
src: usize,
lhs: Value,
rhs: Value,
) !Value {
const arena = scope.arena();
switch (float_type.tag()) {
.f16 => {
@panic("TODO add __trunctfhf2 to compiler-rt");
//const lhs_val = lhs.toFloat(f16);
//const rhs_val = rhs.toFloat(f16);
//return Value.Tag.float_16.create(arena, lhs_val + rhs_val);
},
32 => blk: {
.f32 => {
const lhs_val = lhs.toFloat(f32);
const rhs_val = rhs.toFloat(f32);
const val_payload = try allocator.create(Value.Payload.Float_32);
val_payload.* = .{ .val = lhs_val + rhs_val };
break :blk &val_payload.base;
return Value.Tag.float_32.create(arena, lhs_val + rhs_val);
},
64 => blk: {
.f64 => {
const lhs_val = lhs.toFloat(f64);
const rhs_val = rhs.toFloat(f64);
const val_payload = try allocator.create(Value.Payload.Float_64);
val_payload.* = .{ .val = lhs_val + rhs_val };
break :blk &val_payload.base;
return Value.Tag.float_64.create(arena, lhs_val + rhs_val);
},
128 => {
return self.fail(scope, src, "TODO Implement addition for big floats", .{});
.f128, .comptime_float, .c_longdouble => {
const lhs_val = lhs.toFloat(f128);
const rhs_val = rhs.toFloat(f128);
return Value.Tag.float_128.create(arena, lhs_val + rhs_val);
},
else => unreachable,
};
return Value.initPayload(val_payload);
}
}
pub fn floatSub(self: *Module, scope: *Scope, float_type: Type, src: usize, lhs: Value, rhs: Value) !Value {
var bit_count = switch (float_type.tag()) {
.comptime_float => 128,
else => float_type.floatBits(self.getTarget()),
};
const allocator = scope.arena();
const val_payload = switch (bit_count) {
16 => {
return self.fail(scope, src, "TODO Implement substraction for soft floats", .{});
pub fn floatSub(
self: *Module,
scope: *Scope,
float_type: Type,
src: usize,
lhs: Value,
rhs: Value,
) !Value {
const arena = scope.arena();
switch (float_type.tag()) {
.f16 => {
@panic("TODO add __trunctfhf2 to compiler-rt");
//const lhs_val = lhs.toFloat(f16);
//const rhs_val = rhs.toFloat(f16);
//return Value.Tag.float_16.create(arena, lhs_val - rhs_val);
},
32 => blk: {
.f32 => {
const lhs_val = lhs.toFloat(f32);
const rhs_val = rhs.toFloat(f32);
const val_payload = try allocator.create(Value.Payload.Float_32);
val_payload.* = .{ .val = lhs_val - rhs_val };
break :blk &val_payload.base;
return Value.Tag.float_32.create(arena, lhs_val - rhs_val);
},
64 => blk: {
.f64 => {
const lhs_val = lhs.toFloat(f64);
const rhs_val = rhs.toFloat(f64);
const val_payload = try allocator.create(Value.Payload.Float_64);
val_payload.* = .{ .val = lhs_val - rhs_val };
break :blk &val_payload.base;
return Value.Tag.float_64.create(arena, lhs_val - rhs_val);
},
128 => {
return self.fail(scope, src, "TODO Implement substraction for big floats", .{});
.f128, .comptime_float, .c_longdouble => {
const lhs_val = lhs.toFloat(f128);
const rhs_val = rhs.toFloat(f128);
return Value.Tag.float_128.create(arena, lhs_val - rhs_val);
},
else => unreachable,
};
return Value.initPayload(val_payload);
}
}
pub fn simplePtrType(self: *Module, scope: *Scope, src: usize, elem_ty: Type, mutable: bool, size: std.builtin.TypeInfo.Pointer.Size) Allocator.Error!Type {