diff options
| author | kcbanner <kcbanner@gmail.com> | 2023-09-20 23:53:06 -0400 |
|---|---|---|
| committer | kcbanner <kcbanner@gmail.com> | 2023-09-23 13:04:56 -0400 |
| commit | 2fddd767ba20374e7677003c101e60f470c3804c (patch) | |
| tree | 91ffbed5086771488201cebd82be6e1554ac14b5 /src/value.zig | |
| parent | ce919ccf45951856a762ffdb8ef850301cd8c588 (diff) | |
| download | zig-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.zig | 73 |
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, |
