| ... | ... | @@ -636,7 +636,7 @@ fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!WValue { |
| 636 | 636 | // means we must generate it from a constant. |
| 637 | 637 | const val = self.air.value(ref).?; |
| 638 | 638 | const ty = self.air.typeOf(ref); |
| 639 | | if (!ty.hasRuntimeBitsIgnoreComptime() and !ty.isInt()) { |
| 639 | if (!ty.hasRuntimeBitsIgnoreComptime() and !ty.isInt() and !ty.isError()) { |
| 640 | 640 | gop.value_ptr.* = WValue{ .none = {} }; |
| 641 | 641 | return gop.value_ptr.*; |
| 642 | 642 | } |
| ... | ... | @@ -804,6 +804,8 @@ fn genFunctype(gpa: Allocator, fn_info: Type.Payload.Function.Data, target: std. |
| 804 | 804 | } else { |
| 805 | 805 | try returns.append(typeToValtype(fn_info.return_type, target)); |
| 806 | 806 | } |
| 807 | } else if (fn_info.return_type.isError()) { |
| 808 | try returns.append(.i32); |
| 807 | 809 | } |
| 808 | 810 | |
| 809 | 811 | // param types |
| ... | ... | @@ -1373,10 +1375,15 @@ fn isByRef(ty: Type, target: std.Target) bool { |
| 1373 | 1375 | .Int => return ty.intInfo(target).bits > 64, |
| 1374 | 1376 | .Float => return ty.floatBits(target) > 64, |
| 1375 | 1377 | .ErrorUnion => { |
| 1376 | | const has_tag = ty.errorUnionSet().hasRuntimeBitsIgnoreComptime(); |
| 1377 | | const has_pl = ty.errorUnionPayload().hasRuntimeBitsIgnoreComptime(); |
| 1378 | | if (!has_tag or !has_pl) return false; |
| 1379 | | return ty.hasRuntimeBitsIgnoreComptime(); |
| 1378 | const err_ty = ty.errorUnionSet(); |
| 1379 | const pl_ty = ty.errorUnionPayload(); |
| 1380 | if (err_ty.errorSetCardinality() == .zero) { |
| 1381 | return isByRef(pl_ty, target); |
| 1382 | } |
| 1383 | if (!pl_ty.hasRuntimeBitsIgnoreComptime()) { |
| 1384 | return false; |
| 1385 | } |
| 1386 | return true; |
| 1380 | 1387 | }, |
| 1381 | 1388 | .Optional => { |
| 1382 | 1389 | if (ty.isPtrLikeOptional()) return false; |
| ... | ... | @@ -1624,13 +1631,14 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 1624 | 1631 | fn airRet(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 1625 | 1632 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 1626 | 1633 | const operand = try self.resolveInst(un_op); |
| 1627 | | const ret_ty = self.decl.ty.fnReturnType(); |
| 1634 | const fn_info = self.decl.ty.fnInfo(); |
| 1635 | const ret_ty = fn_info.return_type; |
| 1628 | 1636 | |
| 1629 | 1637 | // result must be stored in the stack and we return a pointer |
| 1630 | 1638 | // to the stack instead |
| 1631 | 1639 | if (self.return_value != .none) { |
| 1632 | | try self.store(self.return_value, operand, self.decl.ty.fnReturnType(), 0); |
| 1633 | | } else if (self.decl.ty.fnInfo().cc == .C and ret_ty.hasRuntimeBitsIgnoreComptime()) { |
| 1640 | try self.store(self.return_value, operand, ret_ty, 0); |
| 1641 | } else if (fn_info.cc == .C and ret_ty.hasRuntimeBitsIgnoreComptime()) { |
| 1634 | 1642 | switch (ret_ty.zigTypeTag()) { |
| 1635 | 1643 | // Aggregate types can be lowered as a singular value |
| 1636 | 1644 | .Struct, .Union => { |
| ... | ... | @@ -1650,7 +1658,11 @@ fn airRet(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 1650 | 1658 | else => try self.emitWValue(operand), |
| 1651 | 1659 | } |
| 1652 | 1660 | } else { |
| 1653 | | try self.emitWValue(operand); |
| 1661 | if (!ret_ty.hasRuntimeBitsIgnoreComptime() and ret_ty.isError()) { |
| 1662 | try self.addImm32(0); |
| 1663 | } else { |
| 1664 | try self.emitWValue(operand); |
| 1665 | } |
| 1654 | 1666 | } |
| 1655 | 1667 | try self.restoreStackPointer(); |
| 1656 | 1668 | try self.addTag(.@"return"); |
| ... | ... | @@ -1675,7 +1687,13 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 1675 | 1687 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 1676 | 1688 | const operand = try self.resolveInst(un_op); |
| 1677 | 1689 | const ret_ty = self.air.typeOf(un_op).childType(); |
| 1678 | | if (!ret_ty.hasRuntimeBitsIgnoreComptime()) return WValue.none; |
| 1690 | if (!ret_ty.hasRuntimeBitsIgnoreComptime()) { |
| 1691 | if (ret_ty.isError()) { |
| 1692 | try self.addImm32(0); |
| 1693 | } else { |
| 1694 | return WValue.none; |
| 1695 | } |
| 1696 | } |
| 1679 | 1697 | |
| 1680 | 1698 | if (!firstParamSRet(self.decl.ty.fnInfo(), self.target)) { |
| 1681 | 1699 | const result = try self.load(operand, ret_ty, 0); |
| ... | ... | @@ -1723,8 +1741,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. |
| 1723 | 1741 | |
| 1724 | 1742 | const sret = if (first_param_sret) blk: { |
| 1725 | 1743 | const sret_local = try self.allocStack(ret_ty); |
| 1726 | | const ptr_offset = try self.buildPointerOffset(sret_local, 0, .new); |
| 1727 | | try self.emitWValue(ptr_offset); |
| 1744 | try self.lowerToStack(sret_local); |
| 1728 | 1745 | break :blk sret_local; |
| 1729 | 1746 | } else WValue{ .none = {} }; |
| 1730 | 1747 | |
| ... | ... | @@ -1754,7 +1771,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. |
| 1754 | 1771 | try self.addLabel(.call_indirect, fn_type_index); |
| 1755 | 1772 | } |
| 1756 | 1773 | |
| 1757 | | if (self.liveness.isUnused(inst) or !ret_ty.hasRuntimeBitsIgnoreComptime()) { |
| 1774 | if (self.liveness.isUnused(inst) or (!ret_ty.hasRuntimeBitsIgnoreComptime() and !ret_ty.isError())) { |
| 1758 | 1775 | return WValue.none; |
| 1759 | 1776 | } else if (ret_ty.isNoReturn()) { |
| 1760 | 1777 | try self.addTag(.@"unreachable"); |
| ... | ... | @@ -1796,8 +1813,11 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro |
| 1796 | 1813 | .ErrorUnion => { |
| 1797 | 1814 | const err_ty = ty.errorUnionSet(); |
| 1798 | 1815 | const pl_ty = ty.errorUnionPayload(); |
| 1816 | if (err_ty.errorSetCardinality() == .zero) { |
| 1817 | return self.store(lhs, rhs, pl_ty, 0); |
| 1818 | } |
| 1799 | 1819 | if (!pl_ty.hasRuntimeBitsIgnoreComptime()) { |
| 1800 | | return self.store(lhs, rhs, err_ty, 0); |
| 1820 | return self.store(lhs, rhs, Type.anyerror, 0); |
| 1801 | 1821 | } |
| 1802 | 1822 | |
| 1803 | 1823 | const len = @intCast(u32, ty.abiSize(self.target)); |
| ... | ... | @@ -2256,6 +2276,7 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue { |
| 2256 | 2276 | const target = self.target; |
| 2257 | 2277 | |
| 2258 | 2278 | switch (ty.zigTypeTag()) { |
| 2279 | .Void => return WValue{ .none = {} }, |
| 2259 | 2280 | .Int => { |
| 2260 | 2281 | const int_info = ty.intInfo(self.target); |
| 2261 | 2282 | switch (int_info.signedness) { |
| ... | ... | @@ -2324,6 +2345,10 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue { |
| 2324 | 2345 | }, |
| 2325 | 2346 | .ErrorUnion => { |
| 2326 | 2347 | const error_type = ty.errorUnionSet(); |
| 2348 | if (error_type.errorSetCardinality() == .zero) { |
| 2349 | const pl_val = if (val.castTag(.eu_payload)) |pl| pl.data else Value.initTag(.undef); |
| 2350 | return self.lowerConstant(pl_val, ty.errorUnionPayload()); |
| 2351 | } |
| 2327 | 2352 | const is_pl = val.errorUnionIsPayload(); |
| 2328 | 2353 | const err_val = if (!is_pl) val else Value.initTag(.zero); |
| 2329 | 2354 | return self.lowerConstant(err_val, error_type); |
| ... | ... | @@ -2892,12 +2917,19 @@ fn airIsErr(self: *Self, inst: Air.Inst.Index, opcode: wasm.Opcode) InnerError!W |
| 2892 | 2917 | const err_ty = self.air.typeOf(un_op); |
| 2893 | 2918 | const pl_ty = err_ty.errorUnionPayload(); |
| 2894 | 2919 | |
| 2895 | | // load the error tag value |
| 2920 | if (err_ty.errorUnionSet().errorSetCardinality() == .zero) { |
| 2921 | switch (opcode) { |
| 2922 | .i32_ne => return WValue{ .imm32 = 0 }, |
| 2923 | .i32_eq => return WValue{ .imm32 = 1 }, |
| 2924 | else => unreachable, |
| 2925 | } |
| 2926 | } |
| 2927 | |
| 2896 | 2928 | try self.emitWValue(operand); |
| 2897 | 2929 | if (pl_ty.hasRuntimeBitsIgnoreComptime()) { |
| 2898 | 2930 | try self.addMemArg(.i32_load16_u, .{ |
| 2899 | | .offset = operand.offset(), |
| 2900 | | .alignment = err_ty.errorUnionSet().abiAlignment(self.target), |
| 2931 | .offset = operand.offset() + errUnionErrorOffset(pl_ty, self.target), |
| 2932 | .alignment = Type.anyerror.abiAlignment(self.target), |
| 2901 | 2933 | }); |
| 2902 | 2934 | } |
| 2903 | 2935 | |
| ... | ... | @@ -2905,7 +2937,7 @@ fn airIsErr(self: *Self, inst: Air.Inst.Index, opcode: wasm.Opcode) InnerError!W |
| 2905 | 2937 | try self.addImm32(0); |
| 2906 | 2938 | try self.addTag(Mir.Inst.Tag.fromOpcode(opcode)); |
| 2907 | 2939 | |
| 2908 | | const is_err_tmp = try self.allocLocal(Type.initTag(.i32)); // result is always an i32 |
| 2940 | const is_err_tmp = try self.allocLocal(Type.i32); |
| 2909 | 2941 | try self.addLabel(.local_set, is_err_tmp.local); |
| 2910 | 2942 | return is_err_tmp; |
| 2911 | 2943 | } |
| ... | ... | @@ -2917,14 +2949,18 @@ fn airUnwrapErrUnionPayload(self: *Self, inst: Air.Inst.Index, op_is_ptr: bool) |
| 2917 | 2949 | const op_ty = self.air.typeOf(ty_op.operand); |
| 2918 | 2950 | const err_ty = if (op_is_ptr) op_ty.childType() else op_ty; |
| 2919 | 2951 | const payload_ty = err_ty.errorUnionPayload(); |
| 2952 | |
| 2953 | if (err_ty.errorUnionSet().errorSetCardinality() == .zero) { |
| 2954 | return operand; |
| 2955 | } |
| 2956 | |
| 2920 | 2957 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) return WValue{ .none = {} }; |
| 2921 | | const err_align = err_ty.abiAlignment(self.target); |
| 2922 | | const set_size = err_ty.errorUnionSet().abiSize(self.target); |
| 2923 | | const offset = mem.alignForwardGeneric(u64, set_size, err_align); |
| 2958 | |
| 2959 | const pl_offset = errUnionPayloadOffset(payload_ty, self.target); |
| 2924 | 2960 | if (op_is_ptr or isByRef(payload_ty, self.target)) { |
| 2925 | | return self.buildPointerOffset(operand, offset, .new); |
| 2961 | return self.buildPointerOffset(operand, pl_offset, .new); |
| 2926 | 2962 | } |
| 2927 | | return self.load(operand, payload_ty, @intCast(u32, offset)); |
| 2963 | return self.load(operand, payload_ty, pl_offset); |
| 2928 | 2964 | } |
| 2929 | 2965 | |
| 2930 | 2966 | fn airUnwrapErrUnionError(self: *Self, inst: Air.Inst.Index, op_is_ptr: bool) InnerError!WValue { |
| ... | ... | @@ -2935,11 +2971,16 @@ fn airUnwrapErrUnionError(self: *Self, inst: Air.Inst.Index, op_is_ptr: bool) In |
| 2935 | 2971 | const op_ty = self.air.typeOf(ty_op.operand); |
| 2936 | 2972 | const err_ty = if (op_is_ptr) op_ty.childType() else op_ty; |
| 2937 | 2973 | const payload_ty = err_ty.errorUnionPayload(); |
| 2974 | |
| 2975 | if (err_ty.errorUnionSet().errorSetCardinality() == .zero) { |
| 2976 | return WValue{ .imm32 = 0 }; |
| 2977 | } |
| 2978 | |
| 2938 | 2979 | if (op_is_ptr or !payload_ty.hasRuntimeBitsIgnoreComptime()) { |
| 2939 | 2980 | return operand; |
| 2940 | 2981 | } |
| 2941 | 2982 | |
| 2942 | | return self.load(operand, err_ty.errorUnionSet(), 0); |
| 2983 | return self.load(operand, Type.anyerror, errUnionErrorOffset(payload_ty, self.target)); |
| 2943 | 2984 | } |
| 2944 | 2985 | |
| 2945 | 2986 | fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| ... | ... | @@ -2947,22 +2988,26 @@ fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 2947 | 2988 | |
| 2948 | 2989 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2949 | 2990 | const operand = try self.resolveInst(ty_op.operand); |
| 2991 | const err_ty = self.air.typeOfIndex(inst); |
| 2950 | 2992 | |
| 2951 | | const op_ty = self.air.typeOf(ty_op.operand); |
| 2952 | | if (!op_ty.hasRuntimeBitsIgnoreComptime()) return operand; |
| 2953 | | const err_union_ty = self.air.getRefType(ty_op.ty); |
| 2954 | | const err_align = err_union_ty.abiAlignment(self.target); |
| 2955 | | const set_size = err_union_ty.errorUnionSet().abiSize(self.target); |
| 2956 | | const offset = mem.alignForwardGeneric(u64, set_size, err_align); |
| 2993 | if (err_ty.errorUnionSet().errorSetCardinality() == .zero) { |
| 2994 | return operand; |
| 2995 | } |
| 2996 | |
| 2997 | const pl_ty = self.air.typeOf(ty_op.operand); |
| 2998 | if (!pl_ty.hasRuntimeBitsIgnoreComptime()) { |
| 2999 | return operand; |
| 3000 | } |
| 2957 | 3001 | |
| 2958 | | const err_union = try self.allocStack(err_union_ty); |
| 2959 | | const payload_ptr = try self.buildPointerOffset(err_union, offset, .new); |
| 2960 | | try self.store(payload_ptr, operand, op_ty, 0); |
| 3002 | const err_union = try self.allocStack(err_ty); |
| 3003 | const payload_ptr = try self.buildPointerOffset(err_union, errUnionPayloadOffset(pl_ty, self.target), .new); |
| 3004 | try self.store(payload_ptr, operand, pl_ty, 0); |
| 2961 | 3005 | |
| 2962 | 3006 | // ensure we also write '0' to the error part, so any present stack value gets overwritten by it. |
| 2963 | 3007 | try self.emitWValue(err_union); |
| 2964 | 3008 | try self.addImm32(0); |
| 2965 | | try self.addMemArg(.i32_store16, .{ .offset = err_union.offset(), .alignment = 2 }); |
| 3009 | const err_val_offset = errUnionErrorOffset(pl_ty, self.target); |
| 3010 | try self.addMemArg(.i32_store16, .{ .offset = err_union.offset() + err_val_offset, .alignment = 2 }); |
| 2966 | 3011 | |
| 2967 | 3012 | return err_union; |
| 2968 | 3013 | } |
| ... | ... | @@ -2973,17 +3018,18 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 2973 | 3018 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2974 | 3019 | const operand = try self.resolveInst(ty_op.operand); |
| 2975 | 3020 | const err_ty = self.air.getRefType(ty_op.ty); |
| 3021 | const pl_ty = err_ty.errorUnionPayload(); |
| 2976 | 3022 | |
| 2977 | | if (!err_ty.errorUnionPayload().hasRuntimeBitsIgnoreComptime()) return operand; |
| 3023 | if (!pl_ty.hasRuntimeBitsIgnoreComptime()) { |
| 3024 | return operand; |
| 3025 | } |
| 2978 | 3026 | |
| 2979 | 3027 | const err_union = try self.allocStack(err_ty); |
| 2980 | | try self.store(err_union, operand, err_ty.errorUnionSet(), 0); |
| 3028 | // store error value |
| 3029 | try self.store(err_union, operand, Type.anyerror, errUnionErrorOffset(pl_ty, self.target)); |
| 2981 | 3030 | |
| 2982 | 3031 | // write 'undefined' to the payload |
| 2983 | | const err_align = err_ty.abiAlignment(self.target); |
| 2984 | | const set_size = err_ty.errorUnionSet().abiSize(self.target); |
| 2985 | | const offset = mem.alignForwardGeneric(u64, set_size, err_align); |
| 2986 | | const payload_ptr = try self.buildPointerOffset(err_union, offset, .new); |
| 3032 | const payload_ptr = try self.buildPointerOffset(err_union, errUnionPayloadOffset(pl_ty, self.target), .new); |
| 2987 | 3033 | const len = @intCast(u32, err_ty.errorUnionPayload().abiSize(self.target)); |
| 2988 | 3034 | try self.memset(payload_ptr, .{ .imm32 = len }, .{ .imm32 = 0xaaaaaaaa }); |
| 2989 | 3035 | |
| ... | ... | @@ -3927,12 +3973,16 @@ fn airFptrunc(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 3927 | 3973 | fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 3928 | 3974 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 3929 | 3975 | const err_set_ty = self.air.typeOf(ty_op.operand).childType(); |
| 3930 | | const err_ty = err_set_ty.errorUnionSet(); |
| 3931 | 3976 | const payload_ty = err_set_ty.errorUnionPayload(); |
| 3932 | 3977 | const operand = try self.resolveInst(ty_op.operand); |
| 3933 | 3978 | |
| 3934 | 3979 | // set error-tag to '0' to annotate error union is non-error |
| 3935 | | try self.store(operand, .{ .imm32 = 0 }, err_ty, 0); |
| 3980 | try self.store( |
| 3981 | operand, |
| 3982 | .{ .imm32 = 0 }, |
| 3983 | Type.anyerror, |
| 3984 | errUnionErrorOffset(payload_ty, self.target), |
| 3985 | ); |
| 3936 | 3986 | |
| 3937 | 3987 | if (self.liveness.isUnused(inst)) return WValue{ .none = {} }; |
| 3938 | 3988 | |
| ... | ... | @@ -3940,11 +3990,7 @@ fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) InnerError!WValue |
| 3940 | 3990 | return operand; |
| 3941 | 3991 | } |
| 3942 | 3992 | |
| 3943 | | const err_align = err_set_ty.abiAlignment(self.target); |
| 3944 | | const set_size = err_ty.abiSize(self.target); |
| 3945 | | const offset = mem.alignForwardGeneric(u64, set_size, err_align); |
| 3946 | | |
| 3947 | | return self.buildPointerOffset(operand, @intCast(u32, offset), .new); |
| 3993 | return self.buildPointerOffset(operand, errUnionPayloadOffset(payload_ty, self.target), .new); |
| 3948 | 3994 | } |
| 3949 | 3995 | |
| 3950 | 3996 | fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| ... | ... | @@ -4572,3 +4618,17 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !WValue { |
| 4572 | 4618 | } }); |
| 4573 | 4619 | return WValue{ .none = {} }; |
| 4574 | 4620 | } |
| 4621 | |
| 4622 | fn errUnionPayloadOffset(payload_ty: Type, target: std.Target) u32 { |
| 4623 | if (Type.anyerror.abiAlignment(target) > payload_ty.abiAlignment(target)) { |
| 4624 | return @intCast(u32, Type.anyerror.abiSize(target)); |
| 4625 | } |
| 4626 | return 0; |
| 4627 | } |
| 4628 | |
| 4629 | fn errUnionErrorOffset(payload_ty: Type, target: std.Target) u32 { |
| 4630 | if (Type.anyerror.abiAlignment(target) > payload_ty.abiAlignment(target)) { |
| 4631 | return 0; |
| 4632 | } |
| 4633 | return @intCast(u32, payload_ty.abiSize(target)); |
| 4634 | } |