| ... | ... | @@ -33814,11 +33814,11 @@ fn cmpNumeric( |
| 33814 | 33814 | const maybe_lhs_val = try sema.resolveValue(lhs); |
| 33815 | 33815 | const maybe_rhs_val = try sema.resolveValue(rhs); |
| 33816 | 33816 | |
| 33817 | | // If the LHS is const, check if there is a guaranteed result which does not depend on ths RHS. |
| 33817 | // If the LHS is const, check if there is a guaranteed result which does not depend on ths RHS value. |
| 33818 | 33818 | if (maybe_lhs_val) |lhs_val| { |
| 33819 | 33819 | // Result based on comparison exceeding type bounds |
| 33820 | | if (!lhs_val.isUndef(zcu) and (lhs_ty.isInt(zcu) or lhs_ty_tag == .comptime_int) and rhs_ty.isInt(zcu)) { |
| 33821 | | if (try sema.compareIntsOnlyPossibleResult(try sema.resolveLazyValue(lhs_val), op, rhs_ty)) |res| { |
| 33820 | if (!lhs_val.isUndef(zcu) and (lhs_ty_tag == .int or lhs_ty_tag == .comptime_int) and rhs_ty.isInt(zcu)) { |
| 33821 | if (try sema.compareIntsOnlyPossibleResult(lhs_val, op, rhs_ty)) |res| { |
| 33822 | 33822 | return if (res) .bool_true else .bool_false; |
| 33823 | 33823 | } |
| 33824 | 33824 | } |
| ... | ... | @@ -33826,13 +33826,20 @@ fn cmpNumeric( |
| 33826 | 33826 | if (lhs_val.isNan(zcu)) { |
| 33827 | 33827 | return if (op == .neq) .bool_true else .bool_false; |
| 33828 | 33828 | } |
| 33829 | // Result based on inf comparison to int |
| 33830 | if (lhs_val.isInf(zcu) and rhs_ty_tag == .int) return switch (op) { |
| 33831 | .neq => .bool_true, |
| 33832 | .eq => .bool_false, |
| 33833 | .gt, .gte => if (lhs_val.isNegativeInf(zcu)) .bool_false else .bool_true, |
| 33834 | .lt, .lte => if (lhs_val.isNegativeInf(zcu)) .bool_true else .bool_false, |
| 33835 | }; |
| 33829 | 33836 | } |
| 33830 | 33837 | |
| 33831 | | // If the RHS is const, check if there is a guaranteed result which does not depend on ths LHS. |
| 33838 | // If the RHS is const, check if there is a guaranteed result which does not depend on ths LHS value. |
| 33832 | 33839 | if (maybe_rhs_val) |rhs_val| { |
| 33833 | 33840 | // Result based on comparison exceeding type bounds |
| 33834 | | if (!rhs_val.isUndef(zcu) and (rhs_ty.isInt(zcu) or rhs_ty_tag == .comptime_int) and lhs_ty.isInt(zcu)) { |
| 33835 | | if (try sema.compareIntsOnlyPossibleResult(try sema.resolveLazyValue(rhs_val), op.reverse(), lhs_ty)) |res| { |
| 33841 | if (!rhs_val.isUndef(zcu) and (rhs_ty_tag == .int or rhs_ty_tag == .comptime_int) and lhs_ty.isInt(zcu)) { |
| 33842 | if (try sema.compareIntsOnlyPossibleResult(rhs_val, op.reverse(), lhs_ty)) |res| { |
| 33836 | 33843 | return if (res) .bool_true else .bool_false; |
| 33837 | 33844 | } |
| 33838 | 33845 | } |
| ... | ... | @@ -33840,6 +33847,13 @@ fn cmpNumeric( |
| 33840 | 33847 | if (rhs_val.isNan(zcu)) { |
| 33841 | 33848 | return if (op == .neq) .bool_true else .bool_false; |
| 33842 | 33849 | } |
| 33850 | // Result based on inf comparison to int |
| 33851 | if (rhs_val.isInf(zcu) and lhs_ty_tag == .int) return switch (op) { |
| 33852 | .neq => .bool_true, |
| 33853 | .eq => .bool_false, |
| 33854 | .gt, .gte => if (rhs_val.isNegativeInf(zcu)) .bool_true else .bool_false, |
| 33855 | .lt, .lte => if (rhs_val.isNegativeInf(zcu)) .bool_false else .bool_true, |
| 33856 | }; |
| 33843 | 33857 | } |
| 33844 | 33858 | |
| 33845 | 33859 | // Any other comparison depends on both values, so the result is undef if either is undef. |
| ... | ... | @@ -33889,17 +33903,18 @@ fn cmpNumeric( |
| 33889 | 33903 | const casted_rhs = try sema.coerce(block, dest_ty, rhs, rhs_src); |
| 33890 | 33904 | return block.addBinOp(Air.Inst.Tag.fromCmpOp(op, block.float_mode == .optimized), casted_lhs, casted_rhs); |
| 33891 | 33905 | } |
| 33906 | |
| 33892 | 33907 | // For mixed unsigned integer sizes, implicit cast both operands to the larger integer. |
| 33893 | 33908 | // For mixed signed and unsigned integers, implicit cast both operands to a signed |
| 33894 | 33909 | // integer with + 1 bit. |
| 33895 | 33910 | // For mixed floats and integers, extract the integer part from the float, cast that to |
| 33896 | 33911 | // a signed integer with mantissa bits + 1, and if there was any non-integral part of the float, |
| 33897 | 33912 | // add/subtract 1. |
| 33898 | | const lhs_is_signed = if (try sema.resolveDefinedValue(block, lhs_src, lhs)) |lhs_val| |
| 33913 | const lhs_is_signed = if (maybe_lhs_val) |lhs_val| |
| 33899 | 33914 | !(try lhs_val.compareAllWithZeroSema(.gte, pt)) |
| 33900 | 33915 | else |
| 33901 | 33916 | (lhs_ty.isRuntimeFloat() or lhs_ty.isSignedInt(zcu)); |
| 33902 | | const rhs_is_signed = if (try sema.resolveDefinedValue(block, rhs_src, rhs)) |rhs_val| |
| 33917 | const rhs_is_signed = if (maybe_rhs_val) |rhs_val| |
| 33903 | 33918 | !(try rhs_val.compareAllWithZeroSema(.gte, pt)) |
| 33904 | 33919 | else |
| 33905 | 33920 | (rhs_ty.isRuntimeFloat() or rhs_ty.isSignedInt(zcu)); |
| ... | ... | @@ -33908,19 +33923,8 @@ fn cmpNumeric( |
| 33908 | 33923 | var dest_float_type: ?Type = null; |
| 33909 | 33924 | |
| 33910 | 33925 | var lhs_bits: usize = undefined; |
| 33911 | | if (try sema.resolveValueResolveLazy(lhs)) |lhs_val| { |
| 33912 | | if (lhs_val.isUndef(zcu)) |
| 33913 | | return pt.undefRef(Type.bool); |
| 33914 | | if (lhs_val.isNan(zcu)) switch (op) { |
| 33915 | | .neq => return .bool_true, |
| 33916 | | else => return .bool_false, |
| 33917 | | }; |
| 33918 | | if (lhs_val.isInf(zcu)) switch (op) { |
| 33919 | | .neq => return .bool_true, |
| 33920 | | .eq => return .bool_false, |
| 33921 | | .gt, .gte => return if (lhs_val.isNegativeInf(zcu)) .bool_false else .bool_true, |
| 33922 | | .lt, .lte => return if (lhs_val.isNegativeInf(zcu)) .bool_true else .bool_false, |
| 33923 | | }; |
| 33926 | if (maybe_lhs_val) |unresolved_lhs_val| { |
| 33927 | const lhs_val = try sema.resolveLazyValue(unresolved_lhs_val); |
| 33924 | 33928 | if (!rhs_is_signed) { |
| 33925 | 33929 | switch (lhs_val.orderAgainstZero(zcu)) { |
| 33926 | 33930 | .gt => {}, |
| ... | ... | @@ -33966,19 +33970,8 @@ fn cmpNumeric( |
| 33966 | 33970 | } |
| 33967 | 33971 | |
| 33968 | 33972 | var rhs_bits: usize = undefined; |
| 33969 | | if (try sema.resolveValueResolveLazy(rhs)) |rhs_val| { |
| 33970 | | if (rhs_val.isUndef(zcu)) |
| 33971 | | return pt.undefRef(Type.bool); |
| 33972 | | if (rhs_val.isNan(zcu)) switch (op) { |
| 33973 | | .neq => return .bool_true, |
| 33974 | | else => return .bool_false, |
| 33975 | | }; |
| 33976 | | if (rhs_val.isInf(zcu)) switch (op) { |
| 33977 | | .neq => return .bool_true, |
| 33978 | | .eq => return .bool_false, |
| 33979 | | .gt, .gte => return if (rhs_val.isNegativeInf(zcu)) .bool_true else .bool_false, |
| 33980 | | .lt, .lte => return if (rhs_val.isNegativeInf(zcu)) .bool_false else .bool_true, |
| 33981 | | }; |
| 33973 | if (maybe_rhs_val) |unresolved_rhs_val| { |
| 33974 | const rhs_val = try sema.resolveLazyValue(unresolved_rhs_val); |
| 33982 | 33975 | if (!lhs_is_signed) { |
| 33983 | 33976 | switch (rhs_val.orderAgainstZero(zcu)) { |
| 33984 | 33977 | .gt => {}, |
| ... | ... | @@ -34045,90 +34038,49 @@ fn compareIntsOnlyPossibleResult( |
| 34045 | 34038 | lhs_val: Value, |
| 34046 | 34039 | op: std.math.CompareOperator, |
| 34047 | 34040 | rhs_ty: Type, |
| 34048 | | ) Allocator.Error!?bool { |
| 34041 | ) SemaError!?bool { |
| 34049 | 34042 | const pt = sema.pt; |
| 34050 | 34043 | const zcu = pt.zcu; |
| 34051 | | const rhs_info = rhs_ty.intInfo(zcu); |
| 34052 | | const vs_zero = lhs_val.orderAgainstZeroSema(pt) catch unreachable; |
| 34053 | | const is_zero = vs_zero == .eq; |
| 34054 | | const is_negative = vs_zero == .lt; |
| 34055 | | const is_positive = vs_zero == .gt; |
| 34056 | 34044 | |
| 34057 | | // Anything vs. zero-sized type has guaranteed outcome. |
| 34058 | | if (rhs_info.bits == 0) return switch (op) { |
| 34059 | | .eq, .lte, .gte => is_zero, |
| 34060 | | .neq, .lt, .gt => !is_zero, |
| 34061 | | }; |
| 34045 | const min_rhs = try rhs_ty.minInt(pt, rhs_ty); |
| 34046 | const max_rhs = try rhs_ty.maxInt(pt, rhs_ty); |
| 34062 | 34047 | |
| 34063 | | // Special case for i1, which can only be 0 or -1. |
| 34064 | | // Zero and positive ints have guaranteed outcome. |
| 34065 | | if (rhs_info.bits == 1 and rhs_info.signedness == .signed) { |
| 34066 | | if (is_positive) return switch (op) { |
| 34067 | | .gt, .gte, .neq => true, |
| 34068 | | .lt, .lte, .eq => false, |
| 34069 | | }; |
| 34070 | | if (is_zero) return switch (op) { |
| 34071 | | .gte => true, |
| 34072 | | .lt => false, |
| 34073 | | .gt, .lte, .eq, .neq => null, |
| 34074 | | }; |
| 34048 | if (min_rhs.toIntern() == max_rhs.toIntern()) { |
| 34049 | // RHS is effectively comptime-known. |
| 34050 | return try Value.compareHeteroSema(lhs_val, op, min_rhs, pt); |
| 34075 | 34051 | } |
| 34076 | 34052 | |
| 34077 | | // Negative vs. unsigned has guaranteed outcome. |
| 34078 | | if (rhs_info.signedness == .unsigned and is_negative) return switch (op) { |
| 34079 | | .eq, .gt, .gte => false, |
| 34080 | | .neq, .lt, .lte => true, |
| 34081 | | }; |
| 34082 | | |
| 34083 | | const sign_adj = @intFromBool(!is_negative and rhs_info.signedness == .signed); |
| 34084 | | const req_bits = lhs_val.intBitCountTwosComp(zcu) + sign_adj; |
| 34085 | | |
| 34086 | | // No sized type can have more than 65535 bits. |
| 34087 | | // The RHS type operand is either a runtime value or sized (but undefined) constant. |
| 34088 | | if (req_bits > 65535) return switch (op) { |
| 34089 | | .lt, .lte => is_negative, |
| 34090 | | .gt, .gte => is_positive, |
| 34091 | | .eq => false, |
| 34092 | | .neq => true, |
| 34093 | | }; |
| 34094 | | const fits = req_bits <= rhs_info.bits; |
| 34053 | const against_min = try lhs_val.orderAdvanced(min_rhs, .sema, zcu, pt.tid); |
| 34054 | const against_max = try lhs_val.orderAdvanced(max_rhs, .sema, zcu, pt.tid); |
| 34095 | 34055 | |
| 34096 | | // Oversized int has guaranteed outcome. |
| 34097 | 34056 | switch (op) { |
| 34098 | | .eq => return if (!fits) false else null, |
| 34099 | | .neq => return if (!fits) true else null, |
| 34100 | | .lt, .lte => if (!fits) return is_negative, |
| 34101 | | .gt, .gte => if (!fits) return !is_negative, |
| 34057 | .eq => { |
| 34058 | if (against_min.compare(.lt)) return false; |
| 34059 | if (against_max.compare(.gt)) return false; |
| 34060 | }, |
| 34061 | .neq => { |
| 34062 | if (against_min.compare(.lt)) return true; |
| 34063 | if (against_max.compare(.gt)) return true; |
| 34064 | }, |
| 34065 | .lt => { |
| 34066 | if (against_min.compare(.lt)) return true; |
| 34067 | if (against_max.compare(.gte)) return false; |
| 34068 | }, |
| 34069 | .gt => { |
| 34070 | if (against_max.compare(.gt)) return true; |
| 34071 | if (against_min.compare(.lte)) return false; |
| 34072 | }, |
| 34073 | .lte => { |
| 34074 | if (against_min.compare(.lte)) return true; |
| 34075 | if (against_max.compare(.gt)) return false; |
| 34076 | }, |
| 34077 | .gte => { |
| 34078 | if (against_max.compare(.gte)) return true; |
| 34079 | if (against_min.compare(.lt)) return false; |
| 34080 | }, |
| 34102 | 34081 | } |
| 34103 | 34082 | |
| 34104 | | // For any other comparison, we need to know if the LHS value is |
| 34105 | | // equal to the maximum or minimum possible value of the RHS type. |
| 34106 | | const is_min, const is_max = edge: { |
| 34107 | | if (is_zero and rhs_info.signedness == .unsigned) break :edge .{ true, false }; |
| 34108 | | |
| 34109 | | if (req_bits != rhs_info.bits) break :edge .{ false, false }; |
| 34110 | | |
| 34111 | | const ty = try pt.intType( |
| 34112 | | if (is_negative) .signed else .unsigned, |
| 34113 | | @intCast(req_bits), |
| 34114 | | ); |
| 34115 | | const pop_count = lhs_val.popCount(ty, zcu); |
| 34116 | | |
| 34117 | | if (is_negative) { |
| 34118 | | break :edge .{ pop_count == 1, false }; |
| 34119 | | } else { |
| 34120 | | break :edge .{ false, pop_count == req_bits - sign_adj }; |
| 34121 | | } |
| 34122 | | }; |
| 34123 | | |
| 34124 | | assert(fits); |
| 34125 | | return switch (op) { |
| 34126 | | .lt => if (is_max) false else null, |
| 34127 | | .lte => if (is_min) true else null, |
| 34128 | | .gt => if (is_min) false else null, |
| 34129 | | .gte => if (is_max) true else null, |
| 34130 | | .eq, .neq => unreachable, |
| 34131 | | }; |
| 34083 | return null; |
| 34132 | 34084 | } |
| 34133 | 34085 | |
| 34134 | 34086 | /// Asserts that lhs and rhs types are both vectors. |