aboutsummaryrefslogtreecommitdiff
path: root/src/value.zig
diff options
context:
space:
mode:
authorkcbanner <kcbanner@gmail.com>2023-09-20 23:53:06 -0400
committerkcbanner <kcbanner@gmail.com>2023-09-23 13:04:56 -0400
commit2fddd767ba20374e7677003c101e60f470c3804c (patch)
tree91ffbed5086771488201cebd82be6e1554ac14b5 /src/value.zig
parentce919ccf45951856a762ffdb8ef850301cd8c588 (diff)
downloadzig-2fddd767ba20374e7677003c101e60f470c3804c.tar.gz
zig-2fddd767ba20374e7677003c101e60f470c3804c.zip
sema: add support for unions in readFromMemory and writeToMemory
Diffstat (limited to 'src/value.zig')
-rw-r--r--src/value.zig73
1 files changed, 69 insertions, 4 deletions
diff --git a/src/value.zig b/src/value.zig
index 2d0523f986..cfac880110 100644
--- a/src/value.zig
+++ b/src/value.zig
@@ -704,7 +704,22 @@ pub const Value = struct {
},
.Union => switch (ty.containerLayout(mod)) {
.Auto => return error.IllDefinedMemoryLayout,
- .Extern => return error.Unimplemented,
+ .Extern => {
+ const union_obj = mod.typeToUnion(ty).?;
+ const union_tag = val.unionTag(mod);
+
+ const field_type, const field_index = if (mod.unionTagFieldIndex(union_obj, union_tag)) |field_index| .{
+ union_obj.field_types.get(&mod.intern_pool)[field_index].toType(),
+ field_index,
+ } else f: {
+ const largest_field = mod.unionLargestField(union_obj);
+ break :f .{ largest_field.ty, largest_field.index };
+ };
+
+ const field_val = try val.fieldValue(mod, field_index);
+ const byte_count = @as(usize, @intCast(field_type.abiSize(mod)));
+ return writeToMemory(field_val, field_type, mod, buffer[0..byte_count]);
+ },
.Packed => {
const byte_count = (@as(usize, @intCast(ty.bitSize(mod))) + 7) / 8;
return writeToPackedMemory(val, ty, mod, buffer[0..byte_count], 0);
@@ -856,7 +871,11 @@ pub const Value = struct {
mod: *Module,
buffer: []const u8,
arena: Allocator,
- ) Allocator.Error!Value {
+ ) error{
+ IllDefinedMemoryLayout,
+ Unimplemented,
+ OutOfMemory,
+ }!Value {
const ip = &mod.intern_pool;
const target = mod.getTarget();
const endian = target.cpu.arch.endian();
@@ -966,6 +985,26 @@ pub const Value = struct {
.name = name,
} })).toValue();
},
+ .Union => switch (ty.containerLayout(mod)) {
+ .Auto => return error.IllDefinedMemoryLayout,
+ .Extern => {
+ const union_obj = mod.typeToUnion(ty).?;
+ const largest_field = mod.unionLargestField(union_obj);
+ const field_size: usize = @intCast(largest_field.size);
+ const val = try (try readFromMemory(largest_field.ty, mod, buffer[0..field_size], arena)).intern(largest_field.ty, mod);
+ return (try mod.intern(.{
+ .un = .{
+ .ty = ty.toIntern(),
+ .tag = .undef,
+ .val = val,
+ },
+ })).toValue();
+ },
+ .Packed => {
+ const byte_count = (@as(usize, @intCast(ty.bitSize(mod))) + 7) / 8;
+ return readFromPackedMemory(ty, mod, buffer[0..byte_count], 0, arena);
+ },
+ },
.Pointer => {
assert(!ty.isSlice(mod)); // No well defined layout.
const int_val = try readFromMemory(Type.usize, mod, buffer, arena);
@@ -987,7 +1026,7 @@ pub const Value = struct {
},
} })).toValue();
},
- else => @panic("TODO implement readFromMemory for more types"),
+ else => return error.Unimplemented,
}
}
@@ -1001,7 +1040,10 @@ pub const Value = struct {
buffer: []const u8,
bit_offset: usize,
arena: Allocator,
- ) Allocator.Error!Value {
+ ) error{
+ IllDefinedMemoryLayout,
+ OutOfMemory,
+ }!Value {
const ip = &mod.intern_pool;
const target = mod.getTarget();
const endian = target.cpu.arch.endian();
@@ -1098,6 +1140,21 @@ pub const Value = struct {
.storage = .{ .elems = field_vals },
} })).toValue();
},
+ .Union => switch (ty.containerLayout(mod)) {
+ .Auto => return error.IllDefinedMemoryLayout,
+ .Extern => unreachable, // Handled by non-packed readFromMemory
+ .Packed => {
+ const union_obj = mod.typeToUnion(ty).?;
+ const largest_field = mod.unionLargestField(union_obj);
+ const un_tag_val = try mod.enumValueFieldIndex(union_obj.enum_tag_ty.toType(), largest_field.index);
+ const un_val = try (try readFromPackedMemory(largest_field.ty, mod, buffer, bit_offset, arena)).intern(largest_field.ty, mod);
+ return (try mod.intern(.{ .un = .{
+ .ty = ty.toIntern(),
+ .tag = un_tag_val.ip_index,
+ .val = un_val,
+ } })).toValue();
+ },
+ },
.Pointer => {
assert(!ty.isSlice(mod)); // No well defined layout.
return readFromPackedMemory(Type.usize, mod, buffer, bit_offset, arena);
@@ -1713,6 +1770,14 @@ pub const Value = struct {
};
}
+ pub fn unionValue(val: Value, mod: *Module) Value {
+ if (val.ip_index == .none) return val.castTag(.@"union").?.data.val;
+ return switch (mod.intern_pool.indexToKey(val.toIntern())) {
+ .un => |un| un.val.toValue(),
+ else => unreachable,
+ };
+ }
+
/// Returns a pointer to the element value at the index.
pub fn elemPtr(
val: Value,