| ... | @@ -876,9 +876,6 @@ fn analyzeBodyInner( | ... | @@ -876,9 +876,6 @@ fn analyzeBodyInner( |
| 876 | .add => try sema.zirArithmetic(block, inst, .add), | 876 | .add => try sema.zirArithmetic(block, inst, .add), |
| 877 | .addwrap => try sema.zirArithmetic(block, inst, .addwrap), | 877 | .addwrap => try sema.zirArithmetic(block, inst, .addwrap), |
| 878 | .add_sat => try sema.zirArithmetic(block, inst, .add_sat), | 878 | .add_sat => try sema.zirArithmetic(block, inst, .add_sat), |
| 879 | .mod_rem => try sema.zirArithmetic(block, inst, .mod_rem), | | |
| 880 | .mod => try sema.zirArithmetic(block, inst, .mod), | | |
| 881 | .rem => try sema.zirArithmetic(block, inst, .rem), | | |
| 882 | .mul => try sema.zirArithmetic(block, inst, .mul), | 879 | .mul => try sema.zirArithmetic(block, inst, .mul), |
| 883 | .mulwrap => try sema.zirArithmetic(block, inst, .mulwrap), | 880 | .mulwrap => try sema.zirArithmetic(block, inst, .mulwrap), |
| 884 | .mul_sat => try sema.zirArithmetic(block, inst, .mul_sat), | 881 | .mul_sat => try sema.zirArithmetic(block, inst, .mul_sat), |
| ... | @@ -891,6 +888,10 @@ fn analyzeBodyInner( | ... | @@ -891,6 +888,10 @@ fn analyzeBodyInner( |
| 891 | .div_floor => try sema.zirDivFloor(block, inst), | 888 | .div_floor => try sema.zirDivFloor(block, inst), |
| 892 | .div_trunc => try sema.zirDivTrunc(block, inst), | 889 | .div_trunc => try sema.zirDivTrunc(block, inst), |
| 893 | | 890 | |
| | 891 | .mod_rem => try sema.zirModRem(block, inst), |
| | 892 | .mod => try sema.zirMod(block, inst), |
| | 893 | .rem => try sema.zirRem(block, inst), |
| | 894 | |
| 894 | .maximum => try sema.zirMinMax(block, inst, .max), | 895 | .maximum => try sema.zirMinMax(block, inst, .max), |
| 895 | .minimum => try sema.zirMinMax(block, inst, .min), | 896 | .minimum => try sema.zirMinMax(block, inst, .min), |
| 896 | | 897 | |
| ... | @@ -11621,6 +11622,341 @@ fn airTag(block: *Block, is_int: bool, normal: Air.Inst.Tag, optimized: Air.Inst | ... | @@ -11621,6 +11622,341 @@ fn airTag(block: *Block, is_int: bool, normal: Air.Inst.Tag, optimized: Air.Inst |
| 11621 | }; | 11622 | }; |
| 11622 | } | 11623 | } |
| 11623 | | 11624 | |
| | 11625 | fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| | 11626 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| | 11627 | const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node }; |
| | 11628 | const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; |
| | 11629 | const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; |
| | 11630 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; |
| | 11631 | const lhs = try sema.resolveInst(extra.lhs); |
| | 11632 | const rhs = try sema.resolveInst(extra.rhs); |
| | 11633 | const lhs_ty = sema.typeOf(lhs); |
| | 11634 | const rhs_ty = sema.typeOf(rhs); |
| | 11635 | const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(); |
| | 11636 | const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(); |
| | 11637 | try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); |
| | 11638 | try sema.checkInvalidPtrArithmetic(block, src, lhs_ty, .mod_rem); |
| | 11639 | |
| | 11640 | const instructions = &[_]Air.Inst.Ref{ lhs, rhs }; |
| | 11641 | const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ |
| | 11642 | .override = &[_]LazySrcLoc{ lhs_src, rhs_src }, |
| | 11643 | }); |
| | 11644 | |
| | 11645 | const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src); |
| | 11646 | const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src); |
| | 11647 | |
| | 11648 | const lhs_scalar_ty = lhs_ty.scalarType(); |
| | 11649 | const rhs_scalar_ty = rhs_ty.scalarType(); |
| | 11650 | const scalar_tag = resolved_type.scalarType().zigTypeTag(); |
| | 11651 | |
| | 11652 | const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt; |
| | 11653 | |
| | 11654 | try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .mod_rem); |
| | 11655 | |
| | 11656 | const mod = sema.mod; |
| | 11657 | const target = mod.getTarget(); |
| | 11658 | const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(block, lhs_src, casted_lhs); |
| | 11659 | const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(block, rhs_src, casted_rhs); |
| | 11660 | |
| | 11661 | const runtime_src = rs: { |
| | 11662 | // For integers: |
| | 11663 | // Either operand being undef is a compile error because there exists |
| | 11664 | // a possible value (TODO what is it?) that would invoke illegal behavior. |
| | 11665 | // TODO: can lhs undef be handled better? |
| | 11666 | // |
| | 11667 | // For floats: |
| | 11668 | // If the rhs is zero, compile error for division by zero. |
| | 11669 | // If the rhs is undefined, compile error because there is a possible |
| | 11670 | // value (zero) for which the division would be illegal behavior. |
| | 11671 | // If the lhs is undefined, result is undefined. |
| | 11672 | // |
| | 11673 | // For either one: if the result would be different between @mod and @rem, |
| | 11674 | // then emit a compile error saying you have to pick one. |
| | 11675 | if (is_int) { |
| | 11676 | if (maybe_lhs_val) |lhs_val| { |
| | 11677 | if (lhs_val.isUndef()) { |
| | 11678 | return sema.failWithUseOfUndef(block, lhs_src); |
| | 11679 | } |
| | 11680 | if (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { |
| | 11681 | return sema.addConstant(resolved_type, Value.zero); |
| | 11682 | } |
| | 11683 | } else if (lhs_scalar_ty.isSignedInt()) { |
| | 11684 | return sema.failWithModRemNegative(block, lhs_src, lhs_ty, rhs_ty); |
| | 11685 | } |
| | 11686 | if (maybe_rhs_val) |rhs_val| { |
| | 11687 | if (rhs_val.isUndef()) { |
| | 11688 | return sema.failWithUseOfUndef(block, rhs_src); |
| | 11689 | } |
| | 11690 | if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { |
| | 11691 | return sema.failWithDivideByZero(block, rhs_src); |
| | 11692 | } |
| | 11693 | if (maybe_lhs_val) |lhs_val| { |
| | 11694 | const rem_result = try lhs_val.intRem(rhs_val, resolved_type, sema.arena, target); |
| | 11695 | // If this answer could possibly be different by doing `intMod`, |
| | 11696 | // we must emit a compile error. Otherwise, it's OK. |
| | 11697 | if ((try rhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src))) != (try lhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src))) and |
| | 11698 | !(try rem_result.compareWithZeroAdvanced(.eq, sema.kit(block, src)))) |
| | 11699 | { |
| | 11700 | const bad_src = if (try lhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src))) |
| | 11701 | lhs_src |
| | 11702 | else |
| | 11703 | rhs_src; |
| | 11704 | return sema.failWithModRemNegative(block, bad_src, lhs_ty, rhs_ty); |
| | 11705 | } |
| | 11706 | if (try lhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src))) { |
| | 11707 | // Negative |
| | 11708 | return sema.addConstant(resolved_type, Value.zero); |
| | 11709 | } |
| | 11710 | return sema.addConstant(resolved_type, rem_result); |
| | 11711 | } |
| | 11712 | break :rs lhs_src; |
| | 11713 | } else if (rhs_scalar_ty.isSignedInt()) { |
| | 11714 | return sema.failWithModRemNegative(block, rhs_src, lhs_ty, rhs_ty); |
| | 11715 | } else { |
| | 11716 | break :rs rhs_src; |
| | 11717 | } |
| | 11718 | } |
| | 11719 | // float operands |
| | 11720 | if (maybe_rhs_val) |rhs_val| { |
| | 11721 | if (rhs_val.isUndef()) { |
| | 11722 | return sema.failWithUseOfUndef(block, rhs_src); |
| | 11723 | } |
| | 11724 | if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { |
| | 11725 | return sema.failWithDivideByZero(block, rhs_src); |
| | 11726 | } |
| | 11727 | if (try rhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src))) { |
| | 11728 | return sema.failWithModRemNegative(block, rhs_src, lhs_ty, rhs_ty); |
| | 11729 | } |
| | 11730 | if (maybe_lhs_val) |lhs_val| { |
| | 11731 | if (lhs_val.isUndef() or (try lhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src)))) { |
| | 11732 | return sema.failWithModRemNegative(block, lhs_src, lhs_ty, rhs_ty); |
| | 11733 | } |
| | 11734 | return sema.addConstant( |
| | 11735 | resolved_type, |
| | 11736 | try lhs_val.floatRem(rhs_val, resolved_type, sema.arena, target), |
| | 11737 | ); |
| | 11738 | } else { |
| | 11739 | return sema.failWithModRemNegative(block, lhs_src, lhs_ty, rhs_ty); |
| | 11740 | } |
| | 11741 | } else { |
| | 11742 | return sema.failWithModRemNegative(block, rhs_src, lhs_ty, rhs_ty); |
| | 11743 | } |
| | 11744 | }; |
| | 11745 | |
| | 11746 | try sema.requireRuntimeBlock(block, src, runtime_src); |
| | 11747 | |
| | 11748 | if (block.wantSafety()) { |
| | 11749 | try sema.addDivByZeroSafety(block, resolved_type, maybe_rhs_val, casted_rhs, is_int); |
| | 11750 | } |
| | 11751 | |
| | 11752 | const air_tag = airTag(block, is_int, .rem, .rem_optimized); |
| | 11753 | return block.addBinOp(air_tag, casted_lhs, casted_rhs); |
| | 11754 | } |
| | 11755 | |
| | 11756 | fn zirMod(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| | 11757 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| | 11758 | const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node }; |
| | 11759 | const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; |
| | 11760 | const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; |
| | 11761 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; |
| | 11762 | const lhs = try sema.resolveInst(extra.lhs); |
| | 11763 | const rhs = try sema.resolveInst(extra.rhs); |
| | 11764 | const lhs_ty = sema.typeOf(lhs); |
| | 11765 | const rhs_ty = sema.typeOf(rhs); |
| | 11766 | const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(); |
| | 11767 | const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(); |
| | 11768 | try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); |
| | 11769 | try sema.checkInvalidPtrArithmetic(block, src, lhs_ty, .mod); |
| | 11770 | |
| | 11771 | const instructions = &[_]Air.Inst.Ref{ lhs, rhs }; |
| | 11772 | const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ |
| | 11773 | .override = &[_]LazySrcLoc{ lhs_src, rhs_src }, |
| | 11774 | }); |
| | 11775 | |
| | 11776 | const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src); |
| | 11777 | const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src); |
| | 11778 | |
| | 11779 | const scalar_tag = resolved_type.scalarType().zigTypeTag(); |
| | 11780 | |
| | 11781 | const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt; |
| | 11782 | |
| | 11783 | try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .mod); |
| | 11784 | |
| | 11785 | const mod = sema.mod; |
| | 11786 | const target = mod.getTarget(); |
| | 11787 | const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(block, lhs_src, casted_lhs); |
| | 11788 | const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(block, rhs_src, casted_rhs); |
| | 11789 | |
| | 11790 | const runtime_src = rs: { |
| | 11791 | // For integers: |
| | 11792 | // Either operand being undef is a compile error because there exists |
| | 11793 | // a possible value (TODO what is it?) that would invoke illegal behavior. |
| | 11794 | // TODO: can lhs zero be handled better? |
| | 11795 | // TODO: can lhs undef be handled better? |
| | 11796 | // |
| | 11797 | // For floats: |
| | 11798 | // If the rhs is zero, compile error for division by zero. |
| | 11799 | // If the rhs is undefined, compile error because there is a possible |
| | 11800 | // value (zero) for which the division would be illegal behavior. |
| | 11801 | // If the lhs is undefined, result is undefined. |
| | 11802 | if (is_int) { |
| | 11803 | if (maybe_lhs_val) |lhs_val| { |
| | 11804 | if (lhs_val.isUndef()) { |
| | 11805 | return sema.failWithUseOfUndef(block, lhs_src); |
| | 11806 | } |
| | 11807 | } |
| | 11808 | if (maybe_rhs_val) |rhs_val| { |
| | 11809 | if (rhs_val.isUndef()) { |
| | 11810 | return sema.failWithUseOfUndef(block, rhs_src); |
| | 11811 | } |
| | 11812 | if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { |
| | 11813 | return sema.failWithDivideByZero(block, rhs_src); |
| | 11814 | } |
| | 11815 | if (maybe_lhs_val) |lhs_val| { |
| | 11816 | return sema.addConstant( |
| | 11817 | resolved_type, |
| | 11818 | try lhs_val.intMod(rhs_val, resolved_type, sema.arena, target), |
| | 11819 | ); |
| | 11820 | } |
| | 11821 | break :rs lhs_src; |
| | 11822 | } else { |
| | 11823 | break :rs rhs_src; |
| | 11824 | } |
| | 11825 | } |
| | 11826 | // float operands |
| | 11827 | if (maybe_rhs_val) |rhs_val| { |
| | 11828 | if (rhs_val.isUndef()) { |
| | 11829 | return sema.failWithUseOfUndef(block, rhs_src); |
| | 11830 | } |
| | 11831 | if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { |
| | 11832 | return sema.failWithDivideByZero(block, rhs_src); |
| | 11833 | } |
| | 11834 | } |
| | 11835 | if (maybe_lhs_val) |lhs_val| { |
| | 11836 | if (lhs_val.isUndef()) { |
| | 11837 | return sema.addConstUndef(resolved_type); |
| | 11838 | } |
| | 11839 | if (maybe_rhs_val) |rhs_val| { |
| | 11840 | return sema.addConstant( |
| | 11841 | resolved_type, |
| | 11842 | try lhs_val.floatMod(rhs_val, resolved_type, sema.arena, target), |
| | 11843 | ); |
| | 11844 | } else break :rs rhs_src; |
| | 11845 | } else break :rs lhs_src; |
| | 11846 | }; |
| | 11847 | |
| | 11848 | try sema.requireRuntimeBlock(block, src, runtime_src); |
| | 11849 | |
| | 11850 | if (block.wantSafety()) { |
| | 11851 | try sema.addDivByZeroSafety(block, resolved_type, maybe_rhs_val, casted_rhs, is_int); |
| | 11852 | } |
| | 11853 | |
| | 11854 | const air_tag = airTag(block, is_int, .mod, .mod_optimized); |
| | 11855 | return block.addBinOp(air_tag, casted_lhs, casted_rhs); |
| | 11856 | } |
| | 11857 | |
| | 11858 | fn zirRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| | 11859 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| | 11860 | const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node }; |
| | 11861 | const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; |
| | 11862 | const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; |
| | 11863 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; |
| | 11864 | const lhs = try sema.resolveInst(extra.lhs); |
| | 11865 | const rhs = try sema.resolveInst(extra.rhs); |
| | 11866 | const lhs_ty = sema.typeOf(lhs); |
| | 11867 | const rhs_ty = sema.typeOf(rhs); |
| | 11868 | const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(); |
| | 11869 | const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(); |
| | 11870 | try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); |
| | 11871 | try sema.checkInvalidPtrArithmetic(block, src, lhs_ty, .rem); |
| | 11872 | |
| | 11873 | const instructions = &[_]Air.Inst.Ref{ lhs, rhs }; |
| | 11874 | const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ |
| | 11875 | .override = &[_]LazySrcLoc{ lhs_src, rhs_src }, |
| | 11876 | }); |
| | 11877 | |
| | 11878 | const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src); |
| | 11879 | const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src); |
| | 11880 | |
| | 11881 | const scalar_tag = resolved_type.scalarType().zigTypeTag(); |
| | 11882 | |
| | 11883 | const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt; |
| | 11884 | |
| | 11885 | try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .rem); |
| | 11886 | |
| | 11887 | const mod = sema.mod; |
| | 11888 | const target = mod.getTarget(); |
| | 11889 | const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(block, lhs_src, casted_lhs); |
| | 11890 | const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(block, rhs_src, casted_rhs); |
| | 11891 | |
| | 11892 | const runtime_src = rs: { |
| | 11893 | // For integers: |
| | 11894 | // Either operand being undef is a compile error because there exists |
| | 11895 | // a possible value (TODO what is it?) that would invoke illegal behavior. |
| | 11896 | // TODO: can lhs zero be handled better? |
| | 11897 | // TODO: can lhs undef be handled better? |
| | 11898 | // |
| | 11899 | // For floats: |
| | 11900 | // If the rhs is zero, compile error for division by zero. |
| | 11901 | // If the rhs is undefined, compile error because there is a possible |
| | 11902 | // value (zero) for which the division would be illegal behavior. |
| | 11903 | // If the lhs is undefined, result is undefined. |
| | 11904 | if (is_int) { |
| | 11905 | if (maybe_lhs_val) |lhs_val| { |
| | 11906 | if (lhs_val.isUndef()) { |
| | 11907 | return sema.failWithUseOfUndef(block, lhs_src); |
| | 11908 | } |
| | 11909 | } |
| | 11910 | if (maybe_rhs_val) |rhs_val| { |
| | 11911 | if (rhs_val.isUndef()) { |
| | 11912 | return sema.failWithUseOfUndef(block, rhs_src); |
| | 11913 | } |
| | 11914 | if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { |
| | 11915 | return sema.failWithDivideByZero(block, rhs_src); |
| | 11916 | } |
| | 11917 | if (maybe_lhs_val) |lhs_val| { |
| | 11918 | return sema.addConstant( |
| | 11919 | resolved_type, |
| | 11920 | try lhs_val.intRem(rhs_val, resolved_type, sema.arena, target), |
| | 11921 | ); |
| | 11922 | } |
| | 11923 | break :rs lhs_src; |
| | 11924 | } else { |
| | 11925 | break :rs rhs_src; |
| | 11926 | } |
| | 11927 | } |
| | 11928 | // float operands |
| | 11929 | if (maybe_rhs_val) |rhs_val| { |
| | 11930 | if (rhs_val.isUndef()) { |
| | 11931 | return sema.failWithUseOfUndef(block, rhs_src); |
| | 11932 | } |
| | 11933 | if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { |
| | 11934 | return sema.failWithDivideByZero(block, rhs_src); |
| | 11935 | } |
| | 11936 | } |
| | 11937 | if (maybe_lhs_val) |lhs_val| { |
| | 11938 | if (lhs_val.isUndef()) { |
| | 11939 | return sema.addConstUndef(resolved_type); |
| | 11940 | } |
| | 11941 | if (maybe_rhs_val) |rhs_val| { |
| | 11942 | return sema.addConstant( |
| | 11943 | resolved_type, |
| | 11944 | try lhs_val.floatRem(rhs_val, resolved_type, sema.arena, target), |
| | 11945 | ); |
| | 11946 | } else break :rs rhs_src; |
| | 11947 | } else break :rs lhs_src; |
| | 11948 | }; |
| | 11949 | |
| | 11950 | try sema.requireRuntimeBlock(block, src, runtime_src); |
| | 11951 | |
| | 11952 | if (block.wantSafety()) { |
| | 11953 | try sema.addDivByZeroSafety(block, resolved_type, maybe_rhs_val, casted_rhs, is_int); |
| | 11954 | } |
| | 11955 | |
| | 11956 | const air_tag = airTag(block, is_int, .rem, .rem_optimized); |
| | 11957 | return block.addBinOp(air_tag, casted_lhs, casted_rhs); |
| | 11958 | } |
| | 11959 | |
| 11624 | fn zirOverflowArithmetic( | 11960 | fn zirOverflowArithmetic( |
| 11625 | sema: *Sema, | 11961 | sema: *Sema, |
| 11626 | block: *Block, | 11962 | block: *Block, |
| ... | @@ -11882,8 +12218,6 @@ fn analyzeArithmetic( | ... | @@ -11882,8 +12218,6 @@ fn analyzeArithmetic( |
| 11882 | const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src); | 12218 | const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src); |
| 11883 | const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src); | 12219 | const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src); |
| 11884 | | 12220 | |
| 11885 | const lhs_scalar_ty = lhs_ty.scalarType(); | | |
| 11886 | const rhs_scalar_ty = rhs_ty.scalarType(); | | |
| 11887 | const scalar_tag = resolved_type.scalarType().zigTypeTag(); | 12221 | const scalar_tag = resolved_type.scalarType().zigTypeTag(); |
| 11888 | | 12222 | |
| 11889 | const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt; | 12223 | const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt; |
| ... | @@ -12229,206 +12563,6 @@ fn analyzeArithmetic( | ... | @@ -12229,206 +12563,6 @@ fn analyzeArithmetic( |
| 12229 | } else break :rs .{ .src = lhs_src, .air_tag = .mul_sat }; | 12563 | } else break :rs .{ .src = lhs_src, .air_tag = .mul_sat }; |
| 12230 | } else break :rs .{ .src = rhs_src, .air_tag = .mul_sat }; | 12564 | } else break :rs .{ .src = rhs_src, .air_tag = .mul_sat }; |
| 12231 | }, | 12565 | }, |
| 12232 | .mod_rem => { | | |
| 12233 | // For integers: | | |
| 12234 | // Either operand being undef is a compile error because there exists | | |
| 12235 | // a possible value (TODO what is it?) that would invoke illegal behavior. | | |
| 12236 | // TODO: can lhs undef be handled better? | | |
| 12237 | // | | |
| 12238 | // For floats: | | |
| 12239 | // If the rhs is zero, compile error for division by zero. | | |
| 12240 | // If the rhs is undefined, compile error because there is a possible | | |
| 12241 | // value (zero) for which the division would be illegal behavior. | | |
| 12242 | // If the lhs is undefined, result is undefined. | | |
| 12243 | // | | |
| 12244 | // For either one: if the result would be different between @mod and @rem, | | |
| 12245 | // then emit a compile error saying you have to pick one. | | |
| 12246 | if (is_int) { | | |
| 12247 | if (maybe_lhs_val) |lhs_val| { | | |
| 12248 | if (lhs_val.isUndef()) { | | |
| 12249 | return sema.failWithUseOfUndef(block, lhs_src); | | |
| 12250 | } | | |
| 12251 | if (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { | | |
| 12252 | return sema.addConstant(resolved_type, Value.zero); | | |
| 12253 | } | | |
| 12254 | } else if (lhs_scalar_ty.isSignedInt()) { | | |
| 12255 | return sema.failWithModRemNegative(block, lhs_src, lhs_ty, rhs_ty); | | |
| 12256 | } | | |
| 12257 | if (maybe_rhs_val) |rhs_val| { | | |
| 12258 | if (rhs_val.isUndef()) { | | |
| 12259 | return sema.failWithUseOfUndef(block, rhs_src); | | |
| 12260 | } | | |
| 12261 | if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { | | |
| 12262 | return sema.failWithDivideByZero(block, rhs_src); | | |
| 12263 | } | | |
| 12264 | if (maybe_lhs_val) |lhs_val| { | | |
| 12265 | const rem_result = try lhs_val.intRem(rhs_val, resolved_type, sema.arena, target); | | |
| 12266 | // If this answer could possibly be different by doing `intMod`, | | |
| 12267 | // we must emit a compile error. Otherwise, it's OK. | | |
| 12268 | if ((try rhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src))) != (try lhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src))) and | | |
| 12269 | !(try rem_result.compareWithZeroAdvanced(.eq, sema.kit(block, src)))) | | |
| 12270 | { | | |
| 12271 | const bad_src = if (try lhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src))) | | |
| 12272 | lhs_src | | |
| 12273 | else | | |
| 12274 | rhs_src; | | |
| 12275 | return sema.failWithModRemNegative(block, bad_src, lhs_ty, rhs_ty); | | |
| 12276 | } | | |
| 12277 | if (try lhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src))) { | | |
| 12278 | // Negative | | |
| 12279 | return sema.addConstant(resolved_type, Value.zero); | | |
| 12280 | } | | |
| 12281 | return sema.addConstant(resolved_type, rem_result); | | |
| 12282 | } | | |
| 12283 | break :rs .{ .src = lhs_src, .air_tag = .rem }; | | |
| 12284 | } else if (rhs_scalar_ty.isSignedInt()) { | | |
| 12285 | return sema.failWithModRemNegative(block, rhs_src, lhs_ty, rhs_ty); | | |
| 12286 | } else { | | |
| 12287 | break :rs .{ .src = rhs_src, .air_tag = .rem }; | | |
| 12288 | } | | |
| 12289 | } | | |
| 12290 | // float operands | | |
| 12291 | if (maybe_rhs_val) |rhs_val| { | | |
| 12292 | if (rhs_val.isUndef()) { | | |
| 12293 | return sema.failWithUseOfUndef(block, rhs_src); | | |
| 12294 | } | | |
| 12295 | if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { | | |
| 12296 | return sema.failWithDivideByZero(block, rhs_src); | | |
| 12297 | } | | |
| 12298 | if (try rhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src))) { | | |
| 12299 | return sema.failWithModRemNegative(block, rhs_src, lhs_ty, rhs_ty); | | |
| 12300 | } | | |
| 12301 | if (maybe_lhs_val) |lhs_val| { | | |
| 12302 | if (lhs_val.isUndef() or (try lhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src)))) { | | |
| 12303 | return sema.failWithModRemNegative(block, lhs_src, lhs_ty, rhs_ty); | | |
| 12304 | } | | |
| 12305 | return sema.addConstant( | | |
| 12306 | resolved_type, | | |
| 12307 | try lhs_val.floatRem(rhs_val, resolved_type, sema.arena, target), | | |
| 12308 | ); | | |
| 12309 | } else { | | |
| 12310 | return sema.failWithModRemNegative(block, lhs_src, lhs_ty, rhs_ty); | | |
| 12311 | } | | |
| 12312 | } else { | | |
| 12313 | return sema.failWithModRemNegative(block, rhs_src, lhs_ty, rhs_ty); | | |
| 12314 | } | | |
| 12315 | }, | | |
| 12316 | .rem => { | | |
| 12317 | // For integers: | | |
| 12318 | // Either operand being undef is a compile error because there exists | | |
| 12319 | // a possible value (TODO what is it?) that would invoke illegal behavior. | | |
| 12320 | // TODO: can lhs zero be handled better? | | |
| 12321 | // TODO: can lhs undef be handled better? | | |
| 12322 | // | | |
| 12323 | // For floats: | | |
| 12324 | // If the rhs is zero, compile error for division by zero. | | |
| 12325 | // If the rhs is undefined, compile error because there is a possible | | |
| 12326 | // value (zero) for which the division would be illegal behavior. | | |
| 12327 | // If the lhs is undefined, result is undefined. | | |
| 12328 | if (is_int) { | | |
| 12329 | if (maybe_lhs_val) |lhs_val| { | | |
| 12330 | if (lhs_val.isUndef()) { | | |
| 12331 | return sema.failWithUseOfUndef(block, lhs_src); | | |
| 12332 | } | | |
| 12333 | } | | |
| 12334 | if (maybe_rhs_val) |rhs_val| { | | |
| 12335 | if (rhs_val.isUndef()) { | | |
| 12336 | return sema.failWithUseOfUndef(block, rhs_src); | | |
| 12337 | } | | |
| 12338 | if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { | | |
| 12339 | return sema.failWithDivideByZero(block, rhs_src); | | |
| 12340 | } | | |
| 12341 | if (maybe_lhs_val) |lhs_val| { | | |
| 12342 | return sema.addConstant( | | |
| 12343 | resolved_type, | | |
| 12344 | try lhs_val.intRem(rhs_val, resolved_type, sema.arena, target), | | |
| 12345 | ); | | |
| 12346 | } | | |
| 12347 | break :rs .{ .src = lhs_src, .air_tag = .rem }; | | |
| 12348 | } else { | | |
| 12349 | break :rs .{ .src = rhs_src, .air_tag = .rem }; | | |
| 12350 | } | | |
| 12351 | } | | |
| 12352 | // float operands | | |
| 12353 | if (maybe_rhs_val) |rhs_val| { | | |
| 12354 | if (rhs_val.isUndef()) { | | |
| 12355 | return sema.failWithUseOfUndef(block, rhs_src); | | |
| 12356 | } | | |
| 12357 | if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { | | |
| 12358 | return sema.failWithDivideByZero(block, rhs_src); | | |
| 12359 | } | | |
| 12360 | } | | |
| 12361 | const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .rem_optimized else .rem; | | |
| 12362 | if (maybe_lhs_val) |lhs_val| { | | |
| 12363 | if (lhs_val.isUndef()) { | | |
| 12364 | return sema.addConstUndef(resolved_type); | | |
| 12365 | } | | |
| 12366 | if (maybe_rhs_val) |rhs_val| { | | |
| 12367 | return sema.addConstant( | | |
| 12368 | resolved_type, | | |
| 12369 | try lhs_val.floatRem(rhs_val, resolved_type, sema.arena, target), | | |
| 12370 | ); | | |
| 12371 | } else break :rs .{ .src = rhs_src, .air_tag = air_tag }; | | |
| 12372 | } else break :rs .{ .src = lhs_src, .air_tag = air_tag }; | | |
| 12373 | }, | | |
| 12374 | .mod => { | | |
| 12375 | // For integers: | | |
| 12376 | // Either operand being undef is a compile error because there exists | | |
| 12377 | // a possible value (TODO what is it?) that would invoke illegal behavior. | | |
| 12378 | // TODO: can lhs zero be handled better? | | |
| 12379 | // TODO: can lhs undef be handled better? | | |
| 12380 | // | | |
| 12381 | // For floats: | | |
| 12382 | // If the rhs is zero, compile error for division by zero. | | |
| 12383 | // If the rhs is undefined, compile error because there is a possible | | |
| 12384 | // value (zero) for which the division would be illegal behavior. | | |
| 12385 | // If the lhs is undefined, result is undefined. | | |
| 12386 | if (is_int) { | | |
| 12387 | if (maybe_lhs_val) |lhs_val| { | | |
| 12388 | if (lhs_val.isUndef()) { | | |
| 12389 | return sema.failWithUseOfUndef(block, lhs_src); | | |
| 12390 | } | | |
| 12391 | } | | |
| 12392 | if (maybe_rhs_val) |rhs_val| { | | |
| 12393 | if (rhs_val.isUndef()) { | | |
| 12394 | return sema.failWithUseOfUndef(block, rhs_src); | | |
| 12395 | } | | |
| 12396 | if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { | | |
| 12397 | return sema.failWithDivideByZero(block, rhs_src); | | |
| 12398 | } | | |
| 12399 | if (maybe_lhs_val) |lhs_val| { | | |
| 12400 | return sema.addConstant( | | |
| 12401 | resolved_type, | | |
| 12402 | try lhs_val.intMod(rhs_val, resolved_type, sema.arena, target), | | |
| 12403 | ); | | |
| 12404 | } | | |
| 12405 | break :rs .{ .src = lhs_src, .air_tag = .mod }; | | |
| 12406 | } else { | | |
| 12407 | break :rs .{ .src = rhs_src, .air_tag = .mod }; | | |
| 12408 | } | | |
| 12409 | } | | |
| 12410 | // float operands | | |
| 12411 | if (maybe_rhs_val) |rhs_val| { | | |
| 12412 | if (rhs_val.isUndef()) { | | |
| 12413 | return sema.failWithUseOfUndef(block, rhs_src); | | |
| 12414 | } | | |
| 12415 | if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { | | |
| 12416 | return sema.failWithDivideByZero(block, rhs_src); | | |
| 12417 | } | | |
| 12418 | } | | |
| 12419 | const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .mod_optimized else .mod; | | |
| 12420 | if (maybe_lhs_val) |lhs_val| { | | |
| 12421 | if (lhs_val.isUndef()) { | | |
| 12422 | return sema.addConstUndef(resolved_type); | | |
| 12423 | } | | |
| 12424 | if (maybe_rhs_val) |rhs_val| { | | |
| 12425 | return sema.addConstant( | | |
| 12426 | resolved_type, | | |
| 12427 | try lhs_val.floatMod(rhs_val, resolved_type, sema.arena, target), | | |
| 12428 | ); | | |
| 12429 | } else break :rs .{ .src = rhs_src, .air_tag = air_tag }; | | |
| 12430 | } else break :rs .{ .src = lhs_src, .air_tag = air_tag }; | | |
| 12431 | }, | | |
| 12432 | else => unreachable, | 12566 | else => unreachable, |
| 12433 | } | 12567 | } |
| 12434 | }; | 12568 | }; |
| ... | @@ -12472,33 +12606,6 @@ fn analyzeArithmetic( | ... | @@ -12472,33 +12606,6 @@ fn analyzeArithmetic( |
| 12472 | return sema.tupleFieldValByIndex(block, src, op_ov, 0, op_ov_tuple_ty); | 12606 | return sema.tupleFieldValByIndex(block, src, op_ov, 0, op_ov_tuple_ty); |
| 12473 | } | 12607 | } |
| 12474 | } | 12608 | } |
| 12475 | switch (rs.air_tag) { | | |
| 12476 | .rem, .mod, .rem_optimized, .mod_optimized => { | | |
| 12477 | const ok = if (resolved_type.zigTypeTag() == .Vector) ok: { | | |
| 12478 | const zero_val = try Value.Tag.repeated.create(sema.arena, Value.zero); | | |
| 12479 | const zero = try sema.addConstant(sema.typeOf(casted_rhs), zero_val); | | |
| 12480 | const ok = try block.addCmpVector(casted_rhs, zero, if (scalar_tag == .Int) .gt else .neq, try sema.addType(resolved_type)); | | |
| 12481 | break :ok try block.addInst(.{ | | |
| 12482 | .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce, | | |
| 12483 | .data = .{ .reduce = .{ | | |
| 12484 | .operand = ok, | | |
| 12485 | .operation = .And, | | |
| 12486 | } }, | | |
| 12487 | }); | | |
| 12488 | } else ok: { | | |
| 12489 | const zero = try sema.addConstant(sema.typeOf(casted_rhs), Value.zero); | | |
| 12490 | const air_tag = if (scalar_tag == .Int) | | |
| 12491 | Air.Inst.Tag.cmp_gt | | |
| 12492 | else if (block.float_mode == .Optimized) | | |
| 12493 | Air.Inst.Tag.cmp_neq_optimized | | |
| 12494 | else | | |
| 12495 | Air.Inst.Tag.cmp_neq; | | |
| 12496 | break :ok try block.addBinOp(air_tag, casted_rhs, zero); | | |
| 12497 | }; | | |
| 12498 | try sema.addSafetyCheck(block, ok, .remainder_division_zero_negative); | | |
| 12499 | }, | | |
| 12500 | else => {}, | | |
| 12501 | } | | |
| 12502 | } | 12609 | } |
| 12503 | return block.addBinOp(rs.air_tag, casted_lhs, casted_rhs); | 12610 | return block.addBinOp(rs.air_tag, casted_lhs, casted_rhs); |
| 12504 | } | 12611 | } |
| ... | @@ -19965,7 +20072,6 @@ pub const PanicId = enum { | ... | @@ -19965,7 +20072,6 @@ pub const PanicId = enum { |
| 19965 | shl_overflow, | 20072 | shl_overflow, |
| 19966 | shr_overflow, | 20073 | shr_overflow, |
| 19967 | divide_by_zero, | 20074 | divide_by_zero, |
| 19968 | remainder_division_zero_negative, | | |
| 19969 | exact_division_remainder, | 20075 | exact_division_remainder, |
| 19970 | /// TODO make this call `std.builtin.panicInactiveUnionField`. | 20076 | /// TODO make this call `std.builtin.panicInactiveUnionField`. |
| 19971 | inactive_union_field, | 20077 | inactive_union_field, |
| ... | @@ -20261,7 +20367,6 @@ fn safetyPanic( | ... | @@ -20261,7 +20367,6 @@ fn safetyPanic( |
| 20261 | .shl_overflow => "left shift overflowed bits", | 20367 | .shl_overflow => "left shift overflowed bits", |
| 20262 | .shr_overflow => "right shift overflowed bits", | 20368 | .shr_overflow => "right shift overflowed bits", |
| 20263 | .divide_by_zero => "division by zero", | 20369 | .divide_by_zero => "division by zero", |
| 20264 | .remainder_division_zero_negative => "remainder division by zero or negative value", | | |
| 20265 | .exact_division_remainder => "exact division produced remainder", | 20370 | .exact_division_remainder => "exact division produced remainder", |
| 20266 | .inactive_union_field => "access of inactive union field", | 20371 | .inactive_union_field => "access of inactive union field", |
| 20267 | .integer_part_out_of_bounds => "integer part of floating point value out of bounds", | 20372 | .integer_part_out_of_bounds => "integer part of floating point value out of bounds", |