codegen: impl lowering of union type to memory

This commit is contained in:
Jakub Konka 2022-02-28 10:58:22 +01:00
parent 1dc05e9e77
commit 06f58a0b3b

View File

@ -466,10 +466,74 @@ pub fn generateSymbol(
return Result{ .appended = {} };
},
.Union => {
// TODO generateSymbol for unions
// TODO generate debug info for unions
const target = bin_file.options.target;
const abi_size = try math.cast(usize, typed_value.ty.abiSize(target));
try code.writer().writeByteNTimes(0xaa, abi_size);
const union_obj = typed_value.val.castTag(.@"union").?.data;
const layout = typed_value.ty.unionGetLayout(target);
if (layout.payload_size == 0) {
switch (try generateSymbol(bin_file, parent_atom_index, src_loc, .{
.ty = typed_value.ty.unionTagType().?,
.val = union_obj.tag,
}, code, debug_output)) {
.appended => {},
.externally_managed => |external_slice| {
code.appendSliceAssumeCapacity(external_slice);
},
.fail => |em| return Result{ .fail = em },
}
}
// Check if we should store the tag first.
if (layout.tag_align >= layout.payload_align) {
switch (try generateSymbol(bin_file, parent_atom_index, src_loc, .{
.ty = typed_value.ty.unionTagType().?,
.val = union_obj.tag,
}, code, debug_output)) {
.appended => {},
.externally_managed => |external_slice| {
code.appendSliceAssumeCapacity(external_slice);
},
.fail => |em| return Result{ .fail = em },
}
}
const union_ty = typed_value.ty.cast(Type.Payload.Union).?.data;
const field_index = union_ty.tag_ty.enumTagFieldIndex(union_obj.tag).?;
assert(union_ty.haveFieldTypes());
const field_ty = union_ty.fields.values()[field_index].ty;
if (!field_ty.hasRuntimeBits()) {
try code.writer().writeByteNTimes(0xaa, try math.cast(usize, layout.payload_size));
} else {
switch (try generateSymbol(bin_file, parent_atom_index, src_loc, .{
.ty = field_ty,
.val = union_obj.val,
}, code, debug_output)) {
.appended => {},
.externally_managed => |external_slice| {
code.appendSliceAssumeCapacity(external_slice);
},
.fail => |em| return Result{ .fail = em },
}
const padding = try math.cast(usize, layout.payload_size - field_ty.abiSize(target));
if (padding > 0) {
try code.writer().writeByteNTimes(0, padding);
}
}
if (layout.tag_size > 0) {
switch (try generateSymbol(bin_file, parent_atom_index, src_loc, .{
.ty = union_ty.tag_ty,
.val = union_obj.tag,
}, code, debug_output)) {
.appended => {},
.externally_managed => |external_slice| {
code.appendSliceAssumeCapacity(external_slice);
},
.fail => |em| return Result{ .fail = em },
}
}
return Result{ .appended = {} };
},