diff options
| author | Luuk de Gram <luuk@degram.dev> | 2022-01-22 21:23:17 +0100 |
|---|---|---|
| committer | Luuk de Gram <luuk@degram.dev> | 2022-01-25 19:00:52 +0100 |
| commit | e9d122f1640bcf7ad71d731e6b1b259d1f065da8 (patch) | |
| tree | 2065756d7513e5b3198124921354ffe05fd618c6 /src/arch/wasm/CodeGen.zig | |
| parent | 288b407fa9c40addafe521862c3eef08c878b1f6 (diff) | |
| download | zig-e9d122f1640bcf7ad71d731e6b1b259d1f065da8.tar.gz zig-e9d122f1640bcf7ad71d731e6b1b259d1f065da8.zip | |
wasm: Implement lowering unions
Diffstat (limited to 'src/arch/wasm/CodeGen.zig')
| -rw-r--r-- | src/arch/wasm/CodeGen.zig | 43 |
1 files 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 => { |
