authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-05-20 18:35:19-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-05-20 18:35:19-04:00
log1a92264b3d3f3e14f9a3b724fccefb5f5a38346f
treebf2447d9fed7334cbe1a909398f53396879a8609
parent704d38ba4981d46ac1d4687d8f6dcce72bf4067c
parentfcd4efd8ecda01fe06735ed8b7e2cd2aa93daa19
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #11671 from ziglang/stage2-behavior

stage2 bug fixes aimed towards more behavior tests passing

10 files changed, 1162 insertions(+), 847 deletions(-)

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