authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-05-18 21:24:42-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-05-20 02:47:20-07:00
logfcd4efd8ecda01fe06735ed8b7e2cd2aa93daa19
treeadc90f10a7a762b65350a1de3fd36bc7e2bb071b
parentcd04b49041200b36c5af23ac3700cbfa82f037ca

Sema: introduce laziness to `@sizeOf`

Motivation: the behavior test that is now passing. The main change in this commit is introducing `Type.abiSizeAdvanced`, `Value.Tag.lazy_size`, and adjusting `Sema.zirSizeOf` to take advantage of these. However, the bulk of lines changed in this commit ended up being moving logic from value.zig and type.zig into Sema.zig. This logic had no business being in Type/Value as it was only called from a Sema context, and we need access to the Sema context for error reporting when a lazy Value is resolved. Also worth mentioning is that I bumped up the comptime `@floatToInt` implementation from using f64 to f128.

5 files changed, 1063 insertions(+), 808 deletions(-)

src/Sema.zig+820-129
...@@ -2228,7 +2228,6 @@ fn zirEnumDecl(...@@ -2228,7 +2228,6 @@ fn zirEnumDecl(
2228 enum_obj.tag_ty_inferred = true;2228 enum_obj.tag_ty_inferred = true;
2229 }2229 }
2230 }2230 }
2231 const target = mod.getTarget();
22322231
2233 try enum_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len);2232 try enum_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len);
2234 const any_values = for (sema.code.extra[body_end..][0..bit_bags_count]) |bag| {2233 const any_values = for (sema.code.extra[body_end..][0..bit_bags_count]) |bag| {
...@@ -2291,7 +2290,7 @@ fn zirEnumDecl(...@@ -2291,7 +2290,7 @@ fn zirEnumDecl(
2291 });2290 });
2292 } else if (any_values) {2291 } else if (any_values) {
2293 const tag_val = if (last_tag_val) |val|2292 const tag_val = if (last_tag_val) |val|
2294 try val.intAdd(Value.one, enum_obj.tag_ty, sema.arena, target)2293 try sema.intAdd(block, src, val, Value.one, enum_obj.tag_ty)
2295 else2294 else
2296 Value.zero;2295 Value.zero;
2297 last_tag_val = tag_val;2296 last_tag_val = tag_val;
...@@ -6054,7 +6053,7 @@ fn zirIntToEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A...@@ -6054,7 +6053,7 @@ fn zirIntToEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
6054 if (int_val.isUndef()) {6053 if (int_val.isUndef()) {
6055 return sema.failWithUseOfUndef(block, operand_src);6054 return sema.failWithUseOfUndef(block, operand_src);
6056 }6055 }
6057 if (!dest_ty.enumHasInt(int_val, sema.mod)) {6056 if (!(try sema.enumHasInt(block, src, dest_ty, int_val))) {
6058 const msg = msg: {6057 const msg = msg: {
6059 const msg = try sema.errMsg(6058 const msg = try sema.errMsg(
6060 block,6059 block,
...@@ -7082,7 +7081,7 @@ fn intCast(...@@ -7082,7 +7081,7 @@ fn intCast(
7082 // range to account for negative values.7081 // range to account for negative values.
7083 const dest_range_val = if (wanted_info.signedness == .signed) range_val: {7082 const dest_range_val = if (wanted_info.signedness == .signed) range_val: {
7084 const range_minus_one = try dest_max_val.shl(Value.one, unsigned_operand_ty, sema.arena, target);7083 const range_minus_one = try dest_max_val.shl(Value.one, unsigned_operand_ty, sema.arena, target);
7085 break :range_val try range_minus_one.intAdd(Value.one, unsigned_operand_ty, sema.arena, target);7084 break :range_val try sema.intAdd(block, operand_src, range_minus_one, Value.one, unsigned_operand_ty);
7086 } else dest_max_val;7085 } else dest_max_val;
7087 const dest_range = try sema.addConstant(unsigned_operand_ty, dest_range_val);7086 const dest_range = try sema.addConstant(unsigned_operand_ty, dest_range_val);
70887087
...@@ -8203,8 +8202,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -8203,8 +8202,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
8203 // Validation above ensured these will succeed.8202 // Validation above ensured these will succeed.
8204 const first_tv = sema.resolveInstConst(&child_block, .unneeded, item_first) catch unreachable;8203 const first_tv = sema.resolveInstConst(&child_block, .unneeded, item_first) catch unreachable;
8205 const last_tv = sema.resolveInstConst(&child_block, .unneeded, item_last) catch unreachable;8204 const last_tv = sema.resolveInstConst(&child_block, .unneeded, item_last) catch unreachable;
8206 if (Value.compare(operand_val, .gte, first_tv.val, operand_ty, sema.mod) and8205 if ((try sema.compare(block, src, operand_val, .gte, first_tv.val, operand_ty)) and
8207 Value.compare(operand_val, .lte, last_tv.val, operand_ty, sema.mod))8206 (try sema.compare(block, src, operand_val, .lte, last_tv.val, operand_ty)))
8208 {8207 {
8209 return sema.resolveBlockBody(block, src, &child_block, body, inst, merges);8208 return sema.resolveBlockBody(block, src, &child_block, body, inst, merges);
8210 }8209 }
...@@ -8878,7 +8877,7 @@ fn zirShl(...@@ -8878,7 +8877,7 @@ fn zirShl(
8878 if (rhs_val.isUndef()) {8877 if (rhs_val.isUndef()) {
8879 return sema.addConstUndef(sema.typeOf(lhs));8878 return sema.addConstUndef(sema.typeOf(lhs));
8880 }8879 }
8881 if (rhs_val.compareWithZero(.eq)) {8880 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
8882 return lhs;8881 return lhs;
8883 }8882 }
8884 }8883 }
...@@ -8895,7 +8894,7 @@ fn zirShl(...@@ -8895,7 +8894,7 @@ fn zirShl(
8895 }8894 }
8896 const int_info = scalar_ty.intInfo(target);8895 const int_info = scalar_ty.intInfo(target);
8897 const truncated = try shifted.intTrunc(lhs_ty, sema.arena, int_info.signedness, int_info.bits, target);8896 const truncated = try shifted.intTrunc(lhs_ty, sema.arena, int_info.signedness, int_info.bits, target);
8898 if (truncated.compare(.eq, shifted, lhs_ty, sema.mod)) {8897 if (try sema.compare(block, src, truncated, .eq, shifted, lhs_ty)) {
8899 break :val shifted;8898 break :val shifted;
8900 }8899 }
8901 return sema.addConstUndef(lhs_ty);8900 return sema.addConstUndef(lhs_ty);
...@@ -8999,13 +8998,13 @@ fn zirShr(...@@ -8999,13 +8998,13 @@ fn zirShr(
8999 return sema.addConstUndef(lhs_ty);8998 return sema.addConstUndef(lhs_ty);
9000 }8999 }
9001 // If rhs is 0, return lhs without doing any calculations.9000 // If rhs is 0, return lhs without doing any calculations.
9002 if (rhs_val.compareWithZero(.eq)) {9001 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
9003 return sema.addConstant(lhs_ty, lhs_val);9002 return sema.addConstant(lhs_ty, lhs_val);
9004 }9003 }
9005 if (air_tag == .shr_exact) {9004 if (air_tag == .shr_exact) {
9006 // Detect if any ones would be shifted out.9005 // Detect if any ones would be shifted out.
9007 const truncated = try lhs_val.intTruncBitsAsValue(lhs_ty, sema.arena, .unsigned, rhs_val, target);9006 const truncated = try lhs_val.intTruncBitsAsValue(lhs_ty, sema.arena, .unsigned, rhs_val, target);
9008 if (!truncated.compareWithZero(.eq)) {9007 if (!(try truncated.compareWithZeroAdvanced(.eq, sema.kit(block, src)))) {
9009 return sema.addConstUndef(lhs_ty);9008 return sema.addConstUndef(lhs_ty);
9010 }9009 }
9011 }9010 }
...@@ -9015,7 +9014,7 @@ fn zirShr(...@@ -9015,7 +9014,7 @@ fn zirShr(
9015 // Even if lhs is not comptime known, we can still deduce certain things based9014 // Even if lhs is not comptime known, we can still deduce certain things based
9016 // on rhs.9015 // on rhs.
9017 // If rhs is 0, return lhs without doing any calculations.9016 // If rhs is 0, return lhs without doing any calculations.
9018 if (rhs_val.compareWithZero(.eq)) {9017 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
9019 return lhs;9018 return lhs;
9020 }9019 }
9021 break :rs lhs_src;9020 break :rs lhs_src;
...@@ -9578,12 +9577,12 @@ fn zirOverflowArithmetic(...@@ -9578,12 +9577,12 @@ fn zirOverflowArithmetic(
9578 // to the result, even if it is undefined..9577 // to the result, even if it is undefined..
9579 // Otherwise, if either of the argument is undefined, undefined is returned.9578 // Otherwise, if either of the argument is undefined, undefined is returned.
9580 if (maybe_lhs_val) |lhs_val| {9579 if (maybe_lhs_val) |lhs_val| {
9581 if (!lhs_val.isUndef() and lhs_val.compareWithZero(.eq)) {9580 if (!lhs_val.isUndef() and (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src)))) {
9582 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = rhs };9581 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = rhs };
9583 }9582 }
9584 }9583 }
9585 if (maybe_rhs_val) |rhs_val| {9584 if (maybe_rhs_val) |rhs_val| {
9586 if (!rhs_val.isUndef() and rhs_val.compareWithZero(.eq)) {9585 if (!rhs_val.isUndef() and (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src)))) {
9587 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs };9586 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs };
9588 }9587 }
9589 }9588 }
...@@ -9593,7 +9592,7 @@ fn zirOverflowArithmetic(...@@ -9593,7 +9592,7 @@ fn zirOverflowArithmetic(
9593 break :result .{ .overflowed = try sema.addConstUndef(overflowed_ty), .wrapped = try sema.addConstUndef(dest_ty) };9592 break :result .{ .overflowed = try sema.addConstUndef(overflowed_ty), .wrapped = try sema.addConstUndef(dest_ty) };
9594 }9593 }
95959594
9596 const result = try lhs_val.intAddWithOverflow(rhs_val, dest_ty, sema.arena, target);9595 const result = try sema.intAddWithOverflow(block, src, lhs_val, rhs_val, dest_ty);
9597 const overflowed = try sema.addConstant(overflowed_ty, result.overflowed);9596 const overflowed = try sema.addConstant(overflowed_ty, result.overflowed);
9598 const wrapped = try sema.addConstant(dest_ty, result.wrapped_result);9597 const wrapped = try sema.addConstant(dest_ty, result.wrapped_result);
9599 break :result .{ .overflowed = overflowed, .wrapped = wrapped };9598 break :result .{ .overflowed = overflowed, .wrapped = wrapped };
...@@ -9606,14 +9605,14 @@ fn zirOverflowArithmetic(...@@ -9606,14 +9605,14 @@ fn zirOverflowArithmetic(
9606 if (maybe_rhs_val) |rhs_val| {9605 if (maybe_rhs_val) |rhs_val| {
9607 if (rhs_val.isUndef()) {9606 if (rhs_val.isUndef()) {
9608 break :result .{ .overflowed = try sema.addConstUndef(overflowed_ty), .wrapped = try sema.addConstUndef(dest_ty) };9607 break :result .{ .overflowed = try sema.addConstUndef(overflowed_ty), .wrapped = try sema.addConstUndef(dest_ty) };
9609 } else if (rhs_val.compareWithZero(.eq)) {9608 } else if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
9610 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs };9609 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs };
9611 } else if (maybe_lhs_val) |lhs_val| {9610 } else if (maybe_lhs_val) |lhs_val| {
9612 if (lhs_val.isUndef()) {9611 if (lhs_val.isUndef()) {
9613 break :result .{ .overflowed = try sema.addConstUndef(overflowed_ty), .wrapped = try sema.addConstUndef(dest_ty) };9612 break :result .{ .overflowed = try sema.addConstUndef(overflowed_ty), .wrapped = try sema.addConstUndef(dest_ty) };
9614 }9613 }
96159614
9616 const result = try lhs_val.intSubWithOverflow(rhs_val, dest_ty, sema.arena, target);9615 const result = try sema.intSubWithOverflow(block, src, lhs_val, rhs_val, dest_ty);
9617 const overflowed = try sema.addConstant(overflowed_ty, result.overflowed);9616 const overflowed = try sema.addConstant(overflowed_ty, result.overflowed);
9618 const wrapped = try sema.addConstant(dest_ty, result.wrapped_result);9617 const wrapped = try sema.addConstant(dest_ty, result.wrapped_result);
9619 break :result .{ .overflowed = overflowed, .wrapped = wrapped };9618 break :result .{ .overflowed = overflowed, .wrapped = wrapped };
...@@ -9626,9 +9625,9 @@ fn zirOverflowArithmetic(...@@ -9626,9 +9625,9 @@ fn zirOverflowArithmetic(
9626 // Otherwise, if either of the arguments is undefined, both results are undefined.9625 // Otherwise, if either of the arguments is undefined, both results are undefined.
9627 if (maybe_lhs_val) |lhs_val| {9626 if (maybe_lhs_val) |lhs_val| {
9628 if (!lhs_val.isUndef()) {9627 if (!lhs_val.isUndef()) {
9629 if (lhs_val.compareWithZero(.eq)) {9628 if (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
9630 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs };9629 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs };
9631 } else if (lhs_val.compare(.eq, Value.one, dest_ty, mod)) {9630 } else if (try sema.compare(block, src, lhs_val, .eq, Value.one, dest_ty)) {
9632 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = rhs };9631 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = rhs };
9633 }9632 }
9634 }9633 }
...@@ -9636,9 +9635,9 @@ fn zirOverflowArithmetic(...@@ -9636,9 +9635,9 @@ fn zirOverflowArithmetic(
96369635
9637 if (maybe_rhs_val) |rhs_val| {9636 if (maybe_rhs_val) |rhs_val| {
9638 if (!rhs_val.isUndef()) {9637 if (!rhs_val.isUndef()) {
9639 if (rhs_val.compareWithZero(.eq)) {9638 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
9640 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = rhs };9639 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = rhs };
9641 } else if (rhs_val.compare(.eq, Value.one, dest_ty, mod)) {9640 } else if (try sema.compare(block, src, rhs_val, .eq, Value.one, dest_ty)) {
9642 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs };9641 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs };
9643 }9642 }
9644 }9643 }
...@@ -9662,12 +9661,12 @@ fn zirOverflowArithmetic(...@@ -9662,12 +9661,12 @@ fn zirOverflowArithmetic(
9662 // If rhs is zero, the result is lhs (even if undefined) and no overflow occurred.9661 // If rhs is zero, the result is lhs (even if undefined) and no overflow occurred.
9663 // Oterhwise if either of the arguments is undefined, both results are undefined.9662 // Oterhwise if either of the arguments is undefined, both results are undefined.
9664 if (maybe_lhs_val) |lhs_val| {9663 if (maybe_lhs_val) |lhs_val| {
9665 if (!lhs_val.isUndef() and lhs_val.compareWithZero(.eq)) {9664 if (!lhs_val.isUndef() and (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src)))) {
9666 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs };9665 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs };
9667 }9666 }
9668 }9667 }
9669 if (maybe_rhs_val) |rhs_val| {9668 if (maybe_rhs_val) |rhs_val| {
9670 if (!rhs_val.isUndef() and rhs_val.compareWithZero(.eq)) {9669 if (!rhs_val.isUndef() and (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src)))) {
9671 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs };9670 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs };
9672 }9671 }
9673 }9672 }
...@@ -9815,7 +9814,7 @@ fn analyzeArithmetic(...@@ -9815,7 +9814,7 @@ fn analyzeArithmetic(
9815 // overflow (max_int), causing illegal behavior.9814 // overflow (max_int), causing illegal behavior.
9816 // For floats: either operand being undef makes the result undef.9815 // For floats: either operand being undef makes the result undef.
9817 if (maybe_lhs_val) |lhs_val| {9816 if (maybe_lhs_val) |lhs_val| {
9818 if (!lhs_val.isUndef() and lhs_val.compareWithZero(.eq)) {9817 if (!lhs_val.isUndef() and (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src)))) {
9819 return casted_rhs;9818 return casted_rhs;
9820 }9819 }
9821 }9820 }
...@@ -9827,7 +9826,7 @@ fn analyzeArithmetic(...@@ -9827,7 +9826,7 @@ fn analyzeArithmetic(
9827 return sema.addConstUndef(resolved_type);9826 return sema.addConstUndef(resolved_type);
9828 }9827 }
9829 }9828 }
9830 if (rhs_val.compareWithZero(.eq)) {9829 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
9831 return casted_lhs;9830 return casted_lhs;
9832 }9831 }
9833 }9832 }
...@@ -9841,15 +9840,15 @@ fn analyzeArithmetic(...@@ -9841,15 +9840,15 @@ fn analyzeArithmetic(
9841 }9840 }
9842 if (maybe_rhs_val) |rhs_val| {9841 if (maybe_rhs_val) |rhs_val| {
9843 if (is_int) {9842 if (is_int) {
9844 const sum = try lhs_val.intAdd(rhs_val, resolved_type, sema.arena, target);9843 const sum = try sema.intAdd(block, src, lhs_val, rhs_val, resolved_type);
9845 if (!sum.intFitsInType(resolved_type, target)) {9844 if (!(try sema.intFitsInType(block, src, sum, resolved_type))) {
9846 return sema.failWithIntegerOverflow(block, src, resolved_type, sum);9845 return sema.failWithIntegerOverflow(block, src, resolved_type, sum);
9847 }9846 }
9848 return sema.addConstant(resolved_type, sum);9847 return sema.addConstant(resolved_type, sum);
9849 } else {9848 } else {
9850 return sema.addConstant(9849 return sema.addConstant(
9851 resolved_type,9850 resolved_type,
9852 try lhs_val.floatAdd(rhs_val, resolved_type, sema.arena, target),9851 try sema.floatAdd(lhs_val, rhs_val, resolved_type),
9853 );9852 );
9854 }9853 }
9855 } else break :rs .{ .src = rhs_src, .air_tag = .add };9854 } else break :rs .{ .src = rhs_src, .air_tag = .add };
...@@ -9860,7 +9859,7 @@ fn analyzeArithmetic(...@@ -9860,7 +9859,7 @@ fn analyzeArithmetic(
9860 // If either of the operands are zero, the other operand is returned.9859 // If either of the operands are zero, the other operand is returned.
9861 // If either of the operands are undefined, the result is undefined.9860 // If either of the operands are undefined, the result is undefined.
9862 if (maybe_lhs_val) |lhs_val| {9861 if (maybe_lhs_val) |lhs_val| {
9863 if (!lhs_val.isUndef() and lhs_val.compareWithZero(.eq)) {9862 if (!lhs_val.isUndef() and (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src)))) {
9864 return casted_rhs;9863 return casted_rhs;
9865 }9864 }
9866 }9865 }
...@@ -9868,13 +9867,13 @@ fn analyzeArithmetic(...@@ -9868,13 +9867,13 @@ fn analyzeArithmetic(
9868 if (rhs_val.isUndef()) {9867 if (rhs_val.isUndef()) {
9869 return sema.addConstUndef(resolved_type);9868 return sema.addConstUndef(resolved_type);
9870 }9869 }
9871 if (rhs_val.compareWithZero(.eq)) {9870 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
9872 return casted_lhs;9871 return casted_lhs;
9873 }9872 }
9874 if (maybe_lhs_val) |lhs_val| {9873 if (maybe_lhs_val) |lhs_val| {
9875 return sema.addConstant(9874 return sema.addConstant(
9876 resolved_type,9875 resolved_type,
9877 try lhs_val.numberAddWrap(rhs_val, resolved_type, sema.arena, target),9876 try sema.numberAddWrap(block, src, lhs_val, rhs_val, resolved_type),
9878 );9877 );
9879 } else break :rs .{ .src = lhs_src, .air_tag = .addwrap };9878 } else break :rs .{ .src = lhs_src, .air_tag = .addwrap };
9880 } else break :rs .{ .src = rhs_src, .air_tag = .addwrap };9879 } else break :rs .{ .src = rhs_src, .air_tag = .addwrap };
...@@ -9884,7 +9883,7 @@ fn analyzeArithmetic(...@@ -9884,7 +9883,7 @@ fn analyzeArithmetic(
9884 // If either of the operands are zero, then the other operand is returned.9883 // If either of the operands are zero, then the other operand is returned.
9885 // If either of the operands are undefined, the result is undefined.9884 // If either of the operands are undefined, the result is undefined.
9886 if (maybe_lhs_val) |lhs_val| {9885 if (maybe_lhs_val) |lhs_val| {
9887 if (!lhs_val.isUndef() and lhs_val.compareWithZero(.eq)) {9886 if (!lhs_val.isUndef() and (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src)))) {
9888 return casted_rhs;9887 return casted_rhs;
9889 }9888 }
9890 }9889 }
...@@ -9892,12 +9891,12 @@ fn analyzeArithmetic(...@@ -9892,12 +9891,12 @@ fn analyzeArithmetic(
9892 if (rhs_val.isUndef()) {9891 if (rhs_val.isUndef()) {
9893 return sema.addConstUndef(resolved_type);9892 return sema.addConstUndef(resolved_type);
9894 }9893 }
9895 if (rhs_val.compareWithZero(.eq)) {9894 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
9896 return casted_lhs;9895 return casted_lhs;
9897 }9896 }
9898 if (maybe_lhs_val) |lhs_val| {9897 if (maybe_lhs_val) |lhs_val| {
9899 const val = if (scalar_tag == .ComptimeInt)9898 const val = if (scalar_tag == .ComptimeInt)
9900 try lhs_val.intAdd(rhs_val, resolved_type, sema.arena, target)9899 try sema.intAdd(block, src, lhs_val, rhs_val, resolved_type)
9901 else9900 else
9902 try lhs_val.intAddSat(rhs_val, resolved_type, sema.arena, target);9901 try lhs_val.intAddSat(rhs_val, resolved_type, sema.arena, target);
99039902
...@@ -9921,7 +9920,7 @@ fn analyzeArithmetic(...@@ -9921,7 +9920,7 @@ fn analyzeArithmetic(
9921 return sema.addConstUndef(resolved_type);9920 return sema.addConstUndef(resolved_type);
9922 }9921 }
9923 }9922 }
9924 if (rhs_val.compareWithZero(.eq)) {9923 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
9925 return casted_lhs;9924 return casted_lhs;
9926 }9925 }
9927 }9926 }
...@@ -9935,15 +9934,15 @@ fn analyzeArithmetic(...@@ -9935,15 +9934,15 @@ fn analyzeArithmetic(
9935 }9934 }
9936 if (maybe_rhs_val) |rhs_val| {9935 if (maybe_rhs_val) |rhs_val| {
9937 if (is_int) {9936 if (is_int) {
9938 const diff = try lhs_val.intSub(rhs_val, resolved_type, sema.arena, target);9937 const diff = try sema.intSub(block, src, lhs_val, rhs_val, resolved_type);
9939 if (!diff.intFitsInType(resolved_type, target)) {9938 if (!(try sema.intFitsInType(block, src, diff, resolved_type))) {
9940 return sema.failWithIntegerOverflow(block, src, resolved_type, diff);9939 return sema.failWithIntegerOverflow(block, src, resolved_type, diff);
9941 }9940 }
9942 return sema.addConstant(resolved_type, diff);9941 return sema.addConstant(resolved_type, diff);
9943 } else {9942 } else {
9944 return sema.addConstant(9943 return sema.addConstant(
9945 resolved_type,9944 resolved_type,
9946 try lhs_val.floatSub(rhs_val, resolved_type, sema.arena, target),9945 try sema.floatSub(lhs_val, rhs_val, resolved_type),
9947 );9946 );
9948 }9947 }
9949 } else break :rs .{ .src = rhs_src, .air_tag = .sub };9948 } else break :rs .{ .src = rhs_src, .air_tag = .sub };
...@@ -9957,7 +9956,7 @@ fn analyzeArithmetic(...@@ -9957,7 +9956,7 @@ fn analyzeArithmetic(
9957 if (rhs_val.isUndef()) {9956 if (rhs_val.isUndef()) {
9958 return sema.addConstUndef(resolved_type);9957 return sema.addConstUndef(resolved_type);
9959 }9958 }
9960 if (rhs_val.compareWithZero(.eq)) {9959 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
9961 return casted_lhs;9960 return casted_lhs;
9962 }9961 }
9963 }9962 }
...@@ -9968,7 +9967,7 @@ fn analyzeArithmetic(...@@ -9968,7 +9967,7 @@ fn analyzeArithmetic(
9968 if (maybe_rhs_val) |rhs_val| {9967 if (maybe_rhs_val) |rhs_val| {
9969 return sema.addConstant(9968 return sema.addConstant(
9970 resolved_type,9969 resolved_type,
9971 try lhs_val.numberSubWrap(rhs_val, resolved_type, sema.arena, target),9970 try sema.numberSubWrap(block, src, lhs_val, rhs_val, resolved_type),
9972 );9971 );
9973 } else break :rs .{ .src = rhs_src, .air_tag = .subwrap };9972 } else break :rs .{ .src = rhs_src, .air_tag = .subwrap };
9974 } else break :rs .{ .src = lhs_src, .air_tag = .subwrap };9973 } else break :rs .{ .src = lhs_src, .air_tag = .subwrap };
...@@ -9981,7 +9980,7 @@ fn analyzeArithmetic(...@@ -9981,7 +9980,7 @@ fn analyzeArithmetic(
9981 if (rhs_val.isUndef()) {9980 if (rhs_val.isUndef()) {
9982 return sema.addConstUndef(resolved_type);9981 return sema.addConstUndef(resolved_type);
9983 }9982 }
9984 if (rhs_val.compareWithZero(.eq)) {9983 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
9985 return casted_lhs;9984 return casted_lhs;
9986 }9985 }
9987 }9986 }
...@@ -9991,7 +9990,7 @@ fn analyzeArithmetic(...@@ -9991,7 +9990,7 @@ fn analyzeArithmetic(
9991 }9990 }
9992 if (maybe_rhs_val) |rhs_val| {9991 if (maybe_rhs_val) |rhs_val| {
9993 const val = if (scalar_tag == .ComptimeInt)9992 const val = if (scalar_tag == .ComptimeInt)
9994 try lhs_val.intSub(rhs_val, resolved_type, sema.arena, target)9993 try sema.intSub(block, src, lhs_val, rhs_val, resolved_type)
9995 else9994 else
9996 try lhs_val.intSubSat(rhs_val, resolved_type, sema.arena, target);9995 try lhs_val.intSubSat(rhs_val, resolved_type, sema.arena, target);
99979996
...@@ -10032,7 +10031,7 @@ fn analyzeArithmetic(...@@ -10032,7 +10031,7 @@ fn analyzeArithmetic(
10032 .Int, .ComptimeInt, .ComptimeFloat => {10031 .Int, .ComptimeInt, .ComptimeFloat => {
10033 if (maybe_lhs_val) |lhs_val| {10032 if (maybe_lhs_val) |lhs_val| {
10034 if (!lhs_val.isUndef()) {10033 if (!lhs_val.isUndef()) {
10035 if (lhs_val.compareWithZero(.eq)) {10034 if (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
10036 return sema.addConstant(resolved_type, Value.zero);10035 return sema.addConstant(resolved_type, Value.zero);
10037 }10036 }
10038 }10037 }
...@@ -10041,7 +10040,7 @@ fn analyzeArithmetic(...@@ -10041,7 +10040,7 @@ fn analyzeArithmetic(
10041 if (rhs_val.isUndef()) {10040 if (rhs_val.isUndef()) {
10042 return sema.failWithUseOfUndef(block, rhs_src);10041 return sema.failWithUseOfUndef(block, rhs_src);
10043 }10042 }
10044 if (rhs_val.compareWithZero(.eq)) {10043 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
10045 return sema.failWithDivideByZero(block, rhs_src);10044 return sema.failWithDivideByZero(block, rhs_src);
10046 }10045 }
10047 }10046 }
...@@ -10053,7 +10052,7 @@ fn analyzeArithmetic(...@@ -10053,7 +10052,7 @@ fn analyzeArithmetic(
10053 if (lhs_val.isUndef()) {10052 if (lhs_val.isUndef()) {
10054 if (lhs_scalar_ty.isSignedInt() and rhs_scalar_ty.isSignedInt()) {10053 if (lhs_scalar_ty.isSignedInt() and rhs_scalar_ty.isSignedInt()) {
10055 if (maybe_rhs_val) |rhs_val| {10054 if (maybe_rhs_val) |rhs_val| {
10056 if (rhs_val.compare(.neq, Value.negative_one, resolved_type, mod)) {10055 if (try sema.compare(block, src, rhs_val, .neq, Value.negative_one, resolved_type)) {
10057 return sema.addConstUndef(resolved_type);10056 return sema.addConstUndef(resolved_type);
10058 }10057 }
10059 }10058 }
...@@ -10111,7 +10110,7 @@ fn analyzeArithmetic(...@@ -10111,7 +10110,7 @@ fn analyzeArithmetic(
10111 // If the lhs is undefined, result is undefined.10110 // If the lhs is undefined, result is undefined.
10112 if (maybe_lhs_val) |lhs_val| {10111 if (maybe_lhs_val) |lhs_val| {
10113 if (!lhs_val.isUndef()) {10112 if (!lhs_val.isUndef()) {
10114 if (lhs_val.compareWithZero(.eq)) {10113 if (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
10115 return sema.addConstant(resolved_type, Value.zero);10114 return sema.addConstant(resolved_type, Value.zero);
10116 }10115 }
10117 }10116 }
...@@ -10120,7 +10119,7 @@ fn analyzeArithmetic(...@@ -10120,7 +10119,7 @@ fn analyzeArithmetic(
10120 if (rhs_val.isUndef()) {10119 if (rhs_val.isUndef()) {
10121 return sema.failWithUseOfUndef(block, rhs_src);10120 return sema.failWithUseOfUndef(block, rhs_src);
10122 }10121 }
10123 if (rhs_val.compareWithZero(.eq)) {10122 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
10124 return sema.failWithDivideByZero(block, rhs_src);10123 return sema.failWithDivideByZero(block, rhs_src);
10125 }10124 }
10126 }10125 }
...@@ -10128,7 +10127,7 @@ fn analyzeArithmetic(...@@ -10128,7 +10127,7 @@ fn analyzeArithmetic(
10128 if (lhs_val.isUndef()) {10127 if (lhs_val.isUndef()) {
10129 if (lhs_scalar_ty.isSignedInt() and rhs_scalar_ty.isSignedInt()) {10128 if (lhs_scalar_ty.isSignedInt() and rhs_scalar_ty.isSignedInt()) {
10130 if (maybe_rhs_val) |rhs_val| {10129 if (maybe_rhs_val) |rhs_val| {
10131 if (rhs_val.compare(.neq, Value.negative_one, resolved_type, mod)) {10130 if (try sema.compare(block, src, rhs_val, .neq, Value.negative_one, resolved_type)) {
10132 return sema.addConstUndef(resolved_type);10131 return sema.addConstUndef(resolved_type);
10133 }10132 }
10134 }10133 }
...@@ -10174,7 +10173,7 @@ fn analyzeArithmetic(...@@ -10174,7 +10173,7 @@ fn analyzeArithmetic(
10174 // If the lhs is undefined, result is undefined.10173 // If the lhs is undefined, result is undefined.
10175 if (maybe_lhs_val) |lhs_val| {10174 if (maybe_lhs_val) |lhs_val| {
10176 if (!lhs_val.isUndef()) {10175 if (!lhs_val.isUndef()) {
10177 if (lhs_val.compareWithZero(.eq)) {10176 if (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
10178 return sema.addConstant(resolved_type, Value.zero);10177 return sema.addConstant(resolved_type, Value.zero);
10179 }10178 }
10180 }10179 }
...@@ -10183,7 +10182,7 @@ fn analyzeArithmetic(...@@ -10183,7 +10182,7 @@ fn analyzeArithmetic(
10183 if (rhs_val.isUndef()) {10182 if (rhs_val.isUndef()) {
10184 return sema.failWithUseOfUndef(block, rhs_src);10183 return sema.failWithUseOfUndef(block, rhs_src);
10185 }10184 }
10186 if (rhs_val.compareWithZero(.eq)) {10185 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
10187 return sema.failWithDivideByZero(block, rhs_src);10186 return sema.failWithDivideByZero(block, rhs_src);
10188 }10187 }
10189 }10188 }
...@@ -10191,7 +10190,7 @@ fn analyzeArithmetic(...@@ -10191,7 +10190,7 @@ fn analyzeArithmetic(
10191 if (lhs_val.isUndef()) {10190 if (lhs_val.isUndef()) {
10192 if (lhs_scalar_ty.isSignedInt() and rhs_scalar_ty.isSignedInt()) {10191 if (lhs_scalar_ty.isSignedInt() and rhs_scalar_ty.isSignedInt()) {
10193 if (maybe_rhs_val) |rhs_val| {10192 if (maybe_rhs_val) |rhs_val| {
10194 if (rhs_val.compare(.neq, Value.negative_one, resolved_type, mod)) {10193 if (try sema.compare(block, src, rhs_val, .neq, Value.negative_one, resolved_type)) {
10195 return sema.addConstUndef(resolved_type);10194 return sema.addConstUndef(resolved_type);
10196 }10195 }
10197 }10196 }
...@@ -10236,7 +10235,7 @@ fn analyzeArithmetic(...@@ -10236,7 +10235,7 @@ fn analyzeArithmetic(
10236 if (lhs_val.isUndef()) {10235 if (lhs_val.isUndef()) {
10237 return sema.failWithUseOfUndef(block, rhs_src);10236 return sema.failWithUseOfUndef(block, rhs_src);
10238 } else {10237 } else {
10239 if (lhs_val.compareWithZero(.eq)) {10238 if (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
10240 return sema.addConstant(resolved_type, Value.zero);10239 return sema.addConstant(resolved_type, Value.zero);
10241 }10240 }
10242 }10241 }
...@@ -10245,7 +10244,7 @@ fn analyzeArithmetic(...@@ -10245,7 +10244,7 @@ fn analyzeArithmetic(
10245 if (rhs_val.isUndef()) {10244 if (rhs_val.isUndef()) {
10246 return sema.failWithUseOfUndef(block, rhs_src);10245 return sema.failWithUseOfUndef(block, rhs_src);
10247 }10246 }
10248 if (rhs_val.compareWithZero(.eq)) {10247 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
10249 return sema.failWithDivideByZero(block, rhs_src);10248 return sema.failWithDivideByZero(block, rhs_src);
10250 }10249 }
10251 }10250 }
...@@ -10278,10 +10277,10 @@ fn analyzeArithmetic(...@@ -10278,10 +10277,10 @@ fn analyzeArithmetic(
10278 // For floats: either operand being undef makes the result undef.10277 // For floats: either operand being undef makes the result undef.
10279 if (maybe_lhs_val) |lhs_val| {10278 if (maybe_lhs_val) |lhs_val| {
10280 if (!lhs_val.isUndef()) {10279 if (!lhs_val.isUndef()) {
10281 if (lhs_val.compareWithZero(.eq)) {10280 if (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
10282 return sema.addConstant(resolved_type, Value.zero);10281 return sema.addConstant(resolved_type, Value.zero);
10283 }10282 }
10284 if (lhs_val.compare(.eq, Value.one, resolved_type, mod)) {10283 if (try sema.compare(block, src, lhs_val, .eq, Value.one, resolved_type)) {
10285 return casted_rhs;10284 return casted_rhs;
10286 }10285 }
10287 }10286 }
...@@ -10294,10 +10293,10 @@ fn analyzeArithmetic(...@@ -10294,10 +10293,10 @@ fn analyzeArithmetic(
10294 return sema.addConstUndef(resolved_type);10293 return sema.addConstUndef(resolved_type);
10295 }10294 }
10296 }10295 }
10297 if (rhs_val.compareWithZero(.eq)) {10296 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
10298 return sema.addConstant(resolved_type, Value.zero);10297 return sema.addConstant(resolved_type, Value.zero);
10299 }10298 }
10300 if (rhs_val.compare(.eq, Value.one, resolved_type, mod)) {10299 if (try sema.compare(block, src, rhs_val, .eq, Value.one, resolved_type)) {
10301 return casted_lhs;10300 return casted_lhs;
10302 }10301 }
10303 if (maybe_lhs_val) |lhs_val| {10302 if (maybe_lhs_val) |lhs_val| {
...@@ -10310,7 +10309,7 @@ fn analyzeArithmetic(...@@ -10310,7 +10309,7 @@ fn analyzeArithmetic(
10310 }10309 }
10311 if (is_int) {10310 if (is_int) {
10312 const product = try lhs_val.intMul(rhs_val, resolved_type, sema.arena, target);10311 const product = try lhs_val.intMul(rhs_val, resolved_type, sema.arena, target);
10313 if (!product.intFitsInType(resolved_type, target)) {10312 if (!(try sema.intFitsInType(block, src, product, resolved_type))) {
10314 return sema.failWithIntegerOverflow(block, src, resolved_type, product);10313 return sema.failWithIntegerOverflow(block, src, resolved_type, product);
10315 }10314 }
10316 return sema.addConstant(resolved_type, product);10315 return sema.addConstant(resolved_type, product);
...@@ -10330,10 +10329,10 @@ fn analyzeArithmetic(...@@ -10330,10 +10329,10 @@ fn analyzeArithmetic(
10330 // If either of the operands are undefined, result is undefined.10329 // If either of the operands are undefined, result is undefined.
10331 if (maybe_lhs_val) |lhs_val| {10330 if (maybe_lhs_val) |lhs_val| {
10332 if (!lhs_val.isUndef()) {10331 if (!lhs_val.isUndef()) {
10333 if (lhs_val.compareWithZero(.eq)) {10332 if (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
10334 return sema.addConstant(resolved_type, Value.zero);10333 return sema.addConstant(resolved_type, Value.zero);
10335 }10334 }
10336 if (lhs_val.compare(.eq, Value.one, resolved_type, mod)) {10335 if (try sema.compare(block, src, lhs_val, .eq, Value.one, resolved_type)) {
10337 return casted_rhs;10336 return casted_rhs;
10338 }10337 }
10339 }10338 }
...@@ -10342,10 +10341,10 @@ fn analyzeArithmetic(...@@ -10342,10 +10341,10 @@ fn analyzeArithmetic(
10342 if (rhs_val.isUndef()) {10341 if (rhs_val.isUndef()) {
10343 return sema.addConstUndef(resolved_type);10342 return sema.addConstUndef(resolved_type);
10344 }10343 }
10345 if (rhs_val.compareWithZero(.eq)) {10344 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
10346 return sema.addConstant(resolved_type, Value.zero);10345 return sema.addConstant(resolved_type, Value.zero);
10347 }10346 }
10348 if (rhs_val.compare(.eq, Value.one, resolved_type, mod)) {10347 if (try sema.compare(block, src, rhs_val, .eq, Value.one, resolved_type)) {
10349 return casted_lhs;10348 return casted_lhs;
10350 }10349 }
10351 if (maybe_lhs_val) |lhs_val| {10350 if (maybe_lhs_val) |lhs_val| {
...@@ -10366,10 +10365,10 @@ fn analyzeArithmetic(...@@ -10366,10 +10365,10 @@ fn analyzeArithmetic(
10366 // If either of the operands are undefined, result is undefined.10365 // If either of the operands are undefined, result is undefined.
10367 if (maybe_lhs_val) |lhs_val| {10366 if (maybe_lhs_val) |lhs_val| {
10368 if (!lhs_val.isUndef()) {10367 if (!lhs_val.isUndef()) {
10369 if (lhs_val.compareWithZero(.eq)) {10368 if (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
10370 return sema.addConstant(resolved_type, Value.zero);10369 return sema.addConstant(resolved_type, Value.zero);
10371 }10370 }
10372 if (lhs_val.compare(.eq, Value.one, resolved_type, mod)) {10371 if (try sema.compare(block, src, lhs_val, .eq, Value.one, resolved_type)) {
10373 return casted_rhs;10372 return casted_rhs;
10374 }10373 }
10375 }10374 }
...@@ -10378,10 +10377,10 @@ fn analyzeArithmetic(...@@ -10378,10 +10377,10 @@ fn analyzeArithmetic(
10378 if (rhs_val.isUndef()) {10377 if (rhs_val.isUndef()) {
10379 return sema.addConstUndef(resolved_type);10378 return sema.addConstUndef(resolved_type);
10380 }10379 }
10381 if (rhs_val.compareWithZero(.eq)) {10380 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
10382 return sema.addConstant(resolved_type, Value.zero);10381 return sema.addConstant(resolved_type, Value.zero);
10383 }10382 }
10384 if (rhs_val.compare(.eq, Value.one, resolved_type, mod)) {10383 if (try sema.compare(block, src, rhs_val, .eq, Value.one, resolved_type)) {
10385 return casted_lhs;10384 return casted_lhs;
10386 }10385 }
10387 if (maybe_lhs_val) |lhs_val| {10386 if (maybe_lhs_val) |lhs_val| {
...@@ -10417,7 +10416,7 @@ fn analyzeArithmetic(...@@ -10417,7 +10416,7 @@ fn analyzeArithmetic(
10417 if (lhs_val.isUndef()) {10416 if (lhs_val.isUndef()) {
10418 return sema.failWithUseOfUndef(block, lhs_src);10417 return sema.failWithUseOfUndef(block, lhs_src);
10419 }10418 }
10420 if (lhs_val.compareWithZero(.eq)) {10419 if (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
10421 return sema.addConstant(resolved_type, Value.zero);10420 return sema.addConstant(resolved_type, Value.zero);
10422 }10421 }
10423 } else if (lhs_scalar_ty.isSignedInt()) {10422 } else if (lhs_scalar_ty.isSignedInt()) {
...@@ -10427,23 +10426,23 @@ fn analyzeArithmetic(...@@ -10427,23 +10426,23 @@ fn analyzeArithmetic(
10427 if (rhs_val.isUndef()) {10426 if (rhs_val.isUndef()) {
10428 return sema.failWithUseOfUndef(block, rhs_src);10427 return sema.failWithUseOfUndef(block, rhs_src);
10429 }10428 }
10430 if (rhs_val.compareWithZero(.eq)) {10429 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
10431 return sema.failWithDivideByZero(block, rhs_src);10430 return sema.failWithDivideByZero(block, rhs_src);
10432 }10431 }
10433 if (maybe_lhs_val) |lhs_val| {10432 if (maybe_lhs_val) |lhs_val| {
10434 const rem_result = try lhs_val.intRem(rhs_val, resolved_type, sema.arena, target);10433 const rem_result = try lhs_val.intRem(rhs_val, resolved_type, sema.arena, target);
10435 // If this answer could possibly be different by doing `intMod`,10434 // If this answer could possibly be different by doing `intMod`,
10436 // we must emit a compile error. Otherwise, it's OK.10435 // we must emit a compile error. Otherwise, it's OK.
10437 if (rhs_val.compareWithZero(.lt) != lhs_val.compareWithZero(.lt) and10436 if ((try rhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src))) != (try lhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src))) and
10438 !rem_result.compareWithZero(.eq))10437 !(try rem_result.compareWithZeroAdvanced(.eq, sema.kit(block, src))))
10439 {10438 {
10440 const bad_src = if (lhs_val.compareWithZero(.lt))10439 const bad_src = if (try lhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src)))
10441 lhs_src10440 lhs_src
10442 else10441 else
10443 rhs_src;10442 rhs_src;
10444 return sema.failWithModRemNegative(block, bad_src, lhs_ty, rhs_ty);10443 return sema.failWithModRemNegative(block, bad_src, lhs_ty, rhs_ty);
10445 }10444 }
10446 if (lhs_val.compareWithZero(.lt)) {10445 if (try lhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src))) {
10447 // Negative10446 // Negative
10448 return sema.addConstant(resolved_type, Value.zero);10447 return sema.addConstant(resolved_type, Value.zero);
10449 }10448 }
...@@ -10461,14 +10460,14 @@ fn analyzeArithmetic(...@@ -10461,14 +10460,14 @@ fn analyzeArithmetic(
10461 if (rhs_val.isUndef()) {10460 if (rhs_val.isUndef()) {
10462 return sema.failWithUseOfUndef(block, rhs_src);10461 return sema.failWithUseOfUndef(block, rhs_src);
10463 }10462 }
10464 if (rhs_val.compareWithZero(.eq)) {10463 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
10465 return sema.failWithDivideByZero(block, rhs_src);10464 return sema.failWithDivideByZero(block, rhs_src);
10466 }10465 }
10467 if (rhs_val.compareWithZero(.lt)) {10466 if (try rhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src))) {
10468 return sema.failWithModRemNegative(block, rhs_src, lhs_ty, rhs_ty);10467 return sema.failWithModRemNegative(block, rhs_src, lhs_ty, rhs_ty);
10469 }10468 }
10470 if (maybe_lhs_val) |lhs_val| {10469 if (maybe_lhs_val) |lhs_val| {
10471 if (lhs_val.isUndef() or lhs_val.compareWithZero(.lt)) {10470 if (lhs_val.isUndef() or (try lhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src)))) {
10472 return sema.failWithModRemNegative(block, lhs_src, lhs_ty, rhs_ty);10471 return sema.failWithModRemNegative(block, lhs_src, lhs_ty, rhs_ty);
10473 }10472 }
10474 return sema.addConstant(10473 return sema.addConstant(
...@@ -10504,7 +10503,7 @@ fn analyzeArithmetic(...@@ -10504,7 +10503,7 @@ fn analyzeArithmetic(
10504 if (rhs_val.isUndef()) {10503 if (rhs_val.isUndef()) {
10505 return sema.failWithUseOfUndef(block, rhs_src);10504 return sema.failWithUseOfUndef(block, rhs_src);
10506 }10505 }
10507 if (rhs_val.compareWithZero(.eq)) {10506 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
10508 return sema.failWithDivideByZero(block, rhs_src);10507 return sema.failWithDivideByZero(block, rhs_src);
10509 }10508 }
10510 if (maybe_lhs_val) |lhs_val| {10509 if (maybe_lhs_val) |lhs_val| {
...@@ -10523,7 +10522,7 @@ fn analyzeArithmetic(...@@ -10523,7 +10522,7 @@ fn analyzeArithmetic(
10523 if (rhs_val.isUndef()) {10522 if (rhs_val.isUndef()) {
10524 return sema.failWithUseOfUndef(block, rhs_src);10523 return sema.failWithUseOfUndef(block, rhs_src);
10525 }10524 }
10526 if (rhs_val.compareWithZero(.eq)) {10525 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
10527 return sema.failWithDivideByZero(block, rhs_src);10526 return sema.failWithDivideByZero(block, rhs_src);
10528 }10527 }
10529 }10528 }
...@@ -10561,7 +10560,7 @@ fn analyzeArithmetic(...@@ -10561,7 +10560,7 @@ fn analyzeArithmetic(
10561 if (rhs_val.isUndef()) {10560 if (rhs_val.isUndef()) {
10562 return sema.failWithUseOfUndef(block, rhs_src);10561 return sema.failWithUseOfUndef(block, rhs_src);
10563 }10562 }
10564 if (rhs_val.compareWithZero(.eq)) {10563 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
10565 return sema.failWithDivideByZero(block, rhs_src);10564 return sema.failWithDivideByZero(block, rhs_src);
10566 }10565 }
10567 if (maybe_lhs_val) |lhs_val| {10566 if (maybe_lhs_val) |lhs_val| {
...@@ -10580,7 +10579,7 @@ fn analyzeArithmetic(...@@ -10580,7 +10579,7 @@ fn analyzeArithmetic(
10580 if (rhs_val.isUndef()) {10579 if (rhs_val.isUndef()) {
10581 return sema.failWithUseOfUndef(block, rhs_src);10580 return sema.failWithUseOfUndef(block, rhs_src);
10582 }10581 }
10583 if (rhs_val.compareWithZero(.eq)) {10582 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
10584 return sema.failWithDivideByZero(block, rhs_src);10583 return sema.failWithDivideByZero(block, rhs_src);
10585 }10584 }
10586 }10585 }
...@@ -11095,11 +11094,11 @@ fn cmpSelf(...@@ -11095,11 +11094,11 @@ fn cmpSelf(
1109511094
11096 if (resolved_type.zigTypeTag() == .Vector) {11095 if (resolved_type.zigTypeTag() == .Vector) {
11097 const result_ty = try Type.vector(sema.arena, resolved_type.vectorLen(), Type.@"bool");11096 const result_ty = try Type.vector(sema.arena, resolved_type.vectorLen(), Type.@"bool");
11098 const cmp_val = try lhs_val.compareVector(op, rhs_val, resolved_type, sema.arena, sema.mod);11097 const cmp_val = try sema.compareVector(block, lhs_src, lhs_val, op, rhs_val, resolved_type);
11099 return sema.addConstant(result_ty, cmp_val);11098 return sema.addConstant(result_ty, cmp_val);
11100 }11099 }
1110111100
11102 if (lhs_val.compare(op, rhs_val, resolved_type, sema.mod)) {11101 if (try sema.compare(block, lhs_src, lhs_val, op, rhs_val, resolved_type)) {
11103 return Air.Inst.Ref.bool_true;11102 return Air.Inst.Ref.bool_true;
11104 } else {11103 } else {
11105 return Air.Inst.Ref.bool_false;11104 return Air.Inst.Ref.bool_false;
...@@ -11157,24 +11156,22 @@ fn zirSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air....@@ -11157,24 +11156,22 @@ fn zirSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
11157 const inst_data = sema.code.instructions.items(.data)[inst].un_node;11156 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
11158 const src = inst_data.src();11157 const src = inst_data.src();
11159 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };11158 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
11160 const operand_ty = try sema.resolveType(block, operand_src, inst_data.operand);11159 const ty = try sema.resolveType(block, operand_src, inst_data.operand);
11161 try sema.resolveTypeLayout(block, src, operand_ty);11160 switch (ty.zigTypeTag()) {
11162 const target = sema.mod.getTarget();
11163 const abi_size = switch (operand_ty.zigTypeTag()) {
11164 .Fn => unreachable,11161 .Fn => unreachable,
11165 .NoReturn,11162 .NoReturn,
11166 .Undefined,11163 .Undefined,
11167 .Null,11164 .Null,
11168 .BoundFn,11165 .BoundFn,
11169 .Opaque,11166 .Opaque,
11170 => return sema.fail(block, src, "no size available for type '{}'", .{operand_ty.fmt(sema.mod)}),11167 => return sema.fail(block, src, "no size available for type '{}'", .{ty.fmt(sema.mod)}),
1117111168
11172 .Type,11169 .Type,
11173 .EnumLiteral,11170 .EnumLiteral,
11174 .ComptimeFloat,11171 .ComptimeFloat,
11175 .ComptimeInt,11172 .ComptimeInt,
11176 .Void,11173 .Void,
11177 => 0,11174 => return sema.addIntUnsigned(Type.comptime_int, 0),
1117811175
11179 .Bool,11176 .Bool,
11180 .Int,11177 .Int,
...@@ -11190,9 +11187,14 @@ fn zirSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air....@@ -11190,9 +11187,14 @@ fn zirSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
11190 .Vector,11187 .Vector,
11191 .Frame,11188 .Frame,
11192 .AnyFrame,11189 .AnyFrame,
11193 => operand_ty.abiSize(target),11190 => {},
11194 };11191 }
11195 return sema.addIntUnsigned(Type.comptime_int, abi_size);11192 const target = sema.mod.getTarget();
11193 const val = try ty.lazyAbiSize(target, sema.arena);
11194 if (val.tag() == .lazy_size) {
11195 try sema.queueFullTypeResolution(ty);
11196 }
11197 return sema.addConstant(Type.comptime_int, val);
11196}11198}
1119711199
11198fn zirBitSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {11200fn zirBitSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
...@@ -11202,7 +11204,7 @@ fn zirBitSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A...@@ -11202,7 +11204,7 @@ fn zirBitSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
11202 const operand_ty = try sema.resolveTypeFields(block, operand_src, unresolved_operand_ty);11204 const operand_ty = try sema.resolveTypeFields(block, operand_src, unresolved_operand_ty);
11203 const target = sema.mod.getTarget();11205 const target = sema.mod.getTarget();
11204 const bit_size = operand_ty.bitSize(target);11206 const bit_size = operand_ty.bitSize(target);
11205 return sema.addIntUnsigned(Type.initTag(.comptime_int), bit_size);11207 return sema.addIntUnsigned(Type.comptime_int, bit_size);
11206}11208}
1120711209
11208fn zirThis(11210fn zirThis(
...@@ -13516,10 +13518,11 @@ fn zirAlignOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air...@@ -13516,10 +13518,11 @@ fn zirAlignOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
13516 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };13518 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
13517 const ty = try sema.resolveType(block, operand_src, inst_data.operand);13519 const ty = try sema.resolveType(block, operand_src, inst_data.operand);
13518 const target = sema.mod.getTarget();13520 const target = sema.mod.getTarget();
13519 return sema.addConstant(13521 const val = try ty.lazyAbiAlignment(target, sema.arena);
13520 Type.comptime_int,13522 if (val.tag() == .lazy_align) {
13521 try ty.lazyAbiAlignment(target, sema.arena),13523 try sema.queueFullTypeResolution(ty);
13522 );13524 }
13525 return sema.addConstant(Type.comptime_int, val);
13523}13526}
1352413527
13525fn zirBoolToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {13528fn zirBoolToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
...@@ -14362,16 +14365,7 @@ fn zirFloatToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!...@@ -14362,16 +14365,7 @@ fn zirFloatToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
14362 try sema.checkFloatType(block, operand_src, operand_ty);14365 try sema.checkFloatType(block, operand_src, operand_ty);
1436314366
14364 if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |val| {14367 if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |val| {
14365 const target = sema.mod.getTarget();14368 const result_val = try sema.floatToInt(block, operand_src, val, operand_ty, dest_ty);
14366 const result_val = val.floatToInt(sema.arena, operand_ty, dest_ty, target) catch |err| switch (err) {
14367 error.FloatCannotFit => {
14368 return sema.fail(block, operand_src, "integer value {d} cannot be stored in type '{}'", .{
14369 @floor(val.toFloat(f64)),
14370 dest_ty.fmt(sema.mod),
14371 });
14372 },
14373 else => |e| return e,
14374 };
14375 return sema.addConstant(dest_ty, result_val);14369 return sema.addConstant(dest_ty, result_val);
14376 }14370 }
1437714371
...@@ -15563,7 +15557,7 @@ fn zirReduce(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air....@@ -15563,7 +15557,7 @@ fn zirReduce(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
15563 .Xor => accum = try accum.bitwiseXor(elem_val, scalar_ty, sema.arena, target),15557 .Xor => accum = try accum.bitwiseXor(elem_val, scalar_ty, sema.arena, target),
15564 .Min => accum = accum.numberMin(elem_val, target),15558 .Min => accum = accum.numberMin(elem_val, target),
15565 .Max => accum = accum.numberMax(elem_val, target),15559 .Max => accum = accum.numberMax(elem_val, target),
15566 .Add => accum = try accum.numberAddWrap(elem_val, scalar_ty, sema.arena, target),15560 .Add => accum = try sema.numberAddWrap(block, operand_src, accum, elem_val, scalar_ty),
15567 .Mul => accum = try accum.numberMulWrap(elem_val, scalar_ty, sema.arena, target),15561 .Mul => accum = try accum.numberMulWrap(elem_val, scalar_ty, sema.arena, target),
15568 }15562 }
15569 }15563 }
...@@ -15958,14 +15952,14 @@ fn zirAtomicRmw(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A...@@ -15958,14 +15952,14 @@ fn zirAtomicRmw(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
15958 const new_val = switch (op) {15952 const new_val = switch (op) {
15959 // zig fmt: off15953 // zig fmt: off
15960 .Xchg => operand_val,15954 .Xchg => operand_val,
15961 .Add => try stored_val.numberAddWrap(operand_val, elem_ty, sema.arena, target),15955 .Add => try sema.numberAddWrap(block, src, stored_val, operand_val, elem_ty),
15962 .Sub => try stored_val.numberSubWrap(operand_val, elem_ty, sema.arena, target),15956 .Sub => try sema.numberSubWrap(block, src, stored_val, operand_val, elem_ty),
15963 .And => try stored_val.bitwiseAnd (operand_val, elem_ty, sema.arena, target),15957 .And => try stored_val.bitwiseAnd (operand_val, elem_ty, sema.arena, target),
15964 .Nand => try stored_val.bitwiseNand (operand_val, elem_ty, sema.arena, target),15958 .Nand => try stored_val.bitwiseNand (operand_val, elem_ty, sema.arena, target),
15965 .Or => try stored_val.bitwiseOr (operand_val, elem_ty, sema.arena, target),15959 .Or => try stored_val.bitwiseOr (operand_val, elem_ty, sema.arena, target),
15966 .Xor => try stored_val.bitwiseXor (operand_val, elem_ty, sema.arena, target),15960 .Xor => try stored_val.bitwiseXor (operand_val, elem_ty, sema.arena, target),
15967 .Max => stored_val.numberMax (operand_val, target),15961 .Max => stored_val.numberMax (operand_val, target),
15968 .Min => stored_val.numberMin (operand_val, target),15962 .Min => stored_val.numberMin (operand_val, target),
15969 // zig fmt: on15963 // zig fmt: on
15970 };15964 };
15971 try sema.storePtrVal(block, src, ptr_val, new_val, elem_ty);15965 try sema.storePtrVal(block, src, ptr_val, new_val, elem_ty);
...@@ -18890,18 +18884,13 @@ fn coerce(...@@ -18890,18 +18884,13 @@ fn coerce(
18890 .{ val.fmtValue(inst_ty, sema.mod), dest_ty.fmt(sema.mod) },18884 .{ val.fmtValue(inst_ty, sema.mod), dest_ty.fmt(sema.mod) },
18891 );18885 );
18892 }18886 }
18893 const result_val = val.floatToInt(sema.arena, inst_ty, dest_ty, target) catch |err| switch (err) {18887 const result_val = try sema.floatToInt(block, inst_src, val, inst_ty, dest_ty);
18894 error.FloatCannotFit => {
18895 return sema.fail(block, inst_src, "integer value {d} cannot be stored in type '{}'", .{ @floor(val.toFloat(f64)), dest_ty.fmt(sema.mod) });
18896 },
18897 else => |e| return e,
18898 };
18899 return try sema.addConstant(dest_ty, result_val);18888 return try sema.addConstant(dest_ty, result_val);
18900 },18889 },
18901 .Int, .ComptimeInt => {18890 .Int, .ComptimeInt => {
18902 if (try sema.resolveDefinedValue(block, inst_src, inst)) |val| {18891 if (try sema.resolveDefinedValue(block, inst_src, inst)) |val| {
18903 // comptime known integer to other number18892 // comptime known integer to other number
18904 if (!val.intFitsInType(dest_ty, target)) {18893 if (!(try sema.intFitsInType(block, inst_src, val, dest_ty))) {
18905 return sema.fail(block, inst_src, "type {} cannot represent integer value {}", .{ dest_ty.fmt(sema.mod), val.fmtValue(inst_ty, sema.mod) });18894 return sema.fail(block, inst_src, "type {} cannot represent integer value {}", .{ dest_ty.fmt(sema.mod), val.fmtValue(inst_ty, sema.mod) });
18906 }18895 }
18907 return try sema.addConstant(dest_ty, val);18896 return try sema.addConstant(dest_ty, val);
...@@ -21093,7 +21082,7 @@ fn analyzeSlice(...@@ -21093,7 +21082,7 @@ fn analyzeSlice(
21093 sema.arena,21082 sema.arena,
21094 array_ty.arrayLenIncludingSentinel(),21083 array_ty.arrayLenIncludingSentinel(),
21095 );21084 );
21096 if (end_val.compare(.gt, len_s_val, Type.usize, mod)) {21085 if (try sema.compare(block, src, end_val, .gt, len_s_val, Type.usize)) {
21097 const sentinel_label: []const u8 = if (array_ty.sentinel() != null)21086 const sentinel_label: []const u8 = if (array_ty.sentinel() != null)
21098 " +1 (sentinel)"21087 " +1 (sentinel)"
21099 else21088 else
...@@ -21133,7 +21122,7 @@ fn analyzeSlice(...@@ -21133,7 +21122,7 @@ fn analyzeSlice(
21133 .data = slice_val.sliceLen(mod) + @boolToInt(has_sentinel),21122 .data = slice_val.sliceLen(mod) + @boolToInt(has_sentinel),
21134 };21123 };
21135 const slice_len_val = Value.initPayload(&int_payload.base);21124 const slice_len_val = Value.initPayload(&int_payload.base);
21136 if (end_val.compare(.gt, slice_len_val, Type.usize, mod)) {21125 if (try sema.compare(block, src, end_val, .gt, slice_len_val, Type.usize)) {
21137 const sentinel_label: []const u8 = if (has_sentinel)21126 const sentinel_label: []const u8 = if (has_sentinel)
21138 " +1 (sentinel)"21127 " +1 (sentinel)"
21139 else21128 else
...@@ -21191,7 +21180,7 @@ fn analyzeSlice(...@@ -21191,7 +21180,7 @@ fn analyzeSlice(
21191 // requirement: start <= end21180 // requirement: start <= end
21192 if (try sema.resolveDefinedValue(block, src, end)) |end_val| {21181 if (try sema.resolveDefinedValue(block, src, end)) |end_val| {
21193 if (try sema.resolveDefinedValue(block, src, start)) |start_val| {21182 if (try sema.resolveDefinedValue(block, src, start)) |start_val| {
21194 if (start_val.compare(.gt, end_val, Type.usize, mod)) {21183 if (try sema.compare(block, src, start_val, .gt, end_val, Type.usize)) {
21195 return sema.fail(21184 return sema.fail(
21196 block,21185 block,
21197 start_src,21186 start_src,
...@@ -21399,11 +21388,11 @@ fn cmpNumeric(...@@ -21399,11 +21388,11 @@ fn cmpNumeric(
21399 // a signed integer with mantissa bits + 1, and if there was any non-integral part of the float,21388 // a signed integer with mantissa bits + 1, and if there was any non-integral part of the float,
21400 // add/subtract 1.21389 // add/subtract 1.
21401 const lhs_is_signed = if (try sema.resolveDefinedValue(block, lhs_src, lhs)) |lhs_val|21390 const lhs_is_signed = if (try sema.resolveDefinedValue(block, lhs_src, lhs)) |lhs_val|
21402 lhs_val.compareWithZero(.lt)21391 (try lhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src)))
21403 else21392 else
21404 (lhs_ty.isRuntimeFloat() or lhs_ty.isSignedInt());21393 (lhs_ty.isRuntimeFloat() or lhs_ty.isSignedInt());
21405 const rhs_is_signed = if (try sema.resolveDefinedValue(block, rhs_src, rhs)) |rhs_val|21394 const rhs_is_signed = if (try sema.resolveDefinedValue(block, rhs_src, rhs)) |rhs_val|
21406 rhs_val.compareWithZero(.lt)21395 (try rhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src)))
21407 else21396 else
21408 (rhs_ty.isRuntimeFloat() or rhs_ty.isSignedInt());21397 (rhs_ty.isRuntimeFloat() or rhs_ty.isSignedInt());
21409 const dest_int_is_signed = lhs_is_signed or rhs_is_signed;21398 const dest_int_is_signed = lhs_is_signed or rhs_is_signed;
...@@ -21541,7 +21530,7 @@ fn cmpVector(...@@ -21541,7 +21530,7 @@ fn cmpVector(
21541 if (lhs_val.isUndef() or rhs_val.isUndef()) {21530 if (lhs_val.isUndef() or rhs_val.isUndef()) {
21542 return sema.addConstUndef(result_ty);21531 return sema.addConstUndef(result_ty);
21543 }21532 }
21544 const cmp_val = try lhs_val.compareVector(op, rhs_val, lhs_ty, sema.arena, sema.mod);21533 const cmp_val = try sema.compareVector(block, src, lhs_val, op, rhs_val, lhs_ty);
21545 return sema.addConstant(result_ty, cmp_val);21534 return sema.addConstant(result_ty, cmp_val);
21546 } else {21535 } else {
21547 break :src rhs_src;21536 break :src rhs_src;
...@@ -22904,8 +22893,6 @@ fn semaUnionFields(block: *Block, mod: *Module, union_obj: *Module.Union) Compil...@@ -22904,8 +22893,6 @@ fn semaUnionFields(block: *Block, mod: *Module, union_obj: *Module.Union) Compil
22904 enum_field_names = &union_obj.tag_ty.castTag(.enum_simple).?.data.fields;22893 enum_field_names = &union_obj.tag_ty.castTag(.enum_simple).?.data.fields;
22905 }22894 }
2290622895
22907 const target = sema.mod.getTarget();
22908
22909 const bits_per_field = 4;22896 const bits_per_field = 4;
22910 const fields_per_u32 = 32 / bits_per_field;22897 const fields_per_u32 = 32 / bits_per_field;
22911 const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable;22898 const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable;
...@@ -22969,7 +22956,7 @@ fn semaUnionFields(block: *Block, mod: *Module, union_obj: *Module.Union) Compil...@@ -22969,7 +22956,7 @@ fn semaUnionFields(block: *Block, mod: *Module, union_obj: *Module.Union) Compil
22969 });22956 });
22970 } else {22957 } else {
22971 const val = if (last_tag_val) |val|22958 const val = if (last_tag_val) |val|
22972 try val.intAdd(Value.one, int_tag_ty, sema.arena, target)22959 try sema.intAdd(block, src, val, Value.one, int_tag_ty)
22973 else22960 else
22974 Value.zero;22961 Value.zero;
22975 last_tag_val = val;22962 last_tag_val = val;
...@@ -24119,3 +24106,707 @@ fn queueFullTypeResolution(sema: *Sema, ty: Type) !void {...@@ -24119,3 +24106,707 @@ fn queueFullTypeResolution(sema: *Sema, ty: Type) !void {
24119 const inst_ref = try sema.addType(ty);24106 const inst_ref = try sema.addType(ty);
24120 try sema.types_to_resolve.append(sema.gpa, inst_ref);24107 try sema.types_to_resolve.append(sema.gpa, inst_ref);
24121}24108}
24109
24110fn intAdd(sema: *Sema, block: *Block, src: LazySrcLoc, lhs: Value, rhs: Value, ty: Type) !Value {
24111 if (ty.zigTypeTag() == .Vector) {
24112 const result_data = try sema.arena.alloc(Value, ty.vectorLen());
24113 for (result_data) |*scalar, i| {
24114 scalar.* = try sema.intAddScalar(block, src, lhs.indexVectorlike(i), rhs.indexVectorlike(i));
24115 }
24116 return Value.Tag.aggregate.create(sema.arena, result_data);
24117 }
24118 return sema.intAddScalar(block, src, lhs, rhs);
24119}
24120
24121fn intAddScalar(sema: *Sema, block: *Block, src: LazySrcLoc, lhs: Value, rhs: Value) !Value {
24122 // TODO is this a performance issue? maybe we should try the operation without
24123 // resorting to BigInt first.
24124 var lhs_space: Value.BigIntSpace = undefined;
24125 var rhs_space: Value.BigIntSpace = undefined;
24126 const target = sema.mod.getTarget();
24127 const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, target, sema.kit(block, src));
24128 const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, target, sema.kit(block, src));
24129 const limbs = try sema.arena.alloc(
24130 std.math.big.Limb,
24131 std.math.max(lhs_bigint.limbs.len, rhs_bigint.limbs.len) + 1,
24132 );
24133 var result_bigint = std.math.big.int.Mutable{ .limbs = limbs, .positive = undefined, .len = undefined };
24134 result_bigint.add(lhs_bigint, rhs_bigint);
24135 return Value.fromBigInt(sema.arena, result_bigint.toConst());
24136}
24137
24138/// Supports both (vectors of) floats and ints; handles undefined scalars.
24139fn numberAddWrap(
24140 sema: *Sema,
24141 block: *Block,
24142 src: LazySrcLoc,
24143 lhs: Value,
24144 rhs: Value,
24145 ty: Type,
24146) !Value {
24147 if (ty.zigTypeTag() == .Vector) {
24148 const result_data = try sema.arena.alloc(Value, ty.vectorLen());
24149 for (result_data) |*scalar, i| {
24150 scalar.* = try sema.numberAddWrapScalar(block, src, lhs.indexVectorlike(i), rhs.indexVectorlike(i), ty.scalarType());
24151 }
24152 return Value.Tag.aggregate.create(sema.arena, result_data);
24153 }
24154 return sema.numberAddWrapScalar(block, src, lhs, rhs, ty);
24155}
24156
24157/// Supports both floats and ints; handles undefined.
24158fn numberAddWrapScalar(
24159 sema: *Sema,
24160 block: *Block,
24161 src: LazySrcLoc,
24162 lhs: Value,
24163 rhs: Value,
24164 ty: Type,
24165) !Value {
24166 if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef);
24167
24168 if (ty.zigTypeTag() == .ComptimeInt) {
24169 return sema.intAdd(block, src, lhs, rhs, ty);
24170 }
24171
24172 if (ty.isAnyFloat()) {
24173 return sema.floatAdd(lhs, rhs, ty);
24174 }
24175
24176 const overflow_result = try sema.intAddWithOverflow(block, src, lhs, rhs, ty);
24177 return overflow_result.wrapped_result;
24178}
24179
24180fn intSub(
24181 sema: *Sema,
24182 block: *Block,
24183 src: LazySrcLoc,
24184 lhs: Value,
24185 rhs: Value,
24186 ty: Type,
24187) !Value {
24188 if (ty.zigTypeTag() == .Vector) {
24189 const result_data = try sema.arena.alloc(Value, ty.vectorLen());
24190 for (result_data) |*scalar, i| {
24191 scalar.* = try sema.intSubScalar(block, src, lhs.indexVectorlike(i), rhs.indexVectorlike(i));
24192 }
24193 return Value.Tag.aggregate.create(sema.arena, result_data);
24194 }
24195 return sema.intSubScalar(block, src, lhs, rhs);
24196}
24197
24198fn intSubScalar(sema: *Sema, block: *Block, src: LazySrcLoc, lhs: Value, rhs: Value) !Value {
24199 // TODO is this a performance issue? maybe we should try the operation without
24200 // resorting to BigInt first.
24201 var lhs_space: Value.BigIntSpace = undefined;
24202 var rhs_space: Value.BigIntSpace = undefined;
24203 const target = sema.mod.getTarget();
24204 const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, target, sema.kit(block, src));
24205 const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, target, sema.kit(block, src));
24206 const limbs = try sema.arena.alloc(
24207 std.math.big.Limb,
24208 std.math.max(lhs_bigint.limbs.len, rhs_bigint.limbs.len) + 1,
24209 );
24210 var result_bigint = std.math.big.int.Mutable{ .limbs = limbs, .positive = undefined, .len = undefined };
24211 result_bigint.sub(lhs_bigint, rhs_bigint);
24212 return Value.fromBigInt(sema.arena, result_bigint.toConst());
24213}
24214
24215/// Supports both (vectors of) floats and ints; handles undefined scalars.
24216fn numberSubWrap(
24217 sema: *Sema,
24218 block: *Block,
24219 src: LazySrcLoc,
24220 lhs: Value,
24221 rhs: Value,
24222 ty: Type,
24223) !Value {
24224 if (ty.zigTypeTag() == .Vector) {
24225 const result_data = try sema.arena.alloc(Value, ty.vectorLen());
24226 for (result_data) |*scalar, i| {
24227 scalar.* = try sema.numberSubWrapScalar(block, src, lhs.indexVectorlike(i), rhs.indexVectorlike(i), ty.scalarType());
24228 }
24229 return Value.Tag.aggregate.create(sema.arena, result_data);
24230 }
24231 return sema.numberSubWrapScalar(block, src, lhs, rhs, ty);
24232}
24233
24234/// Supports both floats and ints; handles undefined.
24235fn numberSubWrapScalar(
24236 sema: *Sema,
24237 block: *Block,
24238 src: LazySrcLoc,
24239 lhs: Value,
24240 rhs: Value,
24241 ty: Type,
24242) !Value {
24243 if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef);
24244
24245 if (ty.zigTypeTag() == .ComptimeInt) {
24246 return sema.intSub(block, src, lhs, rhs, ty);
24247 }
24248
24249 if (ty.isAnyFloat()) {
24250 return sema.floatSub(lhs, rhs, ty);
24251 }
24252
24253 const overflow_result = try sema.intSubWithOverflow(block, src, lhs, rhs, ty);
24254 return overflow_result.wrapped_result;
24255}
24256
24257fn floatAdd(
24258 sema: *Sema,
24259 lhs: Value,
24260 rhs: Value,
24261 float_type: Type,
24262) !Value {
24263 if (float_type.zigTypeTag() == .Vector) {
24264 const result_data = try sema.arena.alloc(Value, float_type.vectorLen());
24265 for (result_data) |*scalar, i| {
24266 scalar.* = try sema.floatAddScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), float_type.scalarType());
24267 }
24268 return Value.Tag.aggregate.create(sema.arena, result_data);
24269 }
24270 return sema.floatAddScalar(lhs, rhs, float_type);
24271}
24272
24273fn floatAddScalar(
24274 sema: *Sema,
24275 lhs: Value,
24276 rhs: Value,
24277 float_type: Type,
24278) !Value {
24279 const target = sema.mod.getTarget();
24280 switch (float_type.floatBits(target)) {
24281 16 => {
24282 const lhs_val = lhs.toFloat(f16);
24283 const rhs_val = rhs.toFloat(f16);
24284 return Value.Tag.float_16.create(sema.arena, lhs_val + rhs_val);
24285 },
24286 32 => {
24287 const lhs_val = lhs.toFloat(f32);
24288 const rhs_val = rhs.toFloat(f32);
24289 return Value.Tag.float_32.create(sema.arena, lhs_val + rhs_val);
24290 },
24291 64 => {
24292 const lhs_val = lhs.toFloat(f64);
24293 const rhs_val = rhs.toFloat(f64);
24294 return Value.Tag.float_64.create(sema.arena, lhs_val + rhs_val);
24295 },
24296 80 => {
24297 const lhs_val = lhs.toFloat(f80);
24298 const rhs_val = rhs.toFloat(f80);
24299 return Value.Tag.float_80.create(sema.arena, lhs_val + rhs_val);
24300 },
24301 128 => {
24302 const lhs_val = lhs.toFloat(f128);
24303 const rhs_val = rhs.toFloat(f128);
24304 return Value.Tag.float_128.create(sema.arena, lhs_val + rhs_val);
24305 },
24306 else => unreachable,
24307 }
24308}
24309
24310fn floatSub(
24311 sema: *Sema,
24312 lhs: Value,
24313 rhs: Value,
24314 float_type: Type,
24315) !Value {
24316 if (float_type.zigTypeTag() == .Vector) {
24317 const result_data = try sema.arena.alloc(Value, float_type.vectorLen());
24318 for (result_data) |*scalar, i| {
24319 scalar.* = try sema.floatSubScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), float_type.scalarType());
24320 }
24321 return Value.Tag.aggregate.create(sema.arena, result_data);
24322 }
24323 return sema.floatSubScalar(lhs, rhs, float_type);
24324}
24325
24326fn floatSubScalar(
24327 sema: *Sema,
24328 lhs: Value,
24329 rhs: Value,
24330 float_type: Type,
24331) !Value {
24332 const target = sema.mod.getTarget();
24333 switch (float_type.floatBits(target)) {
24334 16 => {
24335 const lhs_val = lhs.toFloat(f16);
24336 const rhs_val = rhs.toFloat(f16);
24337 return Value.Tag.float_16.create(sema.arena, lhs_val - rhs_val);
24338 },
24339 32 => {
24340 const lhs_val = lhs.toFloat(f32);
24341 const rhs_val = rhs.toFloat(f32);
24342 return Value.Tag.float_32.create(sema.arena, lhs_val - rhs_val);
24343 },
24344 64 => {
24345 const lhs_val = lhs.toFloat(f64);
24346 const rhs_val = rhs.toFloat(f64);
24347 return Value.Tag.float_64.create(sema.arena, lhs_val - rhs_val);
24348 },
24349 80 => {
24350 const lhs_val = lhs.toFloat(f80);
24351 const rhs_val = rhs.toFloat(f80);
24352 return Value.Tag.float_80.create(sema.arena, lhs_val - rhs_val);
24353 },
24354 128 => {
24355 const lhs_val = lhs.toFloat(f128);
24356 const rhs_val = rhs.toFloat(f128);
24357 return Value.Tag.float_128.create(sema.arena, lhs_val - rhs_val);
24358 },
24359 else => unreachable,
24360 }
24361}
24362
24363fn intSubWithOverflow(
24364 sema: *Sema,
24365 block: *Block,
24366 src: LazySrcLoc,
24367 lhs: Value,
24368 rhs: Value,
24369 ty: Type,
24370) !Value.OverflowArithmeticResult {
24371 if (ty.zigTypeTag() == .Vector) {
24372 const overflowed_data = try sema.arena.alloc(Value, ty.vectorLen());
24373 const result_data = try sema.arena.alloc(Value, ty.vectorLen());
24374 for (result_data) |*scalar, i| {
24375 const of_math_result = try sema.intSubWithOverflowScalar(block, src, lhs.indexVectorlike(i), rhs.indexVectorlike(i), ty.scalarType());
24376 overflowed_data[i] = of_math_result.overflowed;
24377 scalar.* = of_math_result.wrapped_result;
24378 }
24379 return Value.OverflowArithmeticResult{
24380 .overflowed = try Value.Tag.aggregate.create(sema.arena, overflowed_data),
24381 .wrapped_result = try Value.Tag.aggregate.create(sema.arena, result_data),
24382 };
24383 }
24384 return sema.intSubWithOverflowScalar(block, src, lhs, rhs, ty);
24385}
24386
24387fn intSubWithOverflowScalar(
24388 sema: *Sema,
24389 block: *Block,
24390 src: LazySrcLoc,
24391 lhs: Value,
24392 rhs: Value,
24393 ty: Type,
24394) !Value.OverflowArithmeticResult {
24395 const target = sema.mod.getTarget();
24396 const info = ty.intInfo(target);
24397
24398 var lhs_space: Value.BigIntSpace = undefined;
24399 var rhs_space: Value.BigIntSpace = undefined;
24400 const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, target, sema.kit(block, src));
24401 const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, target, sema.kit(block, src));
24402 const limbs = try sema.arena.alloc(
24403 std.math.big.Limb,
24404 std.math.big.int.calcTwosCompLimbCount(info.bits),
24405 );
24406 var result_bigint = std.math.big.int.Mutable{ .limbs = limbs, .positive = undefined, .len = undefined };
24407 const overflowed = result_bigint.subWrap(lhs_bigint, rhs_bigint, info.signedness, info.bits);
24408 const wrapped_result = try Value.fromBigInt(sema.arena, result_bigint.toConst());
24409 return Value.OverflowArithmeticResult{
24410 .overflowed = Value.makeBool(overflowed),
24411 .wrapped_result = wrapped_result,
24412 };
24413}
24414
24415fn floatToInt(
24416 sema: *Sema,
24417 block: *Block,
24418 src: LazySrcLoc,
24419 val: Value,
24420 float_ty: Type,
24421 int_ty: Type,
24422) CompileError!Value {
24423 if (float_ty.zigTypeTag() == .Vector) {
24424 const elem_ty = float_ty.childType();
24425 const result_data = try sema.arena.alloc(Value, float_ty.vectorLen());
24426 for (result_data) |*scalar, i| {
24427 scalar.* = try sema.floatToIntScalar(block, src, val.indexVectorlike(i), elem_ty, int_ty.scalarType());
24428 }
24429 return Value.Tag.aggregate.create(sema.arena, result_data);
24430 }
24431 return sema.floatToIntScalar(block, src, val, float_ty, int_ty);
24432}
24433
24434fn floatToIntScalar(
24435 sema: *Sema,
24436 block: *Block,
24437 src: LazySrcLoc,
24438 val: Value,
24439 float_ty: Type,
24440 int_ty: Type,
24441) CompileError!Value {
24442 const Limb = std.math.big.Limb;
24443
24444 const float = val.toFloat(f128);
24445 if (std.math.isNan(float)) {
24446 return sema.fail(block, src, "float value NaN cannot be stored in integer type '{}'", .{
24447 int_ty.fmt(sema.mod),
24448 });
24449 }
24450 if (std.math.isInf(float)) {
24451 return sema.fail(block, src, "float value Inf cannot be stored in integer type '{}'", .{
24452 int_ty.fmt(sema.mod),
24453 });
24454 }
24455
24456 const is_negative = std.math.signbit(float);
24457 const floored = @floor(@fabs(float));
24458
24459 var rational = try std.math.big.Rational.init(sema.arena);
24460 defer rational.deinit();
24461 rational.setFloat(f128, floored) catch |err| switch (err) {
24462 error.NonFiniteFloat => unreachable,
24463 error.OutOfMemory => return error.OutOfMemory,
24464 };
24465
24466 // The float is reduced in rational.setFloat, so we assert that denominator is equal to one
24467 const big_one = std.math.big.int.Const{ .limbs = &.{1}, .positive = true };
24468 assert(rational.q.toConst().eqAbs(big_one));
24469
24470 const result_limbs = try sema.arena.dupe(Limb, rational.p.toConst().limbs);
24471 const result = if (is_negative)
24472 try Value.Tag.int_big_negative.create(sema.arena, result_limbs)
24473 else
24474 try Value.Tag.int_big_positive.create(sema.arena, result_limbs);
24475
24476 if (!(try sema.intFitsInType(block, src, result, int_ty))) {
24477 return sema.fail(block, src, "float value {} cannot be stored in integer type '{}'", .{
24478 val.fmtValue(float_ty, sema.mod), int_ty.fmt(sema.mod),
24479 });
24480 }
24481 return result;
24482}
24483
24484/// Asserts the value is an integer, and the destination type is ComptimeInt or Int.
24485/// Vectors are also accepted. Vector results are reduced with AND.
24486fn intFitsInType(
24487 sema: *Sema,
24488 block: *Block,
24489 src: LazySrcLoc,
24490 self: Value,
24491 ty: Type,
24492) CompileError!bool {
24493 const target = sema.mod.getTarget();
24494 switch (self.tag()) {
24495 .zero,
24496 .undef,
24497 .bool_false,
24498 => return true,
24499
24500 .one,
24501 .bool_true,
24502 => switch (ty.zigTypeTag()) {
24503 .Int => {
24504 const info = ty.intInfo(target);
24505 return switch (info.signedness) {
24506 .signed => info.bits >= 2,
24507 .unsigned => info.bits >= 1,
24508 };
24509 },
24510 .ComptimeInt => return true,
24511 else => unreachable,
24512 },
24513
24514 .lazy_align => {
24515 const info = ty.intInfo(target);
24516 const max_needed_bits = @as(u16, 16) + @boolToInt(info.signedness == .signed);
24517 // If it is u16 or bigger we know the alignment fits without resolving it.
24518 if (info.bits >= max_needed_bits) return true;
24519 const x = try sema.typeAbiAlignment(block, src, self.castTag(.lazy_align).?.data);
24520 if (x == 0) return true;
24521 const actual_needed_bits = std.math.log2(x) + 1 + @boolToInt(info.signedness == .signed);
24522 return info.bits >= actual_needed_bits;
24523 },
24524 .lazy_size => {
24525 const info = ty.intInfo(target);
24526 const max_needed_bits = @as(u16, 64) + @boolToInt(info.signedness == .signed);
24527 // If it is u64 or bigger we know the size fits without resolving it.
24528 if (info.bits >= max_needed_bits) return true;
24529 const x = try sema.typeAbiSize(block, src, self.castTag(.lazy_size).?.data);
24530 if (x == 0) return true;
24531 const actual_needed_bits = std.math.log2(x) + 1 + @boolToInt(info.signedness == .signed);
24532 return info.bits >= actual_needed_bits;
24533 },
24534
24535 .int_u64 => switch (ty.zigTypeTag()) {
24536 .Int => {
24537 const x = self.castTag(.int_u64).?.data;
24538 if (x == 0) return true;
24539 const info = ty.intInfo(target);
24540 const needed_bits = std.math.log2(x) + 1 + @boolToInt(info.signedness == .signed);
24541 return info.bits >= needed_bits;
24542 },
24543 .ComptimeInt => return true,
24544 else => unreachable,
24545 },
24546 .int_i64 => switch (ty.zigTypeTag()) {
24547 .Int => {
24548 const x = self.castTag(.int_i64).?.data;
24549 if (x == 0) return true;
24550 const info = ty.intInfo(target);
24551 if (info.signedness == .unsigned and x < 0)
24552 return false;
24553 var buffer: Value.BigIntSpace = undefined;
24554 return (try self.toBigIntAdvanced(&buffer, target, sema.kit(block, src))).fitsInTwosComp(info.signedness, info.bits);
24555 },
24556 .ComptimeInt => return true,
24557 else => unreachable,
24558 },
24559 .int_big_positive => switch (ty.zigTypeTag()) {
24560 .Int => {
24561 const info = ty.intInfo(target);
24562 return self.castTag(.int_big_positive).?.asBigInt().fitsInTwosComp(info.signedness, info.bits);
24563 },
24564 .ComptimeInt => return true,
24565 else => unreachable,
24566 },
24567 .int_big_negative => switch (ty.zigTypeTag()) {
24568 .Int => {
24569 const info = ty.intInfo(target);
24570 return self.castTag(.int_big_negative).?.asBigInt().fitsInTwosComp(info.signedness, info.bits);
24571 },
24572 .ComptimeInt => return true,
24573 else => unreachable,
24574 },
24575
24576 .the_only_possible_value => {
24577 assert(ty.intInfo(target).bits == 0);
24578 return true;
24579 },
24580
24581 .decl_ref_mut,
24582 .extern_fn,
24583 .decl_ref,
24584 .function,
24585 .variable,
24586 => switch (ty.zigTypeTag()) {
24587 .Int => {
24588 const info = ty.intInfo(target);
24589 const ptr_bits = target.cpu.arch.ptrBitWidth();
24590 return switch (info.signedness) {
24591 .signed => info.bits > ptr_bits,
24592 .unsigned => info.bits >= ptr_bits,
24593 };
24594 },
24595 .ComptimeInt => return true,
24596 else => unreachable,
24597 },
24598
24599 .aggregate => {
24600 assert(ty.zigTypeTag() == .Vector);
24601 for (self.castTag(.aggregate).?.data) |elem| {
24602 if (!(try sema.intFitsInType(block, src, elem, ty.scalarType()))) {
24603 return false;
24604 }
24605 }
24606 return true;
24607 },
24608
24609 else => unreachable,
24610 }
24611}
24612
24613fn intInRange(
24614 sema: *Sema,
24615 block: *Block,
24616 src: LazySrcLoc,
24617 tag_ty: Type,
24618 int_val: Value,
24619 end: usize,
24620) !bool {
24621 if (try int_val.compareWithZeroAdvanced(.lt, sema.kit(block, src))) return false;
24622 var end_payload: Value.Payload.U64 = .{
24623 .base = .{ .tag = .int_u64 },
24624 .data = end,
24625 };
24626 const end_val = Value.initPayload(&end_payload.base);
24627 if (try sema.compare(block, src, int_val, .gte, end_val, tag_ty)) return false;
24628 return true;
24629}
24630
24631/// Asserts the type is an enum.
24632fn enumHasInt(
24633 sema: *Sema,
24634 block: *Block,
24635 src: LazySrcLoc,
24636 ty: Type,
24637 int: Value,
24638) CompileError!bool {
24639 switch (ty.tag()) {
24640 .enum_nonexhaustive => return sema.intFitsInType(block, src, int, ty),
24641 .enum_full => {
24642 const enum_full = ty.castTag(.enum_full).?.data;
24643 const tag_ty = enum_full.tag_ty;
24644 if (enum_full.values.count() == 0) {
24645 return intInRange(sema, block, src, tag_ty, int, enum_full.fields.count());
24646 } else {
24647 return enum_full.values.containsContext(int, .{
24648 .ty = tag_ty,
24649 .mod = sema.mod,
24650 });
24651 }
24652 },
24653 .enum_numbered => {
24654 const enum_obj = ty.castTag(.enum_numbered).?.data;
24655 const tag_ty = enum_obj.tag_ty;
24656 if (enum_obj.values.count() == 0) {
24657 return intInRange(sema, block, src, tag_ty, int, enum_obj.fields.count());
24658 } else {
24659 return enum_obj.values.containsContext(int, .{
24660 .ty = tag_ty,
24661 .mod = sema.mod,
24662 });
24663 }
24664 },
24665 .enum_simple => {
24666 const enum_simple = ty.castTag(.enum_simple).?.data;
24667 const fields_len = enum_simple.fields.count();
24668 const bits = std.math.log2_int_ceil(usize, fields_len);
24669 var buffer: Type.Payload.Bits = .{
24670 .base = .{ .tag = .int_unsigned },
24671 .data = bits,
24672 };
24673 const tag_ty = Type.initPayload(&buffer.base);
24674 return intInRange(sema, block, src, tag_ty, int, fields_len);
24675 },
24676 .atomic_order,
24677 .atomic_rmw_op,
24678 .calling_convention,
24679 .address_space,
24680 .float_mode,
24681 .reduce_op,
24682 .call_options,
24683 .prefetch_options,
24684 .export_options,
24685 .extern_options,
24686 => unreachable,
24687
24688 else => unreachable,
24689 }
24690}
24691
24692fn intAddWithOverflow(
24693 sema: *Sema,
24694 block: *Block,
24695 src: LazySrcLoc,
24696 lhs: Value,
24697 rhs: Value,
24698 ty: Type,
24699) !Value.OverflowArithmeticResult {
24700 if (ty.zigTypeTag() == .Vector) {
24701 const overflowed_data = try sema.arena.alloc(Value, ty.vectorLen());
24702 const result_data = try sema.arena.alloc(Value, ty.vectorLen());
24703 for (result_data) |*scalar, i| {
24704 const of_math_result = try sema.intAddWithOverflowScalar(block, src, lhs.indexVectorlike(i), rhs.indexVectorlike(i), ty.scalarType());
24705 overflowed_data[i] = of_math_result.overflowed;
24706 scalar.* = of_math_result.wrapped_result;
24707 }
24708 return Value.OverflowArithmeticResult{
24709 .overflowed = try Value.Tag.aggregate.create(sema.arena, overflowed_data),
24710 .wrapped_result = try Value.Tag.aggregate.create(sema.arena, result_data),
24711 };
24712 }
24713 return sema.intAddWithOverflowScalar(block, src, lhs, rhs, ty);
24714}
24715
24716fn intAddWithOverflowScalar(
24717 sema: *Sema,
24718 block: *Block,
24719 src: LazySrcLoc,
24720 lhs: Value,
24721 rhs: Value,
24722 ty: Type,
24723) !Value.OverflowArithmeticResult {
24724 const target = sema.mod.getTarget();
24725 const info = ty.intInfo(target);
24726
24727 var lhs_space: Value.BigIntSpace = undefined;
24728 var rhs_space: Value.BigIntSpace = undefined;
24729 const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, target, sema.kit(block, src));
24730 const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, target, sema.kit(block, src));
24731 const limbs = try sema.arena.alloc(
24732 std.math.big.Limb,
24733 std.math.big.int.calcTwosCompLimbCount(info.bits),
24734 );
24735 var result_bigint = std.math.big.int.Mutable{ .limbs = limbs, .positive = undefined, .len = undefined };
24736 const overflowed = result_bigint.addWrap(lhs_bigint, rhs_bigint, info.signedness, info.bits);
24737 const result = try Value.fromBigInt(sema.arena, result_bigint.toConst());
24738 return Value.OverflowArithmeticResult{
24739 .overflowed = Value.makeBool(overflowed),
24740 .wrapped_result = result,
24741 };
24742}
24743
24744/// Asserts the values are comparable. Both operands have type `ty`.
24745/// Vector results will be reduced with AND.
24746fn compare(
24747 sema: *Sema,
24748 block: *Block,
24749 src: LazySrcLoc,
24750 lhs: Value,
24751 op: std.math.CompareOperator,
24752 rhs: Value,
24753 ty: Type,
24754) CompileError!bool {
24755 if (ty.zigTypeTag() == .Vector) {
24756 var i: usize = 0;
24757 while (i < ty.vectorLen()) : (i += 1) {
24758 if (!(try sema.compareScalar(block, src, lhs.indexVectorlike(i), op, rhs.indexVectorlike(i), ty.scalarType()))) {
24759 return false;
24760 }
24761 }
24762 return true;
24763 }
24764 return sema.compareScalar(block, src, lhs, op, rhs, ty);
24765}
24766
24767/// Asserts the values are comparable. Both operands have type `ty`.
24768fn compareScalar(
24769 sema: *Sema,
24770 block: *Block,
24771 src: LazySrcLoc,
24772 lhs: Value,
24773 op: std.math.CompareOperator,
24774 rhs: Value,
24775 ty: Type,
24776) CompileError!bool {
24777 switch (op) {
24778 .eq => return sema.valuesEqual(block, src, lhs, rhs, ty),
24779 .neq => return !(try sema.valuesEqual(block, src, lhs, rhs, ty)),
24780 else => return Value.compareHeteroAdvanced(lhs, op, rhs, sema.mod.getTarget(), sema.kit(block, src)),
24781 }
24782}
24783
24784fn valuesEqual(
24785 sema: *Sema,
24786 block: *Block,
24787 src: LazySrcLoc,
24788 lhs: Value,
24789 rhs: Value,
24790 ty: Type,
24791) CompileError!bool {
24792 return Value.eqlAdvanced(lhs, rhs, ty, sema.mod, sema.kit(block, src));
24793}
24794
24795/// Asserts the values are comparable vectors of type `ty`.
24796pub fn compareVector(
24797 sema: *Sema,
24798 block: *Block,
24799 src: LazySrcLoc,
24800 lhs: Value,
24801 op: std.math.CompareOperator,
24802 rhs: Value,
24803 ty: Type,
24804) !Value {
24805 assert(ty.zigTypeTag() == .Vector);
24806 const result_data = try sema.arena.alloc(Value, ty.vectorLen());
24807 for (result_data) |*scalar, i| {
24808 const res_bool = try sema.compareScalar(block, src, lhs.indexVectorlike(i), op, rhs.indexVectorlike(i), ty.scalarType());
24809 scalar.* = Value.makeBool(res_bool);
24810 }
24811 return Value.Tag.aggregate.create(sema.arena, result_data);
24812}
src/TypedValue.zig+5
...@@ -232,6 +232,11 @@ pub fn print(...@@ -232,6 +232,11 @@ pub fn print(
232 const x = sub_ty.abiAlignment(target);232 const x = sub_ty.abiAlignment(target);
233 return writer.print("{d}", .{x});233 return writer.print("{d}", .{x});
234 },234 },
235 .lazy_size => {
236 const sub_ty = val.castTag(.lazy_size).?.data;
237 const x = sub_ty.abiSize(target);
238 return writer.print("{d}", .{x});
239 },
235 .function => return writer.print("(function '{s}')", .{240 .function => return writer.print("(function '{s}')", .{
236 mod.declPtr(val.castTag(.function).?.data.owner_decl).name,241 mod.declPtr(val.castTag(.function).?.data.owner_decl).name,
237 }),242 }),
src/type.zig+154-137
...@@ -2760,7 +2760,7 @@ pub const Type = extern union {...@@ -2760,7 +2760,7 @@ pub const Type = extern union {
2760 .sema_kit => |sk| sk,2760 .sema_kit => |sk| sk,
2761 else => null,2761 else => null,
2762 };2762 };
2763 return switch (ty.tag()) {2763 switch (ty.tag()) {
2764 .u1,2764 .u1,
2765 .u8,2765 .u8,
2766 .i8,2766 .i8,
...@@ -3028,7 +3028,7 @@ pub const Type = extern union {...@@ -3028,7 +3028,7 @@ pub const Type = extern union {
3028 => unreachable,3028 => unreachable,
30293029
3030 .generic_poison => unreachable,3030 .generic_poison => unreachable,
3031 };3031 }
3032 }3032 }
30333033
3034 pub fn abiAlignmentAdvancedUnion(3034 pub fn abiAlignmentAdvancedUnion(
...@@ -3076,10 +3076,37 @@ pub const Type = extern union {...@@ -3076,10 +3076,37 @@ pub const Type = extern union {
3076 return AbiAlignmentAdvanced{ .scalar = max_align };3076 return AbiAlignmentAdvanced{ .scalar = max_align };
3077 }3077 }
30783078
3079 /// May capture a reference to `ty`.
3080 pub fn lazyAbiSize(ty: Type, target: Target, arena: Allocator) !Value {
3081 switch (try ty.abiSizeAdvanced(target, .{ .lazy = arena })) {
3082 .val => |val| return val,
3083 .scalar => |x| return Value.Tag.int_u64.create(arena, x),
3084 }
3085 }
3086
3079 /// Asserts the type has the ABI size already resolved.3087 /// Asserts the type has the ABI size already resolved.
3080 /// Types that return false for hasRuntimeBits() return 0.3088 /// Types that return false for hasRuntimeBits() return 0.
3081 pub fn abiSize(self: Type, target: Target) u64 {3089 pub fn abiSize(ty: Type, target: Target) u64 {
3082 return switch (self.tag()) {3090 return (abiSizeAdvanced(ty, target, .eager) catch unreachable).scalar;
3091 }
3092
3093 const AbiSizeAdvanced = union(enum) {
3094 scalar: u64,
3095 val: Value,
3096 };
3097
3098 /// If you pass `eager` you will get back `scalar` and assert the type is resolved.
3099 /// In this case there will be no error, guaranteed.
3100 /// If you pass `lazy` you may get back `scalar` or `val`.
3101 /// If `val` is returned, a reference to `ty` has been captured.
3102 /// If you pass `sema_kit` you will get back `scalar` and resolve the type if
3103 /// necessary, possibly returning a CompileError.
3104 pub fn abiSizeAdvanced(
3105 ty: Type,
3106 target: Target,
3107 strat: AbiAlignmentAdvancedStrat,
3108 ) Module.CompileError!AbiSizeAdvanced {
3109 switch (ty.tag()) {
3083 .fn_noreturn_no_args => unreachable, // represents machine code; not a pointer3110 .fn_noreturn_no_args => unreachable, // represents machine code; not a pointer
3084 .fn_void_no_args => unreachable, // represents machine code; not a pointer3111 .fn_void_no_args => unreachable, // represents machine code; not a pointer
3085 .fn_naked_noreturn_no_args => unreachable, // represents machine code; not a pointer3112 .fn_naked_noreturn_no_args => unreachable, // represents machine code; not a pointer
...@@ -3109,32 +3136,59 @@ pub const Type = extern union {...@@ -3109,32 +3136,59 @@ pub const Type = extern union {
3109 .empty_struct_literal,3136 .empty_struct_literal,
3110 .empty_struct,3137 .empty_struct,
3111 .void,3138 .void,
3112 => 0,3139 => return AbiSizeAdvanced{ .scalar = 0 },
31133140
3114 .@"struct", .tuple, .anon_struct => switch (self.containerLayout()) {3141 .@"struct", .tuple, .anon_struct => switch (ty.containerLayout()) {
3115 .Packed => {3142 .Packed => {
3116 const struct_obj = self.castTag(.@"struct").?.data;3143 const struct_obj = ty.castTag(.@"struct").?.data;
3144 switch (strat) {
3145 .sema_kit => |sk| _ = try sk.sema.resolveTypeFields(sk.block, sk.src, ty),
3146 .lazy => |arena| {
3147 if (!struct_obj.haveFieldTypes()) {
3148 return AbiSizeAdvanced{ .val = try Value.Tag.lazy_size.create(arena, ty) };
3149 }
3150 },
3151 .eager => {},
3152 }
3117 var buf: Type.Payload.Bits = undefined;3153 var buf: Type.Payload.Bits = undefined;
3118 const int_ty = struct_obj.packedIntegerType(target, &buf);3154 const int_ty = struct_obj.packedIntegerType(target, &buf);
3119 return int_ty.abiSize(target);3155 return AbiSizeAdvanced{ .scalar = int_ty.abiSize(target) };
3120 },3156 },
3121 else => {3157 else => {
3122 const field_count = self.structFieldCount();3158 switch (strat) {
3159 .sema_kit => |sk| try sk.sema.resolveTypeLayout(sk.block, sk.src, ty),
3160 .lazy => |arena| {
3161 if (ty.castTag(.@"struct")) |payload| {
3162 const struct_obj = payload.data;
3163 if (!struct_obj.haveLayout()) {
3164 return AbiSizeAdvanced{ .val = try Value.Tag.lazy_size.create(arena, ty) };
3165 }
3166 }
3167 },
3168 .eager => {},
3169 }
3170 const field_count = ty.structFieldCount();
3123 if (field_count == 0) {3171 if (field_count == 0) {
3124 return 0;3172 return AbiSizeAdvanced{ .scalar = 0 };
3125 }3173 }
3126 return self.structFieldOffset(field_count, target);3174 return AbiSizeAdvanced{ .scalar = ty.structFieldOffset(field_count, target) };
3127 },3175 },
3128 },3176 },
31293177
3130 .enum_simple, .enum_full, .enum_nonexhaustive, .enum_numbered => {3178 .enum_simple, .enum_full, .enum_nonexhaustive, .enum_numbered => {
3131 var buffer: Payload.Bits = undefined;3179 var buffer: Payload.Bits = undefined;
3132 const int_tag_ty = self.intTagType(&buffer);3180 const int_tag_ty = ty.intTagType(&buffer);
3133 return int_tag_ty.abiSize(target);3181 return AbiSizeAdvanced{ .scalar = int_tag_ty.abiSize(target) };
3182 },
3183 .@"union" => {
3184 const union_obj = ty.castTag(.@"union").?.data;
3185 // TODO pass `true` for have_tag when unions have a safety tag
3186 return abiSizeAdvancedUnion(ty, target, strat, union_obj, false);
3187 },
3188 .union_tagged => {
3189 const union_obj = ty.castTag(.union_tagged).?.data;
3190 return abiSizeAdvancedUnion(ty, target, strat, union_obj, true);
3134 },3191 },
3135 // TODO pass `true` for have_tag when unions have a safety tag
3136 .@"union" => return self.castTag(.@"union").?.data.abiSize(target, false),
3137 .union_tagged => return self.castTag(.union_tagged).?.data.abiSize(target, true),
31383192
3139 .u1,3193 .u1,
3140 .u8,3194 .u8,
...@@ -3146,21 +3200,31 @@ pub const Type = extern union {...@@ -3146,21 +3200,31 @@ pub const Type = extern union {
3146 .address_space,3200 .address_space,
3147 .float_mode,3201 .float_mode,
3148 .reduce_op,3202 .reduce_op,
3149 => return 1,3203 => return AbiSizeAdvanced{ .scalar = 1 },
31503204
3151 .array_u8 => self.castTag(.array_u8).?.data,3205 .array_u8 => return AbiSizeAdvanced{ .scalar = ty.castTag(.array_u8).?.data },
3152 .array_u8_sentinel_0 => self.castTag(.array_u8_sentinel_0).?.data + 1,3206 .array_u8_sentinel_0 => return AbiSizeAdvanced{ .scalar = ty.castTag(.array_u8_sentinel_0).?.data + 1 },
3153 .array, .vector => {3207 .array, .vector => {
3154 const payload = self.cast(Payload.Array).?.data;3208 const payload = ty.cast(Payload.Array).?.data;
3155 const elem_size = payload.elem_type.abiSize(target);3209 switch (try payload.elem_type.abiSizeAdvanced(target, strat)) {
3156 assert(elem_size >= payload.elem_type.abiAlignment(target));3210 .scalar => |elem_size| return AbiSizeAdvanced{ .scalar = payload.len * elem_size },
3157 return payload.len * elem_size;3211 .val => switch (strat) {
3212 .sema_kit => unreachable,
3213 .eager => unreachable,
3214 .lazy => |arena| return AbiSizeAdvanced{ .val = try Value.Tag.lazy_size.create(arena, ty) },
3215 },
3216 }
3158 },3217 },
3159 .array_sentinel => {3218 .array_sentinel => {
3160 const payload = self.castTag(.array_sentinel).?.data;3219 const payload = ty.castTag(.array_sentinel).?.data;
3161 const elem_size = payload.elem_type.abiSize(target);3220 switch (try payload.elem_type.abiSizeAdvanced(target, strat)) {
3162 assert(elem_size >= payload.elem_type.abiAlignment(target));3221 .scalar => |elem_size| return AbiSizeAdvanced{ .scalar = (payload.len + 1) * elem_size },
3163 return (payload.len + 1) * elem_size;3222 .val => switch (strat) {
3223 .sema_kit => unreachable,
3224 .eager => unreachable,
3225 .lazy => |arena| return AbiSizeAdvanced{ .val = try Value.Tag.lazy_size.create(arena, ty) },
3226 },
3227 }
3164 },3228 },
31653229
3166 .isize,3230 .isize,
...@@ -3178,95 +3242,96 @@ pub const Type = extern union {...@@ -3178,95 +3242,96 @@ pub const Type = extern union {
3178 .manyptr_u8,3242 .manyptr_u8,
3179 .manyptr_const_u8,3243 .manyptr_const_u8,
3180 .manyptr_const_u8_sentinel_0,3244 .manyptr_const_u8_sentinel_0,
3181 => return @divExact(target.cpu.arch.ptrBitWidth(), 8),3245 => return AbiSizeAdvanced{ .scalar = @divExact(target.cpu.arch.ptrBitWidth(), 8) },
31823246
3183 .const_slice,3247 .const_slice,
3184 .mut_slice,3248 .mut_slice,
3185 .const_slice_u8,3249 .const_slice_u8,
3186 .const_slice_u8_sentinel_0,3250 .const_slice_u8_sentinel_0,
3187 => return @divExact(target.cpu.arch.ptrBitWidth(), 8) * 2,3251 => return AbiSizeAdvanced{ .scalar = @divExact(target.cpu.arch.ptrBitWidth(), 8) * 2 },
31883252
3189 .pointer => switch (self.castTag(.pointer).?.data.size) {3253 .pointer => switch (ty.castTag(.pointer).?.data.size) {
3190 .Slice => @divExact(target.cpu.arch.ptrBitWidth(), 8) * 2,3254 .Slice => return AbiSizeAdvanced{ .scalar = @divExact(target.cpu.arch.ptrBitWidth(), 8) * 2 },
3191 else => @divExact(target.cpu.arch.ptrBitWidth(), 8),3255 else => return AbiSizeAdvanced{ .scalar = @divExact(target.cpu.arch.ptrBitWidth(), 8) },
3192 },3256 },
31933257
3194 .c_short => return @divExact(CType.short.sizeInBits(target), 8),3258 .c_short => return AbiSizeAdvanced{ .scalar = @divExact(CType.short.sizeInBits(target), 8) },
3195 .c_ushort => return @divExact(CType.ushort.sizeInBits(target), 8),3259 .c_ushort => return AbiSizeAdvanced{ .scalar = @divExact(CType.ushort.sizeInBits(target), 8) },
3196 .c_int => return @divExact(CType.int.sizeInBits(target), 8),3260 .c_int => return AbiSizeAdvanced{ .scalar = @divExact(CType.int.sizeInBits(target), 8) },
3197 .c_uint => return @divExact(CType.uint.sizeInBits(target), 8),3261 .c_uint => return AbiSizeAdvanced{ .scalar = @divExact(CType.uint.sizeInBits(target), 8) },
3198 .c_long => return @divExact(CType.long.sizeInBits(target), 8),3262 .c_long => return AbiSizeAdvanced{ .scalar = @divExact(CType.long.sizeInBits(target), 8) },
3199 .c_ulong => return @divExact(CType.ulong.sizeInBits(target), 8),3263 .c_ulong => return AbiSizeAdvanced{ .scalar = @divExact(CType.ulong.sizeInBits(target), 8) },
3200 .c_longlong => return @divExact(CType.longlong.sizeInBits(target), 8),3264 .c_longlong => return AbiSizeAdvanced{ .scalar = @divExact(CType.longlong.sizeInBits(target), 8) },
3201 .c_ulonglong => return @divExact(CType.ulonglong.sizeInBits(target), 8),3265 .c_ulonglong => return AbiSizeAdvanced{ .scalar = @divExact(CType.ulonglong.sizeInBits(target), 8) },
32023266
3203 .f16 => return 2,3267 .f16 => return AbiSizeAdvanced{ .scalar = 2 },
3204 .f32 => return 4,3268 .f32 => return AbiSizeAdvanced{ .scalar = 4 },
3205 .f64 => return 8,3269 .f64 => return AbiSizeAdvanced{ .scalar = 8 },
3206 .f128 => return 16,3270 .f128 => return AbiSizeAdvanced{ .scalar = 16 },
32073271
3208 .f80 => switch (target.cpu.arch) {3272 .f80 => switch (target.cpu.arch) {
3209 .i386 => return 12,3273 .i386 => return AbiSizeAdvanced{ .scalar = 12 },
3210 .x86_64 => return 16,3274 .x86_64 => return AbiSizeAdvanced{ .scalar = 16 },
3211 else => {3275 else => {
3212 var payload: Payload.Bits = .{3276 var payload: Payload.Bits = .{
3213 .base = .{ .tag = .int_unsigned },3277 .base = .{ .tag = .int_unsigned },
3214 .data = 80,3278 .data = 80,
3215 };3279 };
3216 const u80_ty = initPayload(&payload.base);3280 const u80_ty = initPayload(&payload.base);
3217 return abiSize(u80_ty, target);3281 return AbiSizeAdvanced{ .scalar = abiSize(u80_ty, target) };
3218 },3282 },
3219 },3283 },
3220 .c_longdouble => switch (CType.longdouble.sizeInBits(target)) {3284 .c_longdouble => switch (CType.longdouble.sizeInBits(target)) {
3221 16 => return abiSize(Type.f16, target),3285 16 => return AbiSizeAdvanced{ .scalar = abiSize(Type.f16, target) },
3222 32 => return abiSize(Type.f32, target),3286 32 => return AbiSizeAdvanced{ .scalar = abiSize(Type.f32, target) },
3223 64 => return abiSize(Type.f64, target),3287 64 => return AbiSizeAdvanced{ .scalar = abiSize(Type.f64, target) },
3224 80 => return abiSize(Type.f80, target),3288 80 => return AbiSizeAdvanced{ .scalar = abiSize(Type.f80, target) },
3225 128 => return abiSize(Type.f128, target),3289 128 => return AbiSizeAdvanced{ .scalar = abiSize(Type.f128, target) },
3226 else => unreachable,3290 else => unreachable,
3227 },3291 },
32283292
3293 // TODO revisit this when we have the concept of the error tag type
3229 .error_set,3294 .error_set,
3230 .error_set_single,3295 .error_set_single,
3231 .anyerror_void_error_union,3296 .anyerror_void_error_union,
3232 .anyerror,3297 .anyerror,
3233 .error_set_inferred,3298 .error_set_inferred,
3234 .error_set_merged,3299 .error_set_merged,
3235 => return 2, // TODO revisit this when we have the concept of the error tag type3300 => return AbiSizeAdvanced{ .scalar = 2 },
32363301
3237 .i16, .u16 => return intAbiSize(16, target),3302 .i16, .u16 => return AbiSizeAdvanced{ .scalar = intAbiSize(16, target) },
3238 .i32, .u32 => return intAbiSize(32, target),3303 .i32, .u32 => return AbiSizeAdvanced{ .scalar = intAbiSize(32, target) },
3239 .i64, .u64 => return intAbiSize(64, target),3304 .i64, .u64 => return AbiSizeAdvanced{ .scalar = intAbiSize(64, target) },
3240 .u128, .i128 => return intAbiSize(128, target),3305 .u128, .i128 => return AbiSizeAdvanced{ .scalar = intAbiSize(128, target) },
3241 .int_signed, .int_unsigned => {3306 .int_signed, .int_unsigned => {
3242 const bits: u16 = self.cast(Payload.Bits).?.data;3307 const bits: u16 = ty.cast(Payload.Bits).?.data;
3243 if (bits == 0) return 0;3308 if (bits == 0) return AbiSizeAdvanced{ .scalar = 0 };
3244 return intAbiSize(bits, target);3309 return AbiSizeAdvanced{ .scalar = intAbiSize(bits, target) };
3245 },3310 },
32463311
3247 .optional => {3312 .optional => {
3248 var buf: Payload.ElemType = undefined;3313 var buf: Payload.ElemType = undefined;
3249 const child_type = self.optionalChild(&buf);3314 const child_type = ty.optionalChild(&buf);
3250 if (!child_type.hasRuntimeBits()) return 1;3315 if (!child_type.hasRuntimeBits()) return AbiSizeAdvanced{ .scalar = 1 };
32513316
3252 if (child_type.zigTypeTag() == .Pointer and !child_type.isCPtr() and !child_type.isSlice())3317 if (child_type.zigTypeTag() == .Pointer and !child_type.isCPtr() and !child_type.isSlice())
3253 return @divExact(target.cpu.arch.ptrBitWidth(), 8);3318 return AbiSizeAdvanced{ .scalar = @divExact(target.cpu.arch.ptrBitWidth(), 8) };
32543319
3255 // Optional types are represented as a struct with the child type as the first3320 // Optional types are represented as a struct with the child type as the first
3256 // field and a boolean as the second. Since the child type's abi alignment is3321 // field and a boolean as the second. Since the child type's abi alignment is
3257 // guaranteed to be >= that of bool's (1 byte) the added size is exactly equal3322 // guaranteed to be >= that of bool's (1 byte) the added size is exactly equal
3258 // to the child type's ABI alignment.3323 // to the child type's ABI alignment.
3259 return child_type.abiAlignment(target) + child_type.abiSize(target);3324 return AbiSizeAdvanced{ .scalar = child_type.abiAlignment(target) + child_type.abiSize(target) };
3260 },3325 },
32613326
3262 .error_union => {3327 .error_union => {
3263 const data = self.castTag(.error_union).?.data;3328 const data = ty.castTag(.error_union).?.data;
3264 if (!data.error_set.hasRuntimeBits() and !data.payload.hasRuntimeBits()) {3329 if (!data.error_set.hasRuntimeBits() and !data.payload.hasRuntimeBits()) {
3265 return 0;3330 return AbiSizeAdvanced{ .scalar = 0 };
3266 } else if (!data.error_set.hasRuntimeBits()) {3331 } else if (!data.error_set.hasRuntimeBits()) {
3267 return data.payload.abiSize(target);3332 return AbiSizeAdvanced{ .scalar = data.payload.abiSize(target) };
3268 } else if (!data.payload.hasRuntimeBits()) {3333 } else if (!data.payload.hasRuntimeBits()) {
3269 return data.error_set.abiSize(target);3334 return AbiSizeAdvanced{ .scalar = data.error_set.abiSize(target) };
3270 }3335 }
3271 const code_align = abiAlignment(data.error_set, target);3336 const code_align = abiAlignment(data.error_set, target);
3272 const payload_align = abiAlignment(data.payload, target);3337 const payload_align = abiAlignment(data.payload, target);
...@@ -3278,9 +3343,28 @@ pub const Type = extern union {...@@ -3278,9 +3343,28 @@ pub const Type = extern union {
3278 size = std.mem.alignForwardGeneric(u64, size, payload_align);3343 size = std.mem.alignForwardGeneric(u64, size, payload_align);
3279 size += payload_size;3344 size += payload_size;
3280 size = std.mem.alignForwardGeneric(u64, size, big_align);3345 size = std.mem.alignForwardGeneric(u64, size, big_align);
3281 return size;3346 return AbiSizeAdvanced{ .scalar = size };
3282 },3347 },
3283 };3348 }
3349 }
3350
3351 pub fn abiSizeAdvancedUnion(
3352 ty: Type,
3353 target: Target,
3354 strat: AbiAlignmentAdvancedStrat,
3355 union_obj: *Module.Union,
3356 have_tag: bool,
3357 ) Module.CompileError!AbiSizeAdvanced {
3358 switch (strat) {
3359 .sema_kit => |sk| try sk.sema.resolveTypeLayout(sk.block, sk.src, ty),
3360 .lazy => |arena| {
3361 if (!union_obj.haveLayout()) {
3362 return AbiSizeAdvanced{ .val = try Value.Tag.lazy_size.create(arena, ty) };
3363 }
3364 },
3365 .eager => {},
3366 }
3367 return AbiSizeAdvanced{ .scalar = union_obj.abiSize(target, have_tag) };
3284 }3368 }
32853369
3286 fn intAbiSize(bits: u16, target: Target) u64 {3370 fn intAbiSize(bits: u16, target: Target) u64 {
...@@ -5448,73 +5532,6 @@ pub const Type = extern union {...@@ -5448,73 +5532,6 @@ pub const Type = extern union {
5448 }5532 }
5449 }5533 }
54505534
5451 /// Asserts the type is an enum.
5452 pub fn enumHasInt(ty: Type, int: Value, mod: *Module) bool {
5453 const S = struct {
5454 fn intInRange(tag_ty: Type, int_val: Value, end: usize, m: *Module) bool {
5455 if (int_val.compareWithZero(.lt)) return false;
5456 var end_payload: Value.Payload.U64 = .{
5457 .base = .{ .tag = .int_u64 },
5458 .data = end,
5459 };
5460 const end_val = Value.initPayload(&end_payload.base);
5461 if (int_val.compare(.gte, end_val, tag_ty, m)) return false;
5462 return true;
5463 }
5464 };
5465 switch (ty.tag()) {
5466 .enum_nonexhaustive => return int.intFitsInType(ty, mod.getTarget()),
5467 .enum_full => {
5468 const enum_full = ty.castTag(.enum_full).?.data;
5469 const tag_ty = enum_full.tag_ty;
5470 if (enum_full.values.count() == 0) {
5471 return S.intInRange(tag_ty, int, enum_full.fields.count(), mod);
5472 } else {
5473 return enum_full.values.containsContext(int, .{
5474 .ty = tag_ty,
5475 .mod = mod,
5476 });
5477 }
5478 },
5479 .enum_numbered => {
5480 const enum_obj = ty.castTag(.enum_numbered).?.data;
5481 const tag_ty = enum_obj.tag_ty;
5482 if (enum_obj.values.count() == 0) {
5483 return S.intInRange(tag_ty, int, enum_obj.fields.count(), mod);
5484 } else {
5485 return enum_obj.values.containsContext(int, .{
5486 .ty = tag_ty,
5487 .mod = mod,
5488 });
5489 }
5490 },
5491 .enum_simple => {
5492 const enum_simple = ty.castTag(.enum_simple).?.data;
5493 const fields_len = enum_simple.fields.count();
5494 const bits = std.math.log2_int_ceil(usize, fields_len);
5495 var buffer: Payload.Bits = .{
5496 .base = .{ .tag = .int_unsigned },
5497 .data = bits,
5498 };
5499 const tag_ty = Type.initPayload(&buffer.base);
5500 return S.intInRange(tag_ty, int, fields_len, mod);
5501 },
5502 .atomic_order,
5503 .atomic_rmw_op,
5504 .calling_convention,
5505 .address_space,
5506 .float_mode,
5507 .reduce_op,
5508 .call_options,
5509 .prefetch_options,
5510 .export_options,
5511 .extern_options,
5512 => unreachable,
5513
5514 else => unreachable,
5515 }
5516 }
5517
5518 /// This enum does not directly correspond to `std.builtin.TypeId` because5535 /// This enum does not directly correspond to `std.builtin.TypeId` because
5519 /// it has extra enum tags in it, as a way of using less memory. For example,5536 /// it has extra enum tags in it, as a way of using less memory. For example,
5520 /// even though Zig recognizes `*align(10) i32` and `*i32` both as Pointer types5537 /// even though Zig recognizes `*align(10) i32` and `*i32` both as Pointer types
src/value.zig+84-540
...@@ -179,6 +179,8 @@ pub const Value = extern union {...@@ -179,6 +179,8 @@ pub const Value = extern union {
179 bound_fn,179 bound_fn,
180 /// The ABI alignment of the payload type.180 /// The ABI alignment of the payload type.
181 lazy_align,181 lazy_align,
182 /// The ABI alignment of the payload type.
183 lazy_size,
182184
183 pub const last_no_payload_tag = Tag.empty_array;185 pub const last_no_payload_tag = Tag.empty_array;
184 pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;186 pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;
...@@ -289,6 +291,7 @@ pub const Value = extern union {...@@ -289,6 +291,7 @@ pub const Value = extern union {
289291
290 .ty,292 .ty,
291 .lazy_align,293 .lazy_align,
294 .lazy_size,
292 => Payload.Ty,295 => Payload.Ty,
293296
294 .int_type => Payload.IntType,297 .int_type => Payload.IntType,
...@@ -460,7 +463,7 @@ pub const Value = extern union {...@@ -460,7 +463,7 @@ pub const Value = extern union {
460 .bound_fn,463 .bound_fn,
461 => unreachable,464 => unreachable,
462465
463 .ty, .lazy_align => {466 .ty, .lazy_align, .lazy_size => {
464 const payload = self.cast(Payload.Ty).?;467 const payload = self.cast(Payload.Ty).?;
465 const new_payload = try arena.create(Payload.Ty);468 const new_payload = try arena.create(Payload.Ty);
466 new_payload.* = .{469 new_payload.* = .{
...@@ -720,6 +723,11 @@ pub const Value = extern union {...@@ -720,6 +723,11 @@ pub const Value = extern union {
720 try val.castTag(.lazy_align).?.data.dump("", options, out_stream);723 try val.castTag(.lazy_align).?.data.dump("", options, out_stream);
721 return try out_stream.writeAll(")");724 return try out_stream.writeAll(")");
722 },725 },
726 .lazy_size => {
727 try out_stream.writeAll("@sizeOf(");
728 try val.castTag(.lazy_size).?.data.dump("", options, out_stream);
729 return try out_stream.writeAll(")");
730 },
723 .int_type => {731 .int_type => {
724 const int_type = val.castTag(.int_type).?.data;732 const int_type = val.castTag(.int_type).?.data;
725 return out_stream.print("{s}{d}", .{733 return out_stream.print("{s}{d}", .{
...@@ -1040,6 +1048,14 @@ pub const Value = extern union {...@@ -1040,6 +1048,14 @@ pub const Value = extern union {
1040 const x = ty.abiAlignment(target);1048 const x = ty.abiAlignment(target);
1041 return BigIntMutable.init(&space.limbs, x).toConst();1049 return BigIntMutable.init(&space.limbs, x).toConst();
1042 },1050 },
1051 .lazy_size => {
1052 const ty = val.castTag(.lazy_size).?.data;
1053 if (sema_kit) |sk| {
1054 try sk.sema.resolveTypeLayout(sk.block, sk.src, ty);
1055 }
1056 const x = ty.abiSize(target);
1057 return BigIntMutable.init(&space.limbs, x).toConst();
1058 },
10431059
1044 .elem_ptr => {1060 .elem_ptr => {
1045 const elem_ptr = val.castTag(.elem_ptr).?.data;1061 const elem_ptr = val.castTag(.elem_ptr).?.data;
...@@ -1087,6 +1103,14 @@ pub const Value = extern union {...@@ -1087,6 +1103,14 @@ pub const Value = extern union {
1087 return ty.abiAlignment(target);1103 return ty.abiAlignment(target);
1088 }1104 }
1089 },1105 },
1106 .lazy_size => {
1107 const ty = val.castTag(.lazy_size).?.data;
1108 if (sema_kit) |sk| {
1109 return (try ty.abiSizeAdvanced(target, .{ .sema_kit = sk })).scalar;
1110 } else {
1111 return ty.abiSize(target);
1112 }
1113 },
10901114
1091 else => return null,1115 else => return null,
1092 }1116 }
...@@ -1670,118 +1694,6 @@ pub const Value = extern union {...@@ -1670,118 +1694,6 @@ pub const Value = extern union {
1670 }1694 }
1671 }1695 }
16721696
1673 /// Asserts the value is an integer, and the destination type is ComptimeInt or Int.
1674 /// Vectors are also accepted. Vector results are reduced with AND.
1675 pub fn intFitsInType(self: Value, ty: Type, target: Target) bool {
1676 switch (self.tag()) {
1677 .zero,
1678 .undef,
1679 .bool_false,
1680 => return true,
1681
1682 .one,
1683 .bool_true,
1684 => switch (ty.zigTypeTag()) {
1685 .Int => {
1686 const info = ty.intInfo(target);
1687 return switch (info.signedness) {
1688 .signed => info.bits >= 2,
1689 .unsigned => info.bits >= 1,
1690 };
1691 },
1692 .ComptimeInt => return true,
1693 else => unreachable,
1694 },
1695
1696 .lazy_align => {
1697 const info = ty.intInfo(target);
1698 const max_needed_bits = @as(u16, 16) + @boolToInt(info.signedness == .signed);
1699 // If it is u16 or bigger we know the alignment fits without resolving it.
1700 if (info.bits >= max_needed_bits) return true;
1701 const x = self.castTag(.lazy_align).?.data.abiAlignment(target);
1702 if (x == 0) return true;
1703 const actual_needed_bits = std.math.log2(x) + 1 + @boolToInt(info.signedness == .signed);
1704 return info.bits >= actual_needed_bits;
1705 },
1706
1707 .int_u64 => switch (ty.zigTypeTag()) {
1708 .Int => {
1709 const x = self.castTag(.int_u64).?.data;
1710 if (x == 0) return true;
1711 const info = ty.intInfo(target);
1712 const needed_bits = std.math.log2(x) + 1 + @boolToInt(info.signedness == .signed);
1713 return info.bits >= needed_bits;
1714 },
1715 .ComptimeInt => return true,
1716 else => unreachable,
1717 },
1718 .int_i64 => switch (ty.zigTypeTag()) {
1719 .Int => {
1720 const x = self.castTag(.int_i64).?.data;
1721 if (x == 0) return true;
1722 const info = ty.intInfo(target);
1723 if (info.signedness == .unsigned and x < 0)
1724 return false;
1725 var buffer: BigIntSpace = undefined;
1726 return self.toBigInt(&buffer, target).fitsInTwosComp(info.signedness, info.bits);
1727 },
1728 .ComptimeInt => return true,
1729 else => unreachable,
1730 },
1731 .int_big_positive => switch (ty.zigTypeTag()) {
1732 .Int => {
1733 const info = ty.intInfo(target);
1734 return self.castTag(.int_big_positive).?.asBigInt().fitsInTwosComp(info.signedness, info.bits);
1735 },
1736 .ComptimeInt => return true,
1737 else => unreachable,
1738 },
1739 .int_big_negative => switch (ty.zigTypeTag()) {
1740 .Int => {
1741 const info = ty.intInfo(target);
1742 return self.castTag(.int_big_negative).?.asBigInt().fitsInTwosComp(info.signedness, info.bits);
1743 },
1744 .ComptimeInt => return true,
1745 else => unreachable,
1746 },
1747
1748 .the_only_possible_value => {
1749 assert(ty.intInfo(target).bits == 0);
1750 return true;
1751 },
1752
1753 .decl_ref_mut,
1754 .extern_fn,
1755 .decl_ref,
1756 .function,
1757 .variable,
1758 => switch (ty.zigTypeTag()) {
1759 .Int => {
1760 const info = ty.intInfo(target);
1761 const ptr_bits = target.cpu.arch.ptrBitWidth();
1762 return switch (info.signedness) {
1763 .signed => info.bits > ptr_bits,
1764 .unsigned => info.bits >= ptr_bits,
1765 };
1766 },
1767 .ComptimeInt => return true,
1768 else => unreachable,
1769 },
1770
1771 .aggregate => {
1772 assert(ty.zigTypeTag() == .Vector);
1773 for (self.castTag(.aggregate).?.data) |elem| {
1774 if (!elem.intFitsInType(ty.scalarType(), target)) {
1775 return false;
1776 }
1777 }
1778 return true;
1779 },
1780
1781 else => unreachable,
1782 }
1783 }
1784
1785 /// Converts an integer or a float to a float. May result in a loss of information.1697 /// Converts an integer or a float to a float. May result in a loss of information.
1786 /// Caller can find out by equality checking the result against the operand.1698 /// Caller can find out by equality checking the result against the operand.
1787 pub fn floatCast(self: Value, arena: Allocator, dest_ty: Type, target: Target) !Value {1699 pub fn floatCast(self: Value, arena: Allocator, dest_ty: Type, target: Target) !Value {
...@@ -1849,6 +1761,14 @@ pub const Value = extern union {...@@ -1849,6 +1761,14 @@ pub const Value = extern union {
1849 return .eq;1761 return .eq;
1850 }1762 }
1851 },1763 },
1764 .lazy_size => {
1765 const ty = lhs.castTag(.lazy_size).?.data;
1766 if (try ty.hasRuntimeBitsAdvanced(false, sema_kit)) {
1767 return .gt;
1768 } else {
1769 return .eq;
1770 }
1771 },
18521772
1853 .float_16 => std.math.order(lhs.castTag(.float_16).?.data, 0),1773 .float_16 => std.math.order(lhs.castTag(.float_16).?.data, 0),
1854 .float_32 => std.math.order(lhs.castTag(.float_32).?.data, 0),1774 .float_32 => std.math.order(lhs.castTag(.float_32).?.data, 0),
...@@ -1992,38 +1912,28 @@ pub const Value = extern union {...@@ -1992,38 +1912,28 @@ pub const Value = extern union {
1992 };1912 };
1993 }1913 }
19941914
1995 /// Asserts the values are comparable vectors of type `ty`.
1996 pub fn compareVector(
1997 lhs: Value,
1998 op: std.math.CompareOperator,
1999 rhs: Value,
2000 ty: Type,
2001 allocator: Allocator,
2002 mod: *Module,
2003 ) !Value {
2004 assert(ty.zigTypeTag() == .Vector);
2005 const result_data = try allocator.alloc(Value, ty.vectorLen());
2006 for (result_data) |*scalar, i| {
2007 const res_bool = compareScalar(lhs.indexVectorlike(i), op, rhs.indexVectorlike(i), ty.scalarType(), mod);
2008 scalar.* = makeBool(res_bool);
2009 }
2010 return Value.Tag.aggregate.create(allocator, result_data);
2011 }
2012
2013 /// Asserts the value is comparable.1915 /// Asserts the value is comparable.
2014 /// Vector results will be reduced with AND.1916 /// Vector results will be reduced with AND.
2015 pub fn compareWithZero(lhs: Value, op: std.math.CompareOperator) bool {1917 pub fn compareWithZero(lhs: Value, op: std.math.CompareOperator) bool {
1918 return compareWithZeroAdvanced(lhs, op, null) catch unreachable;
1919 }
1920
1921 pub fn compareWithZeroAdvanced(
1922 lhs: Value,
1923 op: std.math.CompareOperator,
1924 sema_kit: ?Module.WipAnalysis,
1925 ) Module.CompileError!bool {
2016 switch (lhs.tag()) {1926 switch (lhs.tag()) {
2017 .repeated => return lhs.castTag(.repeated).?.data.compareWithZero(op),1927 .repeated => return lhs.castTag(.repeated).?.data.compareWithZeroAdvanced(op, sema_kit),
2018 .aggregate => {1928 .aggregate => {
2019 for (lhs.castTag(.aggregate).?.data) |elem_val| {1929 for (lhs.castTag(.aggregate).?.data) |elem_val| {
2020 if (!elem_val.compareWithZero(op)) return false;1930 if (!(try elem_val.compareWithZeroAdvanced(op, sema_kit))) return false;
2021 }1931 }
2022 return true;1932 return true;
2023 },1933 },
2024 else => {},1934 else => {},
2025 }1935 }
2026 return orderAgainstZero(lhs).compare(op);1936 return (try orderAgainstZeroAdvanced(lhs, sema_kit)).compare(op);
2027 }1937 }
20281938
2029 /// This function is used by hash maps and so treats floating-point NaNs as equal1939 /// This function is used by hash maps and so treats floating-point NaNs as equal
...@@ -2032,9 +1942,20 @@ pub const Value = extern union {...@@ -2032,9 +1942,20 @@ pub const Value = extern union {
2032 /// This function has to be able to support implicit coercion of `a` to `ty`. That is,1942 /// This function has to be able to support implicit coercion of `a` to `ty`. That is,
2033 /// `ty` will be an exactly correct Type for `b` but it may be a post-coerced Type1943 /// `ty` will be an exactly correct Type for `b` but it may be a post-coerced Type
2034 /// for `a`. This function must act *as if* `a` has been coerced to `ty`. This complication1944 /// for `a`. This function must act *as if* `a` has been coerced to `ty`. This complication
2035 /// is required in order to make generic function instantiation effecient - specifically1945 /// is required in order to make generic function instantiation efficient - specifically
2036 /// the insertion into the monomorphized function table.1946 /// the insertion into the monomorphized function table.
2037 pub fn eql(a: Value, b: Value, ty: Type, mod: *Module) bool {1947 pub fn eql(a: Value, b: Value, ty: Type, mod: *Module) bool {
1948 return eqlAdvanced(a, b, ty, mod, null) catch unreachable;
1949 }
1950
1951 /// If `null` is provided for `sema_kit` then it is guaranteed no error will be returned.
1952 pub fn eqlAdvanced(
1953 a: Value,
1954 b: Value,
1955 ty: Type,
1956 mod: *Module,
1957 sema_kit: ?Module.WipAnalysis,
1958 ) Module.CompileError!bool {
2038 const target = mod.getTarget();1959 const target = mod.getTarget();
2039 const a_tag = a.tag();1960 const a_tag = a.tag();
2040 const b_tag = b.tag();1961 const b_tag = b.tag();
...@@ -2055,31 +1976,33 @@ pub const Value = extern union {...@@ -2055,31 +1976,33 @@ pub const Value = extern union {
2055 const a_payload = a.castTag(.opt_payload).?.data;1976 const a_payload = a.castTag(.opt_payload).?.data;
2056 const b_payload = b.castTag(.opt_payload).?.data;1977 const b_payload = b.castTag(.opt_payload).?.data;
2057 var buffer: Type.Payload.ElemType = undefined;1978 var buffer: Type.Payload.ElemType = undefined;
2058 return eql(a_payload, b_payload, ty.optionalChild(&buffer), mod);1979 return eqlAdvanced(a_payload, b_payload, ty.optionalChild(&buffer), mod, sema_kit);
2059 },1980 },
2060 .slice => {1981 .slice => {
2061 const a_payload = a.castTag(.slice).?.data;1982 const a_payload = a.castTag(.slice).?.data;
2062 const b_payload = b.castTag(.slice).?.data;1983 const b_payload = b.castTag(.slice).?.data;
2063 if (!eql(a_payload.len, b_payload.len, Type.usize, mod)) return false;1984 if (!(try eqlAdvanced(a_payload.len, b_payload.len, Type.usize, mod, sema_kit))) {
1985 return false;
1986 }
20641987
2065 var ptr_buf: Type.SlicePtrFieldTypeBuffer = undefined;1988 var ptr_buf: Type.SlicePtrFieldTypeBuffer = undefined;
2066 const ptr_ty = ty.slicePtrFieldType(&ptr_buf);1989 const ptr_ty = ty.slicePtrFieldType(&ptr_buf);
20671990
2068 return eql(a_payload.ptr, b_payload.ptr, ptr_ty, mod);1991 return eqlAdvanced(a_payload.ptr, b_payload.ptr, ptr_ty, mod, sema_kit);
2069 },1992 },
2070 .elem_ptr => {1993 .elem_ptr => {
2071 const a_payload = a.castTag(.elem_ptr).?.data;1994 const a_payload = a.castTag(.elem_ptr).?.data;
2072 const b_payload = b.castTag(.elem_ptr).?.data;1995 const b_payload = b.castTag(.elem_ptr).?.data;
2073 if (a_payload.index != b_payload.index) return false;1996 if (a_payload.index != b_payload.index) return false;
20741997
2075 return eql(a_payload.array_ptr, b_payload.array_ptr, ty, mod);1998 return eqlAdvanced(a_payload.array_ptr, b_payload.array_ptr, ty, mod, sema_kit);
2076 },1999 },
2077 .field_ptr => {2000 .field_ptr => {
2078 const a_payload = a.castTag(.field_ptr).?.data;2001 const a_payload = a.castTag(.field_ptr).?.data;
2079 const b_payload = b.castTag(.field_ptr).?.data;2002 const b_payload = b.castTag(.field_ptr).?.data;
2080 if (a_payload.field_index != b_payload.field_index) return false;2003 if (a_payload.field_index != b_payload.field_index) return false;
20812004
2082 return eql(a_payload.container_ptr, b_payload.container_ptr, ty, mod);2005 return eqlAdvanced(a_payload.container_ptr, b_payload.container_ptr, ty, mod, sema_kit);
2083 },2006 },
2084 .@"error" => {2007 .@"error" => {
2085 const a_name = a.castTag(.@"error").?.data.name;2008 const a_name = a.castTag(.@"error").?.data.name;
...@@ -2089,7 +2012,7 @@ pub const Value = extern union {...@@ -2089,7 +2012,7 @@ pub const Value = extern union {
2089 .eu_payload => {2012 .eu_payload => {
2090 const a_payload = a.castTag(.eu_payload).?.data;2013 const a_payload = a.castTag(.eu_payload).?.data;
2091 const b_payload = b.castTag(.eu_payload).?.data;2014 const b_payload = b.castTag(.eu_payload).?.data;
2092 return eql(a_payload, b_payload, ty.errorUnionPayload(), mod);2015 return eqlAdvanced(a_payload, b_payload, ty.errorUnionPayload(), mod, sema_kit);
2093 },2016 },
2094 .eu_payload_ptr => @panic("TODO: Implement more pointer eql cases"),2017 .eu_payload_ptr => @panic("TODO: Implement more pointer eql cases"),
2095 .opt_payload_ptr => @panic("TODO: Implement more pointer eql cases"),2018 .opt_payload_ptr => @panic("TODO: Implement more pointer eql cases"),
...@@ -2107,7 +2030,9 @@ pub const Value = extern union {...@@ -2107,7 +2030,9 @@ pub const Value = extern union {
2107 const types = ty.tupleFields().types;2030 const types = ty.tupleFields().types;
2108 assert(types.len == a_field_vals.len);2031 assert(types.len == a_field_vals.len);
2109 for (types) |field_ty, i| {2032 for (types) |field_ty, i| {
2110 if (!eql(a_field_vals[i], b_field_vals[i], field_ty, mod)) return false;2033 if (!(try eqlAdvanced(a_field_vals[i], b_field_vals[i], field_ty, mod, sema_kit))) {
2034 return false;
2035 }
2111 }2036 }
2112 return true;2037 return true;
2113 }2038 }
...@@ -2116,7 +2041,9 @@ pub const Value = extern union {...@@ -2116,7 +2041,9 @@ pub const Value = extern union {
2116 const fields = ty.structFields().values();2041 const fields = ty.structFields().values();
2117 assert(fields.len == a_field_vals.len);2042 assert(fields.len == a_field_vals.len);
2118 for (fields) |field, i| {2043 for (fields) |field, i| {
2119 if (!eql(a_field_vals[i], b_field_vals[i], field.ty, mod)) return false;2044 if (!(try eqlAdvanced(a_field_vals[i], b_field_vals[i], field.ty, mod, sema_kit))) {
2045 return false;
2046 }
2120 }2047 }
2121 return true;2048 return true;
2122 }2049 }
...@@ -2125,7 +2052,9 @@ pub const Value = extern union {...@@ -2125,7 +2052,9 @@ pub const Value = extern union {
2125 for (a_field_vals) |a_elem, i| {2052 for (a_field_vals) |a_elem, i| {
2126 const b_elem = b_field_vals[i];2053 const b_elem = b_field_vals[i];
21272054
2128 if (!eql(a_elem, b_elem, elem_ty, mod)) return false;2055 if (!(try eqlAdvanced(a_elem, b_elem, elem_ty, mod, sema_kit))) {
2056 return false;
2057 }
2129 }2058 }
2130 return true;2059 return true;
2131 },2060 },
...@@ -2135,7 +2064,7 @@ pub const Value = extern union {...@@ -2135,7 +2064,7 @@ pub const Value = extern union {
2135 switch (ty.containerLayout()) {2064 switch (ty.containerLayout()) {
2136 .Packed, .Extern => {2065 .Packed, .Extern => {
2137 const tag_ty = ty.unionTagTypeHypothetical();2066 const tag_ty = ty.unionTagTypeHypothetical();
2138 if (!a_union.tag.eql(b_union.tag, tag_ty, mod)) {2067 if (!(try a_union.tag.eqlAdvanced(b_union.tag, tag_ty, mod, sema_kit))) {
2139 // In this case, we must disregard mismatching tags and compare2068 // In this case, we must disregard mismatching tags and compare
2140 // based on the in-memory bytes of the payloads.2069 // based on the in-memory bytes of the payloads.
2141 @panic("TODO comptime comparison of extern union values with mismatching tags");2070 @panic("TODO comptime comparison of extern union values with mismatching tags");
...@@ -2143,13 +2072,13 @@ pub const Value = extern union {...@@ -2143,13 +2072,13 @@ pub const Value = extern union {
2143 },2072 },
2144 .Auto => {2073 .Auto => {
2145 const tag_ty = ty.unionTagTypeHypothetical();2074 const tag_ty = ty.unionTagTypeHypothetical();
2146 if (!a_union.tag.eql(b_union.tag, tag_ty, mod)) {2075 if (!(try a_union.tag.eqlAdvanced(b_union.tag, tag_ty, mod, sema_kit))) {
2147 return false;2076 return false;
2148 }2077 }
2149 },2078 },
2150 }2079 }
2151 const active_field_ty = ty.unionFieldType(a_union.tag, mod);2080 const active_field_ty = ty.unionFieldType(a_union.tag, mod);
2152 return a_union.val.eql(b_union.val, active_field_ty, mod);2081 return a_union.val.eqlAdvanced(b_union.val, active_field_ty, mod, sema_kit);
2153 },2082 },
2154 else => {},2083 else => {},
2155 } else if (a_tag == .null_value or b_tag == .null_value) {2084 } else if (a_tag == .null_value or b_tag == .null_value) {
...@@ -2183,7 +2112,7 @@ pub const Value = extern union {...@@ -2183,7 +2112,7 @@ pub const Value = extern union {
2183 const b_val = b.enumToInt(ty, &buf_b);2112 const b_val = b.enumToInt(ty, &buf_b);
2184 var buf_ty: Type.Payload.Bits = undefined;2113 var buf_ty: Type.Payload.Bits = undefined;
2185 const int_ty = ty.intTagType(&buf_ty);2114 const int_ty = ty.intTagType(&buf_ty);
2186 return eql(a_val, b_val, int_ty, mod);2115 return eqlAdvanced(a_val, b_val, int_ty, mod, sema_kit);
2187 },2116 },
2188 .Array, .Vector => {2117 .Array, .Vector => {
2189 const len = ty.arrayLen();2118 const len = ty.arrayLen();
...@@ -2194,7 +2123,9 @@ pub const Value = extern union {...@@ -2194,7 +2123,9 @@ pub const Value = extern union {
2194 while (i < len) : (i += 1) {2123 while (i < len) : (i += 1) {
2195 const a_elem = elemValueBuffer(a, mod, i, &a_buf);2124 const a_elem = elemValueBuffer(a, mod, i, &a_buf);
2196 const b_elem = elemValueBuffer(b, mod, i, &b_buf);2125 const b_elem = elemValueBuffer(b, mod, i, &b_buf);
2197 if (!eql(a_elem, b_elem, elem_ty, mod)) return false;2126 if (!(try eqlAdvanced(a_elem, b_elem, elem_ty, mod, sema_kit))) {
2127 return false;
2128 }
2198 }2129 }
2199 return true;2130 return true;
2200 },2131 },
...@@ -2218,12 +2149,12 @@ pub const Value = extern union {...@@ -2218,12 +2149,12 @@ pub const Value = extern union {
2218 .base = .{ .tag = .opt_payload },2149 .base = .{ .tag = .opt_payload },
2219 .data = a,2150 .data = a,
2220 };2151 };
2221 return eql(Value.initPayload(&buffer.base), b, ty, mod);2152 return eqlAdvanced(Value.initPayload(&buffer.base), b, ty, mod, sema_kit);
2222 }2153 }
2223 },2154 },
2224 else => {},2155 else => {},
2225 }2156 }
2226 return order(a, b, target).compare(.eq);2157 return (try orderAdvanced(a, b, target, sema_kit)).compare(.eq);
2227 }2158 }
22282159
2229 /// This function is used by hash maps and so treats floating-point NaNs as equal2160 /// This function is used by hash maps and so treats floating-point NaNs as equal
...@@ -2502,6 +2433,7 @@ pub const Value = extern union {...@@ -2502,6 +2433,7 @@ pub const Value = extern union {
2502 .bool_true,2433 .bool_true,
2503 .the_only_possible_value,2434 .the_only_possible_value,
2504 .lazy_align,2435 .lazy_align,
2436 .lazy_size,
2505 => return hashInt(ptr_val, hasher, target),2437 => return hashInt(ptr_val, hasher, target),
25062438
2507 else => unreachable,2439 else => unreachable,
...@@ -2882,54 +2814,6 @@ pub const Value = extern union {...@@ -2882,54 +2814,6 @@ pub const Value = extern union {
2882 }2814 }
2883 }2815 }
28842816
2885 pub fn floatToInt(val: Value, arena: Allocator, float_ty: Type, int_ty: Type, target: Target) error{ FloatCannotFit, OutOfMemory }!Value {
2886 if (float_ty.zigTypeTag() == .Vector) {
2887 const result_data = try arena.alloc(Value, float_ty.vectorLen());
2888 for (result_data) |*scalar, i| {
2889 scalar.* = try floatToIntScalar(val.indexVectorlike(i), arena, int_ty.scalarType(), target);
2890 }
2891 return Value.Tag.aggregate.create(arena, result_data);
2892 }
2893 return floatToIntScalar(val, arena, int_ty, target);
2894 }
2895
2896 pub fn floatToIntScalar(val: Value, arena: Allocator, int_ty: Type, target: Target) error{ FloatCannotFit, OutOfMemory }!Value {
2897 const Limb = std.math.big.Limb;
2898
2899 var value = val.toFloat(f64); // TODO: f128 ?
2900 if (std.math.isNan(value) or std.math.isInf(value)) {
2901 return error.FloatCannotFit;
2902 }
2903
2904 const isNegative = std.math.signbit(value);
2905 value = @fabs(value);
2906
2907 const floored = @floor(value);
2908
2909 var rational = try std.math.big.Rational.init(arena);
2910 defer rational.deinit();
2911 rational.setFloat(f64, floored) catch |err| switch (err) {
2912 error.NonFiniteFloat => unreachable,
2913 error.OutOfMemory => return error.OutOfMemory,
2914 };
2915
2916 // The float is reduced in rational.setFloat, so we assert that denominator is equal to one
2917 const bigOne = std.math.big.int.Const{ .limbs = &.{1}, .positive = true };
2918 assert(rational.q.toConst().eqAbs(bigOne));
2919
2920 const result_limbs = try arena.dupe(Limb, rational.p.toConst().limbs);
2921 const result = if (isNegative)
2922 try Value.Tag.int_big_negative.create(arena, result_limbs)
2923 else
2924 try Value.Tag.int_big_positive.create(arena, result_limbs);
2925
2926 if (result.intFitsInType(int_ty, target)) {
2927 return result;
2928 } else {
2929 return error.FloatCannotFit;
2930 }
2931 }
2932
2933 fn calcLimbLenFloat(scalar: anytype) usize {2817 fn calcLimbLenFloat(scalar: anytype) usize {
2934 if (scalar == 0) {2818 if (scalar == 0) {
2935 return 1;2819 return 1;
...@@ -2945,96 +2829,7 @@ pub const Value = extern union {...@@ -2945,96 +2829,7 @@ pub const Value = extern union {
2945 wrapped_result: Value,2829 wrapped_result: Value,
2946 };2830 };
29472831
2948 pub fn intAddWithOverflow(2832 pub fn fromBigInt(arena: Allocator, big_int: BigIntConst) !Value {
2949 lhs: Value,
2950 rhs: Value,
2951 ty: Type,
2952 arena: Allocator,
2953 target: Target,
2954 ) !OverflowArithmeticResult {
2955 if (ty.zigTypeTag() == .Vector) {
2956 const overflowed_data = try arena.alloc(Value, ty.vectorLen());
2957 const result_data = try arena.alloc(Value, ty.vectorLen());
2958 for (result_data) |*scalar, i| {
2959 const of_math_result = try intAddWithOverflowScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), ty.scalarType(), arena, target);
2960 overflowed_data[i] = of_math_result.overflowed;
2961 scalar.* = of_math_result.wrapped_result;
2962 }
2963 return OverflowArithmeticResult{
2964 .overflowed = try Value.Tag.aggregate.create(arena, overflowed_data),
2965 .wrapped_result = try Value.Tag.aggregate.create(arena, result_data),
2966 };
2967 }
2968 return intAddWithOverflowScalar(lhs, rhs, ty, arena, target);
2969 }
2970
2971 pub fn intAddWithOverflowScalar(
2972 lhs: Value,
2973 rhs: Value,
2974 ty: Type,
2975 arena: Allocator,
2976 target: Target,
2977 ) !OverflowArithmeticResult {
2978 const info = ty.intInfo(target);
2979
2980 var lhs_space: Value.BigIntSpace = undefined;
2981 var rhs_space: Value.BigIntSpace = undefined;
2982 const lhs_bigint = lhs.toBigInt(&lhs_space, target);
2983 const rhs_bigint = rhs.toBigInt(&rhs_space, target);
2984 const limbs = try arena.alloc(
2985 std.math.big.Limb,
2986 std.math.big.int.calcTwosCompLimbCount(info.bits),
2987 );
2988 var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined };
2989 const overflowed = result_bigint.addWrap(lhs_bigint, rhs_bigint, info.signedness, info.bits);
2990 const result = try fromBigInt(arena, result_bigint.toConst());
2991 return OverflowArithmeticResult{
2992 .overflowed = makeBool(overflowed),
2993 .wrapped_result = result,
2994 };
2995 }
2996
2997 /// Supports both (vectors of) floats and ints; handles undefined scalars.
2998 pub fn numberAddWrap(
2999 lhs: Value,
3000 rhs: Value,
3001 ty: Type,
3002 arena: Allocator,
3003 target: Target,
3004 ) !Value {
3005 if (ty.zigTypeTag() == .Vector) {
3006 const result_data = try arena.alloc(Value, ty.vectorLen());
3007 for (result_data) |*scalar, i| {
3008 scalar.* = try numberAddWrapScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), ty.scalarType(), arena, target);
3009 }
3010 return Value.Tag.aggregate.create(arena, result_data);
3011 }
3012 return numberAddWrapScalar(lhs, rhs, ty, arena, target);
3013 }
3014
3015 /// Supports both floats and ints; handles undefined.
3016 pub fn numberAddWrapScalar(
3017 lhs: Value,
3018 rhs: Value,
3019 ty: Type,
3020 arena: Allocator,
3021 target: Target,
3022 ) !Value {
3023 if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef);
3024
3025 if (ty.zigTypeTag() == .ComptimeInt) {
3026 return intAdd(lhs, rhs, ty, arena, target);
3027 }
3028
3029 if (ty.isAnyFloat()) {
3030 return floatAdd(lhs, rhs, ty, arena, target);
3031 }
3032
3033 const overflow_result = try intAddWithOverflow(lhs, rhs, ty, arena, target);
3034 return overflow_result.wrapped_result;
3035 }
3036
3037 fn fromBigInt(arena: Allocator, big_int: BigIntConst) !Value {
3038 if (big_int.positive) {2833 if (big_int.positive) {
3039 if (big_int.to(u64)) |x| {2834 if (big_int.to(u64)) |x| {
3040 return Value.Tag.int_u64.create(arena, x);2835 return Value.Tag.int_u64.create(arena, x);
...@@ -3094,95 +2889,6 @@ pub const Value = extern union {...@@ -3094,95 +2889,6 @@ pub const Value = extern union {
3094 return fromBigInt(arena, result_bigint.toConst());2889 return fromBigInt(arena, result_bigint.toConst());
3095 }2890 }
30962891
3097 pub fn intSubWithOverflow(
3098 lhs: Value,
3099 rhs: Value,
3100 ty: Type,
3101 arena: Allocator,
3102 target: Target,
3103 ) !OverflowArithmeticResult {
3104 if (ty.zigTypeTag() == .Vector) {
3105 const overflowed_data = try arena.alloc(Value, ty.vectorLen());
3106 const result_data = try arena.alloc(Value, ty.vectorLen());
3107 for (result_data) |*scalar, i| {
3108 const of_math_result = try intSubWithOverflowScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), ty.scalarType(), arena, target);
3109 overflowed_data[i] = of_math_result.overflowed;
3110 scalar.* = of_math_result.wrapped_result;
3111 }
3112 return OverflowArithmeticResult{
3113 .overflowed = try Value.Tag.aggregate.create(arena, overflowed_data),
3114 .wrapped_result = try Value.Tag.aggregate.create(arena, result_data),
3115 };
3116 }
3117 return intSubWithOverflowScalar(lhs, rhs, ty, arena, target);
3118 }
3119
3120 pub fn intSubWithOverflowScalar(
3121 lhs: Value,
3122 rhs: Value,
3123 ty: Type,
3124 arena: Allocator,
3125 target: Target,
3126 ) !OverflowArithmeticResult {
3127 const info = ty.intInfo(target);
3128
3129 var lhs_space: Value.BigIntSpace = undefined;
3130 var rhs_space: Value.BigIntSpace = undefined;
3131 const lhs_bigint = lhs.toBigInt(&lhs_space, target);
3132 const rhs_bigint = rhs.toBigInt(&rhs_space, target);
3133 const limbs = try arena.alloc(
3134 std.math.big.Limb,
3135 std.math.big.int.calcTwosCompLimbCount(info.bits),
3136 );
3137 var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined };
3138 const overflowed = result_bigint.subWrap(lhs_bigint, rhs_bigint, info.signedness, info.bits);
3139 const wrapped_result = try fromBigInt(arena, result_bigint.toConst());
3140 return OverflowArithmeticResult{
3141 .overflowed = makeBool(overflowed),
3142 .wrapped_result = wrapped_result,
3143 };
3144 }
3145
3146 /// Supports both (vectors of) floats and ints; handles undefined scalars.
3147 pub fn numberSubWrap(
3148 lhs: Value,
3149 rhs: Value,
3150 ty: Type,
3151 arena: Allocator,
3152 target: Target,
3153 ) !Value {
3154 if (ty.zigTypeTag() == .Vector) {
3155 const result_data = try arena.alloc(Value, ty.vectorLen());
3156 for (result_data) |*scalar, i| {
3157 scalar.* = try numberSubWrapScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), ty.scalarType(), arena, target);
3158 }
3159 return Value.Tag.aggregate.create(arena, result_data);
3160 }
3161 return numberSubWrapScalar(lhs, rhs, ty, arena, target);
3162 }
3163
3164 /// Supports both floats and ints; handles undefined.
3165 pub fn numberSubWrapScalar(
3166 lhs: Value,
3167 rhs: Value,
3168 ty: Type,
3169 arena: Allocator,
3170 target: Target,
3171 ) !Value {
3172 if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef);
3173
3174 if (ty.zigTypeTag() == .ComptimeInt) {
3175 return intSub(lhs, rhs, ty, arena, target);
3176 }
3177
3178 if (ty.isAnyFloat()) {
3179 return floatSub(lhs, rhs, ty, arena, target);
3180 }
3181
3182 const overflow_result = try intSubWithOverflow(lhs, rhs, ty, arena, target);
3183 return overflow_result.wrapped_result;
3184 }
3185
3186 /// Supports (vectors of) integers only; asserts neither operand is undefined.2892 /// Supports (vectors of) integers only; asserts neither operand is undefined.
3187 pub fn intSubSat(2893 pub fn intSubSat(
3188 lhs: Value,2894 lhs: Value,
...@@ -3559,60 +3265,6 @@ pub const Value = extern union {...@@ -3559,60 +3265,6 @@ pub const Value = extern union {
3559 return fromBigInt(arena, result_bigint.toConst());3265 return fromBigInt(arena, result_bigint.toConst());
3560 }3266 }
35613267
3562 pub fn intAdd(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, target: Target) !Value {
3563 if (ty.zigTypeTag() == .Vector) {
3564 const result_data = try allocator.alloc(Value, ty.vectorLen());
3565 for (result_data) |*scalar, i| {
3566 scalar.* = try intAddScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), allocator, target);
3567 }
3568 return Value.Tag.aggregate.create(allocator, result_data);
3569 }
3570 return intAddScalar(lhs, rhs, allocator, target);
3571 }
3572
3573 pub fn intAddScalar(lhs: Value, rhs: Value, allocator: Allocator, target: Target) !Value {
3574 // TODO is this a performance issue? maybe we should try the operation without
3575 // resorting to BigInt first.
3576 var lhs_space: Value.BigIntSpace = undefined;
3577 var rhs_space: Value.BigIntSpace = undefined;
3578 const lhs_bigint = lhs.toBigInt(&lhs_space, target);
3579 const rhs_bigint = rhs.toBigInt(&rhs_space, target);
3580 const limbs = try allocator.alloc(
3581 std.math.big.Limb,
3582 std.math.max(lhs_bigint.limbs.len, rhs_bigint.limbs.len) + 1,
3583 );
3584 var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined };
3585 result_bigint.add(lhs_bigint, rhs_bigint);
3586 return fromBigInt(allocator, result_bigint.toConst());
3587 }
3588
3589 pub fn intSub(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, target: Target) !Value {
3590 if (ty.zigTypeTag() == .Vector) {
3591 const result_data = try allocator.alloc(Value, ty.vectorLen());
3592 for (result_data) |*scalar, i| {
3593 scalar.* = try intSubScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), allocator, target);
3594 }
3595 return Value.Tag.aggregate.create(allocator, result_data);
3596 }
3597 return intSubScalar(lhs, rhs, allocator, target);
3598 }
3599
3600 pub fn intSubScalar(lhs: Value, rhs: Value, allocator: Allocator, target: Target) !Value {
3601 // TODO is this a performance issue? maybe we should try the operation without
3602 // resorting to BigInt first.
3603 var lhs_space: Value.BigIntSpace = undefined;
3604 var rhs_space: Value.BigIntSpace = undefined;
3605 const lhs_bigint = lhs.toBigInt(&lhs_space, target);
3606 const rhs_bigint = rhs.toBigInt(&rhs_space, target);
3607 const limbs = try allocator.alloc(
3608 std.math.big.Limb,
3609 std.math.max(lhs_bigint.limbs.len, rhs_bigint.limbs.len) + 1,
3610 );
3611 var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined };
3612 result_bigint.sub(lhs_bigint, rhs_bigint);
3613 return fromBigInt(allocator, result_bigint.toConst());
3614 }
3615
3616 pub fn intDiv(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, target: Target) !Value {3268 pub fn intDiv(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, target: Target) !Value {
3617 if (ty.zigTypeTag() == .Vector) {3269 if (ty.zigTypeTag() == .Vector) {
3618 const result_data = try allocator.alloc(Value, ty.vectorLen());3270 const result_data = try allocator.alloc(Value, ty.vectorLen());
...@@ -4129,114 +3781,6 @@ pub const Value = extern union {...@@ -4129,114 +3781,6 @@ pub const Value = extern union {
4129 return fromBigInt(allocator, result_bigint.toConst());3781 return fromBigInt(allocator, result_bigint.toConst());
4130 }3782 }
41313783
4132 pub fn floatAdd(
4133 lhs: Value,
4134 rhs: Value,
4135 float_type: Type,
4136 arena: Allocator,
4137 target: Target,
4138 ) !Value {
4139 if (float_type.zigTypeTag() == .Vector) {
4140 const result_data = try arena.alloc(Value, float_type.vectorLen());
4141 for (result_data) |*scalar, i| {
4142 scalar.* = try floatAddScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), float_type.scalarType(), arena, target);
4143 }
4144 return Value.Tag.aggregate.create(arena, result_data);
4145 }
4146 return floatAddScalar(lhs, rhs, float_type, arena, target);
4147 }
4148
4149 pub fn floatAddScalar(
4150 lhs: Value,
4151 rhs: Value,
4152 float_type: Type,
4153 arena: Allocator,
4154 target: Target,
4155 ) !Value {
4156 switch (float_type.floatBits(target)) {
4157 16 => {
4158 const lhs_val = lhs.toFloat(f16);
4159 const rhs_val = rhs.toFloat(f16);
4160 return Value.Tag.float_16.create(arena, lhs_val + rhs_val);
4161 },
4162 32 => {
4163 const lhs_val = lhs.toFloat(f32);
4164 const rhs_val = rhs.toFloat(f32);
4165 return Value.Tag.float_32.create(arena, lhs_val + rhs_val);
4166 },
4167 64 => {
4168 const lhs_val = lhs.toFloat(f64);
4169 const rhs_val = rhs.toFloat(f64);
4170 return Value.Tag.float_64.create(arena, lhs_val + rhs_val);
4171 },
4172 80 => {
4173 const lhs_val = lhs.toFloat(f80);
4174 const rhs_val = rhs.toFloat(f80);
4175 return Value.Tag.float_80.create(arena, lhs_val + rhs_val);
4176 },
4177 128 => {
4178 const lhs_val = lhs.toFloat(f128);
4179 const rhs_val = rhs.toFloat(f128);
4180 return Value.Tag.float_128.create(arena, lhs_val + rhs_val);
4181 },
4182 else => unreachable,
4183 }
4184 }
4185
4186 pub fn floatSub(
4187 lhs: Value,
4188 rhs: Value,
4189 float_type: Type,
4190 arena: Allocator,
4191 target: Target,
4192 ) !Value {
4193 if (float_type.zigTypeTag() == .Vector) {
4194 const result_data = try arena.alloc(Value, float_type.vectorLen());
4195 for (result_data) |*scalar, i| {
4196 scalar.* = try floatSubScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), float_type.scalarType(), arena, target);
4197 }
4198 return Value.Tag.aggregate.create(arena, result_data);
4199 }
4200 return floatSubScalar(lhs, rhs, float_type, arena, target);
4201 }
4202
4203 pub fn floatSubScalar(
4204 lhs: Value,
4205 rhs: Value,
4206 float_type: Type,
4207 arena: Allocator,
4208 target: Target,
4209 ) !Value {
4210 switch (float_type.floatBits(target)) {
4211 16 => {
4212 const lhs_val = lhs.toFloat(f16);
4213 const rhs_val = rhs.toFloat(f16);
4214 return Value.Tag.float_16.create(arena, lhs_val - rhs_val);
4215 },
4216 32 => {
4217 const lhs_val = lhs.toFloat(f32);
4218 const rhs_val = rhs.toFloat(f32);
4219 return Value.Tag.float_32.create(arena, lhs_val - rhs_val);
4220 },
4221 64 => {
4222 const lhs_val = lhs.toFloat(f64);
4223 const rhs_val = rhs.toFloat(f64);
4224 return Value.Tag.float_64.create(arena, lhs_val - rhs_val);
4225 },
4226 80 => {
4227 const lhs_val = lhs.toFloat(f80);
4228 const rhs_val = rhs.toFloat(f80);
4229 return Value.Tag.float_80.create(arena, lhs_val - rhs_val);
4230 },
4231 128 => {
4232 const lhs_val = lhs.toFloat(f128);
4233 const rhs_val = rhs.toFloat(f128);
4234 return Value.Tag.float_128.create(arena, lhs_val - rhs_val);
4235 },
4236 else => unreachable,
4237 }
4238 }
4239
4240 pub fn floatNeg(3784 pub fn floatNeg(
4241 val: Value,3785 val: Value,
4242 float_type: Type,3786 float_type: Type,
test/behavior/sizeof_and_typeof.zig-2
...@@ -169,8 +169,6 @@ test "@bitOffsetOf" {...@@ -169,8 +169,6 @@ test "@bitOffsetOf" {
169}169}
170170
171test "@sizeOf(T) == 0 doesn't force resolving struct size" {171test "@sizeOf(T) == 0 doesn't force resolving struct size" {
172 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
173
174 const S = struct {172 const S = struct {
175 const Foo = struct {173 const Foo = struct {
176 y: if (@sizeOf(Foo) == 0) u64 else u32,174 y: if (@sizeOf(Foo) == 0) u64 else u32,