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(
22282228 enum_obj.tag_ty_inferred = true;
22292229 }
22302230 }
2231 const target = mod.getTarget();
22322231
22332232 try enum_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len);
22342233 const any_values = for (sema.code.extra[body_end..][0..bit_bags_count]) |bag| {
......@@ -2291,7 +2290,7 @@ fn zirEnumDecl(
22912290 });
22922291 } else if (any_values) {
22932292 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)
22952294 else
22962295 Value.zero;
22972296 last_tag_val = tag_val;
......@@ -6054,7 +6053,7 @@ fn zirIntToEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
60546053 if (int_val.isUndef()) {
60556054 return sema.failWithUseOfUndef(block, operand_src);
60566055 }
6057 if (!dest_ty.enumHasInt(int_val, sema.mod)) {
6056 if (!(try sema.enumHasInt(block, src, dest_ty, int_val))) {
60586057 const msg = msg: {
60596058 const msg = try sema.errMsg(
60606059 block,
......@@ -7082,7 +7081,7 @@ fn intCast(
70827081 // range to account for negative values.
70837082 const dest_range_val = if (wanted_info.signedness == .signed) range_val: {
70847083 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);
70867085 } else dest_max_val;
70877086 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
82038202 // Validation above ensured these will succeed.
82048203 const first_tv = sema.resolveInstConst(&child_block, .unneeded, item_first) catch unreachable;
82058204 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) and
8207 Value.compare(operand_val, .lte, last_tv.val, operand_ty, sema.mod))
8205 if ((try sema.compare(block, src, operand_val, .gte, first_tv.val, operand_ty)) and
8206 (try sema.compare(block, src, operand_val, .lte, last_tv.val, operand_ty)))
82088207 {
82098208 return sema.resolveBlockBody(block, src, &child_block, body, inst, merges);
82108209 }
......@@ -8878,7 +8877,7 @@ fn zirShl(
88788877 if (rhs_val.isUndef()) {
88798878 return sema.addConstUndef(sema.typeOf(lhs));
88808879 }
8881 if (rhs_val.compareWithZero(.eq)) {
8880 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
88828881 return lhs;
88838882 }
88848883 }
......@@ -8895,7 +8894,7 @@ fn zirShl(
88958894 }
88968895 const int_info = scalar_ty.intInfo(target);
88978896 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)) {
88998898 break :val shifted;
89008899 }
89018900 return sema.addConstUndef(lhs_ty);
......@@ -8999,13 +8998,13 @@ fn zirShr(
89998998 return sema.addConstUndef(lhs_ty);
90008999 }
90019000 // 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))) {
90039002 return sema.addConstant(lhs_ty, lhs_val);
90049003 }
90059004 if (air_tag == .shr_exact) {
90069005 // Detect if any ones would be shifted out.
90079006 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)))) {
90099008 return sema.addConstUndef(lhs_ty);
90109009 }
90119010 }
......@@ -9015,7 +9014,7 @@ fn zirShr(
90159014 // Even if lhs is not comptime known, we can still deduce certain things based
90169015 // on rhs.
90179016 // 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))) {
90199018 return lhs;
90209019 }
90219020 break :rs lhs_src;
......@@ -9578,12 +9577,12 @@ fn zirOverflowArithmetic(
95789577 // to the result, even if it is undefined..
95799578 // Otherwise, if either of the argument is undefined, undefined is returned.
95809579 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)))) {
95829581 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = rhs };
95839582 }
95849583 }
95859584 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)))) {
95879586 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs };
95889587 }
95899588 }
......@@ -9593,7 +9592,7 @@ fn zirOverflowArithmetic(
95939592 break :result .{ .overflowed = try sema.addConstUndef(overflowed_ty), .wrapped = try sema.addConstUndef(dest_ty) };
95949593 }
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);
95979596 const overflowed = try sema.addConstant(overflowed_ty, result.overflowed);
95989597 const wrapped = try sema.addConstant(dest_ty, result.wrapped_result);
95999598 break :result .{ .overflowed = overflowed, .wrapped = wrapped };
......@@ -9606,14 +9605,14 @@ fn zirOverflowArithmetic(
96069605 if (maybe_rhs_val) |rhs_val| {
96079606 if (rhs_val.isUndef()) {
96089607 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))) {
96109609 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs };
96119610 } else if (maybe_lhs_val) |lhs_val| {
96129611 if (lhs_val.isUndef()) {
96139612 break :result .{ .overflowed = try sema.addConstUndef(overflowed_ty), .wrapped = try sema.addConstUndef(dest_ty) };
96149613 }
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);
96179616 const overflowed = try sema.addConstant(overflowed_ty, result.overflowed);
96189617 const wrapped = try sema.addConstant(dest_ty, result.wrapped_result);
96199618 break :result .{ .overflowed = overflowed, .wrapped = wrapped };
......@@ -9626,9 +9625,9 @@ fn zirOverflowArithmetic(
96269625 // Otherwise, if either of the arguments is undefined, both results are undefined.
96279626 if (maybe_lhs_val) |lhs_val| {
96289627 if (!lhs_val.isUndef()) {
9629 if (lhs_val.compareWithZero(.eq)) {
9628 if (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
96309629 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)) {
96329631 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = rhs };
96339632 }
96349633 }
......@@ -9636,9 +9635,9 @@ fn zirOverflowArithmetic(
96369635
96379636 if (maybe_rhs_val) |rhs_val| {
96389637 if (!rhs_val.isUndef()) {
9639 if (rhs_val.compareWithZero(.eq)) {
9638 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
96409639 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)) {
96429641 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs };
96439642 }
96449643 }
......@@ -9662,12 +9661,12 @@ fn zirOverflowArithmetic(
96629661 // If rhs is zero, the result is lhs (even if undefined) and no overflow occurred.
96639662 // Oterhwise if either of the arguments is undefined, both results are undefined.
96649663 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)))) {
96669665 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs };
96679666 }
96689667 }
96699668 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)))) {
96719670 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs };
96729671 }
96739672 }
......@@ -9815,7 +9814,7 @@ fn analyzeArithmetic(
98159814 // overflow (max_int), causing illegal behavior.
98169815 // For floats: either operand being undef makes the result undef.
98179816 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)))) {
98199818 return casted_rhs;
98209819 }
98219820 }
......@@ -9827,7 +9826,7 @@ fn analyzeArithmetic(
98279826 return sema.addConstUndef(resolved_type);
98289827 }
98299828 }
9830 if (rhs_val.compareWithZero(.eq)) {
9829 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
98319830 return casted_lhs;
98329831 }
98339832 }
......@@ -9841,15 +9840,15 @@ fn analyzeArithmetic(
98419840 }
98429841 if (maybe_rhs_val) |rhs_val| {
98439842 if (is_int) {
9844 const sum = try lhs_val.intAdd(rhs_val, resolved_type, sema.arena, target);
9845 if (!sum.intFitsInType(resolved_type, target)) {
9843 const sum = try sema.intAdd(block, src, lhs_val, rhs_val, resolved_type);
9844 if (!(try sema.intFitsInType(block, src, sum, resolved_type))) {
98469845 return sema.failWithIntegerOverflow(block, src, resolved_type, sum);
98479846 }
98489847 return sema.addConstant(resolved_type, sum);
98499848 } else {
98509849 return sema.addConstant(
98519850 resolved_type,
9852 try lhs_val.floatAdd(rhs_val, resolved_type, sema.arena, target),
9851 try sema.floatAdd(lhs_val, rhs_val, resolved_type),
98539852 );
98549853 }
98559854 } else break :rs .{ .src = rhs_src, .air_tag = .add };
......@@ -9860,7 +9859,7 @@ fn analyzeArithmetic(
98609859 // If either of the operands are zero, the other operand is returned.
98619860 // If either of the operands are undefined, the result is undefined.
98629861 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)))) {
98649863 return casted_rhs;
98659864 }
98669865 }
......@@ -9868,13 +9867,13 @@ fn analyzeArithmetic(
98689867 if (rhs_val.isUndef()) {
98699868 return sema.addConstUndef(resolved_type);
98709869 }
9871 if (rhs_val.compareWithZero(.eq)) {
9870 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
98729871 return casted_lhs;
98739872 }
98749873 if (maybe_lhs_val) |lhs_val| {
98759874 return sema.addConstant(
98769875 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),
98789877 );
98799878 } else break :rs .{ .src = lhs_src, .air_tag = .addwrap };
98809879 } else break :rs .{ .src = rhs_src, .air_tag = .addwrap };
......@@ -9884,7 +9883,7 @@ fn analyzeArithmetic(
98849883 // If either of the operands are zero, then the other operand is returned.
98859884 // If either of the operands are undefined, the result is undefined.
98869885 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)))) {
98889887 return casted_rhs;
98899888 }
98909889 }
......@@ -9892,12 +9891,12 @@ fn analyzeArithmetic(
98929891 if (rhs_val.isUndef()) {
98939892 return sema.addConstUndef(resolved_type);
98949893 }
9895 if (rhs_val.compareWithZero(.eq)) {
9894 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
98969895 return casted_lhs;
98979896 }
98989897 if (maybe_lhs_val) |lhs_val| {
98999898 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)
99019900 else
99029901 try lhs_val.intAddSat(rhs_val, resolved_type, sema.arena, target);
99039902
......@@ -9921,7 +9920,7 @@ fn analyzeArithmetic(
99219920 return sema.addConstUndef(resolved_type);
99229921 }
99239922 }
9924 if (rhs_val.compareWithZero(.eq)) {
9923 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
99259924 return casted_lhs;
99269925 }
99279926 }
......@@ -9935,15 +9934,15 @@ fn analyzeArithmetic(
99359934 }
99369935 if (maybe_rhs_val) |rhs_val| {
99379936 if (is_int) {
9938 const diff = try lhs_val.intSub(rhs_val, resolved_type, sema.arena, target);
9939 if (!diff.intFitsInType(resolved_type, target)) {
9937 const diff = try sema.intSub(block, src, lhs_val, rhs_val, resolved_type);
9938 if (!(try sema.intFitsInType(block, src, diff, resolved_type))) {
99409939 return sema.failWithIntegerOverflow(block, src, resolved_type, diff);
99419940 }
99429941 return sema.addConstant(resolved_type, diff);
99439942 } else {
99449943 return sema.addConstant(
99459944 resolved_type,
9946 try lhs_val.floatSub(rhs_val, resolved_type, sema.arena, target),
9945 try sema.floatSub(lhs_val, rhs_val, resolved_type),
99479946 );
99489947 }
99499948 } else break :rs .{ .src = rhs_src, .air_tag = .sub };
......@@ -9957,7 +9956,7 @@ fn analyzeArithmetic(
99579956 if (rhs_val.isUndef()) {
99589957 return sema.addConstUndef(resolved_type);
99599958 }
9960 if (rhs_val.compareWithZero(.eq)) {
9959 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
99619960 return casted_lhs;
99629961 }
99639962 }
......@@ -9968,7 +9967,7 @@ fn analyzeArithmetic(
99689967 if (maybe_rhs_val) |rhs_val| {
99699968 return sema.addConstant(
99709969 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),
99729971 );
99739972 } else break :rs .{ .src = rhs_src, .air_tag = .subwrap };
99749973 } else break :rs .{ .src = lhs_src, .air_tag = .subwrap };
......@@ -9981,7 +9980,7 @@ fn analyzeArithmetic(
99819980 if (rhs_val.isUndef()) {
99829981 return sema.addConstUndef(resolved_type);
99839982 }
9984 if (rhs_val.compareWithZero(.eq)) {
9983 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
99859984 return casted_lhs;
99869985 }
99879986 }
......@@ -9991,7 +9990,7 @@ fn analyzeArithmetic(
99919990 }
99929991 if (maybe_rhs_val) |rhs_val| {
99939992 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)
99959994 else
99969995 try lhs_val.intSubSat(rhs_val, resolved_type, sema.arena, target);
99979996
......@@ -10032,7 +10031,7 @@ fn analyzeArithmetic(
1003210031 .Int, .ComptimeInt, .ComptimeFloat => {
1003310032 if (maybe_lhs_val) |lhs_val| {
1003410033 if (!lhs_val.isUndef()) {
10035 if (lhs_val.compareWithZero(.eq)) {
10034 if (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
1003610035 return sema.addConstant(resolved_type, Value.zero);
1003710036 }
1003810037 }
......@@ -10041,7 +10040,7 @@ fn analyzeArithmetic(
1004110040 if (rhs_val.isUndef()) {
1004210041 return sema.failWithUseOfUndef(block, rhs_src);
1004310042 }
10044 if (rhs_val.compareWithZero(.eq)) {
10043 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
1004510044 return sema.failWithDivideByZero(block, rhs_src);
1004610045 }
1004710046 }
......@@ -10053,7 +10052,7 @@ fn analyzeArithmetic(
1005310052 if (lhs_val.isUndef()) {
1005410053 if (lhs_scalar_ty.isSignedInt() and rhs_scalar_ty.isSignedInt()) {
1005510054 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)) {
1005710056 return sema.addConstUndef(resolved_type);
1005810057 }
1005910058 }
......@@ -10111,7 +10110,7 @@ fn analyzeArithmetic(
1011110110 // If the lhs is undefined, result is undefined.
1011210111 if (maybe_lhs_val) |lhs_val| {
1011310112 if (!lhs_val.isUndef()) {
10114 if (lhs_val.compareWithZero(.eq)) {
10113 if (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
1011510114 return sema.addConstant(resolved_type, Value.zero);
1011610115 }
1011710116 }
......@@ -10120,7 +10119,7 @@ fn analyzeArithmetic(
1012010119 if (rhs_val.isUndef()) {
1012110120 return sema.failWithUseOfUndef(block, rhs_src);
1012210121 }
10123 if (rhs_val.compareWithZero(.eq)) {
10122 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
1012410123 return sema.failWithDivideByZero(block, rhs_src);
1012510124 }
1012610125 }
......@@ -10128,7 +10127,7 @@ fn analyzeArithmetic(
1012810127 if (lhs_val.isUndef()) {
1012910128 if (lhs_scalar_ty.isSignedInt() and rhs_scalar_ty.isSignedInt()) {
1013010129 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)) {
1013210131 return sema.addConstUndef(resolved_type);
1013310132 }
1013410133 }
......@@ -10174,7 +10173,7 @@ fn analyzeArithmetic(
1017410173 // If the lhs is undefined, result is undefined.
1017510174 if (maybe_lhs_val) |lhs_val| {
1017610175 if (!lhs_val.isUndef()) {
10177 if (lhs_val.compareWithZero(.eq)) {
10176 if (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
1017810177 return sema.addConstant(resolved_type, Value.zero);
1017910178 }
1018010179 }
......@@ -10183,7 +10182,7 @@ fn analyzeArithmetic(
1018310182 if (rhs_val.isUndef()) {
1018410183 return sema.failWithUseOfUndef(block, rhs_src);
1018510184 }
10186 if (rhs_val.compareWithZero(.eq)) {
10185 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
1018710186 return sema.failWithDivideByZero(block, rhs_src);
1018810187 }
1018910188 }
......@@ -10191,7 +10190,7 @@ fn analyzeArithmetic(
1019110190 if (lhs_val.isUndef()) {
1019210191 if (lhs_scalar_ty.isSignedInt() and rhs_scalar_ty.isSignedInt()) {
1019310192 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)) {
1019510194 return sema.addConstUndef(resolved_type);
1019610195 }
1019710196 }
......@@ -10236,7 +10235,7 @@ fn analyzeArithmetic(
1023610235 if (lhs_val.isUndef()) {
1023710236 return sema.failWithUseOfUndef(block, rhs_src);
1023810237 } else {
10239 if (lhs_val.compareWithZero(.eq)) {
10238 if (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
1024010239 return sema.addConstant(resolved_type, Value.zero);
1024110240 }
1024210241 }
......@@ -10245,7 +10244,7 @@ fn analyzeArithmetic(
1024510244 if (rhs_val.isUndef()) {
1024610245 return sema.failWithUseOfUndef(block, rhs_src);
1024710246 }
10248 if (rhs_val.compareWithZero(.eq)) {
10247 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
1024910248 return sema.failWithDivideByZero(block, rhs_src);
1025010249 }
1025110250 }
......@@ -10278,10 +10277,10 @@ fn analyzeArithmetic(
1027810277 // For floats: either operand being undef makes the result undef.
1027910278 if (maybe_lhs_val) |lhs_val| {
1028010279 if (!lhs_val.isUndef()) {
10281 if (lhs_val.compareWithZero(.eq)) {
10280 if (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
1028210281 return sema.addConstant(resolved_type, Value.zero);
1028310282 }
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)) {
1028510284 return casted_rhs;
1028610285 }
1028710286 }
......@@ -10294,10 +10293,10 @@ fn analyzeArithmetic(
1029410293 return sema.addConstUndef(resolved_type);
1029510294 }
1029610295 }
10297 if (rhs_val.compareWithZero(.eq)) {
10296 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
1029810297 return sema.addConstant(resolved_type, Value.zero);
1029910298 }
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)) {
1030110300 return casted_lhs;
1030210301 }
1030310302 if (maybe_lhs_val) |lhs_val| {
......@@ -10310,7 +10309,7 @@ fn analyzeArithmetic(
1031010309 }
1031110310 if (is_int) {
1031210311 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))) {
1031410313 return sema.failWithIntegerOverflow(block, src, resolved_type, product);
1031510314 }
1031610315 return sema.addConstant(resolved_type, product);
......@@ -10330,10 +10329,10 @@ fn analyzeArithmetic(
1033010329 // If either of the operands are undefined, result is undefined.
1033110330 if (maybe_lhs_val) |lhs_val| {
1033210331 if (!lhs_val.isUndef()) {
10333 if (lhs_val.compareWithZero(.eq)) {
10332 if (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
1033410333 return sema.addConstant(resolved_type, Value.zero);
1033510334 }
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)) {
1033710336 return casted_rhs;
1033810337 }
1033910338 }
......@@ -10342,10 +10341,10 @@ fn analyzeArithmetic(
1034210341 if (rhs_val.isUndef()) {
1034310342 return sema.addConstUndef(resolved_type);
1034410343 }
10345 if (rhs_val.compareWithZero(.eq)) {
10344 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
1034610345 return sema.addConstant(resolved_type, Value.zero);
1034710346 }
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)) {
1034910348 return casted_lhs;
1035010349 }
1035110350 if (maybe_lhs_val) |lhs_val| {
......@@ -10366,10 +10365,10 @@ fn analyzeArithmetic(
1036610365 // If either of the operands are undefined, result is undefined.
1036710366 if (maybe_lhs_val) |lhs_val| {
1036810367 if (!lhs_val.isUndef()) {
10369 if (lhs_val.compareWithZero(.eq)) {
10368 if (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
1037010369 return sema.addConstant(resolved_type, Value.zero);
1037110370 }
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)) {
1037310372 return casted_rhs;
1037410373 }
1037510374 }
......@@ -10378,10 +10377,10 @@ fn analyzeArithmetic(
1037810377 if (rhs_val.isUndef()) {
1037910378 return sema.addConstUndef(resolved_type);
1038010379 }
10381 if (rhs_val.compareWithZero(.eq)) {
10380 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
1038210381 return sema.addConstant(resolved_type, Value.zero);
1038310382 }
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)) {
1038510384 return casted_lhs;
1038610385 }
1038710386 if (maybe_lhs_val) |lhs_val| {
......@@ -10417,7 +10416,7 @@ fn analyzeArithmetic(
1041710416 if (lhs_val.isUndef()) {
1041810417 return sema.failWithUseOfUndef(block, lhs_src);
1041910418 }
10420 if (lhs_val.compareWithZero(.eq)) {
10419 if (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
1042110420 return sema.addConstant(resolved_type, Value.zero);
1042210421 }
1042310422 } else if (lhs_scalar_ty.isSignedInt()) {
......@@ -10427,23 +10426,23 @@ fn analyzeArithmetic(
1042710426 if (rhs_val.isUndef()) {
1042810427 return sema.failWithUseOfUndef(block, rhs_src);
1042910428 }
10430 if (rhs_val.compareWithZero(.eq)) {
10429 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
1043110430 return sema.failWithDivideByZero(block, rhs_src);
1043210431 }
1043310432 if (maybe_lhs_val) |lhs_val| {
1043410433 const rem_result = try lhs_val.intRem(rhs_val, resolved_type, sema.arena, target);
1043510434 // If this answer could possibly be different by doing `intMod`,
1043610435 // we must emit a compile error. Otherwise, it's OK.
10437 if (rhs_val.compareWithZero(.lt) != lhs_val.compareWithZero(.lt) and
10438 !rem_result.compareWithZero(.eq))
10436 if ((try rhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src))) != (try lhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src))) and
10437 !(try rem_result.compareWithZeroAdvanced(.eq, sema.kit(block, src))))
1043910438 {
10440 const bad_src = if (lhs_val.compareWithZero(.lt))
10439 const bad_src = if (try lhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src)))
1044110440 lhs_src
1044210441 else
1044310442 rhs_src;
1044410443 return sema.failWithModRemNegative(block, bad_src, lhs_ty, rhs_ty);
1044510444 }
10446 if (lhs_val.compareWithZero(.lt)) {
10445 if (try lhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src))) {
1044710446 // Negative
1044810447 return sema.addConstant(resolved_type, Value.zero);
1044910448 }
......@@ -10461,14 +10460,14 @@ fn analyzeArithmetic(
1046110460 if (rhs_val.isUndef()) {
1046210461 return sema.failWithUseOfUndef(block, rhs_src);
1046310462 }
10464 if (rhs_val.compareWithZero(.eq)) {
10463 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
1046510464 return sema.failWithDivideByZero(block, rhs_src);
1046610465 }
10467 if (rhs_val.compareWithZero(.lt)) {
10466 if (try rhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src))) {
1046810467 return sema.failWithModRemNegative(block, rhs_src, lhs_ty, rhs_ty);
1046910468 }
1047010469 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)))) {
1047210471 return sema.failWithModRemNegative(block, lhs_src, lhs_ty, rhs_ty);
1047310472 }
1047410473 return sema.addConstant(
......@@ -10504,7 +10503,7 @@ fn analyzeArithmetic(
1050410503 if (rhs_val.isUndef()) {
1050510504 return sema.failWithUseOfUndef(block, rhs_src);
1050610505 }
10507 if (rhs_val.compareWithZero(.eq)) {
10506 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
1050810507 return sema.failWithDivideByZero(block, rhs_src);
1050910508 }
1051010509 if (maybe_lhs_val) |lhs_val| {
......@@ -10523,7 +10522,7 @@ fn analyzeArithmetic(
1052310522 if (rhs_val.isUndef()) {
1052410523 return sema.failWithUseOfUndef(block, rhs_src);
1052510524 }
10526 if (rhs_val.compareWithZero(.eq)) {
10525 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
1052710526 return sema.failWithDivideByZero(block, rhs_src);
1052810527 }
1052910528 }
......@@ -10561,7 +10560,7 @@ fn analyzeArithmetic(
1056110560 if (rhs_val.isUndef()) {
1056210561 return sema.failWithUseOfUndef(block, rhs_src);
1056310562 }
10564 if (rhs_val.compareWithZero(.eq)) {
10563 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
1056510564 return sema.failWithDivideByZero(block, rhs_src);
1056610565 }
1056710566 if (maybe_lhs_val) |lhs_val| {
......@@ -10580,7 +10579,7 @@ fn analyzeArithmetic(
1058010579 if (rhs_val.isUndef()) {
1058110580 return sema.failWithUseOfUndef(block, rhs_src);
1058210581 }
10583 if (rhs_val.compareWithZero(.eq)) {
10582 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
1058410583 return sema.failWithDivideByZero(block, rhs_src);
1058510584 }
1058610585 }
......@@ -11095,11 +11094,11 @@ fn cmpSelf(
1109511094
1109611095 if (resolved_type.zigTypeTag() == .Vector) {
1109711096 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);
1109911098 return sema.addConstant(result_ty, cmp_val);
1110011099 }
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)) {
1110311102 return Air.Inst.Ref.bool_true;
1110411103 } else {
1110511104 return Air.Inst.Ref.bool_false;
......@@ -11157,24 +11156,22 @@ fn zirSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
1115711156 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
1115811157 const src = inst_data.src();
1115911158 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);
11161 try sema.resolveTypeLayout(block, src, operand_ty);
11162 const target = sema.mod.getTarget();
11163 const abi_size = switch (operand_ty.zigTypeTag()) {
11159 const ty = try sema.resolveType(block, operand_src, inst_data.operand);
11160 switch (ty.zigTypeTag()) {
1116411161 .Fn => unreachable,
1116511162 .NoReturn,
1116611163 .Undefined,
1116711164 .Null,
1116811165 .BoundFn,
1116911166 .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
1117211169 .Type,
1117311170 .EnumLiteral,
1117411171 .ComptimeFloat,
1117511172 .ComptimeInt,
1117611173 .Void,
11177 => 0,
11174 => return sema.addIntUnsigned(Type.comptime_int, 0),
1117811175
1117911176 .Bool,
1118011177 .Int,
......@@ -11190,9 +11187,14 @@ fn zirSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
1119011187 .Vector,
1119111188 .Frame,
1119211189 .AnyFrame,
11193 => operand_ty.abiSize(target),
11194 };
11195 return sema.addIntUnsigned(Type.comptime_int, abi_size);
11190 => {},
11191 }
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);
1119611198}
1119711199
1119811200fn 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
1120211204 const operand_ty = try sema.resolveTypeFields(block, operand_src, unresolved_operand_ty);
1120311205 const target = sema.mod.getTarget();
1120411206 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);
1120611208}
1120711209
1120811210fn zirThis(
......@@ -13516,10 +13518,11 @@ fn zirAlignOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
1351613518 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
1351713519 const ty = try sema.resolveType(block, operand_src, inst_data.operand);
1351813520 const target = sema.mod.getTarget();
13519 return sema.addConstant(
13520 Type.comptime_int,
13521 try ty.lazyAbiAlignment(target, sema.arena),
13522 );
13521 const val = try ty.lazyAbiAlignment(target, sema.arena);
13522 if (val.tag() == .lazy_align) {
13523 try sema.queueFullTypeResolution(ty);
13524 }
13525 return sema.addConstant(Type.comptime_int, val);
1352313526}
1352413527
1352513528fn 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!
1436214365 try sema.checkFloatType(block, operand_src, operand_ty);
1436314366
1436414367 if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |val| {
14365 const target = sema.mod.getTarget();
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 };
14368 const result_val = try sema.floatToInt(block, operand_src, val, operand_ty, dest_ty);
1437514369 return sema.addConstant(dest_ty, result_val);
1437614370 }
1437714371
......@@ -15563,7 +15557,7 @@ fn zirReduce(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
1556315557 .Xor => accum = try accum.bitwiseXor(elem_val, scalar_ty, sema.arena, target),
1556415558 .Min => accum = accum.numberMin(elem_val, target),
1556515559 .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),
1556715561 .Mul => accum = try accum.numberMulWrap(elem_val, scalar_ty, sema.arena, target),
1556815562 }
1556915563 }
......@@ -15958,14 +15952,14 @@ fn zirAtomicRmw(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
1595815952 const new_val = switch (op) {
1595915953 // zig fmt: off
1596015954 .Xchg => operand_val,
15961 .Add => try stored_val.numberAddWrap(operand_val, elem_ty, sema.arena, target),
15962 .Sub => try stored_val.numberSubWrap(operand_val, elem_ty, sema.arena, target),
15963 .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),
15965 .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),
15967 .Max => stored_val.numberMax (operand_val, target),
15968 .Min => stored_val.numberMin (operand_val, target),
15955 .Add => try sema.numberAddWrap(block, src, stored_val, operand_val, elem_ty),
15956 .Sub => try sema.numberSubWrap(block, src, stored_val, operand_val, elem_ty),
15957 .And => try stored_val.bitwiseAnd (operand_val, elem_ty, sema.arena, target),
15958 .Nand => try stored_val.bitwiseNand (operand_val, elem_ty, sema.arena, target),
15959 .Or => try stored_val.bitwiseOr (operand_val, elem_ty, sema.arena, target),
15960 .Xor => try stored_val.bitwiseXor (operand_val, elem_ty, sema.arena, target),
15961 .Max => stored_val.numberMax (operand_val, target),
15962 .Min => stored_val.numberMin (operand_val, target),
1596915963 // zig fmt: on
1597015964 };
1597115965 try sema.storePtrVal(block, src, ptr_val, new_val, elem_ty);
......@@ -18890,18 +18884,13 @@ fn coerce(
1889018884 .{ val.fmtValue(inst_ty, sema.mod), dest_ty.fmt(sema.mod) },
1889118885 );
1889218886 }
18893 const result_val = val.floatToInt(sema.arena, inst_ty, dest_ty, target) catch |err| switch (err) {
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 };
18887 const result_val = try sema.floatToInt(block, inst_src, val, inst_ty, dest_ty);
1889918888 return try sema.addConstant(dest_ty, result_val);
1890018889 },
1890118890 .Int, .ComptimeInt => {
1890218891 if (try sema.resolveDefinedValue(block, inst_src, inst)) |val| {
1890318892 // comptime known integer to other number
18904 if (!val.intFitsInType(dest_ty, target)) {
18893 if (!(try sema.intFitsInType(block, inst_src, val, dest_ty))) {
1890518894 return sema.fail(block, inst_src, "type {} cannot represent integer value {}", .{ dest_ty.fmt(sema.mod), val.fmtValue(inst_ty, sema.mod) });
1890618895 }
1890718896 return try sema.addConstant(dest_ty, val);
......@@ -21093,7 +21082,7 @@ fn analyzeSlice(
2109321082 sema.arena,
2109421083 array_ty.arrayLenIncludingSentinel(),
2109521084 );
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)) {
2109721086 const sentinel_label: []const u8 = if (array_ty.sentinel() != null)
2109821087 " +1 (sentinel)"
2109921088 else
......@@ -21133,7 +21122,7 @@ fn analyzeSlice(
2113321122 .data = slice_val.sliceLen(mod) + @boolToInt(has_sentinel),
2113421123 };
2113521124 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)) {
2113721126 const sentinel_label: []const u8 = if (has_sentinel)
2113821127 " +1 (sentinel)"
2113921128 else
......@@ -21191,7 +21180,7 @@ fn analyzeSlice(
2119121180 // requirement: start <= end
2119221181 if (try sema.resolveDefinedValue(block, src, end)) |end_val| {
2119321182 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)) {
2119521184 return sema.fail(
2119621185 block,
2119721186 start_src,
......@@ -21399,11 +21388,11 @@ fn cmpNumeric(
2139921388 // a signed integer with mantissa bits + 1, and if there was any non-integral part of the float,
2140021389 // add/subtract 1.
2140121390 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)))
2140321392 else
2140421393 (lhs_ty.isRuntimeFloat() or lhs_ty.isSignedInt());
2140521394 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)))
2140721396 else
2140821397 (rhs_ty.isRuntimeFloat() or rhs_ty.isSignedInt());
2140921398 const dest_int_is_signed = lhs_is_signed or rhs_is_signed;
......@@ -21541,7 +21530,7 @@ fn cmpVector(
2154121530 if (lhs_val.isUndef() or rhs_val.isUndef()) {
2154221531 return sema.addConstUndef(result_ty);
2154321532 }
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);
2154521534 return sema.addConstant(result_ty, cmp_val);
2154621535 } else {
2154721536 break :src rhs_src;
......@@ -22904,8 +22893,6 @@ fn semaUnionFields(block: *Block, mod: *Module, union_obj: *Module.Union) Compil
2290422893 enum_field_names = &union_obj.tag_ty.castTag(.enum_simple).?.data.fields;
2290522894 }
2290622895
22907 const target = sema.mod.getTarget();
22908
2290922896 const bits_per_field = 4;
2291022897 const fields_per_u32 = 32 / bits_per_field;
2291122898 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
2296922956 });
2297022957 } else {
2297122958 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)
2297322960 else
2297422961 Value.zero;
2297522962 last_tag_val = val;
......@@ -24119,3 +24106,707 @@ fn queueFullTypeResolution(sema: *Sema, ty: Type) !void {
2411924106 const inst_ref = try sema.addType(ty);
2412024107 try sema.types_to_resolve.append(sema.gpa, inst_ref);
2412124108}
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(
232232 const x = sub_ty.abiAlignment(target);
233233 return writer.print("{d}", .{x});
234234 },
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 },
235240 .function => return writer.print("(function '{s}')", .{
236241 mod.declPtr(val.castTag(.function).?.data.owner_decl).name,
237242 }),
src/type.zig+154-137
......@@ -2760,7 +2760,7 @@ pub const Type = extern union {
27602760 .sema_kit => |sk| sk,
27612761 else => null,
27622762 };
2763 return switch (ty.tag()) {
2763 switch (ty.tag()) {
27642764 .u1,
27652765 .u8,
27662766 .i8,
......@@ -3028,7 +3028,7 @@ pub const Type = extern union {
30283028 => unreachable,
30293029
30303030 .generic_poison => unreachable,
3031 };
3031 }
30323032 }
30333033
30343034 pub fn abiAlignmentAdvancedUnion(
......@@ -3076,10 +3076,37 @@ pub const Type = extern union {
30763076 return AbiAlignmentAdvanced{ .scalar = max_align };
30773077 }
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
30793087 /// Asserts the type has the ABI size already resolved.
30803088 /// Types that return false for hasRuntimeBits() return 0.
3081 pub fn abiSize(self: Type, target: Target) u64 {
3082 return switch (self.tag()) {
3089 pub fn abiSize(ty: Type, target: Target) u64 {
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()) {
30833110 .fn_noreturn_no_args => unreachable, // represents machine code; not a pointer
30843111 .fn_void_no_args => unreachable, // represents machine code; not a pointer
30853112 .fn_naked_noreturn_no_args => unreachable, // represents machine code; not a pointer
......@@ -3109,32 +3136,59 @@ pub const Type = extern union {
31093136 .empty_struct_literal,
31103137 .empty_struct,
31113138 .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()) {
31153142 .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 }
31173153 var buf: Type.Payload.Bits = undefined;
31183154 const int_ty = struct_obj.packedIntegerType(target, &buf);
3119 return int_ty.abiSize(target);
3155 return AbiSizeAdvanced{ .scalar = int_ty.abiSize(target) };
31203156 },
31213157 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();
31233171 if (field_count == 0) {
3124 return 0;
3172 return AbiSizeAdvanced{ .scalar = 0 };
31253173 }
3126 return self.structFieldOffset(field_count, target);
3174 return AbiSizeAdvanced{ .scalar = ty.structFieldOffset(field_count, target) };
31273175 },
31283176 },
31293177
31303178 .enum_simple, .enum_full, .enum_nonexhaustive, .enum_numbered => {
31313179 var buffer: Payload.Bits = undefined;
3132 const int_tag_ty = self.intTagType(&buffer);
3133 return int_tag_ty.abiSize(target);
3180 const int_tag_ty = ty.intTagType(&buffer);
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);
31343191 },
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
31393193 .u1,
31403194 .u8,
......@@ -3146,21 +3200,31 @@ pub const Type = extern union {
31463200 .address_space,
31473201 .float_mode,
31483202 .reduce_op,
3149 => return 1,
3203 => return AbiSizeAdvanced{ .scalar = 1 },
31503204
3151 .array_u8 => self.castTag(.array_u8).?.data,
3152 .array_u8_sentinel_0 => self.castTag(.array_u8_sentinel_0).?.data + 1,
3205 .array_u8 => return AbiSizeAdvanced{ .scalar = ty.castTag(.array_u8).?.data },
3206 .array_u8_sentinel_0 => return AbiSizeAdvanced{ .scalar = ty.castTag(.array_u8_sentinel_0).?.data + 1 },
31533207 .array, .vector => {
3154 const payload = self.cast(Payload.Array).?.data;
3155 const elem_size = payload.elem_type.abiSize(target);
3156 assert(elem_size >= payload.elem_type.abiAlignment(target));
3157 return payload.len * elem_size;
3208 const payload = ty.cast(Payload.Array).?.data;
3209 switch (try payload.elem_type.abiSizeAdvanced(target, strat)) {
3210 .scalar => |elem_size| return AbiSizeAdvanced{ .scalar = 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 }
31583217 },
31593218 .array_sentinel => {
3160 const payload = self.castTag(.array_sentinel).?.data;
3161 const elem_size = payload.elem_type.abiSize(target);
3162 assert(elem_size >= payload.elem_type.abiAlignment(target));
3163 return (payload.len + 1) * elem_size;
3219 const payload = ty.castTag(.array_sentinel).?.data;
3220 switch (try payload.elem_type.abiSizeAdvanced(target, strat)) {
3221 .scalar => |elem_size| return AbiSizeAdvanced{ .scalar = (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 }
31643228 },
31653229
31663230 .isize,
......@@ -3178,95 +3242,96 @@ pub const Type = extern union {
31783242 .manyptr_u8,
31793243 .manyptr_const_u8,
31803244 .manyptr_const_u8_sentinel_0,
3181 => return @divExact(target.cpu.arch.ptrBitWidth(), 8),
3245 => return AbiSizeAdvanced{ .scalar = @divExact(target.cpu.arch.ptrBitWidth(), 8) },
31823246
31833247 .const_slice,
31843248 .mut_slice,
31853249 .const_slice_u8,
31863250 .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) {
3190 .Slice => @divExact(target.cpu.arch.ptrBitWidth(), 8) * 2,
3191 else => @divExact(target.cpu.arch.ptrBitWidth(), 8),
3253 .pointer => switch (ty.castTag(.pointer).?.data.size) {
3254 .Slice => return AbiSizeAdvanced{ .scalar = @divExact(target.cpu.arch.ptrBitWidth(), 8) * 2 },
3255 else => return AbiSizeAdvanced{ .scalar = @divExact(target.cpu.arch.ptrBitWidth(), 8) },
31923256 },
31933257
3194 .c_short => return @divExact(CType.short.sizeInBits(target), 8),
3195 .c_ushort => return @divExact(CType.ushort.sizeInBits(target), 8),
3196 .c_int => return @divExact(CType.int.sizeInBits(target), 8),
3197 .c_uint => return @divExact(CType.uint.sizeInBits(target), 8),
3198 .c_long => return @divExact(CType.long.sizeInBits(target), 8),
3199 .c_ulong => return @divExact(CType.ulong.sizeInBits(target), 8),
3200 .c_longlong => return @divExact(CType.longlong.sizeInBits(target), 8),
3201 .c_ulonglong => return @divExact(CType.ulonglong.sizeInBits(target), 8),
3258 .c_short => return AbiSizeAdvanced{ .scalar = @divExact(CType.short.sizeInBits(target), 8) },
3259 .c_ushort => return AbiSizeAdvanced{ .scalar = @divExact(CType.ushort.sizeInBits(target), 8) },
3260 .c_int => return AbiSizeAdvanced{ .scalar = @divExact(CType.int.sizeInBits(target), 8) },
3261 .c_uint => return AbiSizeAdvanced{ .scalar = @divExact(CType.uint.sizeInBits(target), 8) },
3262 .c_long => return AbiSizeAdvanced{ .scalar = @divExact(CType.long.sizeInBits(target), 8) },
3263 .c_ulong => return AbiSizeAdvanced{ .scalar = @divExact(CType.ulong.sizeInBits(target), 8) },
3264 .c_longlong => return AbiSizeAdvanced{ .scalar = @divExact(CType.longlong.sizeInBits(target), 8) },
3265 .c_ulonglong => return AbiSizeAdvanced{ .scalar = @divExact(CType.ulonglong.sizeInBits(target), 8) },
32023266
3203 .f16 => return 2,
3204 .f32 => return 4,
3205 .f64 => return 8,
3206 .f128 => return 16,
3267 .f16 => return AbiSizeAdvanced{ .scalar = 2 },
3268 .f32 => return AbiSizeAdvanced{ .scalar = 4 },
3269 .f64 => return AbiSizeAdvanced{ .scalar = 8 },
3270 .f128 => return AbiSizeAdvanced{ .scalar = 16 },
32073271
32083272 .f80 => switch (target.cpu.arch) {
3209 .i386 => return 12,
3210 .x86_64 => return 16,
3273 .i386 => return AbiSizeAdvanced{ .scalar = 12 },
3274 .x86_64 => return AbiSizeAdvanced{ .scalar = 16 },
32113275 else => {
32123276 var payload: Payload.Bits = .{
32133277 .base = .{ .tag = .int_unsigned },
32143278 .data = 80,
32153279 };
32163280 const u80_ty = initPayload(&payload.base);
3217 return abiSize(u80_ty, target);
3281 return AbiSizeAdvanced{ .scalar = abiSize(u80_ty, target) };
32183282 },
32193283 },
32203284 .c_longdouble => switch (CType.longdouble.sizeInBits(target)) {
3221 16 => return abiSize(Type.f16, target),
3222 32 => return abiSize(Type.f32, target),
3223 64 => return abiSize(Type.f64, target),
3224 80 => return abiSize(Type.f80, target),
3225 128 => return abiSize(Type.f128, target),
3285 16 => return AbiSizeAdvanced{ .scalar = abiSize(Type.f16, target) },
3286 32 => return AbiSizeAdvanced{ .scalar = abiSize(Type.f32, target) },
3287 64 => return AbiSizeAdvanced{ .scalar = abiSize(Type.f64, target) },
3288 80 => return AbiSizeAdvanced{ .scalar = abiSize(Type.f80, target) },
3289 128 => return AbiSizeAdvanced{ .scalar = abiSize(Type.f128, target) },
32263290 else => unreachable,
32273291 },
32283292
3293 // TODO revisit this when we have the concept of the error tag type
32293294 .error_set,
32303295 .error_set_single,
32313296 .anyerror_void_error_union,
32323297 .anyerror,
32333298 .error_set_inferred,
32343299 .error_set_merged,
3235 => return 2, // TODO revisit this when we have the concept of the error tag type
3300 => return AbiSizeAdvanced{ .scalar = 2 },
32363301
3237 .i16, .u16 => return intAbiSize(16, target),
3238 .i32, .u32 => return intAbiSize(32, target),
3239 .i64, .u64 => return intAbiSize(64, target),
3240 .u128, .i128 => return intAbiSize(128, target),
3302 .i16, .u16 => return AbiSizeAdvanced{ .scalar = intAbiSize(16, target) },
3303 .i32, .u32 => return AbiSizeAdvanced{ .scalar = intAbiSize(32, target) },
3304 .i64, .u64 => return AbiSizeAdvanced{ .scalar = intAbiSize(64, target) },
3305 .u128, .i128 => return AbiSizeAdvanced{ .scalar = intAbiSize(128, target) },
32413306 .int_signed, .int_unsigned => {
3242 const bits: u16 = self.cast(Payload.Bits).?.data;
3243 if (bits == 0) return 0;
3244 return intAbiSize(bits, target);
3307 const bits: u16 = ty.cast(Payload.Bits).?.data;
3308 if (bits == 0) return AbiSizeAdvanced{ .scalar = 0 };
3309 return AbiSizeAdvanced{ .scalar = intAbiSize(bits, target) };
32453310 },
32463311
32473312 .optional => {
32483313 var buf: Payload.ElemType = undefined;
3249 const child_type = self.optionalChild(&buf);
3250 if (!child_type.hasRuntimeBits()) return 1;
3314 const child_type = ty.optionalChild(&buf);
3315 if (!child_type.hasRuntimeBits()) return AbiSizeAdvanced{ .scalar = 1 };
32513316
32523317 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
32553320 // Optional types are represented as a struct with the child type as the first
32563321 // field and a boolean as the second. Since the child type's abi alignment is
32573322 // guaranteed to be >= that of bool's (1 byte) the added size is exactly equal
32583323 // 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) };
32603325 },
32613326
32623327 .error_union => {
3263 const data = self.castTag(.error_union).?.data;
3328 const data = ty.castTag(.error_union).?.data;
32643329 if (!data.error_set.hasRuntimeBits() and !data.payload.hasRuntimeBits()) {
3265 return 0;
3330 return AbiSizeAdvanced{ .scalar = 0 };
32663331 } else if (!data.error_set.hasRuntimeBits()) {
3267 return data.payload.abiSize(target);
3332 return AbiSizeAdvanced{ .scalar = data.payload.abiSize(target) };
32683333 } else if (!data.payload.hasRuntimeBits()) {
3269 return data.error_set.abiSize(target);
3334 return AbiSizeAdvanced{ .scalar = data.error_set.abiSize(target) };
32703335 }
32713336 const code_align = abiAlignment(data.error_set, target);
32723337 const payload_align = abiAlignment(data.payload, target);
......@@ -3278,9 +3343,28 @@ pub const Type = extern union {
32783343 size = std.mem.alignForwardGeneric(u64, size, payload_align);
32793344 size += payload_size;
32803345 size = std.mem.alignForwardGeneric(u64, size, big_align);
3281 return size;
3346 return AbiSizeAdvanced{ .scalar = size };
32823347 },
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) };
32843368 }
32853369
32863370 fn intAbiSize(bits: u16, target: Target) u64 {
......@@ -5448,73 +5532,6 @@ pub const Type = extern union {
54485532 }
54495533 }
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
55185535 /// This enum does not directly correspond to `std.builtin.TypeId` because
55195536 /// it has extra enum tags in it, as a way of using less memory. For example,
55205537 /// 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 {
179179 bound_fn,
180180 /// The ABI alignment of the payload type.
181181 lazy_align,
182 /// The ABI alignment of the payload type.
183 lazy_size,
182184
183185 pub const last_no_payload_tag = Tag.empty_array;
184186 pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;
......@@ -289,6 +291,7 @@ pub const Value = extern union {
289291
290292 .ty,
291293 .lazy_align,
294 .lazy_size,
292295 => Payload.Ty,
293296
294297 .int_type => Payload.IntType,
......@@ -460,7 +463,7 @@ pub const Value = extern union {
460463 .bound_fn,
461464 => unreachable,
462465
463 .ty, .lazy_align => {
466 .ty, .lazy_align, .lazy_size => {
464467 const payload = self.cast(Payload.Ty).?;
465468 const new_payload = try arena.create(Payload.Ty);
466469 new_payload.* = .{
......@@ -720,6 +723,11 @@ pub const Value = extern union {
720723 try val.castTag(.lazy_align).?.data.dump("", options, out_stream);
721724 return try out_stream.writeAll(")");
722725 },
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 },
723731 .int_type => {
724732 const int_type = val.castTag(.int_type).?.data;
725733 return out_stream.print("{s}{d}", .{
......@@ -1040,6 +1048,14 @@ pub const Value = extern union {
10401048 const x = ty.abiAlignment(target);
10411049 return BigIntMutable.init(&space.limbs, x).toConst();
10421050 },
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
10441060 .elem_ptr => {
10451061 const elem_ptr = val.castTag(.elem_ptr).?.data;
......@@ -1087,6 +1103,14 @@ pub const Value = extern union {
10871103 return ty.abiAlignment(target);
10881104 }
10891105 },
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
10911115 else => return null,
10921116 }
......@@ -1670,118 +1694,6 @@ pub const Value = extern union {
16701694 }
16711695 }
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
17851697 /// Converts an integer or a float to a float. May result in a loss of information.
17861698 /// Caller can find out by equality checking the result against the operand.
17871699 pub fn floatCast(self: Value, arena: Allocator, dest_ty: Type, target: Target) !Value {
......@@ -1849,6 +1761,14 @@ pub const Value = extern union {
18491761 return .eq;
18501762 }
18511763 },
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
18531773 .float_16 => std.math.order(lhs.castTag(.float_16).?.data, 0),
18541774 .float_32 => std.math.order(lhs.castTag(.float_32).?.data, 0),
......@@ -1992,38 +1912,28 @@ pub const Value = extern union {
19921912 };
19931913 }
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
20131915 /// Asserts the value is comparable.
20141916 /// Vector results will be reduced with AND.
20151917 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 {
20161926 switch (lhs.tag()) {
2017 .repeated => return lhs.castTag(.repeated).?.data.compareWithZero(op),
1927 .repeated => return lhs.castTag(.repeated).?.data.compareWithZeroAdvanced(op, sema_kit),
20181928 .aggregate => {
20191929 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;
20211931 }
20221932 return true;
20231933 },
20241934 else => {},
20251935 }
2026 return orderAgainstZero(lhs).compare(op);
1936 return (try orderAgainstZeroAdvanced(lhs, sema_kit)).compare(op);
20271937 }
20281938
20291939 /// This function is used by hash maps and so treats floating-point NaNs as equal
......@@ -2032,9 +1942,20 @@ pub const Value = extern union {
20321942 /// This function has to be able to support implicit coercion of `a` to `ty`. That is,
20331943 /// `ty` will be an exactly correct Type for `b` but it may be a post-coerced Type
20341944 /// 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 - specifically
1945 /// is required in order to make generic function instantiation efficient - specifically
20361946 /// the insertion into the monomorphized function table.
20371947 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 {
20381959 const target = mod.getTarget();
20391960 const a_tag = a.tag();
20401961 const b_tag = b.tag();
......@@ -2055,31 +1976,33 @@ pub const Value = extern union {
20551976 const a_payload = a.castTag(.opt_payload).?.data;
20561977 const b_payload = b.castTag(.opt_payload).?.data;
20571978 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);
20591980 },
20601981 .slice => {
20611982 const a_payload = a.castTag(.slice).?.data;
20621983 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
20651988 var ptr_buf: Type.SlicePtrFieldTypeBuffer = undefined;
20661989 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);
20691992 },
20701993 .elem_ptr => {
20711994 const a_payload = a.castTag(.elem_ptr).?.data;
20721995 const b_payload = b.castTag(.elem_ptr).?.data;
20731996 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);
20761999 },
20772000 .field_ptr => {
20782001 const a_payload = a.castTag(.field_ptr).?.data;
20792002 const b_payload = b.castTag(.field_ptr).?.data;
20802003 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);
20832006 },
20842007 .@"error" => {
20852008 const a_name = a.castTag(.@"error").?.data.name;
......@@ -2089,7 +2012,7 @@ pub const Value = extern union {
20892012 .eu_payload => {
20902013 const a_payload = a.castTag(.eu_payload).?.data;
20912014 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);
20932016 },
20942017 .eu_payload_ptr => @panic("TODO: Implement more pointer eql cases"),
20952018 .opt_payload_ptr => @panic("TODO: Implement more pointer eql cases"),
......@@ -2107,7 +2030,9 @@ pub const Value = extern union {
21072030 const types = ty.tupleFields().types;
21082031 assert(types.len == a_field_vals.len);
21092032 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 }
21112036 }
21122037 return true;
21132038 }
......@@ -2116,7 +2041,9 @@ pub const Value = extern union {
21162041 const fields = ty.structFields().values();
21172042 assert(fields.len == a_field_vals.len);
21182043 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 }
21202047 }
21212048 return true;
21222049 }
......@@ -2125,7 +2052,9 @@ pub const Value = extern union {
21252052 for (a_field_vals) |a_elem, i| {
21262053 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 }
21292058 }
21302059 return true;
21312060 },
......@@ -2135,7 +2064,7 @@ pub const Value = extern union {
21352064 switch (ty.containerLayout()) {
21362065 .Packed, .Extern => {
21372066 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))) {
21392068 // In this case, we must disregard mismatching tags and compare
21402069 // based on the in-memory bytes of the payloads.
21412070 @panic("TODO comptime comparison of extern union values with mismatching tags");
......@@ -2143,13 +2072,13 @@ pub const Value = extern union {
21432072 },
21442073 .Auto => {
21452074 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))) {
21472076 return false;
21482077 }
21492078 },
21502079 }
21512080 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);
21532082 },
21542083 else => {},
21552084 } else if (a_tag == .null_value or b_tag == .null_value) {
......@@ -2183,7 +2112,7 @@ pub const Value = extern union {
21832112 const b_val = b.enumToInt(ty, &buf_b);
21842113 var buf_ty: Type.Payload.Bits = undefined;
21852114 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);
21872116 },
21882117 .Array, .Vector => {
21892118 const len = ty.arrayLen();
......@@ -2194,7 +2123,9 @@ pub const Value = extern union {
21942123 while (i < len) : (i += 1) {
21952124 const a_elem = elemValueBuffer(a, mod, i, &a_buf);
21962125 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 }
21982129 }
21992130 return true;
22002131 },
......@@ -2218,12 +2149,12 @@ pub const Value = extern union {
22182149 .base = .{ .tag = .opt_payload },
22192150 .data = a,
22202151 };
2221 return eql(Value.initPayload(&buffer.base), b, ty, mod);
2152 return eqlAdvanced(Value.initPayload(&buffer.base), b, ty, mod, sema_kit);
22222153 }
22232154 },
22242155 else => {},
22252156 }
2226 return order(a, b, target).compare(.eq);
2157 return (try orderAdvanced(a, b, target, sema_kit)).compare(.eq);
22272158 }
22282159
22292160 /// This function is used by hash maps and so treats floating-point NaNs as equal
......@@ -2502,6 +2433,7 @@ pub const Value = extern union {
25022433 .bool_true,
25032434 .the_only_possible_value,
25042435 .lazy_align,
2436 .lazy_size,
25052437 => return hashInt(ptr_val, hasher, target),
25062438
25072439 else => unreachable,
......@@ -2882,54 +2814,6 @@ pub const Value = extern union {
28822814 }
28832815 }
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
29332817 fn calcLimbLenFloat(scalar: anytype) usize {
29342818 if (scalar == 0) {
29352819 return 1;
......@@ -2945,96 +2829,7 @@ pub const Value = extern union {
29452829 wrapped_result: Value,
29462830 };
29472831
2948 pub fn intAddWithOverflow(
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 {
2832 pub fn fromBigInt(arena: Allocator, big_int: BigIntConst) !Value {
30382833 if (big_int.positive) {
30392834 if (big_int.to(u64)) |x| {
30402835 return Value.Tag.int_u64.create(arena, x);
......@@ -3094,95 +2889,6 @@ pub const Value = extern union {
30942889 return fromBigInt(arena, result_bigint.toConst());
30952890 }
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
31862892 /// Supports (vectors of) integers only; asserts neither operand is undefined.
31872893 pub fn intSubSat(
31882894 lhs: Value,
......@@ -3559,60 +3265,6 @@ pub const Value = extern union {
35593265 return fromBigInt(arena, result_bigint.toConst());
35603266 }
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
36163268 pub fn intDiv(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, target: Target) !Value {
36173269 if (ty.zigTypeTag() == .Vector) {
36183270 const result_data = try allocator.alloc(Value, ty.vectorLen());
......@@ -4129,114 +3781,6 @@ pub const Value = extern union {
41293781 return fromBigInt(allocator, result_bigint.toConst());
41303782 }
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
42403784 pub fn floatNeg(
42413785 val: Value,
42423786 float_type: Type,
test/behavior/sizeof_and_typeof.zig-2
......@@ -169,8 +169,6 @@ test "@bitOffsetOf" {
169169}
170170
171171test "@sizeOf(T) == 0 doesn't force resolving struct size" {
172 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
173
174172 const S = struct {
175173 const Foo = struct {
176174 y: if (@sizeOf(Foo) == 0) u64 else u32,