diff options
| author | Jakub Konka <kubkon@jakubkonka.com> | 2022-02-28 10:58:22 +0100 |
|---|---|---|
| committer | Jakub Konka <kubkon@jakubkonka.com> | 2022-02-28 11:40:25 +0100 |
| commit | 06f58a0b3b241a38ca4092a9f4ee8012370dcff6 (patch) | |
| tree | f69cdaaaea09dd09e9dee4be5e5a5b75b3dfa46f /src/codegen.zig | |
| parent | 1dc05e9e77e7213e384b9b79b370ae14174fdef1 (diff) | |
| download | zig-06f58a0b3b241a38ca4092a9f4ee8012370dcff6.tar.gz zig-06f58a0b3b241a38ca4092a9f4ee8012370dcff6.zip | |
codegen: impl lowering of union type to memory
Diffstat (limited to 'src/codegen.zig')
| -rw-r--r-- | src/codegen.zig | 70 |
1 files changed, 67 insertions, 3 deletions
diff --git a/src/codegen.zig b/src/codegen.zig index 26a4478fb2..2484cb0e59 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -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 = {} }; }, |
