| ... | @@ -17911,12 +17911,15 @@ fn cmpSelf( | ... | @@ -17911,12 +17911,15 @@ fn cmpSelf( |
| 17911 | const pt = sema.pt; | 17911 | const pt = sema.pt; |
| 17912 | const zcu = pt.zcu; | 17912 | const zcu = pt.zcu; |
| 17913 | const resolved_type = sema.typeOf(casted_lhs); | 17913 | const resolved_type = sema.typeOf(casted_lhs); |
| 17914 | const runtime_src: LazySrcLoc = src: { | | |
| 17915 | if (try sema.resolveValue(casted_lhs)) |lhs_val| { | | |
| 17916 | if (lhs_val.isUndef(zcu)) return pt.undefRef(Type.bool); | | |
| 17917 | if (try sema.resolveValue(casted_rhs)) |rhs_val| { | | |
| 17918 | if (rhs_val.isUndef(zcu)) return pt.undefRef(Type.bool); | | |
| 17919 | | 17914 | |
| | 17915 | const maybe_lhs_val = try sema.resolveValue(casted_lhs); |
| | 17916 | const maybe_rhs_val = try sema.resolveValue(casted_rhs); |
| | 17917 | if (maybe_lhs_val) |v| if (v.isUndef(zcu)) return pt.undefRef(Type.bool); |
| | 17918 | if (maybe_rhs_val) |v| if (v.isUndef(zcu)) return pt.undefRef(Type.bool); |
| | 17919 | |
| | 17920 | const runtime_src: LazySrcLoc = src: { |
| | 17921 | if (maybe_lhs_val) |lhs_val| { |
| | 17922 | if (maybe_rhs_val) |rhs_val| { |
| 17920 | if (resolved_type.zigTypeTag(zcu) == .vector) { | 17923 | if (resolved_type.zigTypeTag(zcu) == .vector) { |
| 17921 | const cmp_val = try sema.compareVector(lhs_val, op, rhs_val, resolved_type); | 17924 | const cmp_val = try sema.compareVector(lhs_val, op, rhs_val, resolved_type); |
| 17922 | return Air.internedToRef(cmp_val.toIntern()); | 17925 | return Air.internedToRef(cmp_val.toIntern()); |
| ... | @@ -17937,8 +17940,7 @@ fn cmpSelf( | ... | @@ -17937,8 +17940,7 @@ fn cmpSelf( |
| 17937 | // For bools, we still check the other operand, because we can lower | 17940 | // For bools, we still check the other operand, because we can lower |
| 17938 | // bool eq/neq more efficiently. | 17941 | // bool eq/neq more efficiently. |
| 17939 | if (resolved_type.zigTypeTag(zcu) == .bool) { | 17942 | if (resolved_type.zigTypeTag(zcu) == .bool) { |
| 17940 | if (try sema.resolveValue(casted_rhs)) |rhs_val| { | 17943 | if (maybe_rhs_val) |rhs_val| { |
| 17941 | if (rhs_val.isUndef(zcu)) return pt.undefRef(Type.bool); | | |
| 17942 | return sema.runtimeBoolCmp(block, src, op, casted_lhs, rhs_val.toBool(), lhs_src); | 17944 | return sema.runtimeBoolCmp(block, src, op, casted_lhs, rhs_val.toBool(), lhs_src); |
| 17943 | } | 17945 | } |
| 17944 | } | 17946 | } |
| ... | @@ -33837,51 +33839,61 @@ fn cmpNumeric( | ... | @@ -33837,51 +33839,61 @@ fn cmpNumeric( |
| 33837 | else | 33839 | else |
| 33838 | uncasted_rhs; | 33840 | uncasted_rhs; |
| 33839 | | 33841 | |
| 33840 | const runtime_src: LazySrcLoc = src: { | 33842 | const maybe_lhs_val = try sema.resolveValue(lhs); |
| 33841 | if (try sema.resolveValue(lhs)) |lhs_val| { | 33843 | const maybe_rhs_val = try sema.resolveValue(rhs); |
| 33842 | if (try sema.resolveValue(rhs)) |rhs_val| { | | |
| 33843 | // Compare ints: const vs. undefined (or vice versa) | | |
| 33844 | if (!lhs_val.isUndef(zcu) and (lhs_ty.isInt(zcu) or lhs_ty_tag == .comptime_int) and rhs_ty.isInt(zcu) and rhs_val.isUndef(zcu)) { | | |
| 33845 | if (try sema.compareIntsOnlyPossibleResult(try sema.resolveLazyValue(lhs_val), op, rhs_ty)) |res| { | | |
| 33846 | return if (res) .bool_true else .bool_false; | | |
| 33847 | } | | |
| 33848 | } else if (!rhs_val.isUndef(zcu) and (rhs_ty.isInt(zcu) or rhs_ty_tag == .comptime_int) and lhs_ty.isInt(zcu) and lhs_val.isUndef(zcu)) { | | |
| 33849 | if (try sema.compareIntsOnlyPossibleResult(try sema.resolveLazyValue(rhs_val), op.reverse(), lhs_ty)) |res| { | | |
| 33850 | return if (res) .bool_true else .bool_false; | | |
| 33851 | } | | |
| 33852 | } | | |
| 33853 | | 33844 | |
| 33854 | if (lhs_val.isUndef(zcu) or rhs_val.isUndef(zcu)) { | 33845 | // If the LHS is const, check if there is a guaranteed result which does not depend on ths RHS value. |
| 33855 | return pt.undefRef(Type.bool); | 33846 | if (maybe_lhs_val) |lhs_val| { |
| 33856 | } | 33847 | // Result based on comparison exceeding type bounds |
| 33857 | if (lhs_val.isNan(zcu) or rhs_val.isNan(zcu)) { | 33848 | if (!lhs_val.isUndef(zcu) and (lhs_ty_tag == .int or lhs_ty_tag == .comptime_int) and rhs_ty.isInt(zcu)) { |
| 33858 | return if (op == std.math.CompareOperator.neq) .bool_true else .bool_false; | 33849 | if (try sema.compareIntsOnlyPossibleResult(lhs_val, op, rhs_ty)) |res| { |
| 33859 | } | 33850 | return if (res) .bool_true else .bool_false; |
| 33860 | return if (try Value.compareHeteroSema(lhs_val, op, rhs_val, pt)) | 33851 | } |
| 33861 | .bool_true | 33852 | } |
| 33862 | else | 33853 | // Result based on NaN comparison |
| 33863 | .bool_false; | 33854 | if (lhs_val.isNan(zcu)) { |
| 33864 | } else { | 33855 | return if (op == .neq) .bool_true else .bool_false; |
| 33865 | if (!lhs_val.isUndef(zcu) and (lhs_ty.isInt(zcu) or lhs_ty_tag == .comptime_int) and rhs_ty.isInt(zcu)) { | 33856 | } |
| 33866 | // Compare ints: const vs. var | 33857 | // Result based on inf comparison to int |
| 33867 | if (try sema.compareIntsOnlyPossibleResult(try sema.resolveLazyValue(lhs_val), op, rhs_ty)) |res| { | 33858 | if (lhs_val.isInf(zcu) and rhs_ty_tag == .int) return switch (op) { |
| 33868 | return if (res) .bool_true else .bool_false; | 33859 | .neq => .bool_true, |
| 33869 | } | 33860 | .eq => .bool_false, |
| 33870 | } | 33861 | .gt, .gte => if (lhs_val.isNegativeInf(zcu)) .bool_false else .bool_true, |
| 33871 | break :src rhs_src; | 33862 | .lt, .lte => if (lhs_val.isNegativeInf(zcu)) .bool_true else .bool_false, |
| 33872 | } | 33863 | }; |
| 33873 | } else { | 33864 | } |
| 33874 | if (try sema.resolveValueResolveLazy(rhs)) |rhs_val| { | 33865 | |
| 33875 | if (!rhs_val.isUndef(zcu) and (rhs_ty.isInt(zcu) or rhs_ty_tag == .comptime_int) and lhs_ty.isInt(zcu)) { | 33866 | // If the RHS is const, check if there is a guaranteed result which does not depend on ths LHS value. |
| 33876 | // Compare ints: var vs. const | 33867 | if (maybe_rhs_val) |rhs_val| { |
| 33877 | if (try sema.compareIntsOnlyPossibleResult(try sema.resolveLazyValue(rhs_val), op.reverse(), lhs_ty)) |res| { | 33868 | // Result based on comparison exceeding type bounds |
| 33878 | return if (res) .bool_true else .bool_false; | 33869 | if (!rhs_val.isUndef(zcu) and (rhs_ty_tag == .int or rhs_ty_tag == .comptime_int) and lhs_ty.isInt(zcu)) { |
| 33879 | } | 33870 | if (try sema.compareIntsOnlyPossibleResult(rhs_val, op.reverse(), lhs_ty)) |res| { |
| 33880 | } | 33871 | return if (res) .bool_true else .bool_false; |
| 33881 | } | 33872 | } |
| 33882 | break :src lhs_src; | 33873 | } |
| 33883 | } | 33874 | // Result based on NaN comparison |
| 33884 | }; | 33875 | if (rhs_val.isNan(zcu)) { |
| | 33876 | return if (op == .neq) .bool_true else .bool_false; |
| | 33877 | } |
| | 33878 | // Result based on inf comparison to int |
| | 33879 | if (rhs_val.isInf(zcu) and lhs_ty_tag == .int) return switch (op) { |
| | 33880 | .neq => .bool_true, |
| | 33881 | .eq => .bool_false, |
| | 33882 | .gt, .gte => if (rhs_val.isNegativeInf(zcu)) .bool_true else .bool_false, |
| | 33883 | .lt, .lte => if (rhs_val.isNegativeInf(zcu)) .bool_false else .bool_true, |
| | 33884 | }; |
| | 33885 | } |
| | 33886 | |
| | 33887 | // Any other comparison depends on both values, so the result is undef if either is undef. |
| | 33888 | if (maybe_lhs_val) |v| if (v.isUndef(zcu)) return pt.undefRef(Type.bool); |
| | 33889 | if (maybe_rhs_val) |v| if (v.isUndef(zcu)) return pt.undefRef(Type.bool); |
| | 33890 | |
| | 33891 | const runtime_src: LazySrcLoc = if (maybe_lhs_val) |lhs_val| rs: { |
| | 33892 | if (maybe_rhs_val) |rhs_val| { |
| | 33893 | const res = try Value.compareHeteroSema(lhs_val, op, rhs_val, pt); |
| | 33894 | return if (res) .bool_true else .bool_false; |
| | 33895 | } else break :rs rhs_src; |
| | 33896 | } else lhs_src; |
| 33885 | | 33897 | |
| 33886 | // TODO handle comparisons against lazy zero values | 33898 | // TODO handle comparisons against lazy zero values |
| 33887 | // Some values can be compared against zero without being runtime-known or without forcing | 33899 | // Some values can be compared against zero without being runtime-known or without forcing |
| ... | @@ -33919,17 +33931,18 @@ fn cmpNumeric( | ... | @@ -33919,17 +33931,18 @@ fn cmpNumeric( |
| 33919 | const casted_rhs = try sema.coerce(block, dest_ty, rhs, rhs_src); | 33931 | const casted_rhs = try sema.coerce(block, dest_ty, rhs, rhs_src); |
| 33920 | return block.addBinOp(Air.Inst.Tag.fromCmpOp(op, block.float_mode == .optimized), casted_lhs, casted_rhs); | 33932 | return block.addBinOp(Air.Inst.Tag.fromCmpOp(op, block.float_mode == .optimized), casted_lhs, casted_rhs); |
| 33921 | } | 33933 | } |
| | 33934 | |
| 33922 | // For mixed unsigned integer sizes, implicit cast both operands to the larger integer. | 33935 | // For mixed unsigned integer sizes, implicit cast both operands to the larger integer. |
| 33923 | // For mixed signed and unsigned integers, implicit cast both operands to a signed | 33936 | // For mixed signed and unsigned integers, implicit cast both operands to a signed |
| 33924 | // integer with + 1 bit. | 33937 | // integer with + 1 bit. |
| 33925 | // For mixed floats and integers, extract the integer part from the float, cast that to | 33938 | // For mixed floats and integers, extract the integer part from the float, cast that to |
| 33926 | // a signed integer with mantissa bits + 1, and if there was any non-integral part of the float, | 33939 | // a signed integer with mantissa bits + 1, and if there was any non-integral part of the float, |
| 33927 | // add/subtract 1. | 33940 | // add/subtract 1. |
| 33928 | const lhs_is_signed = if (try sema.resolveDefinedValue(block, lhs_src, lhs)) |lhs_val| | 33941 | const lhs_is_signed = if (maybe_lhs_val) |lhs_val| |
| 33929 | !(try lhs_val.compareAllWithZeroSema(.gte, pt)) | 33942 | !(try lhs_val.compareAllWithZeroSema(.gte, pt)) |
| 33930 | else | 33943 | else |
| 33931 | (lhs_ty.isRuntimeFloat() or lhs_ty.isSignedInt(zcu)); | 33944 | (lhs_ty.isRuntimeFloat() or lhs_ty.isSignedInt(zcu)); |
| 33932 | const rhs_is_signed = if (try sema.resolveDefinedValue(block, rhs_src, rhs)) |rhs_val| | 33945 | const rhs_is_signed = if (maybe_rhs_val) |rhs_val| |
| 33933 | !(try rhs_val.compareAllWithZeroSema(.gte, pt)) | 33946 | !(try rhs_val.compareAllWithZeroSema(.gte, pt)) |
| 33934 | else | 33947 | else |
| 33935 | (rhs_ty.isRuntimeFloat() or rhs_ty.isSignedInt(zcu)); | 33948 | (rhs_ty.isRuntimeFloat() or rhs_ty.isSignedInt(zcu)); |
| ... | @@ -33938,19 +33951,8 @@ fn cmpNumeric( | ... | @@ -33938,19 +33951,8 @@ fn cmpNumeric( |
| 33938 | var dest_float_type: ?Type = null; | 33951 | var dest_float_type: ?Type = null; |
| 33939 | | 33952 | |
| 33940 | var lhs_bits: usize = undefined; | 33953 | var lhs_bits: usize = undefined; |
| 33941 | if (try sema.resolveValueResolveLazy(lhs)) |lhs_val| { | 33954 | if (maybe_lhs_val) |unresolved_lhs_val| { |
| 33942 | if (lhs_val.isUndef(zcu)) | 33955 | const lhs_val = try sema.resolveLazyValue(unresolved_lhs_val); |
| 33943 | return pt.undefRef(Type.bool); | | |
| 33944 | if (lhs_val.isNan(zcu)) switch (op) { | | |
| 33945 | .neq => return .bool_true, | | |
| 33946 | else => return .bool_false, | | |
| 33947 | }; | | |
| 33948 | if (lhs_val.isInf(zcu)) switch (op) { | | |
| 33949 | .neq => return .bool_true, | | |
| 33950 | .eq => return .bool_false, | | |
| 33951 | .gt, .gte => return if (lhs_val.isNegativeInf(zcu)) .bool_false else .bool_true, | | |
| 33952 | .lt, .lte => return if (lhs_val.isNegativeInf(zcu)) .bool_true else .bool_false, | | |
| 33953 | }; | | |
| 33954 | if (!rhs_is_signed) { | 33956 | if (!rhs_is_signed) { |
| 33955 | switch (lhs_val.orderAgainstZero(zcu)) { | 33957 | switch (lhs_val.orderAgainstZero(zcu)) { |
| 33956 | .gt => {}, | 33958 | .gt => {}, |
| ... | @@ -33996,19 +33998,8 @@ fn cmpNumeric( | ... | @@ -33996,19 +33998,8 @@ fn cmpNumeric( |
| 33996 | } | 33998 | } |
| 33997 | | 33999 | |
| 33998 | var rhs_bits: usize = undefined; | 34000 | var rhs_bits: usize = undefined; |
| 33999 | if (try sema.resolveValueResolveLazy(rhs)) |rhs_val| { | 34001 | if (maybe_rhs_val) |unresolved_rhs_val| { |
| 34000 | if (rhs_val.isUndef(zcu)) | 34002 | const rhs_val = try sema.resolveLazyValue(unresolved_rhs_val); |
| 34001 | return pt.undefRef(Type.bool); | | |
| 34002 | if (rhs_val.isNan(zcu)) switch (op) { | | |
| 34003 | .neq => return .bool_true, | | |
| 34004 | else => return .bool_false, | | |
| 34005 | }; | | |
| 34006 | if (rhs_val.isInf(zcu)) switch (op) { | | |
| 34007 | .neq => return .bool_true, | | |
| 34008 | .eq => return .bool_false, | | |
| 34009 | .gt, .gte => return if (rhs_val.isNegativeInf(zcu)) .bool_true else .bool_false, | | |
| 34010 | .lt, .lte => return if (rhs_val.isNegativeInf(zcu)) .bool_false else .bool_true, | | |
| 34011 | }; | | |
| 34012 | if (!lhs_is_signed) { | 34003 | if (!lhs_is_signed) { |
| 34013 | switch (rhs_val.orderAgainstZero(zcu)) { | 34004 | switch (rhs_val.orderAgainstZero(zcu)) { |
| 34014 | .gt => {}, | 34005 | .gt => {}, |
| ... | @@ -34075,90 +34066,49 @@ fn compareIntsOnlyPossibleResult( | ... | @@ -34075,90 +34066,49 @@ fn compareIntsOnlyPossibleResult( |
| 34075 | lhs_val: Value, | 34066 | lhs_val: Value, |
| 34076 | op: std.math.CompareOperator, | 34067 | op: std.math.CompareOperator, |
| 34077 | rhs_ty: Type, | 34068 | rhs_ty: Type, |
| 34078 | ) Allocator.Error!?bool { | 34069 | ) SemaError!?bool { |
| 34079 | const pt = sema.pt; | 34070 | const pt = sema.pt; |
| 34080 | const zcu = pt.zcu; | 34071 | const zcu = pt.zcu; |
| 34081 | const rhs_info = rhs_ty.intInfo(zcu); | | |
| 34082 | const vs_zero = lhs_val.orderAgainstZeroSema(pt) catch unreachable; | | |
| 34083 | const is_zero = vs_zero == .eq; | | |
| 34084 | const is_negative = vs_zero == .lt; | | |
| 34085 | const is_positive = vs_zero == .gt; | | |
| 34086 | | 34072 | |
| 34087 | // Anything vs. zero-sized type has guaranteed outcome. | 34073 | const min_rhs = try rhs_ty.minInt(pt, rhs_ty); |
| 34088 | if (rhs_info.bits == 0) return switch (op) { | 34074 | const max_rhs = try rhs_ty.maxInt(pt, rhs_ty); |
| 34089 | .eq, .lte, .gte => is_zero, | | |
| 34090 | .neq, .lt, .gt => !is_zero, | | |
| 34091 | }; | | |
| 34092 | | 34075 | |
| 34093 | // Special case for i1, which can only be 0 or -1. | 34076 | if (min_rhs.toIntern() == max_rhs.toIntern()) { |
| 34094 | // Zero and positive ints have guaranteed outcome. | 34077 | // RHS is effectively comptime-known. |
| 34095 | if (rhs_info.bits == 1 and rhs_info.signedness == .signed) { | 34078 | return try Value.compareHeteroSema(lhs_val, op, min_rhs, pt); |
| 34096 | if (is_positive) return switch (op) { | | |
| 34097 | .gt, .gte, .neq => true, | | |
| 34098 | .lt, .lte, .eq => false, | | |
| 34099 | }; | | |
| 34100 | if (is_zero) return switch (op) { | | |
| 34101 | .gte => true, | | |
| 34102 | .lt => false, | | |
| 34103 | .gt, .lte, .eq, .neq => null, | | |
| 34104 | }; | | |
| 34105 | } | 34079 | } |
| 34106 | | 34080 | |
| 34107 | // Negative vs. unsigned has guaranteed outcome. | 34081 | const against_min = try lhs_val.orderAdvanced(min_rhs, .sema, zcu, pt.tid); |
| 34108 | if (rhs_info.signedness == .unsigned and is_negative) return switch (op) { | 34082 | const against_max = try lhs_val.orderAdvanced(max_rhs, .sema, zcu, pt.tid); |
| 34109 | .eq, .gt, .gte => false, | | |
| 34110 | .neq, .lt, .lte => true, | | |
| 34111 | }; | | |
| 34112 | | | |
| 34113 | const sign_adj = @intFromBool(!is_negative and rhs_info.signedness == .signed); | | |
| 34114 | const req_bits = lhs_val.intBitCountTwosComp(zcu) + sign_adj; | | |
| 34115 | | | |
| 34116 | // No sized type can have more than 65535 bits. | | |
| 34117 | // The RHS type operand is either a runtime value or sized (but undefined) constant. | | |
| 34118 | if (req_bits > 65535) return switch (op) { | | |
| 34119 | .lt, .lte => is_negative, | | |
| 34120 | .gt, .gte => is_positive, | | |
| 34121 | .eq => false, | | |
| 34122 | .neq => true, | | |
| 34123 | }; | | |
| 34124 | const fits = req_bits <= rhs_info.bits; | | |
| 34125 | | 34083 | |
| 34126 | // Oversized int has guaranteed outcome. | | |
| 34127 | switch (op) { | 34084 | switch (op) { |
| 34128 | .eq => return if (!fits) false else null, | 34085 | .eq => { |
| 34129 | .neq => return if (!fits) true else null, | 34086 | if (against_min.compare(.lt)) return false; |
| 34130 | .lt, .lte => if (!fits) return is_negative, | 34087 | if (against_max.compare(.gt)) return false; |
| 34131 | .gt, .gte => if (!fits) return !is_negative, | 34088 | }, |
| | 34089 | .neq => { |
| | 34090 | if (against_min.compare(.lt)) return true; |
| | 34091 | if (against_max.compare(.gt)) return true; |
| | 34092 | }, |
| | 34093 | .lt => { |
| | 34094 | if (against_min.compare(.lt)) return true; |
| | 34095 | if (against_max.compare(.gte)) return false; |
| | 34096 | }, |
| | 34097 | .gt => { |
| | 34098 | if (against_max.compare(.gt)) return true; |
| | 34099 | if (against_min.compare(.lte)) return false; |
| | 34100 | }, |
| | 34101 | .lte => { |
| | 34102 | if (against_min.compare(.lte)) return true; |
| | 34103 | if (against_max.compare(.gt)) return false; |
| | 34104 | }, |
| | 34105 | .gte => { |
| | 34106 | if (against_max.compare(.gte)) return true; |
| | 34107 | if (against_min.compare(.lt)) return false; |
| | 34108 | }, |
| 34132 | } | 34109 | } |
| 34133 | | 34110 | |
| 34134 | // For any other comparison, we need to know if the LHS value is | 34111 | return null; |
| 34135 | // equal to the maximum or minimum possible value of the RHS type. | | |
| 34136 | const is_min, const is_max = edge: { | | |
| 34137 | if (is_zero and rhs_info.signedness == .unsigned) break :edge .{ true, false }; | | |
| 34138 | | | |
| 34139 | if (req_bits != rhs_info.bits) break :edge .{ false, false }; | | |
| 34140 | | | |
| 34141 | const ty = try pt.intType( | | |
| 34142 | if (is_negative) .signed else .unsigned, | | |
| 34143 | @intCast(req_bits), | | |
| 34144 | ); | | |
| 34145 | const pop_count = lhs_val.popCount(ty, zcu); | | |
| 34146 | | | |
| 34147 | if (is_negative) { | | |
| 34148 | break :edge .{ pop_count == 1, false }; | | |
| 34149 | } else { | | |
| 34150 | break :edge .{ false, pop_count == req_bits - sign_adj }; | | |
| 34151 | } | | |
| 34152 | }; | | |
| 34153 | | | |
| 34154 | assert(fits); | | |
| 34155 | return switch (op) { | | |
| 34156 | .lt => if (is_max) false else null, | | |
| 34157 | .lte => if (is_min) true else null, | | |
| 34158 | .gt => if (is_min) false else null, | | |
| 34159 | .gte => if (is_max) true else null, | | |
| 34160 | .eq, .neq => unreachable, | | |
| 34161 | }; | | |
| 34162 | } | 34112 | } |
| 34163 | | 34113 | |
| 34164 | /// Asserts that lhs and rhs types are both vectors. | 34114 | /// Asserts that lhs and rhs types are both vectors. |
| ... | @@ -34189,21 +34139,17 @@ fn cmpVector( | ... | @@ -34189,21 +34139,17 @@ fn cmpVector( |
| 34189 | .child = .bool_type, | 34139 | .child = .bool_type, |
| 34190 | }); | 34140 | }); |
| 34191 | | 34141 | |
| 34192 | const runtime_src: LazySrcLoc = src: { | 34142 | const maybe_lhs_val = try sema.resolveValue(casted_lhs); |
| 34193 | if (try sema.resolveValue(casted_lhs)) |lhs_val| { | 34143 | const maybe_rhs_val = try sema.resolveValue(casted_rhs); |
| 34194 | if (try sema.resolveValue(casted_rhs)) |rhs_val| { | 34144 | if (maybe_lhs_val) |v| if (v.isUndef(zcu)) return pt.undefRef(result_ty); |
| 34195 | if (lhs_val.isUndef(zcu) or rhs_val.isUndef(zcu)) { | 34145 | if (maybe_rhs_val) |v| if (v.isUndef(zcu)) return pt.undefRef(result_ty); |
| 34196 | return pt.undefRef(result_ty); | 34146 | |
| 34197 | } | 34147 | const runtime_src: LazySrcLoc = if (maybe_lhs_val) |lhs_val| src: { |
| 34198 | const cmp_val = try sema.compareVector(lhs_val, op, rhs_val, resolved_ty); | 34148 | if (maybe_rhs_val) |rhs_val| { |
| 34199 | return Air.internedToRef(cmp_val.toIntern()); | 34149 | const cmp_val = try sema.compareVector(lhs_val, op, rhs_val, resolved_ty); |
| 34200 | } else { | 34150 | return Air.internedToRef(cmp_val.toIntern()); |
| 34201 | break :src rhs_src; | 34151 | } else break :src rhs_src; |
| 34202 | } | 34152 | } else lhs_src; |
| 34203 | } else { | | |
| 34204 | break :src lhs_src; | | |
| 34205 | } | | |
| 34206 | }; | | |
| 34207 | | 34153 | |
| 34208 | try sema.requireRuntimeBlock(block, src, runtime_src); | 34154 | try sema.requireRuntimeBlock(block, src, runtime_src); |
| 34209 | return block.addCmpVector(casted_lhs, casted_rhs, op); | 34155 | return block.addCmpVector(casted_lhs, casted_rhs, op); |
| ... | @@ -38691,8 +38637,12 @@ fn compareVector( | ... | @@ -38691,8 +38637,12 @@ fn compareVector( |
| 38691 | for (result_data, 0..) |*scalar, i| { | 38637 | for (result_data, 0..) |*scalar, i| { |
| 38692 | const lhs_elem = try lhs.elemValue(pt, i); | 38638 | const lhs_elem = try lhs.elemValue(pt, i); |
| 38693 | const rhs_elem = try rhs.elemValue(pt, i); | 38639 | const rhs_elem = try rhs.elemValue(pt, i); |
| 38694 | const res_bool = try sema.compareScalar(lhs_elem, op, rhs_elem, ty.scalarType(zcu)); | 38640 | if (lhs_elem.isUndef(zcu) or rhs_elem.isUndef(zcu)) { |
| 38695 | scalar.* = Value.makeBool(res_bool).toIntern(); | 38641 | scalar.* = try pt.intern(.{ .undef = .bool_type }); |
| | 38642 | } else { |
| | 38643 | const res_bool = try sema.compareScalar(lhs_elem, op, rhs_elem, ty.scalarType(zcu)); |
| | 38644 | scalar.* = Value.makeBool(res_bool).toIntern(); |
| | 38645 | } |
| 38696 | } | 38646 | } |
| 38697 | return Value.fromInterned(try pt.intern(.{ .aggregate = .{ | 38647 | return Value.fromInterned(try pt.intern(.{ .aggregate = .{ |
| 38698 | .ty = (try pt.vectorType(.{ .len = ty.vectorLen(zcu), .child = .bool_type })).toIntern(), | 38648 | .ty = (try pt.vectorType(.{ .len = ty.vectorLen(zcu), .child = .bool_type })).toIntern(), |