aboutsummaryrefslogtreecommitdiff
path: root/src/codegen.zig
diff options
context:
space:
mode:
authorJakub Konka <kubkon@jakubkonka.com>2022-02-28 10:58:22 +0100
committerJakub Konka <kubkon@jakubkonka.com>2022-02-28 11:40:25 +0100
commit06f58a0b3b241a38ca4092a9f4ee8012370dcff6 (patch)
treef69cdaaaea09dd09e9dee4be5e5a5b75b3dfa46f /src/codegen.zig
parent1dc05e9e77e7213e384b9b79b370ae14174fdef1 (diff)
downloadzig-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.zig70
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 = {} };
},