| ... | ... | @@ -1716,7 +1716,14 @@ fn isByRef(ty: Type, target: std.Target) bool { |
| 1716 | 1716 | .Array, |
| 1717 | 1717 | .Frame, |
| 1718 | 1718 | .Union, |
| 1719 | | => return ty.hasRuntimeBitsIgnoreComptime(), |
| 1719 | => { |
| 1720 | if (ty.castTag(.@"union")) |union_ty| { |
| 1721 | if (union_ty.data.layout == .Packed) { |
| 1722 | return ty.abiSize(target) > 8; |
| 1723 | } |
| 1724 | } |
| 1725 | return ty.hasRuntimeBitsIgnoreComptime(); |
| 1726 | }, |
| 1720 | 1727 | .Struct => { |
| 1721 | 1728 | if (ty.castTag(.@"struct")) |struct_ty| { |
| 1722 | 1729 | const struct_obj = struct_ty.data; |
| ... | ... | @@ -3131,6 +3138,14 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue { |
| 3131 | 3138 | val.writeToMemory(ty, func.bin_file.base.options.module.?, &buf) catch unreachable; |
| 3132 | 3139 | return func.storeSimdImmd(buf); |
| 3133 | 3140 | }, |
| 3141 | .Union => { |
| 3142 | // in this case we have a packed union which will not be passed by reference. |
| 3143 | const union_ty = ty.cast(Type.Payload.Union).?.data; |
| 3144 | const union_obj = val.castTag(.@"union").?.data; |
| 3145 | const field_index = ty.unionTagFieldIndex(union_obj.tag, func.bin_file.base.options.module.?).?; |
| 3146 | const field_ty = union_ty.fields.values()[field_index].ty; |
| 3147 | return func.lowerConstant(union_obj.val, field_ty); |
| 3148 | }, |
| 3134 | 3149 | else => |zig_type| return func.fail("Wasm TODO: LowerConstant for zigTypeTag {}", .{zig_type}), |
| 3135 | 3150 | } |
| 3136 | 3151 | } |
| ... | ... | @@ -3661,8 +3676,42 @@ fn airStructFieldVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 3661 | 3676 | break :result try truncated.toLocal(func, field_ty); |
| 3662 | 3677 | }, |
| 3663 | 3678 | .Union => result: { |
| 3664 | | const val = try func.load(operand, field_ty, 0); |
| 3665 | | break :result try val.toLocal(func, field_ty); |
| 3679 | if (isByRef(struct_ty, func.target)) { |
| 3680 | if (!isByRef(field_ty, func.target)) { |
| 3681 | const val = try func.load(operand, field_ty, 0); |
| 3682 | break :result try val.toLocal(func, field_ty); |
| 3683 | } else { |
| 3684 | const new_stack_val = try func.allocStack(field_ty); |
| 3685 | try func.store(new_stack_val, operand, field_ty, 0); |
| 3686 | break :result new_stack_val; |
| 3687 | } |
| 3688 | } |
| 3689 | |
| 3690 | var payload: Type.Payload.Bits = .{ |
| 3691 | .base = .{ .tag = .int_unsigned }, |
| 3692 | .data = @intCast(u16, struct_ty.bitSize(func.target)), |
| 3693 | }; |
| 3694 | const union_int_type = Type.initPayload(&payload.base); |
| 3695 | if (field_ty.zigTypeTag() == .Float) { |
| 3696 | var int_payload: Type.Payload.Bits = .{ |
| 3697 | .base = .{ .tag = .int_unsigned }, |
| 3698 | .data = @intCast(u16, field_ty.bitSize(func.target)), |
| 3699 | }; |
| 3700 | const int_type = Type.initPayload(&int_payload.base); |
| 3701 | const truncated = try func.trunc(operand, int_type, union_int_type); |
| 3702 | const bitcasted = try func.bitcast(field_ty, int_type, truncated); |
| 3703 | break :result try bitcasted.toLocal(func, field_ty); |
| 3704 | } else if (field_ty.isPtrAtRuntime()) { |
| 3705 | var int_payload: Type.Payload.Bits = .{ |
| 3706 | .base = .{ .tag = .int_unsigned }, |
| 3707 | .data = @intCast(u16, field_ty.bitSize(func.target)), |
| 3708 | }; |
| 3709 | const int_type = Type.initPayload(&int_payload.base); |
| 3710 | const truncated = try func.trunc(operand, int_type, union_int_type); |
| 3711 | break :result try truncated.toLocal(func, field_ty); |
| 3712 | } |
| 3713 | const truncated = try func.trunc(operand, field_ty, union_int_type); |
| 3714 | break :result try truncated.toLocal(func, field_ty); |
| 3666 | 3715 | }, |
| 3667 | 3716 | else => unreachable, |
| 3668 | 3717 | }, |