From e9d122f1640bcf7ad71d731e6b1b259d1f065da8 Mon Sep 17 00:00:00 2001 From: Luuk de Gram Date: Sat, 22 Jan 2022 21:23:17 +0100 Subject: [PATCH] wasm: Implement lowering unions --- src/arch/wasm/CodeGen.zig | 43 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index c0800982d6..33a30281f8 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -1053,9 +1053,46 @@ pub const DeclGen = struct { return Result{ .appended = {} }; }, .Union => { - // TODO: Implement Union declarations - try writer.writeByteNTimes(0xaa, @intCast(usize, ty.abiSize(self.target()))); - return Result{ .appended = {} }; + const union_val = val.castTag(.@"union").?.data; + const layout = ty.unionGetLayout(self.target()); + + if (layout.payload_size == 0) { + return self.genTypedValue(ty.unionTagType().?, union_val.tag, writer); + } + + // Check if we should store the tag first, in which case, do so now: + if (layout.tag_align >= layout.payload_align) { + switch (try self.genTypedValue(ty.unionTagType().?, union_val.tag, writer)) { + .appended => {}, + .externally_managed => |payload| try writer.writeAll(payload), + } + } + + const union_ty = ty.cast(Type.Payload.Union).?.data; + const field_index = union_ty.tag_ty.enumTagFieldIndex(union_val.tag).?; + assert(union_ty.haveFieldTypes()); + const field_ty = union_ty.fields.values()[field_index].ty; + if (!field_ty.hasCodeGenBits()) { + try writer.writeByteNTimes(0xaa, layout.payload_size); + } else { + switch (try self.genTypedValue(field_ty, union_val.val, writer)) { + .appended => {}, + .externally_managed => |payload| try writer.writeAll(payload), + } + + // Unions have the size of the largest field, so we must pad + // whenever the active field has a smaller size. + const diff = layout.payload_size - field_ty.abiSize(self.target()); + if (diff > 0) { + try writer.writeByteNTimes(0xaa, diff); + } + } + + if (layout.tag_size == 0) { + return Result{ .appended = {} }; + } + + return self.genTypedValue(union_ty.tag_ty, union_val.tag, writer); }, .Pointer => switch (val.tag()) { .variable => {