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

@ -1457,11 +1457,12 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
.complete, .codegen_failure_retryable => {
const module = self.bin_file.options.module.?;
if (decl.typed_value.most_recent.typed_value.val.cast(Value.Payload.Function)) |payload| {
switch (payload.func.analysis) {
.queued => module.analyzeFnBody(decl, payload.func) catch |err| switch (err) {
if (decl.typed_value.most_recent.typed_value.val.castTag(.function)) |payload| {
const func = payload.data;
switch (func.analysis) {
.queued => module.analyzeFnBody(decl, func) catch |err| switch (err) {
error.AnalysisFail => {
assert(payload.func.analysis != .in_progress);
assert(func.analysis != .in_progress);
continue;
},
error.OutOfMemory => return error.OutOfMemory,
@ -1475,7 +1476,7 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
var decl_arena = decl.typed_value.most_recent.arena.?.promote(module.gpa);
defer decl.typed_value.most_recent.arena.?.* = decl_arena.state;
log.debug("analyze liveness of {}\n", .{decl.name});
try liveness.analyze(module.gpa, &decl_arena.allocator, payload.func.analysis.success);
try liveness.analyze(module.gpa, &decl_arena.allocator, func.analysis.success);
}
assert(decl.typed_value.most_recent.typed_value.ty.hasCodeGenBits());

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 {

View File

@ -1956,13 +1956,13 @@ fn identifier(mod: *Module, scope: *Scope, rl: ResultLoc, ident: *ast.Node.OneTo
32 => if (is_signed) Value.initTag(.i32_type) else Value.initTag(.u32_type),
64 => if (is_signed) Value.initTag(.i64_type) else Value.initTag(.u64_type),
else => {
const int_type_payload = try scope.arena().create(Value.Payload.IntType);
int_type_payload.* = .{ .signed = is_signed, .bits = bit_count };
const result = try addZIRInstConst(mod, scope, src, .{
return rlWrap(mod, scope, rl, try addZIRInstConst(mod, scope, src, .{
.ty = Type.initTag(.type),
.val = Value.initPayload(&int_type_payload.base),
});
return rlWrap(mod, scope, rl, result);
.val = try Value.Tag.int_type.create(scope.arena(), .{
.signed = is_signed,
.bits = bit_count,
}),
}));
},
};
const result = try addZIRInstConst(mod, scope, src, .{
@ -2062,11 +2062,9 @@ fn charLiteral(mod: *Module, scope: *Scope, node: *ast.Node.OneToken) !*zir.Inst
},
};
const int_payload = try scope.arena().create(Value.Payload.Int_u64);
int_payload.* = .{ .int = value };
return addZIRInstConst(mod, scope, src, .{
.ty = Type.initTag(.comptime_int),
.val = Value.initPayload(&int_payload.base),
.val = try Value.Tag.int_u64.create(scope.arena(), value),
});
}
@ -2089,12 +2087,10 @@ fn integerLiteral(mod: *Module, scope: *Scope, int_lit: *ast.Node.OneToken) Inne
prefixed_bytes[2..];
if (std.fmt.parseInt(u64, bytes, base)) |small_int| {
const int_payload = try arena.create(Value.Payload.Int_u64);
int_payload.* = .{ .int = small_int };
const src = tree.token_locs[int_lit.token].start;
return addZIRInstConst(mod, scope, src, .{
.ty = Type.initTag(.comptime_int),
.val = Value.initPayload(&int_payload.base),
.val = try Value.Tag.int_u64.create(arena, small_int),
});
} else |err| {
return mod.failTok(scope, int_lit.token, "TODO implement int literals that don't fit in a u64", .{});
@ -2109,15 +2105,13 @@ fn floatLiteral(mod: *Module, scope: *Scope, float_lit: *ast.Node.OneToken) Inne
return mod.failTok(scope, float_lit.token, "TODO hex floats", .{});
}
const val = std.fmt.parseFloat(f128, bytes) catch |e| switch (e) {
const float_number = std.fmt.parseFloat(f128, bytes) catch |e| switch (e) {
error.InvalidCharacter => unreachable, // validated by tokenizer
};
const float_payload = try arena.create(Value.Payload.Float_128);
float_payload.* = .{ .val = val };
const src = tree.token_locs[float_lit.token].start;
return addZIRInstConst(mod, scope, src, .{
.ty = Type.initTag(.comptime_float),
.val = Value.initPayload(&float_payload.base),
.val = try Value.Tag.float_128.create(arena, float_number),
});
}

View File

@ -137,7 +137,7 @@ pub fn generateSymbol(
},
.Array => {
// TODO populate .debug_info for the array
if (typed_value.val.cast(Value.Payload.Bytes)) |payload| {
if (typed_value.val.castTag(.bytes)) |payload| {
if (typed_value.ty.sentinel()) |sentinel| {
try code.ensureCapacity(code.items.len + payload.data.len + 1);
code.appendSliceAssumeCapacity(payload.data);
@ -168,8 +168,8 @@ pub fn generateSymbol(
},
.Pointer => {
// TODO populate .debug_info for the pointer
if (typed_value.val.cast(Value.Payload.DeclRef)) |payload| {
const decl = payload.decl;
if (typed_value.val.castTag(.decl_ref)) |payload| {
const decl = payload.data;
if (decl.analysis != .complete) return error.AnalysisFail;
// TODO handle the dependency of this symbol on the decl's vaddr.
// If the decl changes vaddr, then this symbol needs to get regenerated.
@ -432,7 +432,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
@panic("Attempted to compile for architecture that was disabled by build configuration");
}
const module_fn = typed_value.val.cast(Value.Payload.Function).?.func;
const module_fn = typed_value.val.castTag(.function).?.data;
const fn_type = module_fn.owner_decl.typed_value.most_recent.typed_value.ty;
@ -1579,9 +1579,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
}
}
if (inst.func.cast(ir.Inst.Constant)) |func_inst| {
if (func_inst.val.cast(Value.Payload.Function)) |func_val| {
const func = func_val.func;
if (inst.func.value()) |func_value| {
if (func_value.castTag(.function)) |func_payload| {
const func = func_payload.data;
const ptr_bits = self.target.cpu.arch.ptrBitWidth();
const ptr_bytes: u64 = @divExact(ptr_bits, 8);
@ -1607,9 +1607,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
.riscv64 => {
if (info.args.len > 0) return self.fail(inst.base.src, "TODO implement fn args for {}", .{self.target.cpu.arch});
if (inst.func.cast(ir.Inst.Constant)) |func_inst| {
if (func_inst.val.cast(Value.Payload.Function)) |func_val| {
const func = func_val.func;
if (inst.func.value()) |func_value| {
if (func_value.castTag(.function)) |func_payload| {
const func = func_payload.data;
const ptr_bits = self.target.cpu.arch.ptrBitWidth();
const ptr_bytes: u64 = @divExact(ptr_bits, 8);
@ -1631,12 +1631,12 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
}
},
.spu_2 => {
if (inst.func.cast(ir.Inst.Constant)) |func_inst| {
if (inst.func.value()) |func_value| {
if (info.args.len != 0) {
return self.fail(inst.base.src, "TODO implement call with more than 0 parameters", .{});
}
if (func_inst.val.cast(Value.Payload.Function)) |func_val| {
const func = func_val.func;
if (func_value.castTag(.function)) |func_payload| {
const func = func_payload.data;
const got_addr = if (self.bin_file.cast(link.File.Elf)) |elf_file| blk: {
const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];
break :blk @intCast(u16, got.p_vaddr + func.owner_decl.link.elf.offset_table_index * 2);
@ -1705,9 +1705,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
}
}
if (inst.func.cast(ir.Inst.Constant)) |func_inst| {
if (func_inst.val.cast(Value.Payload.Function)) |func_val| {
const func = func_val.func;
if (inst.func.value()) |func_value| {
if (func_value.castTag(.function)) |func_payload| {
const func = func_payload.data;
const ptr_bits = self.target.cpu.arch.ptrBitWidth();
const ptr_bytes: u64 = @divExact(ptr_bits, 8);
const got_addr = if (self.bin_file.cast(link.File.Elf)) |elf_file| blk: {
@ -1766,9 +1766,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
}
}
if (inst.func.cast(ir.Inst.Constant)) |func_inst| {
if (func_inst.val.cast(Value.Payload.Function)) |func_val| {
const func = func_val.func;
if (inst.func.value()) |func_value| {
if (func_value.castTag(.function)) |func_payload| {
const func = func_payload.data;
const ptr_bits = self.target.cpu.arch.ptrBitWidth();
const ptr_bytes: u64 = @divExact(ptr_bits, 8);
const got_addr = if (self.bin_file.cast(link.File.Elf)) |elf_file| blk: {
@ -1825,9 +1825,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
}
}
if (inst.func.cast(ir.Inst.Constant)) |func_inst| {
if (func_inst.val.cast(Value.Payload.Function)) |func_val| {
const func = func_val.func;
if (inst.func.value()) |func_value| {
if (func_value.castTag(.function)) |func_payload| {
const func = func_payload.data;
const text_segment = &macho_file.load_commands.items[macho_file.text_segment_cmd_index.?].Segment;
const got = &text_segment.sections.items[macho_file.got_section_index.?];
const got_addr = got.addr + func.owner_decl.link.macho.offset_table_index * @sizeOf(u64);
@ -3223,20 +3223,20 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
const ptr_bytes: u64 = @divExact(ptr_bits, 8);
switch (typed_value.ty.zigTypeTag()) {
.Pointer => {
if (typed_value.val.cast(Value.Payload.DeclRef)) |payload| {
if (typed_value.val.castTag(.decl_ref)) |payload| {
if (self.bin_file.cast(link.File.Elf)) |elf_file| {
const decl = payload.decl;
const decl = payload.data;
const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];
const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes;
return MCValue{ .memory = got_addr };
} else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
const decl = payload.decl;
const decl = payload.data;
const text_segment = &macho_file.load_commands.items[macho_file.text_segment_cmd_index.?].Segment;
const got = &text_segment.sections.items[macho_file.got_section_index.?];
const got_addr = got.addr + decl.link.macho.offset_table_index * ptr_bytes;
return MCValue{ .memory = got_addr };
} else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
const decl = payload.decl;
const decl = payload.data;
const got_addr = coff_file.offset_table_virtual_address + decl.link.coff.offset_table_index * ptr_bytes;
return MCValue{ .memory = got_addr };
} else {

View File

@ -138,25 +138,25 @@ fn renderValue(
.undef, .zero => try writer.writeAll("0"),
.one => try writer.writeAll("1"),
.decl_ref => {
const decl_ref_payload = val.cast(Value.Payload.DeclRef).?;
const decl = val.castTag(.decl_ref).?.data;
// Determine if we must pointer cast.
const decl_tv = decl_ref_payload.decl.typed_value.most_recent.typed_value;
const decl_tv = decl.typed_value.most_recent.typed_value;
if (t.eql(decl_tv.ty)) {
try writer.print("&{s}", .{decl_ref_payload.decl.name});
try writer.print("&{s}", .{decl.name});
} else {
try writer.writeAll("(");
try renderType(ctx, writer, t);
try writer.print(")&{s}", .{decl_ref_payload.decl.name});
try writer.print(")&{s}", .{decl.name});
}
},
.function => {
const payload = val.cast(Value.Payload.Function).?;
try writer.print("{s}", .{payload.func.owner_decl.name});
const func = val.castTag(.function).?.data;
try writer.print("{s}", .{func.owner_decl.name});
},
.extern_fn => {
const payload = val.cast(Value.Payload.ExternFn).?;
try writer.print("{s}", .{payload.decl.name});
const decl = val.castTag(.extern_fn).?.data;
try writer.print("{s}", .{decl.name});
},
else => |e| return ctx.fail(
ctx.decl.src(),
@ -169,7 +169,7 @@ fn renderValue(
switch (val.tag()) {
.undef, .empty_struct_value, .empty_array => try writer.writeAll("{}"),
.bytes => {
const bytes = val.cast(Value.Payload.Bytes).?.data;
const bytes = val.castTag(.bytes).?.data;
// TODO: make our own C string escape instead of using {Z}
try writer.print("\"{Z}\"", .{bytes});
},
@ -209,7 +209,7 @@ fn renderFunctionSignature(
switch (tv.val.tag()) {
.extern_fn => break :blk true,
.function => {
const func = tv.val.cast(Value.Payload.Function).?.func;
const func = tv.val.castTag(.function).?.data;
break :blk ctx.module.decl_exports.contains(func.owner_decl);
},
else => unreachable,
@ -268,13 +268,13 @@ pub fn generate(file: *C, module: *Module, decl: *Decl) !void {
ctx.deinit();
}
if (tv.val.cast(Value.Payload.Function)) |func_payload| {
if (tv.val.castTag(.function)) |func_payload| {
const writer = file.main.writer();
try renderFunctionSignature(&ctx, writer, decl);
try writer.writeAll(" {");
const func: *Module.Fn = func_payload.func;
const func: *Module.Fn = func_payload.data;
const instructions = func.analysis.success.instructions;
if (instructions.len > 0) {
try writer.writeAll("\n");
@ -480,10 +480,10 @@ fn genCall(ctx: *Context, file: *C, inst: *Inst.Call) !?[]u8 {
const writer = file.main.writer();
const header = file.header.buf.writer();
if (inst.func.castTag(.constant)) |func_inst| {
const fn_decl = if (func_inst.val.cast(Value.Payload.ExternFn)) |extern_fn|
extern_fn.decl
else if (func_inst.val.cast(Value.Payload.Function)) |func_val|
func_val.func.owner_decl
const fn_decl = if (func_inst.val.castTag(.extern_fn)) |extern_fn|
extern_fn.data
else if (func_inst.val.castTag(.function)) |func_payload|
func_payload.data.owner_decl
else
unreachable;
@ -513,8 +513,8 @@ fn genCall(ctx: *Context, file: *C, inst: *Inst.Call) !?[]u8 {
if (i > 0) {
try writer.writeAll(", ");
}
if (arg.cast(Inst.Constant)) |con| {
try renderValue(ctx, writer, arg.ty, con.val);
if (arg.value()) |val| {
try renderValue(ctx, writer, arg.ty, val);
} else {
const val = try ctx.resolveInst(arg);
try writer.print("{}", .{val});

View File

@ -62,7 +62,7 @@ pub fn genCode(buf: *ArrayList(u8), decl: *Decl) !void {
// Write instructions
// TODO: check for and handle death of instructions
const tv = decl.typed_value.most_recent.typed_value;
const mod_fn = tv.val.cast(Value.Payload.Function).?.func;
const mod_fn = tv.val.castTag(.function).?.data;
for (mod_fn.analysis.success.instructions) |inst| try genInst(buf, decl, inst);
// Write 'end' opcode
@ -125,8 +125,8 @@ fn genRet(buf: *ArrayList(u8), decl: *Decl, inst: *Inst.UnOp) !void {
fn genCall(buf: *ArrayList(u8), decl: *Decl, inst: *Inst.Call) !void {
const func_inst = inst.func.castTag(.constant).?;
const func_val = func_inst.val.cast(Value.Payload.Function).?;
const target = func_val.func.owner_decl;
const func = func_inst.val.castTag(.function).?.data;
const target = func.owner_decl;
const target_ty = target.typed_value.most_recent.typed_value.ty;
if (inst.args.len != 0) return error.TODOImplementMoreWasmCodegen;

View File

@ -2183,7 +2183,7 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void {
for (zir_dumps) |fn_name| {
if (mem.eql(u8, mem.spanZ(decl.name), fn_name)) {
std.debug.print("\n{}\n", .{decl.name});
typed_value.val.cast(Value.Payload.Function).?.func.dump(module.*);
typed_value.val.castTag(.function).?.data.dump(module.*);
}
}
}

View File

@ -280,7 +280,7 @@ pub const LLVMIRModule = struct {
fn gen(self: *LLVMIRModule, module: *Module, typed_value: TypedValue, src: usize) !void {
switch (typed_value.ty.zigTypeTag()) {
.Fn => {
const func = typed_value.val.cast(Value.Payload.Function).?.func;
const func = typed_value.val.castTag(.function).?.data;
const llvm_func = try self.resolveLLVMFunction(func);
@ -314,9 +314,9 @@ pub const LLVMIRModule = struct {
}
fn genCall(self: *LLVMIRModule, inst: *Inst.Call) !void {
if (inst.func.cast(Inst.Constant)) |func_inst| {
if (func_inst.val.cast(Value.Payload.Function)) |func_val| {
const func = func_val.func;
if (inst.func.value()) |func_value| {
if (func_value.castTag(.function)) |func_payload| {
const func = func_payload.data;
const zig_fn_type = func.owner_decl.typed_value.most_recent.typed_value.ty;
const llvm_fn = try self.resolveLLVMFunction(func);

View File

@ -733,11 +733,7 @@ pub const Type = extern union {
.single_const_pointer_to_comptime_int => return Value.initTag(.single_const_pointer_to_comptime_int_type),
.const_slice_u8 => return Value.initTag(.const_slice_u8_type),
.enum_literal => return Value.initTag(.enum_literal_type),
else => {
const ty_payload = try allocator.create(Value.Payload.Ty);
ty_payload.* = .{ .ty = self };
return Value.initPayload(&ty_payload.base);
},
else => return Value.Tag.ty.create(allocator, self),
}
}
@ -2951,11 +2947,8 @@ pub const Type = extern union {
}
if ((info.bits - 1) <= std.math.maxInt(u6)) {
const payload = try arena.allocator.create(Value.Payload.Int_i64);
payload.* = .{
.int = -(@as(i64, 1) << @truncate(u6, info.bits - 1)),
};
return Value.initPayload(&payload.base);
const n: i64 = -(@as(i64, 1) << @truncate(u6, info.bits - 1));
return Value.Tag.int_i64.create(&arena.allocator, n);
}
var res = try std.math.big.int.Managed.initSet(&arena.allocator, 1);
@ -2964,13 +2957,9 @@ pub const Type = extern union {
const res_const = res.toConst();
if (res_const.positive) {
const val_payload = try arena.allocator.create(Value.Payload.IntBigPositive);
val_payload.* = .{ .limbs = res_const.limbs };
return Value.initPayload(&val_payload.base);
return Value.Tag.int_big_positive.create(&arena.allocator, res_const.limbs);
} else {
const val_payload = try arena.allocator.create(Value.Payload.IntBigNegative);
val_payload.* = .{ .limbs = res_const.limbs };
return Value.initPayload(&val_payload.base);
return Value.Tag.int_big_negative.create(&arena.allocator, res_const.limbs);
}
}
@ -2980,17 +2969,11 @@ pub const Type = extern union {
const info = self.intInfo(target);
if (info.signedness == .signed and (info.bits - 1) <= std.math.maxInt(u6)) {
const payload = try arena.allocator.create(Value.Payload.Int_i64);
payload.* = .{
.int = (@as(i64, 1) << @truncate(u6, info.bits - 1)) - 1,
};
return Value.initPayload(&payload.base);
const n: i64 = (@as(i64, 1) << @truncate(u6, info.bits - 1)) - 1;
return Value.Tag.int_i64.create(&arena.allocator, n);
} else if (info.signedness == .signed and info.bits <= std.math.maxInt(u6)) {
const payload = try arena.allocator.create(Value.Payload.Int_u64);
payload.* = .{
.int = (@as(u64, 1) << @truncate(u6, info.bits)) - 1,
};
return Value.initPayload(&payload.base);
const n: u64 = (@as(u64, 1) << @truncate(u6, info.bits)) - 1;
return Value.Tag.int_u64.create(&arena.allocator, n);
}
var res = try std.math.big.int.Managed.initSet(&arena.allocator, 1);
@ -3003,13 +2986,9 @@ pub const Type = extern union {
const res_const = res.toConst();
if (res_const.positive) {
const val_payload = try arena.allocator.create(Value.Payload.IntBigPositive);
val_payload.* = .{ .limbs = res_const.limbs };
return Value.initPayload(&val_payload.base);
return Value.Tag.int_big_positive.create(&arena.allocator, res_const.limbs);
} else {
const val_payload = try arena.allocator.create(Value.Payload.IntBigNegative);
val_payload.* = .{ .limbs = res_const.limbs };
return Value.initPayload(&val_payload.base);
return Value.Tag.int_big_negative.create(&arena.allocator, res_const.limbs);
}
}

View File

@ -84,11 +84,16 @@ pub const Value = extern union {
function,
extern_fn,
variable,
/// Represents a pointer to another immutable value.
ref_val,
/// Represents a pointer to a decl, not the value of the decl.
decl_ref,
elem_ptr,
/// A slice of u8 whose memory is managed externally.
bytes,
repeated, // the value is a value repeated some number of times
/// This value is repeated some number of times. The amount of times to repeat
/// is stored externally.
repeated,
float_16,
float_32,
float_64,
@ -99,6 +104,106 @@ pub const Value = extern union {
pub const last_no_payload_tag = Tag.bool_false;
pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;
pub fn Type(comptime t: Tag) type {
return switch (t) {
.u8_type,
.i8_type,
.u16_type,
.i16_type,
.u32_type,
.i32_type,
.u64_type,
.i64_type,
.usize_type,
.isize_type,
.c_short_type,
.c_ushort_type,
.c_int_type,
.c_uint_type,
.c_long_type,
.c_ulong_type,
.c_longlong_type,
.c_ulonglong_type,
.c_longdouble_type,
.f16_type,
.f32_type,
.f64_type,
.f128_type,
.c_void_type,
.bool_type,
.void_type,
.type_type,
.anyerror_type,
.comptime_int_type,
.comptime_float_type,
.noreturn_type,
.null_type,
.undefined_type,
.fn_noreturn_no_args_type,
.fn_void_no_args_type,
.fn_naked_noreturn_no_args_type,
.fn_ccc_void_no_args_type,
.single_const_pointer_to_comptime_int_type,
.const_slice_u8_type,
.enum_literal_type,
.anyframe_type,
.undef,
.zero,
.one,
.void_value,
.unreachable_value,
.empty_struct_value,
.empty_array,
.null_value,
.bool_true,
.bool_false,
=> @compileError("Value Tag " ++ @tagName(t) ++ " has no payload"),
.int_big_positive,
.int_big_negative,
=> Payload.BigInt,
.extern_fn,
.decl_ref,
=> Payload.Decl,
.ref_val,
.repeated,
=> Payload.SubValue,
.bytes,
.enum_literal,
=> Payload.Bytes,
.ty => Payload.Ty,
.int_type => Payload.IntType,
.int_u64 => Payload.U64,
.int_i64 => Payload.I64,
.function => Payload.Function,
.variable => Payload.Variable,
.elem_ptr => Payload.ElemPtr,
.float_16 => Payload.Float_16,
.float_32 => Payload.Float_32,
.float_64 => Payload.Float_64,
.float_128 => Payload.Float_128,
.error_set => Payload.ErrorSet,
.@"error" => Payload.Error,
};
}
pub fn create(comptime t: Tag, ally: *Allocator, data: Data(t)) error{OutOfMemory}!Value {
const ptr = try ally.create(t.Type());
ptr.* = .{
.base = .{ .tag = t },
.data = data,
};
return Value{ .ptr_otherwise = &ptr.base };
}
pub fn Data(comptime t: Tag) type {
return std.meta.fieldInfo(t.Type(), "data").field_type;
}
};
pub fn initTag(small_tag: Tag) Value {
@ -119,15 +224,36 @@ pub const Value = extern union {
}
}
/// Prefer `castTag` to this.
pub fn cast(self: Value, comptime T: type) ?*T {
if (@hasField(T, "base_tag")) {
return base.castTag(T.base_tag);
}
if (self.tag_if_small_enough < Tag.no_payload_count) {
return null;
}
inline for (@typeInfo(Tag).Enum.fields) |field| {
if (field.value < Tag.no_payload_count)
continue;
const t = @intToEnum(Tag, field.value);
if (self.ptr_otherwise.tag == t) {
if (T == t.Type()) {
return @fieldParentPtr(T, "base", self.ptr_otherwise);
}
return null;
}
}
unreachable;
}
pub fn castTag(self: Value, comptime t: Tag) ?*t.Type() {
if (self.tag_if_small_enough < Tag.no_payload_count)
return null;
const expected_tag = std.meta.fieldInfo(T, "base").default_value.?.tag;
if (self.ptr_otherwise.tag != expected_tag)
return null;
if (self.ptr_otherwise.tag == t)
return @fieldParentPtr(t.Type(), "base", self.ptr_otherwise);
return @fieldParentPtr(T, "base", self.ptr_otherwise);
return null;
}
pub fn copy(self: Value, allocator: *Allocator) error{OutOfMemory}!Value {
@ -188,17 +314,17 @@ pub const Value = extern union {
=> unreachable,
.ty => {
const payload = @fieldParentPtr(Payload.Ty, "base", self.ptr_otherwise);
const payload = self.castTag(.ty).?;
const new_payload = try allocator.create(Payload.Ty);
new_payload.* = .{
.base = payload.base,
.ty = try payload.ty.copy(allocator),
.data = try payload.data.copy(allocator),
};
return Value{ .ptr_otherwise = &new_payload.base };
},
.int_type => return self.copyPayloadShallow(allocator, Payload.IntType),
.int_u64 => return self.copyPayloadShallow(allocator, Payload.Int_u64),
.int_i64 => return self.copyPayloadShallow(allocator, Payload.Int_i64),
.int_u64 => return self.copyPayloadShallow(allocator, Payload.U64),
.int_i64 => return self.copyPayloadShallow(allocator, Payload.I64),
.int_big_positive => {
@panic("TODO implement copying of big ints");
},
@ -206,35 +332,37 @@ pub const Value = extern union {
@panic("TODO implement copying of big ints");
},
.function => return self.copyPayloadShallow(allocator, Payload.Function),
.extern_fn => return self.copyPayloadShallow(allocator, Payload.ExternFn),
.extern_fn => return self.copyPayloadShallow(allocator, Payload.Decl),
.variable => return self.copyPayloadShallow(allocator, Payload.Variable),
.ref_val => {
const payload = @fieldParentPtr(Payload.RefVal, "base", self.ptr_otherwise);
const new_payload = try allocator.create(Payload.RefVal);
const payload = self.castTag(.ref_val).?;
const new_payload = try allocator.create(Payload.SubValue);
new_payload.* = .{
.base = payload.base,
.val = try payload.val.copy(allocator),
.data = try payload.data.copy(allocator),
};
return Value{ .ptr_otherwise = &new_payload.base };
},
.decl_ref => return self.copyPayloadShallow(allocator, Payload.DeclRef),
.decl_ref => return self.copyPayloadShallow(allocator, Payload.Decl),
.elem_ptr => {
const payload = @fieldParentPtr(Payload.ElemPtr, "base", self.ptr_otherwise);
const payload = self.castTag(.elem_ptr).?;
const new_payload = try allocator.create(Payload.ElemPtr);
new_payload.* = .{
.base = payload.base,
.array_ptr = try payload.array_ptr.copy(allocator),
.index = payload.index,
.data = .{
.array_ptr = try payload.data.array_ptr.copy(allocator),
.index = payload.data.index,
},
};
return Value{ .ptr_otherwise = &new_payload.base };
},
.bytes => return self.copyPayloadShallow(allocator, Payload.Bytes),
.repeated => {
const payload = @fieldParentPtr(Payload.Repeated, "base", self.ptr_otherwise);
const new_payload = try allocator.create(Payload.Repeated);
const payload = self.castTag(.repeated).?;
const new_payload = try allocator.create(Payload.SubValue);
new_payload.* = .{
.base = payload.base,
.val = try payload.val.copy(allocator),
.data = try payload.data.copy(allocator),
};
return Value{ .ptr_otherwise = &new_payload.base };
},
@ -243,7 +371,7 @@ pub const Value = extern union {
.float_64 => return self.copyPayloadShallow(allocator, Payload.Float_64),
.float_128 => return self.copyPayloadShallow(allocator, Payload.Float_128),
.enum_literal => {
const payload = @fieldParentPtr(Payload.Bytes, "base", self.ptr_otherwise);
const payload = self.castTag(.enum_literal).?;
const new_payload = try allocator.create(Payload.Bytes);
new_payload.* = .{
.base = payload.base,
@ -259,7 +387,7 @@ pub const Value = extern union {
}
fn copyPayloadShallow(self: Value, allocator: *Allocator, comptime T: type) error{OutOfMemory}!Value {
const payload = @fieldParentPtr(T, "base", self.ptr_otherwise);
const payload = self.cast(T).?;
const new_payload = try allocator.create(T);
new_payload.* = payload.*;
return Value{ .ptr_otherwise = &new_payload.base };
@ -326,45 +454,45 @@ pub const Value = extern union {
.unreachable_value => return out_stream.writeAll("unreachable"),
.bool_true => return out_stream.writeAll("true"),
.bool_false => return out_stream.writeAll("false"),
.ty => return val.cast(Payload.Ty).?.ty.format("", options, out_stream),
.ty => return val.castTag(.ty).?.data.format("", options, out_stream),
.int_type => {
const int_type = val.cast(Payload.IntType).?;
const int_type = val.castTag(.int_type).?.data;
return out_stream.print("{}{}", .{
if (int_type.signed) "s" else "u",
int_type.bits,
});
},
.int_u64 => return std.fmt.formatIntValue(val.cast(Payload.Int_u64).?.int, "", options, out_stream),
.int_i64 => return std.fmt.formatIntValue(val.cast(Payload.Int_i64).?.int, "", options, out_stream),
.int_big_positive => return out_stream.print("{}", .{val.cast(Payload.IntBigPositive).?.asBigInt()}),
.int_big_negative => return out_stream.print("{}", .{val.cast(Payload.IntBigNegative).?.asBigInt()}),
.int_u64 => return std.fmt.formatIntValue(val.castTag(.int_u64).?.data, "", options, out_stream),
.int_i64 => return std.fmt.formatIntValue(val.castTag(.int_i64).?.data, "", options, out_stream),
.int_big_positive => return out_stream.print("{}", .{val.castTag(.int_big_positive).?.asBigInt()}),
.int_big_negative => return out_stream.print("{}", .{val.castTag(.int_big_negative).?.asBigInt()}),
.function => return out_stream.writeAll("(function)"),
.extern_fn => return out_stream.writeAll("(extern function)"),
.variable => return out_stream.writeAll("(variable)"),
.ref_val => {
const ref_val = val.cast(Payload.RefVal).?;
const ref_val = val.castTag(.ref_val).?.data;
try out_stream.writeAll("&const ");
val = ref_val.val;
val = ref_val;
},
.decl_ref => return out_stream.writeAll("(decl ref)"),
.elem_ptr => {
const elem_ptr = val.cast(Payload.ElemPtr).?;
const elem_ptr = val.castTag(.elem_ptr).?.data;
try out_stream.print("&[{}] ", .{elem_ptr.index});
val = elem_ptr.array_ptr;
},
.empty_array => return out_stream.writeAll(".{}"),
.enum_literal => return out_stream.print(".{z}", .{self.cast(Payload.Bytes).?.data}),
.bytes => return out_stream.print("\"{Z}\"", .{self.cast(Payload.Bytes).?.data}),
.enum_literal => return out_stream.print(".{z}", .{self.castTag(.enum_literal).?.data}),
.bytes => return out_stream.print("\"{Z}\"", .{self.castTag(.bytes).?.data}),
.repeated => {
try out_stream.writeAll("(repeated) ");
val = val.cast(Payload.Repeated).?.val;
val = val.castTag(.repeated).?.data;
},
.float_16 => return out_stream.print("{}", .{val.cast(Payload.Float_16).?.val}),
.float_32 => return out_stream.print("{}", .{val.cast(Payload.Float_32).?.val}),
.float_64 => return out_stream.print("{}", .{val.cast(Payload.Float_64).?.val}),
.float_128 => return out_stream.print("{}", .{val.cast(Payload.Float_128).?.val}),
.float_16 => return out_stream.print("{}", .{val.castTag(.float_16).?.data}),
.float_32 => return out_stream.print("{}", .{val.castTag(.float_32).?.data}),
.float_64 => return out_stream.print("{}", .{val.castTag(.float_64).?.data}),
.float_128 => return out_stream.print("{}", .{val.castTag(.float_128).?.data}),
.error_set => {
const error_set = val.cast(Payload.ErrorSet).?;
const error_set = val.castTag(.error_set).?.data;
try out_stream.writeAll("error{");
var it = error_set.fields.iterator();
while (it.next()) |entry| {
@ -372,21 +500,24 @@ pub const Value = extern union {
}
return out_stream.writeAll("}");
},
.@"error" => return out_stream.print("error.{}", .{val.cast(Payload.Error).?.name}),
.@"error" => return out_stream.print("error.{}", .{val.castTag(.@"error").?.data.name}),
};
}
/// Asserts that the value is representable as an array of bytes.
/// Copies the value into a freshly allocated slice of memory, which is owned by the caller.
pub fn toAllocatedBytes(self: Value, allocator: *Allocator) ![]u8 {
if (self.cast(Payload.Bytes)) |bytes| {
return std.mem.dupe(allocator, u8, bytes.data);
if (self.castTag(.bytes)) |payload| {
return std.mem.dupe(allocator, u8, payload.data);
}
if (self.cast(Payload.Repeated)) |repeated| {
if (self.castTag(.enum_literal)) |payload| {
return std.mem.dupe(allocator, u8, payload.data);
}
if (self.castTag(.repeated)) |payload| {
@panic("TODO implement toAllocatedBytes for this Value tag");
}
if (self.cast(Payload.DeclRef)) |declref| {
const val = try declref.decl.value();
if (self.castTag(.decl_ref)) |payload| {
const val = try payload.data.value();
return val.toAllocatedBytes(allocator);
}
unreachable;
@ -395,7 +526,7 @@ pub const Value = extern union {
/// Asserts that the value is representable as a type.
pub fn toType(self: Value, allocator: *Allocator) !Type {
return switch (self.tag()) {
.ty => self.cast(Payload.Ty).?.ty,
.ty => self.castTag(.ty).?.data,
.u8_type => Type.initTag(.u8),
.i8_type => Type.initTag(.i8),
.u16_type => Type.initTag(.u16),
@ -439,7 +570,7 @@ pub const Value = extern union {
.anyframe_type => Type.initTag(.@"anyframe"),
.int_type => {
const payload = self.cast(Payload.IntType).?;
const payload = self.castTag(.int_type).?.data;
const new = try allocator.create(Type.Payload.Bits);
new.* = .{
.base = .{
@ -450,7 +581,7 @@ pub const Value = extern union {
return Type.initPayload(&new.base);
},
.error_set => {
const payload = self.cast(Payload.ErrorSet).?;
const payload = self.castTag(.error_set).?.data;
return Type.Tag.error_set.create(allocator, payload.decl);
},
@ -564,10 +695,10 @@ pub const Value = extern union {
.bool_true,
=> return BigIntMutable.init(&space.limbs, 1).toConst(),
.int_u64 => return BigIntMutable.init(&space.limbs, self.cast(Payload.Int_u64).?.int).toConst(),
.int_i64 => return BigIntMutable.init(&space.limbs, self.cast(Payload.Int_i64).?.int).toConst(),
.int_big_positive => return self.cast(Payload.IntBigPositive).?.asBigInt(),
.int_big_negative => return self.cast(Payload.IntBigNegative).?.asBigInt(),
.int_u64 => return BigIntMutable.init(&space.limbs, self.castTag(.int_u64).?.data).toConst(),
.int_i64 => return BigIntMutable.init(&space.limbs, self.castTag(.int_i64).?.data).toConst(),
.int_big_positive => return self.castTag(.int_big_positive).?.asBigInt(),
.int_big_negative => return self.castTag(.int_big_negative).?.asBigInt(),
}
}
@ -649,10 +780,10 @@ pub const Value = extern union {
.bool_true,
=> return 1,
.int_u64 => return self.cast(Payload.Int_u64).?.int,
.int_i64 => return @intCast(u64, self.cast(Payload.Int_i64).?.int),
.int_big_positive => return self.cast(Payload.IntBigPositive).?.asBigInt().to(u64) catch unreachable,
.int_big_negative => return self.cast(Payload.IntBigNegative).?.asBigInt().to(u64) catch unreachable,
.int_u64 => return self.castTag(.int_u64).?.data,
.int_i64 => return @intCast(u64, self.castTag(.int_i64).?.data),
.int_big_positive => return self.castTag(.int_big_positive).?.asBigInt().to(u64) catch unreachable,
.int_big_negative => return self.castTag(.int_big_negative).?.asBigInt().to(u64) catch unreachable,
}
}
@ -734,10 +865,10 @@ pub const Value = extern union {
.bool_true,
=> return 1,
.int_u64 => return @intCast(i64, self.cast(Payload.Int_u64).?.int),
.int_i64 => return self.cast(Payload.Int_i64).?.int,
.int_big_positive => return self.cast(Payload.IntBigPositive).?.asBigInt().to(i64) catch unreachable,
.int_big_negative => return self.cast(Payload.IntBigNegative).?.asBigInt().to(i64) catch unreachable,
.int_u64 => return @intCast(i64, self.castTag(.int_u64).?.data),
.int_i64 => return self.castTag(.int_i64).?.data,
.int_big_positive => return self.castTag(.int_big_positive).?.asBigInt().to(i64) catch unreachable,
.int_big_negative => return self.castTag(.int_big_negative).?.asBigInt().to(i64) catch unreachable,
}
}
@ -753,14 +884,14 @@ pub const Value = extern union {
pub fn toFloat(self: Value, comptime T: type) T {
return switch (self.tag()) {
.float_16 => @panic("TODO soft float"),
.float_32 => @floatCast(T, self.cast(Payload.Float_32).?.val),
.float_64 => @floatCast(T, self.cast(Payload.Float_64).?.val),
.float_128 => @floatCast(T, self.cast(Payload.Float_128).?.val),
.float_32 => @floatCast(T, self.castTag(.float_32).?.data),
.float_64 => @floatCast(T, self.castTag(.float_64).?.data),
.float_128 => @floatCast(T, self.castTag(.float_128).?.data),
.zero => 0,
.one => 1,
.int_u64 => @intToFloat(T, self.cast(Payload.Int_u64).?.int),
.int_i64 => @intToFloat(T, self.cast(Payload.Int_i64).?.int),
.int_u64 => @intToFloat(T, self.castTag(.int_u64).?.data),
.int_i64 => @intToFloat(T, self.castTag(.int_i64).?.data),
.int_big_positive, .int_big_negative => @panic("big int to f128"),
else => unreachable,
@ -846,15 +977,15 @@ pub const Value = extern union {
=> return 1,
.int_u64 => {
const x = self.cast(Payload.Int_u64).?.int;
const x = self.castTag(.int_u64).?.data;
if (x == 0) return 0;
return @intCast(usize, std.math.log2(x) + 1);
},
.int_i64 => {
@panic("TODO implement i64 intBitCountTwosComp");
},
.int_big_positive => return self.cast(Payload.IntBigPositive).?.asBigInt().bitCountTwosComp(),
.int_big_negative => return self.cast(Payload.IntBigNegative).?.asBigInt().bitCountTwosComp(),
.int_big_positive => return self.castTag(.int_big_positive).?.asBigInt().bitCountTwosComp(),
.int_big_negative => return self.castTag(.int_big_negative).?.asBigInt().bitCountTwosComp(),
}
}
@ -943,7 +1074,7 @@ pub const Value = extern union {
.int_u64 => switch (ty.zigTypeTag()) {
.Int => {
const x = self.cast(Payload.Int_u64).?.int;
const x = self.castTag(.int_u64).?.data;
if (x == 0) return true;
const info = ty.intInfo(target);
const needed_bits = std.math.log2(x) + 1 + @boolToInt(info.signedness == .signed);
@ -954,7 +1085,7 @@ pub const Value = extern union {
},
.int_i64 => switch (ty.zigTypeTag()) {
.Int => {
const x = self.cast(Payload.Int_i64).?.int;
const x = self.castTag(.int_i64).?.data;
if (x == 0) return true;
const info = ty.intInfo(target);
if (info.signedness == .unsigned and x < 0)
@ -967,7 +1098,7 @@ pub const Value = extern union {
.int_big_positive => switch (ty.zigTypeTag()) {
.Int => {
const info = ty.intInfo(target);
return self.cast(Payload.IntBigPositive).?.asBigInt().fitsInTwosComp(info.signedness, info.bits);
return self.castTag(.int_big_positive).?.asBigInt().fitsInTwosComp(info.signedness, info.bits);
},
.ComptimeInt => return true,
else => unreachable,
@ -975,7 +1106,7 @@ pub const Value = extern union {
.int_big_negative => switch (ty.zigTypeTag()) {
.Int => {
const info = ty.intInfo(target);
return self.cast(Payload.IntBigNegative).?.asBigInt().fitsInTwosComp(info.signedness, info.bits);
return self.castTag(.int_big_negative).?.asBigInt().fitsInTwosComp(info.signedness, info.bits);
},
.ComptimeInt => return true,
else => unreachable,
@ -986,42 +1117,28 @@ pub const Value = extern union {
/// Converts an integer or a float to a float.
/// Returns `error.Overflow` if the value does not fit in the new type.
pub fn floatCast(self: Value, allocator: *Allocator, ty: Type, target: Target) !Value {
const dest_bit_count = switch (ty.tag()) {
.comptime_float => 128,
else => ty.floatBits(target),
};
switch (dest_bit_count) {
16, 32, 64, 128 => {},
else => std.debug.panic("TODO float cast bit count {}\n", .{dest_bit_count}),
}
if (ty.isInt()) {
@panic("TODO int to float");
}
switch (dest_bit_count) {
16 => {
@panic("TODO soft float");
// var res_payload = Value.Payload.Float_16{.val = self.toFloat(f16)};
// if (!self.eql(Value.initPayload(&res_payload.base)))
// return error.Overflow;
// return Value.initPayload(&res_payload.base).copy(allocator);
switch (ty.tag()) {
.f16 => {
@panic("TODO add __trunctfhf2 to compiler-rt");
//const res = try Value.Tag.float_16.create(allocator, self.toFloat(f16));
//if (!self.eql(res))
// return error.Overflow;
//return res;
},
32 => {
var res_payload = Value.Payload.Float_32{ .val = self.toFloat(f32) };
if (!self.eql(Value.initPayload(&res_payload.base)))
.f32 => {
const res = try Value.Tag.float_32.create(allocator, self.toFloat(f32));
if (!self.eql(res))
return error.Overflow;
return Value.initPayload(&res_payload.base).copy(allocator);
return res;
},
64 => {
var res_payload = Value.Payload.Float_64{ .val = self.toFloat(f64) };
if (!self.eql(Value.initPayload(&res_payload.base)))
.f64 => {
const res = try Value.Tag.float_64.create(allocator, self.toFloat(f64));
if (!self.eql(res))
return error.Overflow;
return Value.initPayload(&res_payload.base).copy(allocator);
return res;
},
128 => {
const float_payload = try allocator.create(Value.Payload.Float_128);
float_payload.* = .{ .val = self.toFloat(f128) };
return Value.initPayload(&float_payload.base);
.f128, .comptime_float, .c_longdouble => {
return Value.Tag.float_128.create(allocator, self.toFloat(f128));
},
else => unreachable,
}
@ -1102,10 +1219,10 @@ pub const Value = extern union {
.one,
=> false,
.float_16 => @rem(self.cast(Payload.Float_16).?.val, 1) != 0,
.float_32 => @rem(self.cast(Payload.Float_32).?.val, 1) != 0,
.float_64 => @rem(self.cast(Payload.Float_64).?.val, 1) != 0,
// .float_128 => @rem(self.cast(Payload.Float_128).?.val, 1) != 0,
.float_16 => @rem(self.castTag(.float_16).?.data, 1) != 0,
.float_32 => @rem(self.castTag(.float_32).?.data, 1) != 0,
.float_64 => @rem(self.castTag(.float_64).?.data, 1) != 0,
// .float_128 => @rem(self.castTag(.float_128).?.data, 1) != 0,
.float_128 => @panic("TODO lld: error: undefined symbol: fmodl"),
};
}
@ -1182,15 +1299,15 @@ pub const Value = extern union {
.bool_true,
=> .gt,
.int_u64 => std.math.order(lhs.cast(Payload.Int_u64).?.int, 0),
.int_i64 => std.math.order(lhs.cast(Payload.Int_i64).?.int, 0),
.int_big_positive => lhs.cast(Payload.IntBigPositive).?.asBigInt().orderAgainstScalar(0),
.int_big_negative => lhs.cast(Payload.IntBigNegative).?.asBigInt().orderAgainstScalar(0),
.int_u64 => std.math.order(lhs.castTag(.int_u64).?.data, 0),
.int_i64 => std.math.order(lhs.castTag(.int_i64).?.data, 0),
.int_big_positive => lhs.castTag(.int_big_positive).?.asBigInt().orderAgainstScalar(0),
.int_big_negative => lhs.castTag(.int_big_negative).?.asBigInt().orderAgainstScalar(0),
.float_16 => std.math.order(lhs.cast(Payload.Float_16).?.val, 0),
.float_32 => std.math.order(lhs.cast(Payload.Float_32).?.val, 0),
.float_64 => std.math.order(lhs.cast(Payload.Float_64).?.val, 0),
.float_128 => std.math.order(lhs.cast(Payload.Float_128).?.val, 0),
.float_16 => std.math.order(lhs.castTag(.float_16).?.data, 0),
.float_32 => std.math.order(lhs.castTag(.float_32).?.data, 0),
.float_64 => std.math.order(lhs.castTag(.float_64).?.data, 0),
.float_128 => std.math.order(lhs.castTag(.float_128).?.data, 0),
};
}
@ -1208,10 +1325,10 @@ pub const Value = extern union {
if (lhs_float and rhs_float) {
if (lhs_tag == rhs_tag) {
return switch (lhs.tag()) {
.float_16 => return std.math.order(lhs.cast(Payload.Float_16).?.val, rhs.cast(Payload.Float_16).?.val),
.float_32 => return std.math.order(lhs.cast(Payload.Float_32).?.val, rhs.cast(Payload.Float_32).?.val),
.float_64 => return std.math.order(lhs.cast(Payload.Float_64).?.val, rhs.cast(Payload.Float_64).?.val),
.float_128 => return std.math.order(lhs.cast(Payload.Float_128).?.val, rhs.cast(Payload.Float_128).?.val),
.float_16 => return std.math.order(lhs.castTag(.float_16).?.data, rhs.castTag(.float_16).?.data),
.float_32 => return std.math.order(lhs.castTag(.float_32).?.data, rhs.castTag(.float_32).?.data),
.float_64 => return std.math.order(lhs.castTag(.float_64).?.data, rhs.castTag(.float_64).?.data),
.float_128 => return std.math.order(lhs.castTag(.float_128).?.data, rhs.castTag(.float_128).?.data),
else => unreachable,
};
}
@ -1244,8 +1361,8 @@ pub const Value = extern union {
if (a.tag() == .void_value or a.tag() == .null_value) {
return true;
} else if (a.tag() == .enum_literal) {
const a_name = @fieldParentPtr(Payload.Bytes, "base", a.ptr_otherwise).data;
const b_name = @fieldParentPtr(Payload.Bytes, "base", b.ptr_otherwise).data;
const a_name = a.castTag(.enum_literal).?.data;
const b_name = b.castTag(.enum_literal).?.data;
return std.mem.eql(u8, a_name, b_name);
}
}
@ -1313,11 +1430,11 @@ pub const Value = extern union {
},
.error_set => {
// Payload.decl should be same for all instances of the type.
const payload = @fieldParentPtr(Payload.ErrorSet, "base", self.ptr_otherwise);
const payload = self.castTag(.error_set).?.data;
std.hash.autoHash(&hasher, payload.decl);
},
.int_type => {
const payload = self.cast(Payload.IntType).?;
const payload = self.castTag(.int_type).?.data;
var int_payload = Type.Payload.Bits{
.base = .{
.tag = if (payload.signed) .int_signed else .int_unsigned,
@ -1341,25 +1458,29 @@ pub const Value = extern union {
.one, .bool_true => std.hash.autoHash(&hasher, @as(u64, 1)),
.float_16, .float_32, .float_64, .float_128 => {},
.enum_literal, .bytes => {
const payload = @fieldParentPtr(Payload.Bytes, "base", self.ptr_otherwise);
.enum_literal => {
const payload = self.castTag(.enum_literal).?;
hasher.update(payload.data);
},
.bytes => {
const payload = self.castTag(.bytes).?;
hasher.update(payload.data);
},
.int_u64 => {
const payload = @fieldParentPtr(Payload.Int_u64, "base", self.ptr_otherwise);
std.hash.autoHash(&hasher, payload.int);
const payload = self.castTag(.int_u64).?;
std.hash.autoHash(&hasher, payload.data);
},
.int_i64 => {
const payload = @fieldParentPtr(Payload.Int_i64, "base", self.ptr_otherwise);
std.hash.autoHash(&hasher, payload.int);
const payload = self.castTag(.int_i64).?;
std.hash.autoHash(&hasher, payload.data);
},
.repeated => {
const payload = @fieldParentPtr(Payload.Repeated, "base", self.ptr_otherwise);
std.hash.autoHash(&hasher, payload.val.hash());
const payload = self.castTag(.repeated).?;
std.hash.autoHash(&hasher, payload.data.hash());
},
.ref_val => {
const payload = @fieldParentPtr(Payload.RefVal, "base", self.ptr_otherwise);
std.hash.autoHash(&hasher, payload.val.hash());
const payload = self.castTag(.ref_val).?;
std.hash.autoHash(&hasher, payload.data.hash());
},
.int_big_positive, .int_big_negative => {
var space: BigIntSpace = undefined;
@ -1379,28 +1500,28 @@ pub const Value = extern union {
}
},
.elem_ptr => {
const payload = @fieldParentPtr(Payload.ElemPtr, "base", self.ptr_otherwise);
const payload = self.castTag(.elem_ptr).?.data;
std.hash.autoHash(&hasher, payload.array_ptr.hash());
std.hash.autoHash(&hasher, payload.index);
},
.decl_ref => {
const payload = @fieldParentPtr(Payload.DeclRef, "base", self.ptr_otherwise);
std.hash.autoHash(&hasher, payload.decl);
const decl = self.castTag(.decl_ref).?.data;
std.hash.autoHash(&hasher, decl);
},
.function => {
const payload = @fieldParentPtr(Payload.Function, "base", self.ptr_otherwise);
std.hash.autoHash(&hasher, payload.func);
const func = self.castTag(.function).?.data;
std.hash.autoHash(&hasher, func);
},
.extern_fn => {
const payload = @fieldParentPtr(Payload.ExternFn, "base", self.ptr_otherwise);
std.hash.autoHash(&hasher, payload.decl);
const decl = self.castTag(.extern_fn).?.data;
std.hash.autoHash(&hasher, decl);
},
.variable => {
const payload = @fieldParentPtr(Payload.Variable, "base", self.ptr_otherwise);
std.hash.autoHash(&hasher, payload.variable);
const variable = self.castTag(.variable).?.data;
std.hash.autoHash(&hasher, variable);
},
.@"error" => {
const payload = @fieldParentPtr(Payload.Error, "base", self.ptr_otherwise);
const payload = self.castTag(.@"error").?.data;
hasher.update(payload.name);
std.hash.autoHash(&hasher, payload.value);
},
@ -1483,10 +1604,10 @@ pub const Value = extern union {
.empty_struct_value,
=> unreachable,
.ref_val => self.cast(Payload.RefVal).?.val,
.decl_ref => self.cast(Payload.DeclRef).?.decl.value(),
.ref_val => self.castTag(.ref_val).?.data,
.decl_ref => self.castTag(.decl_ref).?.data.value(),
.elem_ptr => {
const elem_ptr = self.cast(Payload.ElemPtr).?;
const elem_ptr = self.castTag(.elem_ptr).?.data;
const array_val = try elem_ptr.array_ptr.pointerDeref(allocator);
return array_val.elemValue(allocator, elem_ptr.index);
},
@ -1570,26 +1691,26 @@ pub const Value = extern union {
.empty_array => unreachable, // out of bounds array index
.bytes => {
const int_payload = try allocator.create(Payload.Int_u64);
int_payload.* = .{ .int = self.cast(Payload.Bytes).?.data[index] };
return Value.initPayload(&int_payload.base);
},
.bytes => return Tag.int_u64.create(allocator, self.castTag(.bytes).?.data[index]),
// No matter the index; all the elements are the same!
.repeated => return self.cast(Payload.Repeated).?.val,
.repeated => return self.castTag(.repeated).?.data,
}
}
/// Returns a pointer to the element value at the index.
pub fn elemPtr(self: Value, allocator: *Allocator, index: usize) !Value {
const payload = try allocator.create(Payload.ElemPtr);
if (self.cast(Payload.ElemPtr)) |elem_ptr| {
payload.* = .{ .array_ptr = elem_ptr.array_ptr, .index = elem_ptr.index + index };
} else {
payload.* = .{ .array_ptr = self, .index = index };
if (self.castTag(.elem_ptr)) |elem_ptr| {
return Tag.elem_ptr.create(allocator, .{
.array_ptr = elem_ptr.data.array_ptr,
.index = elem_ptr.data.index + index,
});
}
return Value.initPayload(&payload.base);
return Tag.elem_ptr.create(allocator, .{
.array_ptr = self,
.index = index,
});
}
pub fn isUndef(self: Value) bool {
@ -1776,131 +1897,128 @@ pub const Value = extern union {
pub const Payload = struct {
tag: Tag,
pub const Int_u64 = struct {
base: Payload = Payload{ .tag = .int_u64 },
int: u64,
pub const U64 = struct {
base: Payload,
data: u64,
};
pub const Int_i64 = struct {
base: Payload = Payload{ .tag = .int_i64 },
int: i64,
pub const I64 = struct {
base: Payload,
data: i64,
};
pub const IntBigPositive = struct {
base: Payload = Payload{ .tag = .int_big_positive },
limbs: []const std.math.big.Limb,
pub const BigInt = struct {
base: Payload,
data: []const std.math.big.Limb,
pub fn asBigInt(self: IntBigPositive) BigIntConst {
return BigIntConst{ .limbs = self.limbs, .positive = true };
}
};
pub const IntBigNegative = struct {
base: Payload = Payload{ .tag = .int_big_negative },
limbs: []const std.math.big.Limb,
pub fn asBigInt(self: IntBigNegative) BigIntConst {
return BigIntConst{ .limbs = self.limbs, .positive = false };
pub fn asBigInt(self: BigInt) BigIntConst {
const positive = switch (self.base.tag) {
.int_big_positive => true,
.int_big_negative => false,
else => unreachable,
};
return BigIntConst{ .limbs = self.data, .positive = positive };
}
};
pub const Function = struct {
base: Payload = Payload{ .tag = .function },
func: *Module.Fn,
base: Payload,
data: *Module.Fn,
};
pub const ExternFn = struct {
base: Payload = Payload{ .tag = .extern_fn },
decl: *Module.Decl,
pub const Decl = struct {
base: Payload,
data: *Module.Decl,
};
pub const Variable = struct {
base: Payload = Payload{ .tag = .variable },
variable: *Module.Var,
base: Payload,
data: *Module.Var,
};
pub const ArraySentinel0_u8_Type = struct {
base: Payload = Payload{ .tag = .array_sentinel_0_u8_type },
len: u64,
};
/// Represents a pointer to another immutable value.
pub const RefVal = struct {
base: Payload = Payload{ .tag = .ref_val },
val: Value,
};
/// Represents a pointer to a decl, not the value of the decl.
pub const DeclRef = struct {
base: Payload = Payload{ .tag = .decl_ref },
decl: *Module.Decl,
pub const SubValue = struct {
base: Payload,
data: Value,
};
pub const ElemPtr = struct {
base: Payload = Payload{ .tag = .elem_ptr },
array_ptr: Value,
index: usize,
pub const base_tag = Tag.elem_ptr;
base: Payload = Payload{ .tag = base_tag },
data: struct {
array_ptr: Value,
index: usize,
},
};
pub const Bytes = struct {
base: Payload = Payload{ .tag = .bytes },
base: Payload,
data: []const u8,
};
pub const Ty = struct {
base: Payload = Payload{ .tag = .ty },
ty: Type,
base: Payload,
data: Type,
};
pub const IntType = struct {
base: Payload = Payload{ .tag = .int_type },
bits: u16,
signed: bool,
};
pub const base_tag = Tag.int_type;
pub const Repeated = struct {
base: Payload = Payload{ .tag = .ty },
/// This value is repeated some number of times. The amount of times to repeat
/// is stored externally.
val: Value,
base: Payload = Payload{ .tag = base_tag },
data: struct {
bits: u16,
signed: bool,
},
};
pub const Float_16 = struct {
base: Payload = .{ .tag = .float_16 },
val: f16,
pub const base_tag = Tag.float_16;
base: Payload = .{ .tag = base_tag },
data: f16,
};
pub const Float_32 = struct {
base: Payload = .{ .tag = .float_32 },
val: f32,
pub const base_tag = Tag.float_32;
base: Payload = .{ .tag = base_tag },
data: f32,
};
pub const Float_64 = struct {
base: Payload = .{ .tag = .float_64 },
val: f64,
pub const base_tag = Tag.float_64;
base: Payload = .{ .tag = base_tag },
data: f64,
};
pub const Float_128 = struct {
base: Payload = .{ .tag = .float_128 },
val: f128,
pub const base_tag = Tag.float_128;
base: Payload = .{ .tag = base_tag },
data: f128,
};
pub const ErrorSet = struct {
base: Payload = .{ .tag = .error_set },
pub const base_tag = Tag.error_set;
// TODO revisit this when we have the concept of the error tag type
fields: std.StringHashMapUnmanaged(u16),
decl: *Module.Decl,
base: Payload = .{ .tag = base_tag },
data: struct {
// TODO revisit this when we have the concept of the error tag type
fields: std.StringHashMapUnmanaged(u16),
decl: *Module.Decl,
},
};
pub const Error = struct {
base: Payload = .{ .tag = .@"error" },
// TODO revisit this when we have the concept of the error tag type
/// `name` is owned by `Module` and will be valid for the entire
/// duration of the compilation.
name: []const u8,
value: u16,
data: struct {
// TODO revisit this when we have the concept of the error tag type
/// `name` is owned by `Module` and will be valid for the entire
/// duration of the compilation.
name: []const u8,
value: u16,
},
};
};
@ -1914,15 +2032,24 @@ pub const Value = extern union {
test "hash same value different representation" {
const zero_1 = Value.initTag(.zero);
var payload_1 = Value.Payload.Int_u64{ .int = 0 };
var payload_1 = Value.Payload.U64{
.base = .{ .tag = .int_u64 },
.data = 0,
};
const zero_2 = Value.initPayload(&payload_1.base);
std.testing.expectEqual(zero_1.hash(), zero_2.hash());
var payload_2 = Value.Payload.Int_i64{ .int = 0 };
var payload_2 = Value.Payload.I64{
.base = .{ .tag = .int_i64 },
.data = 0,
};
const zero_3 = Value.initPayload(&payload_2.base);
std.testing.expectEqual(zero_2.hash(), zero_3.hash());
var payload_3 = Value.Payload.IntBigNegative{ .limbs = &[_]std.math.big.Limb{0} };
var payload_3 = Value.Payload.BigInt{
.base = .{ .tag = .int_big_negative },
.data = &[_]std.math.big.Limb{0},
};
const zero_4 = Value.initPayload(&payload_3.base);
std.testing.expectEqual(zero_3.hash(), zero_4.hash());
}

View File

@ -1990,15 +1990,15 @@ const EmitZIR = struct {
fn resolveInst(self: *EmitZIR, new_body: ZirBody, inst: *ir.Inst) !*Inst {
if (inst.cast(ir.Inst.Constant)) |const_inst| {
const new_inst = if (const_inst.val.cast(Value.Payload.Function)) |func_pl| blk: {
const owner_decl = func_pl.func.owner_decl;
const new_inst = if (const_inst.val.castTag(.function)) |func_pl| blk: {
const owner_decl = func_pl.data.owner_decl;
break :blk try self.emitDeclVal(inst.src, mem.spanZ(owner_decl.name));
} else if (const_inst.val.cast(Value.Payload.DeclRef)) |declref| blk: {
const decl_ref = try self.emitDeclRef(inst.src, declref.decl);
} else if (const_inst.val.castTag(.decl_ref)) |declref| blk: {
const decl_ref = try self.emitDeclRef(inst.src, declref.data);
try new_body.instructions.append(decl_ref);
break :blk decl_ref;
} else if (const_inst.val.cast(Value.Payload.Variable)) |var_pl| blk: {
const owner_decl = var_pl.variable.owner_decl;
} else if (const_inst.val.castTag(.variable)) |var_pl| blk: {
const owner_decl = var_pl.data.owner_decl;
break :blk try self.emitDeclVal(inst.src, mem.spanZ(owner_decl.name));
} else blk: {
break :blk (try self.emitTypedValue(inst.src, .{ .ty = inst.ty, .val = const_inst.val })).inst;
@ -2150,13 +2150,13 @@ const EmitZIR = struct {
fn emitTypedValue(self: *EmitZIR, src: usize, typed_value: TypedValue) Allocator.Error!*Decl {
const allocator = &self.arena.allocator;
if (typed_value.val.cast(Value.Payload.DeclRef)) |decl_ref| {
const decl = decl_ref.decl;
if (typed_value.val.castTag(.decl_ref)) |decl_ref| {
const decl = decl_ref.data;
return try self.emitUnnamedDecl(try self.emitDeclRef(src, decl));
} else if (typed_value.val.cast(Value.Payload.Variable)) |variable| {
} else if (typed_value.val.castTag(.variable)) |variable| {
return self.emitTypedValue(src, .{
.ty = typed_value.ty,
.val = variable.variable.init,
.val = variable.data.init,
});
}
if (typed_value.val.isUndef()) {
@ -2215,7 +2215,7 @@ const EmitZIR = struct {
return self.emitType(src, ty);
},
.Fn => {
const module_fn = typed_value.val.cast(Value.Payload.Function).?.func;
const module_fn = typed_value.val.castTag(.function).?.data;
return self.emitFn(module_fn, src, typed_value.ty);
},
.Array => {
@ -2248,7 +2248,7 @@ const EmitZIR = struct {
else
return self.emitPrimitive(src, .@"false"),
.EnumLiteral => {
const enum_literal = @fieldParentPtr(Value.Payload.Bytes, "base", typed_value.val.ptr_otherwise);
const enum_literal = typed_value.val.castTag(.enum_literal).?;
const inst = try self.arena.allocator.create(Inst.Str);
inst.* = .{
.base = .{
@ -2748,9 +2748,8 @@ const EmitZIR = struct {
.signed => .@"true",
.unsigned => .@"false",
});
const bits_payload = try self.arena.allocator.create(Value.Payload.Int_u64);
bits_payload.* = .{ .int = info.bits };
const bits = try self.emitComptimeIntVal(src, Value.initPayload(&bits_payload.base));
const bits_val = try Value.Tag.int_u64.create(&self.arena.allocator, info.bits);
const bits = try self.emitComptimeIntVal(src, bits_val);
const inttype_inst = try self.arena.allocator.create(Inst.IntType);
inttype_inst.* = .{
.base = .{
@ -2800,7 +2799,10 @@ const EmitZIR = struct {
return self.emitUnnamedDecl(&inst.base);
},
.Array => {
var len_pl = Value.Payload.Int_u64{ .int = ty.arrayLen() };
var len_pl = Value.Payload.U64{
.base = .{ .tag = .int_u64 },
.data = ty.arrayLen(),
};
const len = Value.initPayload(&len_pl.base);
const inst = if (ty.sentinel()) |sentinel| blk: {

View File

@ -364,12 +364,9 @@ fn analyzeInstRef(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!
const ptr_type = try mod.simplePtrType(scope, inst.base.src, operand.ty, false, .One);
if (operand.value()) |val| {
const ref_payload = try scope.arena().create(Value.Payload.RefVal);
ref_payload.* = .{ .val = val };
return mod.constInst(scope, inst.base.src, .{
.ty = ptr_type,
.val = Value.initPayload(&ref_payload.base),
.val = try Value.Tag.ref_val.create(scope.arena(), val),
});
}
@ -480,12 +477,9 @@ fn analyzeInstStr(mod: *Module, scope: *Scope, str_inst: *zir.Inst.Str) InnerErr
errdefer new_decl_arena.deinit();
const arena_bytes = try new_decl_arena.allocator.dupe(u8, str_inst.positionals.bytes);
const bytes_payload = try scope.arena().create(Value.Payload.Bytes);
bytes_payload.* = .{ .data = arena_bytes };
const new_decl = try mod.createAnonymousDecl(scope, &new_decl_arena, .{
.ty = try Type.Tag.array_u8_sentinel_0.create(scope.arena(), arena_bytes.len),
.val = Value.initPayload(&bytes_payload.base),
.val = try Value.Tag.bytes.create(scope.arena(), arena_bytes),
});
return mod.analyzeDeclRef(scope, str_inst.base.src, new_decl);
}
@ -779,11 +773,9 @@ fn analyzeInstFn(mod: *Module, scope: *Scope, fn_inst: *zir.Inst.Fn) InnerError!
.analysis = .{ .queued = fn_zir },
.owner_decl = scope.decl().?,
};
const fn_payload = try scope.arena().create(Value.Payload.Function);
fn_payload.* = .{ .func = new_func };
return mod.constInst(scope, fn_inst.base.src, .{
.ty = fn_type,
.val = Value.initPayload(&fn_payload.base),
.val = try Value.Tag.function.create(scope.arena(), new_func),
});
}
@ -838,14 +830,17 @@ fn analyzeInstErrorSet(mod: *Module, scope: *Scope, inst: *zir.Inst.ErrorSet) In
const payload = try scope.arena().create(Value.Payload.ErrorSet);
payload.* = .{
.fields = .{},
.decl = undefined, // populated below
.base = .{ .tag = .error_set },
.data = .{
.fields = .{},
.decl = undefined, // populated below
},
};
try payload.fields.ensureCapacity(&new_decl_arena.allocator, @intCast(u32, inst.positionals.fields.len));
try payload.data.fields.ensureCapacity(&new_decl_arena.allocator, @intCast(u32, inst.positionals.fields.len));
for (inst.positionals.fields) |field_name| {
const entry = try mod.getErrorValue(field_name);
if (payload.fields.fetchPutAssumeCapacity(entry.key, entry.value)) |prev| {
if (payload.data.fields.fetchPutAssumeCapacity(entry.key, entry.value)) |prev| {
return mod.fail(scope, inst.base.src, "duplicate error: '{}'", .{field_name});
}
}
@ -854,7 +849,7 @@ fn analyzeInstErrorSet(mod: *Module, scope: *Scope, inst: *zir.Inst.ErrorSet) In
.ty = Type.initTag(.type),
.val = Value.initPayload(&payload.base),
});
payload.decl = new_decl;
payload.data.decl = new_decl;
return mod.analyzeDeclRef(scope, inst.base.src, new_decl);
}
@ -863,14 +858,10 @@ fn analyzeInstMergeErrorSets(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp)
}
fn analyzeInstEnumLiteral(mod: *Module, scope: *Scope, inst: *zir.Inst.EnumLiteral) InnerError!*Inst {
const payload = try scope.arena().create(Value.Payload.Bytes);
payload.* = .{
.base = .{ .tag = .enum_literal },
.data = try scope.arena().dupe(u8, inst.positionals.name),
};
const duped_name = try scope.arena().dupe(u8, inst.positionals.name);
return mod.constInst(scope, inst.base.src, .{
.ty = Type.initTag(.enum_literal),
.val = Value.initPayload(&payload.base),
.val = try Value.Tag.enum_literal.create(scope.arena(), duped_name),
});
}
@ -989,15 +980,12 @@ fn analyzeInstFieldPtr(mod: *Module, scope: *Scope, fieldptr: *zir.Inst.FieldPtr
switch (elem_ty.zigTypeTag()) {
.Array => {
if (mem.eql(u8, field_name, "len")) {
const len_payload = try scope.arena().create(Value.Payload.Int_u64);
len_payload.* = .{ .int = elem_ty.arrayLen() };
const ref_payload = try scope.arena().create(Value.Payload.RefVal);
ref_payload.* = .{ .val = Value.initPayload(&len_payload.base) };
return mod.constInst(scope, fieldptr.base.src, .{
.ty = Type.initTag(.single_const_pointer_to_comptime_int),
.val = Value.initPayload(&ref_payload.base),
.val = try Value.Tag.ref_val.create(
scope.arena(),
try Value.Tag.int_u64.create(scope.arena(), elem_ty.arrayLen()),
),
});
} else {
return mod.fail(
@ -1013,15 +1001,12 @@ fn analyzeInstFieldPtr(mod: *Module, scope: *Scope, fieldptr: *zir.Inst.FieldPtr
switch (ptr_child.zigTypeTag()) {
.Array => {
if (mem.eql(u8, field_name, "len")) {
const len_payload = try scope.arena().create(Value.Payload.Int_u64);
len_payload.* = .{ .int = ptr_child.arrayLen() };
const ref_payload = try scope.arena().create(Value.Payload.RefVal);
ref_payload.* = .{ .val = Value.initPayload(&len_payload.base) };
return mod.constInst(scope, fieldptr.base.src, .{
.ty = Type.initTag(.single_const_pointer_to_comptime_int),
.val = Value.initPayload(&ref_payload.base),
.val = try Value.Tag.ref_val.create(
scope.arena(),
try Value.Tag.int_u64.create(scope.arena(), ptr_child.arrayLen()),
),
});
} else {
return mod.fail(
@ -1043,21 +1028,12 @@ fn analyzeInstFieldPtr(mod: *Module, scope: *Scope, fieldptr: *zir.Inst.FieldPtr
switch (child_type.zigTypeTag()) {
.ErrorSet => {
// TODO resolve inferred error sets
const entry = if (val.cast(Value.Payload.ErrorSet)) |payload|
(payload.fields.getEntry(field_name) orelse
const entry = if (val.castTag(.error_set)) |payload|
(payload.data.fields.getEntry(field_name) orelse
return mod.fail(scope, fieldptr.base.src, "no error named '{}' in '{}'", .{ field_name, child_type })).*
else
try mod.getErrorValue(field_name);
const error_payload = try scope.arena().create(Value.Payload.Error);
error_payload.* = .{
.name = entry.key,
.value = entry.value,
};
const ref_payload = try scope.arena().create(Value.Payload.RefVal);
ref_payload.* = .{ .val = Value.initPayload(&error_payload.base) };
const result_type = if (child_type.tag() == .anyerror)
try Type.Tag.error_set_single.create(scope.arena(), entry.key)
else
@ -1065,7 +1041,13 @@ fn analyzeInstFieldPtr(mod: *Module, scope: *Scope, fieldptr: *zir.Inst.FieldPtr
return mod.constInst(scope, fieldptr.base.src, .{
.ty = try mod.simplePtrType(scope, fieldptr.base.src, result_type, false, .One),
.val = Value.initPayload(&ref_payload.base),
.val = try Value.Tag.ref_val.create(
scope.arena(),
try Value.Tag.@"error".create(scope.arena(), .{
.name = entry.key,
.value = entry.value,
}),
),
});
},
.Struct => {