authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-12-21 11:28:40-08:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2021-12-21 11:28:40-08:00
log8df540aeef33b9b02e98aebe311299c101ce44b9
tree95e6f1de6f6225ebb2e254ec9421240ec52af338
parent7e16bb36d82cf45cd5f6f4da38fba512554f66ed
parente106e18d96595bdc4bc037e0b36900992a576160
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #10370 from Snektron/stage2-inferred-error-sets-2

stage2: Make page_allocator work

21 files changed, 1158 insertions(+), 381 deletions(-)

lib/std/math/big/int.zig+23-13
...@@ -443,12 +443,12 @@ pub const Mutable = struct {...@@ -443,12 +443,12 @@ pub const Mutable = struct {
443 }443 }
444 }444 }
445445
446 /// r = a + b with 2s-complement wrapping semantics.446 /// r = a + b with 2s-complement wrapping semantics. Returns whether overflow occurred.
447 /// r, a and b may be aliases447 /// r, a and b may be aliases
448 ///448 ///
449 /// Asserts the result fits in `r`. An upper bound on the number of limbs needed by449 /// Asserts the result fits in `r`. An upper bound on the number of limbs needed by
450 /// r is `calcTwosCompLimbCount(bit_count)`.450 /// r is `calcTwosCompLimbCount(bit_count)`.
451 pub fn addWrap(r: *Mutable, a: Const, b: Const, signedness: Signedness, bit_count: usize) void {451 pub fn addWrap(r: *Mutable, a: Const, b: Const, signedness: Signedness, bit_count: usize) bool {
452 const req_limbs = calcTwosCompLimbCount(bit_count);452 const req_limbs = calcTwosCompLimbCount(bit_count);
453453
454 // Slice of the upper bits if they exist, these will be ignored and allows us to use addCarry to determine454 // Slice of the upper bits if they exist, these will be ignored and allows us to use addCarry to determine
...@@ -463,6 +463,7 @@ pub const Mutable = struct {...@@ -463,6 +463,7 @@ pub const Mutable = struct {
463 .limbs = b.limbs[0..math.min(req_limbs, b.limbs.len)],463 .limbs = b.limbs[0..math.min(req_limbs, b.limbs.len)],
464 };464 };
465465
466 var carry_truncated = false;
466 if (r.addCarry(x, y)) {467 if (r.addCarry(x, y)) {
467 // There are two possibilities here:468 // There are two possibilities here:
468 // - We overflowed req_limbs. In this case, the carry is ignored, as it would be removed by469 // - We overflowed req_limbs. In this case, the carry is ignored, as it would be removed by
...@@ -473,10 +474,17 @@ pub const Mutable = struct {...@@ -473,10 +474,17 @@ pub const Mutable = struct {
473 if (msl < req_limbs) {474 if (msl < req_limbs) {
474 r.limbs[msl] = 1;475 r.limbs[msl] = 1;
475 r.len = req_limbs;476 r.len = req_limbs;
477 } else {
478 carry_truncated = true;
476 }479 }
477 }480 }
478481
479 r.truncate(r.toConst(), signedness, bit_count);482 if (!r.toConst().fitsInTwosComp(signedness, bit_count)) {
483 r.truncate(r.toConst(), signedness, bit_count);
484 return true;
485 }
486
487 return carry_truncated;
480 }488 }
481489
482 /// r = a + b with 2s-complement saturating semantics.490 /// r = a + b with 2s-complement saturating semantics.
...@@ -581,13 +589,13 @@ pub const Mutable = struct {...@@ -581,13 +589,13 @@ pub const Mutable = struct {
581 r.add(a, b.negate());589 r.add(a, b.negate());
582 }590 }
583591
584 /// r = a - b with 2s-complement wrapping semantics.592 /// r = a - b with 2s-complement wrapping semantics. Returns whether any overflow occured.
585 ///593 ///
586 /// r, a and b may be aliases594 /// r, a and b may be aliases
587 /// Asserts the result fits in `r`. An upper bound on the number of limbs needed by595 /// Asserts the result fits in `r`. An upper bound on the number of limbs needed by
588 /// r is `calcTwosCompLimbCount(bit_count)`.596 /// r is `calcTwosCompLimbCount(bit_count)`.
589 pub fn subWrap(r: *Mutable, a: Const, b: Const, signedness: Signedness, bit_count: usize) void {597 pub fn subWrap(r: *Mutable, a: Const, b: Const, signedness: Signedness, bit_count: usize) bool {
590 r.addWrap(a, b.negate(), signedness, bit_count);598 return r.addWrap(a, b.negate(), signedness, bit_count);
591 }599 }
592600
593 /// r = a - b with 2s-complement saturating semantics.601 /// r = a - b with 2s-complement saturating semantics.
...@@ -1039,7 +1047,7 @@ pub const Mutable = struct {...@@ -1039,7 +1047,7 @@ pub const Mutable = struct {
1039 pub fn bitNotWrap(r: *Mutable, a: Const, signedness: Signedness, bit_count: usize) void {1047 pub fn bitNotWrap(r: *Mutable, a: Const, signedness: Signedness, bit_count: usize) void {
1040 r.copy(a.negate());1048 r.copy(a.negate());
1041 const negative_one = Const{ .limbs = &.{1}, .positive = false };1049 const negative_one = Const{ .limbs = &.{1}, .positive = false };
1042 r.addWrap(r.toConst(), negative_one, signedness, bit_count);1050 _ = r.addWrap(r.toConst(), negative_one, signedness, bit_count);
1043 }1051 }
10441052
1045 /// r = a | b under 2s complement semantics.1053 /// r = a | b under 2s complement semantics.
...@@ -2443,17 +2451,18 @@ pub const Managed = struct {...@@ -2443,17 +2451,18 @@ pub const Managed = struct {
2443 r.setMetadata(m.positive, m.len);2451 r.setMetadata(m.positive, m.len);
2444 }2452 }
24452453
2446 /// r = a + b with 2s-complement wrapping semantics.2454 /// r = a + b with 2s-complement wrapping semantics. Returns whether any overflow occured.
2447 ///2455 ///
2448 /// r, a and b may be aliases. If r aliases a or b, then caller must call2456 /// r, a and b may be aliases. If r aliases a or b, then caller must call
2449 /// `r.ensureTwosCompCapacity` prior to calling `add`.2457 /// `r.ensureTwosCompCapacity` prior to calling `add`.
2450 ///2458 ///
2451 /// Returns an error if memory could not be allocated.2459 /// Returns an error if memory could not be allocated.
2452 pub fn addWrap(r: *Managed, a: Const, b: Const, signedness: Signedness, bit_count: usize) Allocator.Error!void {2460 pub fn addWrap(r: *Managed, a: Const, b: Const, signedness: Signedness, bit_count: usize) Allocator.Error!bool {
2453 try r.ensureTwosCompCapacity(bit_count);2461 try r.ensureTwosCompCapacity(bit_count);
2454 var m = r.toMutable();2462 var m = r.toMutable();
2455 m.addWrap(a, b, signedness, bit_count);2463 const wrapped = m.addWrap(a, b, signedness, bit_count);
2456 r.setMetadata(m.positive, m.len);2464 r.setMetadata(m.positive, m.len);
2465 return wrapped;
2457 }2466 }
24582467
2459 /// r = a + b with 2s-complement saturating semantics.2468 /// r = a + b with 2s-complement saturating semantics.
...@@ -2481,17 +2490,18 @@ pub const Managed = struct {...@@ -2481,17 +2490,18 @@ pub const Managed = struct {
2481 r.setMetadata(m.positive, m.len);2490 r.setMetadata(m.positive, m.len);
2482 }2491 }
24832492
2484 /// r = a - b with 2s-complement wrapping semantics.2493 /// r = a - b with 2s-complement wrapping semantics. Returns whether any overflow occured.
2485 ///2494 ///
2486 /// r, a and b may be aliases. If r aliases a or b, then caller must call2495 /// r, a and b may be aliases. If r aliases a or b, then caller must call
2487 /// `r.ensureTwosCompCapacity` prior to calling `add`.2496 /// `r.ensureTwosCompCapacity` prior to calling `add`.
2488 ///2497 ///
2489 /// Returns an error if memory could not be allocated.2498 /// Returns an error if memory could not be allocated.
2490 pub fn subWrap(r: *Managed, a: Const, b: Const, signedness: Signedness, bit_count: usize) Allocator.Error!void {2499 pub fn subWrap(r: *Managed, a: Const, b: Const, signedness: Signedness, bit_count: usize) Allocator.Error!bool {
2491 try r.ensureTwosCompCapacity(bit_count);2500 try r.ensureTwosCompCapacity(bit_count);
2492 var m = r.toMutable();2501 var m = r.toMutable();
2493 m.subWrap(a, b, signedness, bit_count);2502 const wrapped = m.subWrap(a, b, signedness, bit_count);
2494 r.setMetadata(m.positive, m.len);2503 r.setMetadata(m.positive, m.len);
2504 return wrapped;
2495 }2505 }
24962506
2497 /// r = a - b with 2s-complement saturating semantics.2507 /// r = a - b with 2s-complement saturating semantics.
lib/std/math/big/int_test.zig+16-8
...@@ -590,8 +590,9 @@ test "big.int addWrap single-single, unsigned" {...@@ -590,8 +590,9 @@ test "big.int addWrap single-single, unsigned" {
590 var b = try Managed.initSet(testing.allocator, 10);590 var b = try Managed.initSet(testing.allocator, 10);
591 defer b.deinit();591 defer b.deinit();
592592
593 try a.addWrap(a.toConst(), b.toConst(), .unsigned, 17);593 const wrapped = try a.addWrap(a.toConst(), b.toConst(), .unsigned, 17);
594594
595 try testing.expect(wrapped);
595 try testing.expect((try a.to(u17)) == 9);596 try testing.expect((try a.to(u17)) == 9);
596}597}
597598
...@@ -602,8 +603,9 @@ test "big.int subWrap single-single, unsigned" {...@@ -602,8 +603,9 @@ test "big.int subWrap single-single, unsigned" {
602 var b = try Managed.initSet(testing.allocator, maxInt(u17));603 var b = try Managed.initSet(testing.allocator, maxInt(u17));
603 defer b.deinit();604 defer b.deinit();
604605
605 try a.subWrap(a.toConst(), b.toConst(), .unsigned, 17);606 const wrapped = try a.subWrap(a.toConst(), b.toConst(), .unsigned, 17);
606607
608 try testing.expect(wrapped);
607 try testing.expect((try a.to(u17)) == 1);609 try testing.expect((try a.to(u17)) == 1);
608}610}
609611
...@@ -614,8 +616,9 @@ test "big.int addWrap multi-multi, unsigned, limb aligned" {...@@ -614,8 +616,9 @@ test "big.int addWrap multi-multi, unsigned, limb aligned" {
614 var b = try Managed.initSet(testing.allocator, maxInt(DoubleLimb));616 var b = try Managed.initSet(testing.allocator, maxInt(DoubleLimb));
615 defer b.deinit();617 defer b.deinit();
616618
617 try a.addWrap(a.toConst(), b.toConst(), .unsigned, @bitSizeOf(DoubleLimb));619 const wrapped = try a.addWrap(a.toConst(), b.toConst(), .unsigned, @bitSizeOf(DoubleLimb));
618620
621 try testing.expect(wrapped);
619 try testing.expect((try a.to(DoubleLimb)) == maxInt(DoubleLimb) - 1);622 try testing.expect((try a.to(DoubleLimb)) == maxInt(DoubleLimb) - 1);
620}623}
621624
...@@ -626,8 +629,9 @@ test "big.int subWrap single-multi, unsigned, limb aligned" {...@@ -626,8 +629,9 @@ test "big.int subWrap single-multi, unsigned, limb aligned" {
626 var b = try Managed.initSet(testing.allocator, maxInt(DoubleLimb) + 100);629 var b = try Managed.initSet(testing.allocator, maxInt(DoubleLimb) + 100);
627 defer b.deinit();630 defer b.deinit();
628631
629 try a.subWrap(a.toConst(), b.toConst(), .unsigned, @bitSizeOf(DoubleLimb));632 const wrapped = try a.subWrap(a.toConst(), b.toConst(), .unsigned, @bitSizeOf(DoubleLimb));
630633
634 try testing.expect(wrapped);
631 try testing.expect((try a.to(DoubleLimb)) == maxInt(DoubleLimb) - 88);635 try testing.expect((try a.to(DoubleLimb)) == maxInt(DoubleLimb) - 88);
632}636}
633637
...@@ -638,8 +642,9 @@ test "big.int addWrap single-single, signed" {...@@ -638,8 +642,9 @@ test "big.int addWrap single-single, signed" {
638 var b = try Managed.initSet(testing.allocator, 1 + 1 + maxInt(u21));642 var b = try Managed.initSet(testing.allocator, 1 + 1 + maxInt(u21));
639 defer b.deinit();643 defer b.deinit();
640644
641 try a.addWrap(a.toConst(), b.toConst(), .signed, @bitSizeOf(i21));645 const wrapped = try a.addWrap(a.toConst(), b.toConst(), .signed, @bitSizeOf(i21));
642646
647 try testing.expect(wrapped);
643 try testing.expect((try a.to(i21)) == minInt(i21));648 try testing.expect((try a.to(i21)) == minInt(i21));
644}649}
645650
...@@ -650,8 +655,9 @@ test "big.int subWrap single-single, signed" {...@@ -650,8 +655,9 @@ test "big.int subWrap single-single, signed" {
650 var b = try Managed.initSet(testing.allocator, 1);655 var b = try Managed.initSet(testing.allocator, 1);
651 defer b.deinit();656 defer b.deinit();
652657
653 try a.subWrap(a.toConst(), b.toConst(), .signed, @bitSizeOf(i21));658 const wrapped = try a.subWrap(a.toConst(), b.toConst(), .signed, @bitSizeOf(i21));
654659
660 try testing.expect(wrapped);
655 try testing.expect((try a.to(i21)) == maxInt(i21));661 try testing.expect((try a.to(i21)) == maxInt(i21));
656}662}
657663
...@@ -662,8 +668,9 @@ test "big.int addWrap multi-multi, signed, limb aligned" {...@@ -662,8 +668,9 @@ test "big.int addWrap multi-multi, signed, limb aligned" {
662 var b = try Managed.initSet(testing.allocator, maxInt(SignedDoubleLimb));668 var b = try Managed.initSet(testing.allocator, maxInt(SignedDoubleLimb));
663 defer b.deinit();669 defer b.deinit();
664670
665 try a.addWrap(a.toConst(), b.toConst(), .signed, @bitSizeOf(SignedDoubleLimb));671 const wrapped = try a.addWrap(a.toConst(), b.toConst(), .signed, @bitSizeOf(SignedDoubleLimb));
666672
673 try testing.expect(wrapped);
667 try testing.expect((try a.to(SignedDoubleLimb)) == -2);674 try testing.expect((try a.to(SignedDoubleLimb)) == -2);
668}675}
669676
...@@ -674,8 +681,9 @@ test "big.int subWrap single-multi, signed, limb aligned" {...@@ -674,8 +681,9 @@ test "big.int subWrap single-multi, signed, limb aligned" {
674 var b = try Managed.initSet(testing.allocator, 1);681 var b = try Managed.initSet(testing.allocator, 1);
675 defer b.deinit();682 defer b.deinit();
676683
677 try a.subWrap(a.toConst(), b.toConst(), .signed, @bitSizeOf(SignedDoubleLimb));684 const wrapped = try a.subWrap(a.toConst(), b.toConst(), .signed, @bitSizeOf(SignedDoubleLimb));
678685
686 try testing.expect(wrapped);
679 try testing.expect((try a.to(SignedDoubleLimb)) == maxInt(SignedDoubleLimb));687 try testing.expect((try a.to(SignedDoubleLimb)) == maxInt(SignedDoubleLimb));
680}688}
681689
lib/std/os.zig+5-1
...@@ -4968,7 +4968,11 @@ pub fn toPosixPath(file_path: []const u8) ![MAX_PATH_BYTES - 1:0]u8 {...@@ -4968,7 +4968,11 @@ pub fn toPosixPath(file_path: []const u8) ![MAX_PATH_BYTES - 1:0]u8 {
4968/// if this happens the fix is to add the error code to the corresponding4968/// if this happens the fix is to add the error code to the corresponding
4969/// switch expression, possibly introduce a new error in the error set, and4969/// switch expression, possibly introduce a new error in the error set, and
4970/// send a patch to Zig.4970/// send a patch to Zig.
4971pub const unexpected_error_tracing = builtin.mode == .Debug;4971/// The self-hosted compiler is not fully capable of handle the related code.
4972/// Until then, unexpected error tracing is disabled for the self-hosted compiler.
4973/// TODO remove this once self-hosted is capable enough to handle printing and
4974/// stack trace dumping.
4975pub const unexpected_error_tracing = !builtin.zig_is_stage2 and builtin.mode == .Debug;
49724976
4973pub const UnexpectedError = error{4977pub const UnexpectedError = error{
4974 /// The Operating System returned an undocumented error code.4978 /// The Operating System returned an undocumented error code.
src/Air.zig+34
...@@ -135,6 +135,30 @@ pub const Inst = struct {...@@ -135,6 +135,30 @@ pub const Inst = struct {
135 /// is the same as both operands.135 /// is the same as both operands.
136 /// Uses the `bin_op` field.136 /// Uses the `bin_op` field.
137 min,137 min,
138 /// Integer addition with overflow. Both operands are guaranteed to be the same type,
139 /// and the result is bool. The wrapped value is written to the pointer given by the in
140 /// operand of the `pl_op` field. Payload is `Bin` with `lhs` and `rhs` the relevant types
141 /// of the operation.
142 /// Uses the `pl_op` field with payload `Bin`.
143 add_with_overflow,
144 /// Integer subtraction with overflow. Both operands are guaranteed to be the same type,
145 /// and the result is bool. The wrapped value is written to the pointer given by the in
146 /// operand of the `pl_op` field. Payload is `Bin` with `lhs` and `rhs` the relevant types
147 /// of the operation.
148 /// Uses the `pl_op` field with payload `Bin`.
149 sub_with_overflow,
150 /// Integer multiplication with overflow. Both operands are guaranteed to be the same type,
151 /// and the result is bool. The wrapped value is written to the pointer given by the in
152 /// operand of the `pl_op` field. Payload is `Bin` with `lhs` and `rhs` the relevant types
153 /// of the operation.
154 /// Uses the `pl_op` field with payload `Bin`.
155 mul_with_overflow,
156 /// Integer left-shift with overflow. Both operands are guaranteed to be the same type,
157 /// and the result is bool. The wrapped value is written to the pointer given by the in
158 /// operand of the `pl_op` field. Payload is `Bin` with `lhs` and `rhs` the relevant types
159 /// of the operation.
160 /// Uses the `pl_op` field with payload `Bin`.
161 shl_with_overflow,
138 /// Allocates stack local memory.162 /// Allocates stack local memory.
139 /// Uses the `ty` field.163 /// Uses the `ty` field.
140 alloc,164 alloc,
...@@ -189,6 +213,9 @@ pub const Inst = struct {...@@ -189,6 +213,9 @@ pub const Inst = struct {
189 /// Lowers to a hardware trap instruction, or the next best thing.213 /// Lowers to a hardware trap instruction, or the next best thing.
190 /// Result type is always void.214 /// Result type is always void.
191 breakpoint,215 breakpoint,
216 /// Yields the return address of the current function.
217 /// Uses the `no_op` field.
218 ret_addr,
192 /// Function call.219 /// Function call.
193 /// Result type is the return type of the function being called.220 /// Result type is the return type of the function being called.
194 /// Uses the `pl_op` field with the `Call` payload. operand is the callee.221 /// Uses the `pl_op` field with the `Call` payload. operand is the callee.
...@@ -779,6 +806,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {...@@ -779,6 +806,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
779806
780 .ptrtoint,807 .ptrtoint,
781 .slice_len,808 .slice_len,
809 .ret_addr,
782 => return Type.initTag(.usize),810 => return Type.initTag(.usize),
783811
784 .bool_to_int => return Type.initTag(.u1),812 .bool_to_int => return Type.initTag(.u1),
...@@ -804,6 +832,12 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {...@@ -804,6 +832,12 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
804 const ptr_ty = air.typeOf(datas[inst].pl_op.operand);832 const ptr_ty = air.typeOf(datas[inst].pl_op.operand);
805 return ptr_ty.elemType();833 return ptr_ty.elemType();
806 },834 },
835
836 .add_with_overflow,
837 .sub_with_overflow,
838 .mul_with_overflow,
839 .shl_with_overflow,
840 => return Type.initTag(.bool),
807 }841 }
808}842}
809843
src/AstGen.zig+24-13
...@@ -984,17 +984,17 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr...@@ -984,17 +984,17 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr
984984
985 .fn_proto_simple => {985 .fn_proto_simple => {
986 var params: [1]Ast.Node.Index = undefined;986 var params: [1]Ast.Node.Index = undefined;
987 return fnProtoExpr(gz, scope, rl, tree.fnProtoSimple(&params, node));987 return fnProtoExpr(gz, scope, rl, node, tree.fnProtoSimple(&params, node));
988 },988 },
989 .fn_proto_multi => {989 .fn_proto_multi => {
990 return fnProtoExpr(gz, scope, rl, tree.fnProtoMulti(node));990 return fnProtoExpr(gz, scope, rl, node, tree.fnProtoMulti(node));
991 },991 },
992 .fn_proto_one => {992 .fn_proto_one => {
993 var params: [1]Ast.Node.Index = undefined;993 var params: [1]Ast.Node.Index = undefined;
994 return fnProtoExpr(gz, scope, rl, tree.fnProtoOne(&params, node));994 return fnProtoExpr(gz, scope, rl, node, tree.fnProtoOne(&params, node));
995 },995 },
996 .fn_proto => {996 .fn_proto => {
997 return fnProtoExpr(gz, scope, rl, tree.fnProto(node));997 return fnProtoExpr(gz, scope, rl, node, tree.fnProto(node));
998 },998 },
999 }999 }
1000}1000}
...@@ -1101,6 +1101,7 @@ fn fnProtoExpr(...@@ -1101,6 +1101,7 @@ fn fnProtoExpr(
1101 gz: *GenZir,1101 gz: *GenZir,
1102 scope: *Scope,1102 scope: *Scope,
1103 rl: ResultLoc,1103 rl: ResultLoc,
1104 node: Ast.Node.Index,
1104 fn_proto: Ast.full.FnProto,1105 fn_proto: Ast.full.FnProto,
1105) InnerError!Zir.Inst.Ref {1106) InnerError!Zir.Inst.Ref {
1106 const astgen = gz.astgen;1107 const astgen = gz.astgen;
...@@ -1113,6 +1114,11 @@ fn fnProtoExpr(...@@ -1113,6 +1114,11 @@ fn fnProtoExpr(
1113 };1114 };
1114 assert(!is_extern);1115 assert(!is_extern);
11151116
1117 var block_scope = gz.makeSubBlock(scope);
1118 defer block_scope.unstack();
1119
1120 const block_inst = try gz.makeBlockInst(.block_inline, node);
1121
1116 const is_var_args = is_var_args: {1122 const is_var_args = is_var_args: {
1117 var param_type_i: usize = 0;1123 var param_type_i: usize = 0;
1118 var it = fn_proto.iterate(tree.*);1124 var it = fn_proto.iterate(tree.*);
...@@ -1144,11 +1150,11 @@ fn fnProtoExpr(...@@ -1144,11 +1150,11 @@ fn fnProtoExpr(
1144 .param_anytype_comptime1150 .param_anytype_comptime
1145 else1151 else
1146 .param_anytype;1152 .param_anytype;
1147 _ = try gz.addStrTok(tag, param_name, name_token);1153 _ = try block_scope.addStrTok(tag, param_name, name_token);
1148 } else {1154 } else {
1149 const param_type_node = param.type_expr;1155 const param_type_node = param.type_expr;
1150 assert(param_type_node != 0);1156 assert(param_type_node != 0);
1151 var param_gz = gz.makeSubBlock(scope);1157 var param_gz = block_scope.makeSubBlock(scope);
1152 defer param_gz.unstack();1158 defer param_gz.unstack();
1153 const param_type = try expr(&param_gz, scope, coerced_type_rl, param_type_node);1159 const param_type = try expr(&param_gz, scope, coerced_type_rl, param_type_node);
1154 const param_inst_expected = @intCast(u32, astgen.instructions.len + 1);1160 const param_inst_expected = @intCast(u32, astgen.instructions.len + 1);
...@@ -1156,7 +1162,7 @@ fn fnProtoExpr(...@@ -1156,7 +1162,7 @@ fn fnProtoExpr(
1156 const main_tokens = tree.nodes.items(.main_token);1162 const main_tokens = tree.nodes.items(.main_token);
1157 const name_token = param.name_token orelse main_tokens[param_type_node];1163 const name_token = param.name_token orelse main_tokens[param_type_node];
1158 const tag: Zir.Inst.Tag = if (is_comptime) .param_comptime else .param;1164 const tag: Zir.Inst.Tag = if (is_comptime) .param_comptime else .param;
1159 const param_inst = try gz.addParam(&param_gz, tag, name_token, param_name);1165 const param_inst = try block_scope.addParam(&param_gz, tag, name_token, param_name);
1160 assert(param_inst_expected == param_inst);1166 assert(param_inst_expected == param_inst);
1161 }1167 }
1162 }1168 }
...@@ -1164,7 +1170,7 @@ fn fnProtoExpr(...@@ -1164,7 +1170,7 @@ fn fnProtoExpr(
1164 };1170 };
11651171
1166 const align_inst: Zir.Inst.Ref = if (fn_proto.ast.align_expr == 0) .none else inst: {1172 const align_inst: Zir.Inst.Ref = if (fn_proto.ast.align_expr == 0) .none else inst: {
1167 break :inst try expr(gz, scope, align_rl, fn_proto.ast.align_expr);1173 break :inst try expr(&block_scope, scope, align_rl, fn_proto.ast.align_expr);
1168 };1174 };
11691175
1170 if (fn_proto.ast.addrspace_expr != 0) {1176 if (fn_proto.ast.addrspace_expr != 0) {
...@@ -1177,7 +1183,7 @@ fn fnProtoExpr(...@@ -1177,7 +1183,7 @@ fn fnProtoExpr(
11771183
1178 const cc: Zir.Inst.Ref = if (fn_proto.ast.callconv_expr != 0)1184 const cc: Zir.Inst.Ref = if (fn_proto.ast.callconv_expr != 0)
1179 try expr(1185 try expr(
1180 gz,1186 &block_scope,
1181 scope,1187 scope,
1182 .{ .ty = .calling_convention_type },1188 .{ .ty = .calling_convention_type },
1183 fn_proto.ast.callconv_expr,1189 fn_proto.ast.callconv_expr,
...@@ -1190,14 +1196,14 @@ fn fnProtoExpr(...@@ -1190,14 +1196,14 @@ fn fnProtoExpr(
1190 if (is_inferred_error) {1196 if (is_inferred_error) {
1191 return astgen.failTok(maybe_bang, "function prototype may not have inferred error set", .{});1197 return astgen.failTok(maybe_bang, "function prototype may not have inferred error set", .{});
1192 }1198 }
1193 var ret_gz = gz.makeSubBlock(scope);1199 var ret_gz = block_scope.makeSubBlock(scope);
1194 defer ret_gz.unstack();1200 defer ret_gz.unstack();
1195 const ret_ty = try expr(&ret_gz, scope, coerced_type_rl, fn_proto.ast.return_type);1201 const ret_ty = try expr(&ret_gz, scope, coerced_type_rl, fn_proto.ast.return_type);
1196 const ret_br = try ret_gz.addBreak(.break_inline, 0, ret_ty);1202 const ret_br = try ret_gz.addBreak(.break_inline, 0, ret_ty);
11971203
1198 const result = try gz.addFunc(.{1204 const result = try block_scope.addFunc(.{
1199 .src_node = fn_proto.ast.proto_node,1205 .src_node = fn_proto.ast.proto_node,
1200 .param_block = 0,1206 .param_block = block_inst,
1201 .ret_gz = &ret_gz,1207 .ret_gz = &ret_gz,
1202 .ret_br = ret_br,1208 .ret_br = ret_br,
1203 .body_gz = null,1209 .body_gz = null,
...@@ -1209,7 +1215,12 @@ fn fnProtoExpr(...@@ -1209,7 +1215,12 @@ fn fnProtoExpr(
1209 .is_test = false,1215 .is_test = false,
1210 .is_extern = false,1216 .is_extern = false,
1211 });1217 });
1212 return rvalue(gz, rl, result, fn_proto.ast.proto_node);1218
1219 _ = try block_scope.addBreak(.break_inline, block_inst, result);
1220 try block_scope.setBlockBody(block_inst);
1221 try gz.instructions.append(astgen.gpa, block_inst);
1222
1223 return rvalue(gz, rl, indexToRef(block_inst), fn_proto.ast.proto_node);
1213}1224}
12141225
1215fn arrayInitExpr(1226fn arrayInitExpr(
src/Liveness.zig+8-1
...@@ -281,6 +281,7 @@ fn analyzeInst(...@@ -281,6 +281,7 @@ fn analyzeInst(
281 .dbg_stmt,281 .dbg_stmt,
282 .unreach,282 .unreach,
283 .fence,283 .fence,
284 .ret_addr,
284 => return trackOperands(a, new_set, inst, main_tomb, .{ .none, .none, .none }),285 => return trackOperands(a, new_set, inst, main_tomb, .{ .none, .none, .none }),
285286
286 .not,287 .not,
...@@ -381,7 +382,13 @@ fn analyzeInst(...@@ -381,7 +382,13 @@ fn analyzeInst(
381 const extra = a.air.extraData(Air.AtomicRmw, pl_op.payload).data;382 const extra = a.air.extraData(Air.AtomicRmw, pl_op.payload).data;
382 return trackOperands(a, new_set, inst, main_tomb, .{ pl_op.operand, extra.operand, .none });383 return trackOperands(a, new_set, inst, main_tomb, .{ pl_op.operand, extra.operand, .none });
383 },384 },
384 .memset, .memcpy => {385 .memset,
386 .memcpy,
387 .add_with_overflow,
388 .sub_with_overflow,
389 .mul_with_overflow,
390 .shl_with_overflow,
391 => {
385 const pl_op = inst_datas[inst].pl_op;392 const pl_op = inst_datas[inst].pl_op;
386 const extra = a.air.extraData(Air.Bin, pl_op.payload).data;393 const extra = a.air.extraData(Air.Bin, pl_op.payload).data;
387 return trackOperands(a, new_set, inst, main_tomb, .{ pl_op.operand, extra.lhs, extra.rhs });394 return trackOperands(a, new_set, inst, main_tomb, .{ pl_op.operand, extra.lhs, extra.rhs });
src/Module.zig+70-21
...@@ -796,15 +796,11 @@ pub const ErrorSet = struct {...@@ -796,15 +796,11 @@ pub const ErrorSet = struct {
796 owner_decl: *Decl,796 owner_decl: *Decl,
797 /// Offset from Decl node index, points to the error set AST node.797 /// Offset from Decl node index, points to the error set AST node.
798 node_offset: i32,798 node_offset: i32,
799 names_len: u32,
800 /// The string bytes are stored in the owner Decl arena.799 /// The string bytes are stored in the owner Decl arena.
801 /// They are in the same order they appear in the AST.800 /// They are in the same order they appear in the AST.
802 /// The length is given by `names_len`.801 names: NameMap,
803 names_ptr: [*]const []const u8,
804802
805 pub fn names(self: ErrorSet) []const []const u8 {803 pub const NameMap = std.StringArrayHashMapUnmanaged(void);
806 return self.names_ptr[0..self.names_len];
807 }
808804
809 pub fn srcLoc(self: ErrorSet) SrcLoc {805 pub fn srcLoc(self: ErrorSet) SrcLoc {
810 return .{806 return .{
...@@ -1211,6 +1207,10 @@ pub const Fn = struct {...@@ -1211,6 +1207,10 @@ pub const Fn = struct {
1211 is_cold: bool = false,1207 is_cold: bool = false,
1212 is_noinline: bool = false,1208 is_noinline: bool = false,
12131209
1210 /// Any inferred error sets that this function owns, both it's own inferred error set and
1211 /// inferred error sets of any inline/comptime functions called.
1212 inferred_error_sets: InferredErrorSetList = .{},
1213
1214 pub const Analysis = enum {1214 pub const Analysis = enum {
1215 queued,1215 queued,
1216 /// This function intentionally only has ZIR generated because it is marked1216 /// This function intentionally only has ZIR generated because it is marked
...@@ -1225,24 +1225,73 @@ pub const Fn = struct {...@@ -1225,24 +1225,73 @@ pub const Fn = struct {
1225 success,1225 success,
1226 };1226 };
12271227
1228 pub fn deinit(func: *Fn, gpa: Allocator) void {1228 /// This struct is used to keep track of any dependencies related to functions instances
1229 if (func.getInferredErrorSet()) |error_set_data| {1229 /// that return inferred error sets. Note that a function may be associated to multiple different error sets,
1230 error_set_data.map.deinit(gpa);1230 /// for example an inferred error set which this function returns, but also any inferred error sets
1231 error_set_data.functions.deinit(gpa);1231 /// of called inline or comptime functions.
1232 }1232 pub const InferredErrorSet = struct {
1233 }1233 /// The function from which this error set originates.
1234 /// Note: may be the function itself.
1235 func: *Fn,
12341236
1235 pub fn getInferredErrorSet(func: *Fn) ?*Type.Payload.ErrorSetInferred.Data {1237 /// All currently known errors that this error set contains. This includes direct additions
1236 const ret_ty = func.owner_decl.ty.fnReturnType();1238 /// via `return error.Foo;`, and possibly also errors that are returned from any dependent functions.
1237 if (ret_ty.tag() == .generic_poison) {1239 /// When the inferred error set is fully resolved, this map contains all the errors that the function might return.
1238 return null;1240 errors: std.StringHashMapUnmanaged(void) = .{},
1239 }1241
1240 if (ret_ty.zigTypeTag() == .ErrorUnion) {1242 /// Other inferred error sets which this inferred error set should include.
1241 if (ret_ty.errorUnionSet().castTag(.error_set_inferred)) |payload| {1243 inferred_error_sets: std.AutoHashMapUnmanaged(*InferredErrorSet, void) = .{},
1242 return &payload.data;1244
1245 /// Whether the function returned anyerror. This is true if either of the dependent functions
1246 /// returns anyerror.
1247 is_anyerror: bool = false,
1248
1249 /// Whether this error set is already fully resolved. If true, resolving can skip resolving any dependents
1250 /// of this inferred error set.
1251 is_resolved: bool = false,
1252
1253 pub fn addErrorSet(self: *InferredErrorSet, gpa: Allocator, err_set_ty: Type) !void {
1254 switch (err_set_ty.tag()) {
1255 .error_set => {
1256 const names = err_set_ty.castTag(.error_set).?.data.names.keys();
1257 for (names) |name| {
1258 try self.errors.put(gpa, name, {});
1259 }
1260 },
1261 .error_set_single => {
1262 const name = err_set_ty.castTag(.error_set_single).?.data;
1263 try self.errors.put(gpa, name, {});
1264 },
1265 .error_set_inferred => {
1266 const set = err_set_ty.castTag(.error_set_inferred).?.data;
1267 try self.inferred_error_sets.put(gpa, set, {});
1268 },
1269 .error_set_merged => {
1270 const names = err_set_ty.castTag(.error_set_merged).?.data.keys();
1271 for (names) |name| {
1272 try self.errors.put(gpa, name, {});
1273 }
1274 },
1275 .anyerror => {
1276 self.is_anyerror = true;
1277 },
1278 else => unreachable,
1243 }1279 }
1244 }1280 }
1245 return null;1281 };
1282
1283 pub const InferredErrorSetList = std.SinglyLinkedList(InferredErrorSet);
1284 pub const InferredErrorSetListNode = InferredErrorSetList.Node;
1285
1286 pub fn deinit(func: *Fn, gpa: Allocator) void {
1287 var it = func.inferred_error_sets.first;
1288 while (it) |node| {
1289 const next = node.next;
1290 node.data.errors.deinit(gpa);
1291 node.data.inferred_error_sets.deinit(gpa);
1292 gpa.destroy(node);
1293 it = next;
1294 }
1246 }1295 }
1247};1296};
12481297
src/Sema.zig+432-138
...@@ -940,6 +940,15 @@ pub fn analyzeBody(...@@ -940,6 +940,15 @@ pub fn analyzeBody(
940 const inst_data = datas[inst].pl_node;940 const inst_data = datas[inst].pl_node;
941 const extra = sema.code.extraData(Zir.Inst.Block, inst_data.payload_index);941 const extra = sema.code.extraData(Zir.Inst.Block, inst_data.payload_index);
942 const inline_body = sema.code.extra[extra.end..][0..extra.data.body_len];942 const inline_body = sema.code.extra[extra.end..][0..extra.data.body_len];
943 // If this block contains a function prototype, we need to reset the
944 // current list of parameters and restore it later.
945 // Note: this probably needs to be resolved in a more general manner.
946 const prev_params = block.params;
947 block.params = .{};
948 defer {
949 block.params.deinit(sema.gpa);
950 block.params = prev_params;
951 }
943 const break_inst = try sema.analyzeBody(block, inline_body);952 const break_inst = try sema.analyzeBody(block, inline_body);
944 const break_data = datas[break_inst].@"break";953 const break_data = datas[break_inst].@"break";
945 if (inst == break_data.block_inst) {954 if (inst == break_data.block_inst) {
...@@ -953,6 +962,15 @@ pub fn analyzeBody(...@@ -953,6 +962,15 @@ pub fn analyzeBody(
953 const inst_data = datas[inst].pl_node;962 const inst_data = datas[inst].pl_node;
954 const extra = sema.code.extraData(Zir.Inst.Block, inst_data.payload_index);963 const extra = sema.code.extraData(Zir.Inst.Block, inst_data.payload_index);
955 const inline_body = sema.code.extra[extra.end..][0..extra.data.body_len];964 const inline_body = sema.code.extra[extra.end..][0..extra.data.body_len];
965 // If this block contains a function prototype, we need to reset the
966 // current list of parameters and restore it later.
967 // Note: this probably needs to be resolved in a more general manner.
968 const prev_params = block.params;
969 block.params = .{};
970 defer {
971 block.params.deinit(sema.gpa);
972 block.params = prev_params;
973 }
956 const break_inst = try sema.analyzeBody(block, inline_body);974 const break_inst = try sema.analyzeBody(block, inline_body);
957 const break_data = datas[break_inst].@"break";975 const break_data = datas[break_inst].@"break";
958 if (inst == break_data.block_inst) {976 if (inst == break_data.block_inst) {
...@@ -1033,10 +1051,10 @@ fn zirExtended(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -1033,10 +1051,10 @@ fn zirExtended(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1033 .@"asm" => return sema.zirAsm( block, extended, inst),1051 .@"asm" => return sema.zirAsm( block, extended, inst),
1034 .typeof_peer => return sema.zirTypeofPeer( block, extended),1052 .typeof_peer => return sema.zirTypeofPeer( block, extended),
1035 .compile_log => return sema.zirCompileLog( block, extended),1053 .compile_log => return sema.zirCompileLog( block, extended),
1036 .add_with_overflow => return sema.zirOverflowArithmetic(block, extended),1054 .add_with_overflow => return sema.zirOverflowArithmetic(block, extended, extended.opcode),
1037 .sub_with_overflow => return sema.zirOverflowArithmetic(block, extended),1055 .sub_with_overflow => return sema.zirOverflowArithmetic(block, extended, extended.opcode),
1038 .mul_with_overflow => return sema.zirOverflowArithmetic(block, extended),1056 .mul_with_overflow => return sema.zirOverflowArithmetic(block, extended, extended.opcode),
1039 .shl_with_overflow => return sema.zirOverflowArithmetic(block, extended),1057 .shl_with_overflow => return sema.zirOverflowArithmetic(block, extended, extended.opcode),
1040 .c_undef => return sema.zirCUndef( block, extended),1058 .c_undef => return sema.zirCUndef( block, extended),
1041 .c_include => return sema.zirCInclude( block, extended),1059 .c_include => return sema.zirCInclude( block, extended),
1042 .c_define => return sema.zirCDefine( block, extended),1060 .c_define => return sema.zirCDefine( block, extended),
...@@ -2025,15 +2043,22 @@ fn zirErrorSetDecl(...@@ -2025,15 +2043,22 @@ fn zirErrorSetDecl(
2025 }, type_name);2043 }, type_name);
2026 new_decl.owns_tv = true;2044 new_decl.owns_tv = true;
2027 errdefer sema.mod.abortAnonDecl(new_decl);2045 errdefer sema.mod.abortAnonDecl(new_decl);
2028 const names = try new_decl_arena_allocator.alloc([]const u8, fields.len);2046
2029 for (fields) |str_index, i| {2047 var names = Module.ErrorSet.NameMap{};
2030 names[i] = try new_decl_arena_allocator.dupe(u8, sema.code.nullTerminatedString(str_index));2048 try names.ensureUnusedCapacity(new_decl_arena_allocator, fields.len);
2049 for (fields) |str_index| {
2050 const name = try new_decl_arena_allocator.dupe(u8, sema.code.nullTerminatedString(str_index));
2051
2052 // TODO: This check should be performed in AstGen instead.
2053 const result = names.getOrPutAssumeCapacity(name);
2054 if (result.found_existing) {
2055 return sema.fail(block, src, "duplicate error set field {s}", .{name});
2056 }
2031 }2057 }
2032 error_set.* = .{2058 error_set.* = .{
2033 .owner_decl = new_decl,2059 .owner_decl = new_decl,
2034 .node_offset = inst_data.src_node,2060 .node_offset = inst_data.src_node,
2035 .names_ptr = names.ptr,2061 .names = names,
2036 .names_len = @intCast(u32, names.len),
2037 };2062 };
2038 try new_decl.finalizeNewArena(&new_decl_arena);2063 try new_decl.finalizeNewArena(&new_decl_arena);
2039 return sema.analyzeDeclVal(block, src, new_decl);2064 return sema.analyzeDeclVal(block, src, new_decl);
...@@ -3887,17 +3912,20 @@ fn analyzeCall(...@@ -3887,17 +3912,20 @@ fn analyzeCall(
3887 const ret_ty_inst = try sema.resolveBody(&child_block, fn_info.ret_ty_body);3912 const ret_ty_inst = try sema.resolveBody(&child_block, fn_info.ret_ty_body);
3888 const ret_ty_src = func_src; // TODO better source location3913 const ret_ty_src = func_src; // TODO better source location
3889 const bare_return_type = try sema.analyzeAsType(&child_block, ret_ty_src, ret_ty_inst);3914 const bare_return_type = try sema.analyzeAsType(&child_block, ret_ty_src, ret_ty_inst);
3890 // If the function has an inferred error set, `bare_return_type` is the payload type only.3915 // Create a fresh inferred error set type for inline/comptime calls.
3891 const fn_ret_ty = blk: {3916 const fn_ret_ty = blk: {
3892 // TODO instead of reusing the function's inferred error set, this code should
3893 // create a temporary error set which is used for the comptime/inline function
3894 // call alone, independent from the runtime instantiation.
3895 if (func_ty_info.return_type.castTag(.error_union)) |payload| {3917 if (func_ty_info.return_type.castTag(.error_union)) |payload| {
3896 const error_set_ty = payload.data.error_set;3918 if (payload.data.error_set.tag() == .error_set_inferred) {
3897 break :blk try Type.Tag.error_union.create(sema.arena, .{3919 const node = try sema.gpa.create(Module.Fn.InferredErrorSetListNode);
3898 .error_set = error_set_ty,3920 node.data = .{ .func = module_fn };
3899 .payload = bare_return_type,3921 parent_func.?.inferred_error_sets.prepend(node);
3900 });3922
3923 const error_set_ty = try Type.Tag.error_set_inferred.create(sema.arena, &node.data);
3924 break :blk try Type.Tag.error_union.create(sema.arena, .{
3925 .error_set = error_set_ty,
3926 .payload = bare_return_type,
3927 });
3928 }
3901 }3929 }
3902 break :blk bare_return_type;3930 break :blk bare_return_type;
3903 };3931 };
...@@ -4556,63 +4584,43 @@ fn zirMergeErrorSets(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr...@@ -4556,63 +4584,43 @@ fn zirMergeErrorSets(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr
4556 return Air.Inst.Ref.anyerror_type;4584 return Air.Inst.Ref.anyerror_type;
4557 }4585 }
4558 // Resolve both error sets now.4586 // Resolve both error sets now.
4559 var set: std.StringHashMapUnmanaged(void) = .{};4587 const lhs_names = switch (lhs_ty.tag()) {
4560 defer set.deinit(sema.gpa);4588 .error_set_single => blk: {
45614589 // Work around coercion problems
4562 switch (lhs_ty.tag()) {4590 const tmp: *const [1][]const u8 = &lhs_ty.castTag(.error_set_single).?.data;
4563 .error_set_single => {4591 break :blk tmp;
4564 const name = lhs_ty.castTag(.error_set_single).?.data;
4565 try set.put(sema.gpa, name, {});
4566 },
4567 .error_set_merged => {
4568 const names = lhs_ty.castTag(.error_set_merged).?.data;
4569 for (names) |name| {
4570 try set.put(sema.gpa, name, {});
4571 }
4572 },
4573 .error_set => {
4574 const lhs_set = lhs_ty.castTag(.error_set).?.data;
4575 try set.ensureUnusedCapacity(sema.gpa, lhs_set.names_len);
4576 for (lhs_set.names_ptr[0..lhs_set.names_len]) |name| {
4577 set.putAssumeCapacityNoClobber(name, {});
4578 }
4579 },4592 },
4593 .error_set_merged => lhs_ty.castTag(.error_set_merged).?.data.keys(),
4594 .error_set => lhs_ty.castTag(.error_set).?.data.names.keys(),
4580 else => unreachable,4595 else => unreachable,
4581 }4596 };
4582 switch (rhs_ty.tag()) {4597
4583 .error_set_single => {4598 const rhs_names = switch (rhs_ty.tag()) {
4584 const name = rhs_ty.castTag(.error_set_single).?.data;4599 .error_set_single => blk: {
4585 try set.put(sema.gpa, name, {});4600 const tmp: *const [1][]const u8 = &rhs_ty.castTag(.error_set_single).?.data;
4586 },4601 break :blk tmp;
4587 .error_set_merged => {
4588 const names = rhs_ty.castTag(.error_set_merged).?.data;
4589 for (names) |name| {
4590 try set.put(sema.gpa, name, {});
4591 }
4592 },
4593 .error_set => {
4594 const rhs_set = rhs_ty.castTag(.error_set).?.data;
4595 try set.ensureUnusedCapacity(sema.gpa, rhs_set.names_len);
4596 for (rhs_set.names_ptr[0..rhs_set.names_len]) |name| {
4597 set.putAssumeCapacity(name, {});
4598 }
4599 },4602 },
4603 .error_set_merged => rhs_ty.castTag(.error_set_merged).?.data.keys(),
4604 .error_set => rhs_ty.castTag(.error_set).?.data.names.keys(),
4600 else => unreachable,4605 else => unreachable,
4601 }4606 };
46024607
4603 // TODO do we really want to create a Decl for this?4608 // TODO do we really want to create a Decl for this?
4604 // The reason we do it right now is for memory management.4609 // The reason we do it right now is for memory management.
4605 var anon_decl = try block.startAnonDecl();4610 var anon_decl = try block.startAnonDecl();
4606 defer anon_decl.deinit();4611 defer anon_decl.deinit();
46074612
4608 const new_names = try anon_decl.arena().alloc([]const u8, set.count());4613 var names = Module.ErrorSet.NameMap{};
4609 var it = set.keyIterator();4614 // TODO: Guess is an upper bound, but maybe this needs to be reduced by computing the exact size first.
4610 var i: usize = 0;4615 try names.ensureUnusedCapacity(anon_decl.arena(), @intCast(u32, lhs_names.len + rhs_names.len));
4611 while (it.next()) |key| : (i += 1) {4616 for (lhs_names) |name| {
4612 new_names[i] = key.*;4617 names.putAssumeCapacityNoClobber(name, {});
4618 }
4619 for (rhs_names) |name| {
4620 names.putAssumeCapacity(name, {});
4613 }4621 }
46144622
4615 const err_set_ty = try Type.Tag.error_set_merged.create(anon_decl.arena(), new_names);4623 const err_set_ty = try Type.Tag.error_set_merged.create(anon_decl.arena(), names);
4616 const err_set_decl = try anon_decl.finish(4624 const err_set_decl = try anon_decl.finish(
4617 Type.type,4625 Type.type,
4618 try Value.Tag.ty.create(anon_decl.arena(), err_set_ty),4626 try Value.Tag.ty.create(anon_decl.arena(), err_set_ty),
...@@ -5079,6 +5087,10 @@ fn funcCommon(...@@ -5079,6 +5087,10 @@ fn funcCommon(
5079 };5087 };
5080 errdefer if (body_inst != 0) sema.gpa.destroy(new_func);5088 errdefer if (body_inst != 0) sema.gpa.destroy(new_func);
50815089
5090 var maybe_inferred_error_set_node: ?*Module.Fn.InferredErrorSetListNode = null;
5091 errdefer if (maybe_inferred_error_set_node) |node| sema.gpa.destroy(node);
5092 // Note: no need to errdefer since this will still be in its default state at the end of the function.
5093
5082 const fn_ty: Type = fn_ty: {5094 const fn_ty: Type = fn_ty: {
5083 // Hot path for some common function types.5095 // Hot path for some common function types.
5084 // TODO can we eliminate some of these Type tag values? seems unnecessarily complicated.5096 // TODO can we eliminate some of these Type tag values? seems unnecessarily complicated.
...@@ -5120,12 +5132,11 @@ fn funcCommon(...@@ -5120,12 +5132,11 @@ fn funcCommon(
5120 const return_type = if (!inferred_error_set or bare_return_type.tag() == .generic_poison)5132 const return_type = if (!inferred_error_set or bare_return_type.tag() == .generic_poison)
5121 bare_return_type5133 bare_return_type
5122 else blk: {5134 else blk: {
5123 const error_set_ty = try Type.Tag.error_set_inferred.create(sema.arena, .{5135 const node = try sema.gpa.create(Module.Fn.InferredErrorSetListNode);
5124 .func = new_func,5136 node.data = .{ .func = new_func };
5125 .map = .{},5137 maybe_inferred_error_set_node = node;
5126 .functions = .{},5138
5127 .is_anyerror = false,5139 const error_set_ty = try Type.Tag.error_set_inferred.create(sema.arena, &node.data);
5128 });
5129 break :blk try Type.Tag.error_union.create(sema.arena, .{5140 break :blk try Type.Tag.error_union.create(sema.arena, .{
5130 .error_set = error_set_ty,5141 .error_set = error_set_ty,
5131 .payload = bare_return_type,5142 .payload = bare_return_type,
...@@ -5217,6 +5228,10 @@ fn funcCommon(...@@ -5217,6 +5228,10 @@ fn funcCommon(
5217 .lbrace_column = @truncate(u16, src_locs.columns),5228 .lbrace_column = @truncate(u16, src_locs.columns),
5218 .rbrace_column = @truncate(u16, src_locs.columns >> 16),5229 .rbrace_column = @truncate(u16, src_locs.columns >> 16),
5219 };5230 };
5231 if (maybe_inferred_error_set_node) |node| {
5232 new_func.inferred_error_sets.prepend(node);
5233 }
5234 maybe_inferred_error_set_node = null;
5220 fn_payload.* = .{5235 fn_payload.* = .{
5221 .base = .{ .tag = .function },5236 .base = .{ .tag = .function },
5222 .data = new_func,5237 .data = new_func,
...@@ -5368,7 +5383,7 @@ fn zirPtrToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -5368,7 +5383,7 @@ fn zirPtrToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
5368 const inst_data = sema.code.instructions.items(.data)[inst].un_node;5383 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
5369 const ptr = sema.resolveInst(inst_data.operand);5384 const ptr = sema.resolveInst(inst_data.operand);
5370 const ptr_ty = sema.typeOf(ptr);5385 const ptr_ty = sema.typeOf(ptr);
5371 if (ptr_ty.zigTypeTag() != .Pointer) {5386 if (!ptr_ty.isPtrAtRuntime()) {
5372 const ptr_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };5387 const ptr_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
5373 return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{ptr_ty});5388 return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{ptr_ty});
5374 }5389 }
...@@ -7295,6 +7310,7 @@ fn zirOverflowArithmetic(...@@ -7295,6 +7310,7 @@ fn zirOverflowArithmetic(
7295 sema: *Sema,7310 sema: *Sema,
7296 block: *Block,7311 block: *Block,
7297 extended: Zir.Inst.Extended.InstData,7312 extended: Zir.Inst.Extended.InstData,
7313 zir_tag: Zir.Inst.Extended,
7298) CompileError!Air.Inst.Ref {7314) CompileError!Air.Inst.Ref {
7299 const tracy = trace(@src());7315 const tracy = trace(@src());
7300 defer tracy.end();7316 defer tracy.end();
...@@ -7302,7 +7318,170 @@ fn zirOverflowArithmetic(...@@ -7302,7 +7318,170 @@ fn zirOverflowArithmetic(
7302 const extra = sema.code.extraData(Zir.Inst.OverflowArithmetic, extended.operand).data;7318 const extra = sema.code.extraData(Zir.Inst.OverflowArithmetic, extended.operand).data;
7303 const src: LazySrcLoc = .{ .node_offset = extra.node };7319 const src: LazySrcLoc = .{ .node_offset = extra.node };
73047320
7305 return sema.fail(block, src, "TODO implement Sema.zirOverflowArithmetic", .{});7321 const lhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
7322 const rhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node };
7323 const ptr_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = extra.node };
7324
7325 const lhs = sema.resolveInst(extra.lhs);
7326 const rhs = sema.resolveInst(extra.rhs);
7327 const ptr = sema.resolveInst(extra.ptr);
7328
7329 const lhs_ty = sema.typeOf(lhs);
7330
7331 // Note, the types of lhs/rhs (also for shifting)/ptr are already correct as ensured by astgen.
7332 const dest_ty = lhs_ty;
7333 if (dest_ty.zigTypeTag() != .Int) {
7334 return sema.fail(block, src, "expected integer type, found '{}'", .{dest_ty});
7335 }
7336
7337 const target = sema.mod.getTarget();
7338
7339 const maybe_lhs_val = try sema.resolveMaybeUndefVal(block, lhs_src, lhs);
7340 const maybe_rhs_val = try sema.resolveMaybeUndefVal(block, rhs_src, rhs);
7341
7342 const result: struct {
7343 overflowed: enum { yes, no, undef },
7344 wrapped: Air.Inst.Ref,
7345 } = result: {
7346 switch (zir_tag) {
7347 .add_with_overflow => {
7348 // If either of the arguments is zero, `false` is returned and the other is stored
7349 // to the result, even if it is undefined..
7350 // Otherwise, if either of the argument is undefined, undefined is returned.
7351 if (maybe_lhs_val) |lhs_val| {
7352 if (!lhs_val.isUndef() and lhs_val.compareWithZero(.eq)) {
7353 break :result .{ .overflowed = .no, .wrapped = rhs };
7354 }
7355 }
7356 if (maybe_rhs_val) |rhs_val| {
7357 if (!rhs_val.isUndef() and rhs_val.compareWithZero(.eq)) {
7358 break :result .{ .overflowed = .no, .wrapped = lhs };
7359 }
7360 }
7361 if (maybe_lhs_val) |lhs_val| {
7362 if (maybe_rhs_val) |rhs_val| {
7363 if (lhs_val.isUndef() or rhs_val.isUndef()) {
7364 break :result .{ .overflowed = .undef, .wrapped = try sema.addConstUndef(dest_ty) };
7365 }
7366
7367 const result = try lhs_val.intAddWithOverflow(rhs_val, dest_ty, sema.arena, target);
7368 const inst = try sema.addConstant(dest_ty, result.wrapped_result);
7369 break :result .{ .overflowed = if (result.overflowed) .yes else .no, .wrapped = inst };
7370 }
7371 }
7372 },
7373 .sub_with_overflow => {
7374 // If the rhs is zero, then the result is lhs and no overflow occured.
7375 // Otherwise, if either result is undefined, both results are undefined.
7376 if (maybe_rhs_val) |rhs_val| {
7377 if (rhs_val.isUndef()) {
7378 break :result .{ .overflowed = .undef, .wrapped = try sema.addConstUndef(dest_ty) };
7379 } else if (rhs_val.compareWithZero(.eq)) {
7380 break :result .{ .overflowed = .no, .wrapped = lhs };
7381 } else if (maybe_lhs_val) |lhs_val| {
7382 if (lhs_val.isUndef()) {
7383 break :result .{ .overflowed = .undef, .wrapped = try sema.addConstUndef(dest_ty) };
7384 }
7385
7386 const result = try lhs_val.intSubWithOverflow(rhs_val, dest_ty, sema.arena, target);
7387 const inst = try sema.addConstant(dest_ty, result.wrapped_result);
7388 break :result .{ .overflowed = if (result.overflowed) .yes else .no, .wrapped = inst };
7389 }
7390 }
7391 },
7392 .mul_with_overflow => {
7393 // If either of the arguments is zero, the result is zero and no overflow occured.
7394 // If either of the arguments is one, the result is the other and no overflow occured.
7395 // Otherwise, if either of the arguments is undefined, both results are undefined.
7396 if (maybe_lhs_val) |lhs_val| {
7397 if (!lhs_val.isUndef()) {
7398 if (lhs_val.compareWithZero(.eq)) {
7399 break :result .{ .overflowed = .no, .wrapped = lhs };
7400 } else if (lhs_val.compare(.eq, Value.one, dest_ty)) {
7401 break :result .{ .overflowed = .no, .wrapped = rhs };
7402 }
7403 }
7404 }
7405
7406 if (maybe_rhs_val) |rhs_val| {
7407 if (!rhs_val.isUndef()) {
7408 if (rhs_val.compareWithZero(.eq)) {
7409 break :result .{ .overflowed = .no, .wrapped = rhs };
7410 } else if (rhs_val.compare(.eq, Value.one, dest_ty)) {
7411 break :result .{ .overflowed = .no, .wrapped = lhs };
7412 }
7413 }
7414 }
7415
7416 if (maybe_lhs_val) |lhs_val| {
7417 if (maybe_rhs_val) |rhs_val| {
7418 if (lhs_val.isUndef() or rhs_val.isUndef()) {
7419 break :result .{ .overflowed = .undef, .wrapped = try sema.addConstUndef(dest_ty) };
7420 }
7421
7422 const result = try lhs_val.intMulWithOverflow(rhs_val, dest_ty, sema.arena, target);
7423 const inst = try sema.addConstant(dest_ty, result.wrapped_result);
7424 break :result .{ .overflowed = if (result.overflowed) .yes else .no, .wrapped = inst };
7425 }
7426 }
7427 },
7428 .shl_with_overflow => {
7429 // If lhs is zero, the result is zero and no overflow occurred.
7430 // If rhs is zero, the result is lhs (even if undefined) and no overflow occurred.
7431 // Oterhwise if either of the arguments is undefined, both results are undefined.
7432 if (maybe_lhs_val) |lhs_val| {
7433 if (!lhs_val.isUndef() and lhs_val.compareWithZero(.eq)) {
7434 break :result .{ .overflowed = .no, .wrapped = lhs };
7435 }
7436 }
7437 if (maybe_rhs_val) |rhs_val| {
7438 if (!rhs_val.isUndef() and rhs_val.compareWithZero(.eq)) {
7439 break :result .{ .overflowed = .no, .wrapped = lhs };
7440 }
7441 }
7442 if (maybe_lhs_val) |lhs_val| {
7443 if (maybe_rhs_val) |rhs_val| {
7444 if (lhs_val.isUndef() or rhs_val.isUndef()) {
7445 break :result .{ .overflowed = .undef, .wrapped = try sema.addConstUndef(dest_ty) };
7446 }
7447
7448 const result = try lhs_val.shlWithOverflow(rhs_val, dest_ty, sema.arena, target);
7449 const inst = try sema.addConstant(dest_ty, result.wrapped_result);
7450 break :result .{ .overflowed = if (result.overflowed) .yes else .no, .wrapped = inst };
7451 }
7452 }
7453 },
7454 else => unreachable,
7455 }
7456
7457 const air_tag: Air.Inst.Tag = switch (zir_tag) {
7458 .add_with_overflow => .add_with_overflow,
7459 .mul_with_overflow => .mul_with_overflow,
7460 .sub_with_overflow => .sub_with_overflow,
7461 .shl_with_overflow => .shl_with_overflow,
7462 else => unreachable,
7463 };
7464
7465 try sema.requireRuntimeBlock(block, src);
7466 return block.addInst(.{
7467 .tag = air_tag,
7468 .data = .{ .pl_op = .{
7469 .operand = ptr,
7470 .payload = try sema.addExtra(Air.Bin{
7471 .lhs = lhs,
7472 .rhs = rhs,
7473 }),
7474 } },
7475 });
7476 };
7477
7478 try sema.storePtr2(block, src, ptr, ptr_src, result.wrapped, src, .store);
7479
7480 return switch (result.overflowed) {
7481 .yes => Air.Inst.Ref.bool_true,
7482 .no => Air.Inst.Ref.bool_false,
7483 .undef => try sema.addConstUndef(Type.initTag(.bool)),
7484 };
7306}7485}
73077486
7308fn analyzeArithmetic(7487fn analyzeArithmetic(
...@@ -8635,8 +8814,12 @@ fn zirRetAddr(...@@ -8635,8 +8814,12 @@ fn zirRetAddr(
8635 block: *Block,8814 block: *Block,
8636 extended: Zir.Inst.Extended.InstData,8815 extended: Zir.Inst.Extended.InstData,
8637) CompileError!Air.Inst.Ref {8816) CompileError!Air.Inst.Ref {
8817 const tracy = trace(@src());
8818 defer tracy.end();
8819
8638 const src: LazySrcLoc = .{ .node_offset = @bitCast(i32, extended.operand) };8820 const src: LazySrcLoc = .{ .node_offset = @bitCast(i32, extended.operand) };
8639 return sema.fail(block, src, "TODO: implement Sema.zirRetAddr", .{});8821 try sema.requireRuntimeBlock(block, src);
8822 return try block.addNoOp(.ret_addr);
8640}8823}
86418824
8642fn zirBuiltinSrc(8825fn zirBuiltinSrc(
...@@ -8777,7 +8960,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -8777,7 +8960,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
8777 },8960 },
8778 .Pointer => {8961 .Pointer => {
8779 const info = ty.ptrInfo().data;8962 const info = ty.ptrInfo().data;
8780 const field_values = try sema.arena.alloc(Value, 7);8963 const field_values = try sema.arena.alloc(Value, 8);
8781 // size: Size,8964 // size: Size,
8782 field_values[0] = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(info.size));8965 field_values[0] = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(info.size));
8783 // is_const: bool,8966 // is_const: bool,
...@@ -8786,12 +8969,14 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -8786,12 +8969,14 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
8786 field_values[2] = if (info.@"volatile") Value.initTag(.bool_true) else Value.initTag(.bool_false);8969 field_values[2] = if (info.@"volatile") Value.initTag(.bool_true) else Value.initTag(.bool_false);
8787 // alignment: comptime_int,8970 // alignment: comptime_int,
8788 field_values[3] = try Value.Tag.int_u64.create(sema.arena, info.@"align");8971 field_values[3] = try Value.Tag.int_u64.create(sema.arena, info.@"align");
8972 // address_space: AddressSpace
8973 field_values[4] = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(info.@"addrspace"));
8789 // child: type,8974 // child: type,
8790 field_values[4] = try Value.Tag.ty.create(sema.arena, info.pointee_type);8975 field_values[5] = try Value.Tag.ty.create(sema.arena, info.pointee_type);
8791 // is_allowzero: bool,8976 // is_allowzero: bool,
8792 field_values[5] = if (info.@"allowzero") Value.initTag(.bool_true) else Value.initTag(.bool_false);8977 field_values[6] = if (info.@"allowzero") Value.initTag(.bool_true) else Value.initTag(.bool_false);
8793 // sentinel: anytype,8978 // sentinel: anytype,
8794 field_values[6] = if (info.sentinel) |some| try Value.Tag.opt_payload.create(sema.arena, some) else Value.@"null";8979 field_values[7] = if (info.sentinel) |some| try Value.Tag.opt_payload.create(sema.arena, some) else Value.@"null";
87958980
8796 return sema.addConstant(8981 return sema.addConstant(
8797 type_info_ty,8982 type_info_ty,
...@@ -8881,11 +9066,17 @@ fn log2IntType(sema: *Sema, block: *Block, operand: Type, src: LazySrcLoc) Compi...@@ -8881,11 +9066,17 @@ fn log2IntType(sema: *Sema, block: *Block, operand: Type, src: LazySrcLoc) Compi
8881 switch (operand.zigTypeTag()) {9066 switch (operand.zigTypeTag()) {
8882 .ComptimeInt => return Air.Inst.Ref.comptime_int_type,9067 .ComptimeInt => return Air.Inst.Ref.comptime_int_type,
8883 .Int => {9068 .Int => {
8884 var count: u16 = 0;9069 const bits = operand.bitSize(sema.mod.getTarget());
8885 var s = operand.bitSize(sema.mod.getTarget()) - 1;9070 const count = if (bits == 0)
8886 while (s != 0) : (s >>= 1) {9071 0
8887 count += 1;9072 else blk: {
8888 }9073 var count: u16 = 0;
9074 var s = bits - 1;
9075 while (s != 0) : (s >>= 1) {
9076 count += 1;
9077 }
9078 break :blk count;
9079 };
8889 const res = try Module.makeIntType(sema.arena, .unsigned, count);9080 const res = try Module.makeIntType(sema.arena, .unsigned, count);
8890 return sema.addType(res);9081 return sema.addType(res);
8891 },9082 },
...@@ -11425,14 +11616,8 @@ fn fieldVal(...@@ -11425,14 +11616,8 @@ fn fieldVal(
11425 switch (child_type.zigTypeTag()) {11616 switch (child_type.zigTypeTag()) {
11426 .ErrorSet => {11617 .ErrorSet => {
11427 const name: []const u8 = if (child_type.castTag(.error_set)) |payload| blk: {11618 const name: []const u8 = if (child_type.castTag(.error_set)) |payload| blk: {
11428 const error_set = payload.data;11619 if (payload.data.names.getEntry(field_name)) |entry| {
11429 // TODO this is O(N). I'm putting off solving this until we solve inferred11620 break :blk entry.key_ptr.*;
11430 // error sets at the same time.
11431 const names = error_set.names_ptr[0..error_set.names_len];
11432 for (names) |name| {
11433 if (mem.eql(u8, field_name, name)) {
11434 break :blk name;
11435 }
11436 }11621 }
11437 return sema.fail(block, src, "no error named '{s}' in '{}'", .{11622 return sema.fail(block, src, "no error named '{s}' in '{}'", .{
11438 field_name, child_type,11623 field_name, child_type,
...@@ -11630,14 +11815,8 @@ fn fieldPtr(...@@ -11630,14 +11815,8 @@ fn fieldPtr(
11630 .ErrorSet => {11815 .ErrorSet => {
11631 // TODO resolve inferred error sets11816 // TODO resolve inferred error sets
11632 const name: []const u8 = if (child_type.castTag(.error_set)) |payload| blk: {11817 const name: []const u8 = if (child_type.castTag(.error_set)) |payload| blk: {
11633 const error_set = payload.data;11818 if (payload.data.names.getEntry(field_name)) |entry| {
11634 // TODO this is O(N). I'm putting off solving this until we solve inferred11819 break :blk entry.key_ptr.*;
11635 // error sets at the same time.
11636 const names = error_set.names_ptr[0..error_set.names_len];
11637 for (names) |name| {
11638 if (mem.eql(u8, field_name, name)) {
11639 break :blk name;
11640 }
11641 }11820 }
11642 return sema.fail(block, src, "no error named '{s}' in '{}'", .{11821 return sema.fail(block, src, "no error named '{s}' in '{}'", .{
11643 field_name, child_type,11822 field_name, child_type,
...@@ -12207,7 +12386,7 @@ fn coerce(...@@ -12207,7 +12386,7 @@ fn coerce(
12207 const arena = sema.arena;12386 const arena = sema.arena;
12208 const target = sema.mod.getTarget();12387 const target = sema.mod.getTarget();
1220912388
12210 const in_memory_result = coerceInMemoryAllowed(dest_ty, inst_ty, false, target);12389 const in_memory_result = try sema.coerceInMemoryAllowed(dest_ty, inst_ty, false, target);
12211 if (in_memory_result == .ok) {12390 if (in_memory_result == .ok) {
12212 if (try sema.resolveMaybeUndefVal(block, inst_src, inst)) |val| {12391 if (try sema.resolveMaybeUndefVal(block, inst_src, inst)) |val| {
12213 // Keep the comptime Value representation; take the new type.12392 // Keep the comptime Value representation; take the new type.
...@@ -12266,7 +12445,7 @@ fn coerce(...@@ -12266,7 +12445,7 @@ fn coerce(
12266 if (inst_ty.isConstPtr() and dest_is_mut) break :single_item;12445 if (inst_ty.isConstPtr() and dest_is_mut) break :single_item;
12267 if (inst_ty.isVolatilePtr() and !dest_info.@"volatile") break :single_item;12446 if (inst_ty.isVolatilePtr() and !dest_info.@"volatile") break :single_item;
12268 if (inst_ty.ptrAddressSpace() != dest_info.@"addrspace") break :single_item;12447 if (inst_ty.ptrAddressSpace() != dest_info.@"addrspace") break :single_item;
12269 switch (coerceInMemoryAllowed(array_elem_ty, ptr_elem_ty, dest_is_mut, target)) {12448 switch (try sema.coerceInMemoryAllowed(array_elem_ty, ptr_elem_ty, dest_is_mut, target)) {
12270 .ok => {},12449 .ok => {},
12271 .no_match => break :single_item,12450 .no_match => break :single_item,
12272 }12451 }
...@@ -12285,7 +12464,7 @@ fn coerce(...@@ -12285,7 +12464,7 @@ fn coerce(
12285 if (inst_ty.ptrAddressSpace() != dest_info.@"addrspace") break :src_array_ptr;12464 if (inst_ty.ptrAddressSpace() != dest_info.@"addrspace") break :src_array_ptr;
1228612465
12287 const dst_elem_type = dest_info.pointee_type;12466 const dst_elem_type = dest_info.pointee_type;
12288 switch (coerceInMemoryAllowed(dst_elem_type, array_elem_type, dest_is_mut, target)) {12467 switch (try sema.coerceInMemoryAllowed(dst_elem_type, array_elem_type, dest_is_mut, target)) {
12289 .ok => {},12468 .ok => {},
12290 .no_match => break :src_array_ptr,12469 .no_match => break :src_array_ptr,
12291 }12470 }
...@@ -12324,7 +12503,7 @@ fn coerce(...@@ -12324,7 +12503,7 @@ fn coerce(
12324 const src_elem_ty = inst_ty.childType();12503 const src_elem_ty = inst_ty.childType();
12325 const dest_is_mut = dest_info.mutable;12504 const dest_is_mut = dest_info.mutable;
12326 const dst_elem_type = dest_info.pointee_type;12505 const dst_elem_type = dest_info.pointee_type;
12327 switch (coerceInMemoryAllowed(dst_elem_type, src_elem_ty, dest_is_mut, target)) {12506 switch (try sema.coerceInMemoryAllowed(dst_elem_type, src_elem_ty, dest_is_mut, target)) {
12328 .ok => {},12507 .ok => {},
12329 .no_match => break :src_c_ptr,12508 .no_match => break :src_c_ptr,
12330 }12509 }
...@@ -12467,7 +12646,13 @@ const InMemoryCoercionResult = enum {...@@ -12467,7 +12646,13 @@ const InMemoryCoercionResult = enum {
12467/// * sentinel-terminated pointers can coerce into `[*]`12646/// * sentinel-terminated pointers can coerce into `[*]`
12468/// TODO improve this function to report recursive compile errors like it does in stage1.12647/// TODO improve this function to report recursive compile errors like it does in stage1.
12469/// look at the function types_match_const_cast_only12648/// look at the function types_match_const_cast_only
12470fn coerceInMemoryAllowed(dest_ty: Type, src_ty: Type, dest_is_mut: bool, target: std.Target) InMemoryCoercionResult {12649fn coerceInMemoryAllowed(
12650 sema: *Sema,
12651 dest_ty: Type,
12652 src_ty: Type,
12653 dest_is_mut: bool,
12654 target: std.Target,
12655) CompileError!InMemoryCoercionResult {
12471 if (dest_ty.eql(src_ty))12656 if (dest_ty.eql(src_ty))
12472 return .ok;12657 return .ok;
1247312658
...@@ -12476,32 +12661,35 @@ fn coerceInMemoryAllowed(dest_ty: Type, src_ty: Type, dest_is_mut: bool, target:...@@ -12476,32 +12661,35 @@ fn coerceInMemoryAllowed(dest_ty: Type, src_ty: Type, dest_is_mut: bool, target:
12476 var src_buf: Type.Payload.ElemType = undefined;12661 var src_buf: Type.Payload.ElemType = undefined;
12477 if (dest_ty.ptrOrOptionalPtrTy(&dest_buf)) |dest_ptr_ty| {12662 if (dest_ty.ptrOrOptionalPtrTy(&dest_buf)) |dest_ptr_ty| {
12478 if (src_ty.ptrOrOptionalPtrTy(&src_buf)) |src_ptr_ty| {12663 if (src_ty.ptrOrOptionalPtrTy(&src_buf)) |src_ptr_ty| {
12479 return coerceInMemoryAllowedPtrs(dest_ty, src_ty, dest_ptr_ty, src_ptr_ty, dest_is_mut, target);12664 return try sema.coerceInMemoryAllowedPtrs(dest_ty, src_ty, dest_ptr_ty, src_ptr_ty, dest_is_mut, target);
12480 }12665 }
12481 }12666 }
1248212667
12483 // Slices12668 // Slices
12484 if (dest_ty.isSlice() and src_ty.isSlice()) {12669 if (dest_ty.isSlice() and src_ty.isSlice()) {
12485 return coerceInMemoryAllowedPtrs(dest_ty, src_ty, dest_ty, src_ty, dest_is_mut, target);12670 return try sema.coerceInMemoryAllowedPtrs(dest_ty, src_ty, dest_ty, src_ty, dest_is_mut, target);
12486 }12671 }
1248712672
12673 const dest_tag = dest_ty.zigTypeTag();
12674 const src_tag = src_ty.zigTypeTag();
12675
12488 // Functions12676 // Functions
12489 if (dest_ty.zigTypeTag() == .Fn and src_ty.zigTypeTag() == .Fn) {12677 if (dest_tag == .Fn and src_tag == .Fn) {
12490 return coerceInMemoryAllowedFns(dest_ty, src_ty, target);12678 return try sema.coerceInMemoryAllowedFns(dest_ty, src_ty, target);
12491 }12679 }
1249212680
12493 // Error Unions12681 // Error Unions
12494 if (dest_ty.zigTypeTag() == .ErrorUnion and src_ty.zigTypeTag() == .ErrorUnion) {12682 if (dest_tag == .ErrorUnion and src_tag == .ErrorUnion) {
12495 const child = coerceInMemoryAllowed(dest_ty.errorUnionPayload(), src_ty.errorUnionPayload(), dest_is_mut, target);12683 const child = try sema.coerceInMemoryAllowed(dest_ty.errorUnionPayload(), src_ty.errorUnionPayload(), dest_is_mut, target);
12496 if (child == .no_match) {12684 if (child == .no_match) {
12497 return child;12685 return child;
12498 }12686 }
12499 return coerceInMemoryAllowed(dest_ty.errorUnionSet(), src_ty.errorUnionSet(), dest_is_mut, target);12687 return try sema.coerceInMemoryAllowed(dest_ty.errorUnionSet(), src_ty.errorUnionSet(), dest_is_mut, target);
12500 }12688 }
1250112689
12502 // Error Sets12690 // Error Sets
12503 if (dest_ty.zigTypeTag() == .ErrorSet and src_ty.zigTypeTag() == .ErrorSet) {12691 if (dest_tag == .ErrorSet and src_tag == .ErrorSet) {
12504 return coerceInMemoryAllowedErrorSets(dest_ty, src_ty);12692 return try sema.coerceInMemoryAllowedErrorSets(dest_ty, src_ty);
12505 }12693 }
1250612694
12507 // TODO: arrays12695 // TODO: arrays
...@@ -12512,14 +12700,16 @@ fn coerceInMemoryAllowed(dest_ty: Type, src_ty: Type, dest_is_mut: bool, target:...@@ -12512,14 +12700,16 @@ fn coerceInMemoryAllowed(dest_ty: Type, src_ty: Type, dest_is_mut: bool, target:
12512}12700}
1251312701
12514fn coerceInMemoryAllowedErrorSets(12702fn coerceInMemoryAllowedErrorSets(
12703 sema: *Sema,
12515 dest_ty: Type,12704 dest_ty: Type,
12516 src_ty: Type,12705 src_ty: Type,
12517) InMemoryCoercionResult {12706) !InMemoryCoercionResult {
12518 // Coercion to `anyerror`. Note that this check can return false positives12707 // Coercion to `anyerror`. Note that this check can return false negatives
12519 // in case the error sets did not get resolved.12708 // in case the error sets did not get resolved.
12520 if (dest_ty.isAnyError()) {12709 if (dest_ty.isAnyError()) {
12521 return .ok;12710 return .ok;
12522 }12711 }
12712
12523 // If both are inferred error sets of functions, and12713 // If both are inferred error sets of functions, and
12524 // the dest includes the source function, the coercion is OK.12714 // the dest includes the source function, the coercion is OK.
12525 // This check is important because it works without forcing a full resolution12715 // This check is important because it works without forcing a full resolution
...@@ -12529,21 +12719,85 @@ fn coerceInMemoryAllowedErrorSets(...@@ -12529,21 +12719,85 @@ fn coerceInMemoryAllowedErrorSets(
12529 const src_func = src_payload.data.func;12719 const src_func = src_payload.data.func;
12530 const dst_func = dst_payload.data.func;12720 const dst_func = dst_payload.data.func;
1253112721
12532 if (src_func == dst_func or dst_payload.data.functions.contains(src_func)) {12722 if (src_func == dst_func or dst_payload.data.inferred_error_sets.contains(src_payload.data)) {
12533 return .ok;12723 return .ok;
12534 }12724 }
12725 return .no_match;
12726 }
12727 }
12728
12729 if (dest_ty.castTag(.error_set_inferred)) |payload| {
12730 try sema.resolveInferredErrorSet(payload.data);
12731 // isAnyError might have changed from a false negative to a true positive after resolution.
12732 if (dest_ty.isAnyError()) {
12733 return .ok;
12535 }12734 }
12536 }12735 }
1253712736
12538 // TODO full error set resolution and compare sets by names.12737 switch (src_ty.tag()) {
12738 .error_set_inferred => {
12739 const src_data = src_ty.castTag(.error_set_inferred).?.data;
12740
12741 try sema.resolveInferredErrorSet(src_data);
12742 // src anyerror status might have changed after the resolution.
12743 if (src_ty.isAnyError()) {
12744 // dest_ty.isAnyError() == true is already checked for at this point.
12745 return .no_match;
12746 }
12747
12748 var it = src_data.errors.keyIterator();
12749 while (it.next()) |name_ptr| {
12750 if (!dest_ty.errorSetHasField(name_ptr.*)) {
12751 return .no_match;
12752 }
12753 }
12754
12755 return .ok;
12756 },
12757 .error_set_single => {
12758 const name = src_ty.castTag(.error_set_single).?.data;
12759 if (dest_ty.errorSetHasField(name)) {
12760 return .ok;
12761 }
12762 },
12763 .error_set_merged => {
12764 const names = src_ty.castTag(.error_set_merged).?.data.keys();
12765 for (names) |name| {
12766 if (!dest_ty.errorSetHasField(name)) {
12767 return .no_match;
12768 }
12769 }
12770
12771 return .ok;
12772 },
12773 .error_set => {
12774 const names = src_ty.castTag(.error_set).?.data.names.keys();
12775 for (names) |name| {
12776 if (!dest_ty.errorSetHasField(name)) {
12777 return .no_match;
12778 }
12779 }
12780
12781 return .ok;
12782 },
12783 .anyerror => switch (dest_ty.tag()) {
12784 .error_set_inferred => return .no_match, // Caught by dest.isAnyError() above.
12785 .error_set_single, .error_set_merged, .error_set => {},
12786 .anyerror => unreachable, // Filtered out above.
12787 else => unreachable,
12788 },
12789 else => unreachable,
12790 }
12791
12539 return .no_match;12792 return .no_match;
12540}12793}
1254112794
12542fn coerceInMemoryAllowedFns(12795fn coerceInMemoryAllowedFns(
12796 sema: *Sema,
12543 dest_ty: Type,12797 dest_ty: Type,
12544 src_ty: Type,12798 src_ty: Type,
12545 target: std.Target,12799 target: std.Target,
12546) InMemoryCoercionResult {12800) !InMemoryCoercionResult {
12547 const dest_info = dest_ty.fnInfo();12801 const dest_info = dest_ty.fnInfo();
12548 const src_info = src_ty.fnInfo();12802 const src_info = src_ty.fnInfo();
1254912803
...@@ -12556,7 +12810,7 @@ fn coerceInMemoryAllowedFns(...@@ -12556,7 +12810,7 @@ fn coerceInMemoryAllowedFns(
12556 }12810 }
1255712811
12558 if (!src_info.return_type.isNoReturn()) {12812 if (!src_info.return_type.isNoReturn()) {
12559 const rt = coerceInMemoryAllowed(dest_info.return_type, src_info.return_type, false, target);12813 const rt = try sema.coerceInMemoryAllowed(dest_info.return_type, src_info.return_type, false, target);
12560 if (rt == .no_match) {12814 if (rt == .no_match) {
12561 return rt;12815 return rt;
12562 }12816 }
...@@ -12576,7 +12830,7 @@ fn coerceInMemoryAllowedFns(...@@ -12576,7 +12830,7 @@ fn coerceInMemoryAllowedFns(
12576 // TODO: nolias12830 // TODO: nolias
1257712831
12578 // Note: Cast direction is reversed here.12832 // Note: Cast direction is reversed here.
12579 const param = coerceInMemoryAllowed(src_param_ty, dest_param_ty, false, target);12833 const param = try sema.coerceInMemoryAllowed(src_param_ty, dest_param_ty, false, target);
12580 if (param == .no_match) {12834 if (param == .no_match) {
12581 return param;12835 return param;
12582 }12836 }
...@@ -12590,17 +12844,18 @@ fn coerceInMemoryAllowedFns(...@@ -12590,17 +12844,18 @@ fn coerceInMemoryAllowedFns(
12590}12844}
1259112845
12592fn coerceInMemoryAllowedPtrs(12846fn coerceInMemoryAllowedPtrs(
12847 sema: *Sema,
12593 dest_ty: Type,12848 dest_ty: Type,
12594 src_ty: Type,12849 src_ty: Type,
12595 dest_ptr_ty: Type,12850 dest_ptr_ty: Type,
12596 src_ptr_ty: Type,12851 src_ptr_ty: Type,
12597 dest_is_mut: bool,12852 dest_is_mut: bool,
12598 target: std.Target,12853 target: std.Target,
12599) InMemoryCoercionResult {12854) !InMemoryCoercionResult {
12600 const dest_info = dest_ptr_ty.ptrInfo().data;12855 const dest_info = dest_ptr_ty.ptrInfo().data;
12601 const src_info = src_ptr_ty.ptrInfo().data;12856 const src_info = src_ptr_ty.ptrInfo().data;
1260212857
12603 const child = coerceInMemoryAllowed(dest_info.pointee_type, src_info.pointee_type, dest_info.mutable, target);12858 const child = try sema.coerceInMemoryAllowed(dest_info.pointee_type, src_info.pointee_type, dest_info.mutable, target);
12604 if (child == .no_match) {12859 if (child == .no_match) {
12605 return child;12860 return child;
12606 }12861 }
...@@ -13321,7 +13576,7 @@ fn coerceVectorInMemory(...@@ -13321,7 +13576,7 @@ fn coerceVectorInMemory(
13321 const target = sema.mod.getTarget();13576 const target = sema.mod.getTarget();
13322 const dest_elem_ty = dest_ty.childType();13577 const dest_elem_ty = dest_ty.childType();
13323 const inst_elem_ty = inst_ty.childType();13578 const inst_elem_ty = inst_ty.childType();
13324 const in_memory_result = coerceInMemoryAllowed(dest_elem_ty, inst_elem_ty, false, target);13579 const in_memory_result = try sema.coerceInMemoryAllowed(dest_elem_ty, inst_elem_ty, false, target);
13325 if (in_memory_result != .ok) {13580 if (in_memory_result != .ok) {
13326 // TODO recursive error notes for coerceInMemoryAllowed failure13581 // TODO recursive error notes for coerceInMemoryAllowed failure
13327 return sema.fail(block, inst_src, "expected {}, found {}", .{ dest_ty, inst_ty });13582 return sema.fail(block, inst_src, "expected {}, found {}", .{ dest_ty, inst_ty });
...@@ -13916,25 +14171,28 @@ fn wrapErrorUnion(...@@ -13916,25 +14171,28 @@ fn wrapErrorUnion(
13916 if (mem.eql(u8, expected_name, n)) break :ok;14171 if (mem.eql(u8, expected_name, n)) break :ok;
13917 return sema.failWithErrorSetCodeMissing(block, inst_src, dest_err_set_ty, inst_ty);14172 return sema.failWithErrorSetCodeMissing(block, inst_src, dest_err_set_ty, inst_ty);
13918 },14173 },
13919 .error_set => ok: {14174 .error_set => {
13920 const expected_name = val.castTag(.@"error").?.data.name;14175 const expected_name = val.castTag(.@"error").?.data.name;
13921 const error_set = dest_err_set_ty.castTag(.error_set).?.data;14176 const error_set = dest_err_set_ty.castTag(.error_set).?.data;
13922 const names = error_set.names_ptr[0..error_set.names_len];14177 if (!error_set.names.contains(expected_name)) {
13923 // TODO this is O(N). I'm putting off solving this until we solve inferred14178 return sema.failWithErrorSetCodeMissing(block, inst_src, dest_err_set_ty, inst_ty);
13924 // error sets at the same time.
13925 for (names) |name| {
13926 if (mem.eql(u8, expected_name, name)) break :ok;
13927 }14179 }
13928 return sema.failWithErrorSetCodeMissing(block, inst_src, dest_err_set_ty, inst_ty);
13929 },14180 },
13930 .error_set_inferred => ok: {14181 .error_set_inferred => ok: {
13931 const err_set_payload = dest_err_set_ty.castTag(.error_set_inferred).?.data;
13932 if (err_set_payload.is_anyerror) break :ok;
13933 const expected_name = val.castTag(.@"error").?.data.name;14182 const expected_name = val.castTag(.@"error").?.data.name;
13934 if (err_set_payload.map.contains(expected_name)) break :ok;14183 const data = dest_err_set_ty.castTag(.error_set_inferred).?.data;
13935 // TODO error set resolution here before emitting a compile error14184 try sema.resolveInferredErrorSet(data);
14185 if (data.is_anyerror) break :ok;
14186 if (data.errors.contains(expected_name)) break :ok;
13936 return sema.failWithErrorSetCodeMissing(block, inst_src, dest_err_set_ty, inst_ty);14187 return sema.failWithErrorSetCodeMissing(block, inst_src, dest_err_set_ty, inst_ty);
13937 },14188 },
14189 .error_set_merged => {
14190 const expected_name = val.castTag(.@"error").?.data.name;
14191 const error_set = dest_err_set_ty.castTag(.error_set_merged).?.data;
14192 if (!error_set.contains(expected_name)) {
14193 return sema.failWithErrorSetCodeMissing(block, inst_src, dest_err_set_ty, inst_ty);
14194 }
14195 },
13938 else => unreachable,14196 else => unreachable,
13939 }14197 }
13940 return sema.addConstant(dest_ty, val);14198 return sema.addConstant(dest_ty, val);
...@@ -14077,12 +14335,12 @@ fn resolvePeerTypes(...@@ -14077,12 +14335,12 @@ fn resolvePeerTypes(
14077 .Optional => {14335 .Optional => {
14078 var opt_child_buf: Type.Payload.ElemType = undefined;14336 var opt_child_buf: Type.Payload.ElemType = undefined;
14079 const opt_child_ty = candidate_ty.optionalChild(&opt_child_buf);14337 const opt_child_ty = candidate_ty.optionalChild(&opt_child_buf);
14080 if (coerceInMemoryAllowed(opt_child_ty, chosen_ty, false, target) == .ok) {14338 if ((try sema.coerceInMemoryAllowed(opt_child_ty, chosen_ty, false, target)) == .ok) {
14081 chosen = candidate;14339 chosen = candidate;
14082 chosen_i = candidate_i + 1;14340 chosen_i = candidate_i + 1;
14083 continue;14341 continue;
14084 }14342 }
14085 if (coerceInMemoryAllowed(chosen_ty, opt_child_ty, false, target) == .ok) {14343 if ((try sema.coerceInMemoryAllowed(chosen_ty, opt_child_ty, false, target)) == .ok) {
14086 any_are_null = true;14344 any_are_null = true;
14087 continue;14345 continue;
14088 }14346 }
...@@ -14105,10 +14363,10 @@ fn resolvePeerTypes(...@@ -14105,10 +14363,10 @@ fn resolvePeerTypes(
14105 .Optional => {14363 .Optional => {
14106 var opt_child_buf: Type.Payload.ElemType = undefined;14364 var opt_child_buf: Type.Payload.ElemType = undefined;
14107 const opt_child_ty = chosen_ty.optionalChild(&opt_child_buf);14365 const opt_child_ty = chosen_ty.optionalChild(&opt_child_buf);
14108 if (coerceInMemoryAllowed(opt_child_ty, candidate_ty, false, target) == .ok) {14366 if ((try sema.coerceInMemoryAllowed(opt_child_ty, candidate_ty, false, target)) == .ok) {
14109 continue;14367 continue;
14110 }14368 }
14111 if (coerceInMemoryAllowed(candidate_ty, opt_child_ty, false, target) == .ok) {14369 if ((try sema.coerceInMemoryAllowed(candidate_ty, opt_child_ty, false, target)) == .ok) {
14112 any_are_null = true;14370 any_are_null = true;
14113 chosen = candidate;14371 chosen = candidate;
14114 chosen_i = candidate_i + 1;14372 chosen_i = candidate_i + 1;
...@@ -14274,6 +14532,42 @@ fn resolveBuiltinTypeFields(...@@ -14274,6 +14532,42 @@ fn resolveBuiltinTypeFields(
14274 return sema.resolveTypeFields(block, src, resolved_ty);14532 return sema.resolveTypeFields(block, src, resolved_ty);
14275}14533}
1427614534
14535fn resolveInferredErrorSet(sema: *Sema, inferred_error_set: *Module.Fn.InferredErrorSet) CompileError!void {
14536 // Ensuring that a particular decl is analyzed does not neccesarily mean that
14537 // it's error set is inferred, so traverse all of them to get the complete
14538 // picture.
14539 // Note: We want to skip re-resolving the current function, as recursion
14540 // doesn't change the error set. We can just check for state == .in_progress for this.
14541 // TODO: Is that correct?
14542
14543 if (inferred_error_set.is_resolved) {
14544 return;
14545 }
14546
14547 var it = inferred_error_set.inferred_error_sets.keyIterator();
14548 while (it.next()) |other_error_set_ptr| {
14549 const func = other_error_set_ptr.*.func;
14550 const decl = func.*.owner_decl;
14551
14552 if (func.*.state == .in_progress) {
14553 // Recursion, doesn't alter current error set, keep going.
14554 continue;
14555 }
14556
14557 try sema.ensureDeclAnalyzed(decl); // To ensure that all dependencies are properly added to the set.
14558 try sema.resolveInferredErrorSet(other_error_set_ptr.*);
14559
14560 var error_it = other_error_set_ptr.*.errors.keyIterator();
14561 while (error_it.next()) |entry| {
14562 try inferred_error_set.errors.put(sema.gpa, entry.*, {});
14563 }
14564 if (other_error_set_ptr.*.is_anyerror)
14565 inferred_error_set.is_anyerror = true;
14566 }
14567
14568 inferred_error_set.is_resolved = true;
14569}
14570
14277fn semaStructFields(14571fn semaStructFields(
14278 mod: *Module,14572 mod: *Module,
14279 struct_obj: *Module.Struct,14573 struct_obj: *Module.Struct,
...@@ -15236,8 +15530,8 @@ fn pointerDeref(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, ptr...@@ -15236,8 +15530,8 @@ fn pointerDeref(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, ptr
15236 // We have a Value that lines up in virtual memory exactly with what we want to load.15530 // We have a Value that lines up in virtual memory exactly with what we want to load.
15237 // If the Type is in-memory coercable to `load_ty`, it may be returned without modifications.15531 // If the Type is in-memory coercable to `load_ty`, it may be returned without modifications.
15238 const coerce_in_mem_ok =15532 const coerce_in_mem_ok =
15239 coerceInMemoryAllowed(load_ty, parent.ty, false, target) == .ok or15533 (try sema.coerceInMemoryAllowed(load_ty, parent.ty, false, target)) == .ok or
15240 coerceInMemoryAllowed(parent.ty, load_ty, false, target) == .ok;15534 (try sema.coerceInMemoryAllowed(parent.ty, load_ty, false, target)) == .ok;
15241 if (coerce_in_mem_ok) {15535 if (coerce_in_mem_ok) {
15242 if (parent.is_mutable) {15536 if (parent.is_mutable) {
15243 // The decl whose value we are obtaining here may be overwritten with15537 // The decl whose value we are obtaining here may be overwritten with
src/arch/aarch64/CodeGen.zig+30
...@@ -521,6 +521,11 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -521,6 +521,11 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
521 .max => try self.airMax(inst),521 .max => try self.airMax(inst),
522 .slice => try self.airSlice(inst),522 .slice => try self.airSlice(inst),
523523
524 .add_with_overflow => try self.airAddWithOverflow(inst),
525 .sub_with_overflow => try self.airSubWithOverflow(inst),
526 .mul_with_overflow => try self.airMulWithOverflow(inst),
527 .shl_with_overflow => try self.airShlWithOverflow(inst),
528
524 .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst),529 .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst),
525530
526 .cmp_lt => try self.airCmp(inst, .lt),531 .cmp_lt => try self.airCmp(inst, .lt),
...@@ -545,6 +550,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -545,6 +550,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
545 .block => try self.airBlock(inst),550 .block => try self.airBlock(inst),
546 .br => try self.airBr(inst),551 .br => try self.airBr(inst),
547 .breakpoint => try self.airBreakpoint(),552 .breakpoint => try self.airBreakpoint(),
553 .ret_addr => try self.airRetAddr(),
548 .fence => try self.airFence(),554 .fence => try self.airFence(),
549 .call => try self.airCall(inst),555 .call => try self.airCall(inst),
550 .cond_br => try self.airCondBr(inst),556 .cond_br => try self.airCondBr(inst),
...@@ -968,6 +974,26 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void {...@@ -968,6 +974,26 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void {
968 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });974 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
969}975}
970976
977fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
978 _ = inst;
979 return self.fail("TODO implement airAddWithOverflow for {}", .{self.target.cpu.arch});
980}
981
982fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
983 _ = inst;
984 return self.fail("TODO implement airSubWithOverflow for {}", .{self.target.cpu.arch});
985}
986
987fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
988 _ = inst;
989 return self.fail("TODO implement airMulWithOverflow for {}", .{self.target.cpu.arch});
990}
991
992fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
993 _ = inst;
994 return self.fail("TODO implement airShlWithOverflow for {}", .{self.target.cpu.arch});
995}
996
971fn airDiv(self: *Self, inst: Air.Inst.Index) !void {997fn airDiv(self: *Self, inst: Air.Inst.Index) !void {
972 const bin_op = self.air.instructions.items(.data)[inst].bin_op;998 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
973 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement div for {}", .{self.target.cpu.arch});999 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement div for {}", .{self.target.cpu.arch});
...@@ -1409,6 +1435,10 @@ fn airBreakpoint(self: *Self) !void {...@@ -1409,6 +1435,10 @@ fn airBreakpoint(self: *Self) !void {
1409 return self.finishAirBookkeeping();1435 return self.finishAirBookkeeping();
1410}1436}
14111437
1438fn airRetAddr(self: *Self) !void {
1439 return self.fail("TODO implement airRetAddr for {}", .{self.target.cpu.arch});
1440}
1441
1412fn airFence(self: *Self) !void {1442fn airFence(self: *Self) !void {
1413 return self.fail("TODO implement fence() for {}", .{self.target.cpu.arch});1443 return self.fail("TODO implement fence() for {}", .{self.target.cpu.arch});
1414 //return self.finishAirBookkeeping();1444 //return self.finishAirBookkeeping();
src/arch/arm/CodeGen.zig+30
...@@ -519,6 +519,11 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -519,6 +519,11 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
519 .max => try self.airMax(inst),519 .max => try self.airMax(inst),
520 .slice => try self.airSlice(inst),520 .slice => try self.airSlice(inst),
521521
522 .add_with_overflow => try self.airAddWithOverflow(inst),
523 .sub_with_overflow => try self.airSubWithOverflow(inst),
524 .mul_with_overflow => try self.airMulWithOverflow(inst),
525 .shl_with_overflow => try self.airShlWithOverflow(inst),
526
522 .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst),527 .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst),
523528
524 .cmp_lt => try self.airCmp(inst, .lt),529 .cmp_lt => try self.airCmp(inst, .lt),
...@@ -543,6 +548,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -543,6 +548,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
543 .block => try self.airBlock(inst),548 .block => try self.airBlock(inst),
544 .br => try self.airBr(inst),549 .br => try self.airBr(inst),
545 .breakpoint => try self.airBreakpoint(),550 .breakpoint => try self.airBreakpoint(),
551 .ret_addr => try self.airRetAddr(),
546 .fence => try self.airFence(),552 .fence => try self.airFence(),
547 .call => try self.airCall(inst),553 .call => try self.airCall(inst),
548 .cond_br => try self.airCondBr(inst),554 .cond_br => try self.airCondBr(inst),
...@@ -998,6 +1004,26 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void {...@@ -998,6 +1004,26 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void {
998 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });1004 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
999}1005}
10001006
1007fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1008 _ = inst;
1009 return self.fail("TODO implement airAddWithOverflow for {}", .{self.target.cpu.arch});
1010}
1011
1012fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1013 _ = inst;
1014 return self.fail("TODO implement airSubWithOverflow for {}", .{self.target.cpu.arch});
1015}
1016
1017fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1018 _ = inst;
1019 return self.fail("TODO implement airMulWithOverflow for {}", .{self.target.cpu.arch});
1020}
1021
1022fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1023 _ = inst;
1024 return self.fail("TODO implement airShlWithOverflow for {}", .{self.target.cpu.arch});
1025}
1026
1001fn airDiv(self: *Self, inst: Air.Inst.Index) !void {1027fn airDiv(self: *Self, inst: Air.Inst.Index) !void {
1002 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1028 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1003 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement div for {}", .{self.target.cpu.arch});1029 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement div for {}", .{self.target.cpu.arch});
...@@ -1843,6 +1869,10 @@ fn airBreakpoint(self: *Self) !void {...@@ -1843,6 +1869,10 @@ fn airBreakpoint(self: *Self) !void {
1843 return self.finishAirBookkeeping();1869 return self.finishAirBookkeeping();
1844}1870}
18451871
1872fn airRetAddr(self: *Self) !void {
1873 return self.fail("TODO implement airRetAddr for {}", .{self.target.cpu.arch});
1874}
1875
1846fn airFence(self: *Self) !void {1876fn airFence(self: *Self) !void {
1847 return self.fail("TODO implement fence() for {}", .{self.target.cpu.arch});1877 return self.fail("TODO implement fence() for {}", .{self.target.cpu.arch});
1848 //return self.finishAirBookkeeping();1878 //return self.finishAirBookkeeping();
src/arch/riscv64/CodeGen.zig+30
...@@ -500,6 +500,11 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -500,6 +500,11 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
500 .max => try self.airMax(inst),500 .max => try self.airMax(inst),
501 .slice => try self.airSlice(inst),501 .slice => try self.airSlice(inst),
502502
503 .add_with_overflow => try self.airAddWithOverflow(inst),
504 .sub_with_overflow => try self.airSubWithOverflow(inst),
505 .mul_with_overflow => try self.airMulWithOverflow(inst),
506 .shl_with_overflow => try self.airShlWithOverflow(inst),
507
503 .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst),508 .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst),
504509
505 .cmp_lt => try self.airCmp(inst, .lt),510 .cmp_lt => try self.airCmp(inst, .lt),
...@@ -524,6 +529,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -524,6 +529,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
524 .block => try self.airBlock(inst),529 .block => try self.airBlock(inst),
525 .br => try self.airBr(inst),530 .br => try self.airBr(inst),
526 .breakpoint => try self.airBreakpoint(),531 .breakpoint => try self.airBreakpoint(),
532 .ret_addr => try self.airRetAddr(),
527 .fence => try self.airFence(),533 .fence => try self.airFence(),
528 .call => try self.airCall(inst),534 .call => try self.airCall(inst),
529 .cond_br => try self.airCondBr(inst),535 .cond_br => try self.airCondBr(inst),
...@@ -913,6 +919,26 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void {...@@ -913,6 +919,26 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void {
913 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });919 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
914}920}
915921
922fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
923 _ = inst;
924 return self.fail("TODO implement airAddWithOverflow for {}", .{self.target.cpu.arch});
925}
926
927fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
928 _ = inst;
929 return self.fail("TODO implement airSubWithOverflow for {}", .{self.target.cpu.arch});
930}
931
932fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
933 _ = inst;
934 return self.fail("TODO implement airMulWithOverflow for {}", .{self.target.cpu.arch});
935}
936
937fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
938 _ = inst;
939 return self.fail("TODO implement airShlWithOverflow for {}", .{self.target.cpu.arch});
940}
941
916fn airDiv(self: *Self, inst: Air.Inst.Index) !void {942fn airDiv(self: *Self, inst: Air.Inst.Index) !void {
917 const bin_op = self.air.instructions.items(.data)[inst].bin_op;943 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
918 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement div for {}", .{self.target.cpu.arch});944 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement div for {}", .{self.target.cpu.arch});
...@@ -1347,6 +1373,10 @@ fn airBreakpoint(self: *Self) !void {...@@ -1347,6 +1373,10 @@ fn airBreakpoint(self: *Self) !void {
1347 return self.finishAirBookkeeping();1373 return self.finishAirBookkeeping();
1348}1374}
13491375
1376fn airRetAddr(self: *Self) !void {
1377 return self.fail("TODO implement airRetAddr for {}", .{self.target.cpu.arch});
1378}
1379
1350fn airFence(self: *Self) !void {1380fn airFence(self: *Self) !void {
1351 return self.fail("TODO implement fence() for {}", .{self.target.cpu.arch});1381 return self.fail("TODO implement fence() for {}", .{self.target.cpu.arch});
1352 //return self.finishAirBookkeeping();1382 //return self.finishAirBookkeeping();
src/arch/x86_64/CodeGen.zig+30
...@@ -553,6 +553,11 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -553,6 +553,11 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
553 .max => try self.airMax(inst),553 .max => try self.airMax(inst),
554 .slice => try self.airSlice(inst),554 .slice => try self.airSlice(inst),
555555
556 .add_with_overflow => try self.airAddWithOverflow(inst),
557 .sub_with_overflow => try self.airSubWithOverflow(inst),
558 .mul_with_overflow => try self.airMulWithOverflow(inst),
559 .shl_with_overflow => try self.airShlWithOverflow(inst),
560
556 .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst),561 .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst),
557562
558 .cmp_lt => try self.airCmp(inst, .lt),563 .cmp_lt => try self.airCmp(inst, .lt),
...@@ -577,6 +582,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -577,6 +582,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
577 .block => try self.airBlock(inst),582 .block => try self.airBlock(inst),
578 .br => try self.airBr(inst),583 .br => try self.airBr(inst),
579 .breakpoint => try self.airBreakpoint(),584 .breakpoint => try self.airBreakpoint(),
585 .ret_addr => try self.airRetAddr(),
580 .fence => try self.airFence(),586 .fence => try self.airFence(),
581 .call => try self.airCall(inst),587 .call => try self.airCall(inst),
582 .cond_br => try self.airCondBr(inst),588 .cond_br => try self.airCondBr(inst),
...@@ -1027,6 +1033,26 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void {...@@ -1027,6 +1033,26 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void {
1027 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });1033 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1028}1034}
10291035
1036fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1037 _ = inst;
1038 return self.fail("TODO implement airAddWithOverflow for {}", .{self.target.cpu.arch});
1039}
1040
1041fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1042 _ = inst;
1043 return self.fail("TODO implement airSubWithOverflow for {}", .{self.target.cpu.arch});
1044}
1045
1046fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1047 _ = inst;
1048 return self.fail("TODO implement airMulWithOverflow for {}", .{self.target.cpu.arch});
1049}
1050
1051fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1052 _ = inst;
1053 return self.fail("TODO implement airShlWithOverflow for {}", .{self.target.cpu.arch});
1054}
1055
1030fn airDiv(self: *Self, inst: Air.Inst.Index) !void {1056fn airDiv(self: *Self, inst: Air.Inst.Index) !void {
1031 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1057 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1032 const result: MCValue = if (self.liveness.isUnused(inst))1058 const result: MCValue = if (self.liveness.isUnused(inst))
...@@ -1832,6 +1858,10 @@ fn airBreakpoint(self: *Self) !void {...@@ -1832,6 +1858,10 @@ fn airBreakpoint(self: *Self) !void {
1832 return self.finishAirBookkeeping();1858 return self.finishAirBookkeeping();
1833}1859}
18341860
1861fn airRetAddr(self: *Self) !void {
1862 return self.fail("TODO implement airRetAddr for {}", .{self.target.cpu.arch});
1863}
1864
1835fn airFence(self: *Self) !void {1865fn airFence(self: *Self) !void {
1836 return self.fail("TODO implement fence() for {}", .{self.target.cpu.arch});1866 return self.fail("TODO implement fence() for {}", .{self.target.cpu.arch});
1837 //return self.finishAirBookkeeping();1867 //return self.finishAirBookkeeping();
src/codegen/c.zig+34
...@@ -1125,6 +1125,7 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO...@@ -1125,6 +1125,7 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
1125 .arg => airArg(f),1125 .arg => airArg(f),
11261126
1127 .breakpoint => try airBreakpoint(f),1127 .breakpoint => try airBreakpoint(f),
1128 .ret_addr => try airRetAddr(f),
1128 .unreach => try airUnreach(f),1129 .unreach => try airUnreach(f),
1129 .fence => try airFence(f, inst),1130 .fence => try airFence(f, inst),
11301131
...@@ -1155,6 +1156,11 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO...@@ -1155,6 +1156,11 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
1155 .mul_sat => try airSatOp(f, inst, "muls_"),1156 .mul_sat => try airSatOp(f, inst, "muls_"),
1156 .shl_sat => try airSatOp(f, inst, "shls_"),1157 .shl_sat => try airSatOp(f, inst, "shls_"),
11571158
1159 .add_with_overflow => try airAddWithOverflow(f, inst),
1160 .sub_with_overflow => try airSubWithOverflow(f, inst),
1161 .mul_with_overflow => try airMulWithOverflow(f, inst),
1162 .shl_with_overflow => try airShlWithOverflow(f, inst),
1163
1158 .min => try airMinMax(f, inst, "<"),1164 .min => try airMinMax(f, inst, "<"),
1159 .max => try airMinMax(f, inst, ">"),1165 .max => try airMinMax(f, inst, ">"),
11601166
...@@ -1864,6 +1870,30 @@ fn airSatOp(f: *Function, inst: Air.Inst.Index, fn_op: [*:0]const u8) !CValue {...@@ -1864,6 +1870,30 @@ fn airSatOp(f: *Function, inst: Air.Inst.Index, fn_op: [*:0]const u8) !CValue {
1864 return ret;1870 return ret;
1865}1871}
18661872
1873fn airAddWithOverflow(f: *Function, inst: Air.Inst.Index) !CValue {
1874 _ = f;
1875 _ = inst;
1876 return f.fail("TODO add with overflow", .{});
1877}
1878
1879fn airSubWithOverflow(f: *Function, inst: Air.Inst.Index) !CValue {
1880 _ = f;
1881 _ = inst;
1882 return f.fail("TODO sub with overflow", .{});
1883}
1884
1885fn airMulWithOverflow(f: *Function, inst: Air.Inst.Index) !CValue {
1886 _ = f;
1887 _ = inst;
1888 return f.fail("TODO mul with overflow", .{});
1889}
1890
1891fn airShlWithOverflow(f: *Function, inst: Air.Inst.Index) !CValue {
1892 _ = f;
1893 _ = inst;
1894 return f.fail("TODO shl with overflow", .{});
1895}
1896
1867fn airNot(f: *Function, inst: Air.Inst.Index) !CValue {1897fn airNot(f: *Function, inst: Air.Inst.Index) !CValue {
1868 if (f.liveness.isUnused(inst))1898 if (f.liveness.isUnused(inst))
1869 return CValue.none;1899 return CValue.none;
...@@ -2183,6 +2213,10 @@ fn airBreakpoint(f: *Function) !CValue {...@@ -2183,6 +2213,10 @@ fn airBreakpoint(f: *Function) !CValue {
2183 return CValue.none;2213 return CValue.none;
2184}2214}
21852215
2216fn airRetAddr(f: *Function) !CValue {
2217 return f.fail("TODO implement codegen for airRetAddr", .{});
2218}
2219
2186fn airFence(f: *Function, inst: Air.Inst.Index) !CValue {2220fn airFence(f: *Function, inst: Air.Inst.Index) !CValue {
2187 const atomic_order = f.air.instructions.items(.data)[inst].fence;2221 const atomic_order = f.air.instructions.items(.data)[inst].fence;
2188 const writer = f.object.writer();2222 const writer = f.object.writer();
src/codegen/llvm.zig+103-18
...@@ -761,21 +761,25 @@ pub const DeclGen = struct {...@@ -761,21 +761,25 @@ pub const DeclGen = struct {
761 dg.context.intType(8);761 dg.context.intType(8);
762 return llvm_elem_ty.pointerType(llvm_addrspace);762 return llvm_elem_ty.pointerType(llvm_addrspace);
763 },763 },
764 .Opaque => {764 .Opaque => switch (t.tag()) {
765 const gop = try dg.object.type_map.getOrPut(gpa, t);765 .@"opaque" => {
766 if (gop.found_existing) return gop.value_ptr.*;766 const gop = try dg.object.type_map.getOrPut(gpa, t);
767 if (gop.found_existing) return gop.value_ptr.*;
767768
768 // The Type memory is ephemeral; since we want to store a longer-lived769 // The Type memory is ephemeral; since we want to store a longer-lived
769 // reference, we need to copy it here.770 // reference, we need to copy it here.
770 gop.key_ptr.* = try t.copy(dg.object.type_map_arena.allocator());771 gop.key_ptr.* = try t.copy(dg.object.type_map_arena.allocator());
771772
772 const opaque_obj = t.castTag(.@"opaque").?.data;773 const opaque_obj = t.castTag(.@"opaque").?.data;
773 const name = try opaque_obj.getFullyQualifiedName(gpa);774 const name = try opaque_obj.getFullyQualifiedName(gpa);
774 defer gpa.free(name);775 defer gpa.free(name);
775776
776 const llvm_struct_ty = dg.context.structCreateNamed(name);777 const llvm_struct_ty = dg.context.structCreateNamed(name);
777 gop.value_ptr.* = llvm_struct_ty; // must be done before any recursive calls778 gop.value_ptr.* = llvm_struct_ty; // must be done before any recursive calls
778 return llvm_struct_ty;779 return llvm_struct_ty;
780 },
781 .anyopaque => return dg.context.intType(8),
782 else => unreachable,
779 },783 },
780 .Array => {784 .Array => {
781 const elem_type = try dg.llvmType(t.childType());785 const elem_type = try dg.llvmType(t.childType());
...@@ -1714,6 +1718,11 @@ pub const FuncGen = struct {...@@ -1714,6 +1718,11 @@ pub const FuncGen = struct {
1714 .max => try self.airMax(inst),1718 .max => try self.airMax(inst),
1715 .slice => try self.airSlice(inst),1719 .slice => try self.airSlice(inst),
17161720
1721 .add_with_overflow => try self.airOverflow(inst, "llvm.sadd.with.overflow", "llvm.uadd.with.overflow"),
1722 .sub_with_overflow => try self.airOverflow(inst, "llvm.ssub.with.overflow", "llvm.usub.with.overflow"),
1723 .mul_with_overflow => try self.airOverflow(inst, "llvm.smul.with.overflow", "llvm.umul.with.overflow"),
1724 .shl_with_overflow => try self.airShlWithOverflow(inst),
1725
1717 .bit_and, .bool_and => try self.airAnd(inst),1726 .bit_and, .bool_and => try self.airAnd(inst),
1718 .bit_or, .bool_or => try self.airOr(inst),1727 .bit_or, .bool_or => try self.airOr(inst),
1719 .xor => try self.airXor(inst),1728 .xor => try self.airXor(inst),
...@@ -1745,6 +1754,7 @@ pub const FuncGen = struct {...@@ -1745,6 +1754,7 @@ pub const FuncGen = struct {
1745 .br => try self.airBr(inst),1754 .br => try self.airBr(inst),
1746 .switch_br => try self.airSwitchBr(inst),1755 .switch_br => try self.airSwitchBr(inst),
1747 .breakpoint => try self.airBreakpoint(inst),1756 .breakpoint => try self.airBreakpoint(inst),
1757 .ret_addr => try self.airRetAddr(inst),
1748 .call => try self.airCall(inst),1758 .call => try self.airCall(inst),
1749 .cond_br => try self.airCondBr(inst),1759 .cond_br => try self.airCondBr(inst),
1750 .intcast => try self.airIntCast(inst),1760 .intcast => try self.airIntCast(inst),
...@@ -3133,6 +3143,75 @@ pub const FuncGen = struct {...@@ -3133,6 +3143,75 @@ pub const FuncGen = struct {
3133 }3143 }
3134 }3144 }
31353145
3146 fn airOverflow(
3147 self: *FuncGen,
3148 inst: Air.Inst.Index,
3149 signed_intrinsic: []const u8,
3150 unsigned_intrinsic: []const u8,
3151 ) !?*const llvm.Value {
3152 if (self.liveness.isUnused(inst))
3153 return null;
3154
3155 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
3156 const extra = self.air.extraData(Air.Bin, pl_op.payload).data;
3157
3158 const ptr = try self.resolveInst(pl_op.operand);
3159 const lhs = try self.resolveInst(extra.lhs);
3160 const rhs = try self.resolveInst(extra.rhs);
3161
3162 const ptr_ty = self.air.typeOf(pl_op.operand);
3163 const lhs_ty = self.air.typeOf(extra.lhs);
3164
3165 const intrinsic_name = if (lhs_ty.isSignedInt()) signed_intrinsic else unsigned_intrinsic;
3166
3167 const llvm_lhs_ty = try self.dg.llvmType(lhs_ty);
3168
3169 const llvm_fn = self.getIntrinsic(intrinsic_name, &.{llvm_lhs_ty});
3170 const result_struct = self.builder.buildCall(llvm_fn, &[_]*const llvm.Value{ lhs, rhs }, 2, .Fast, .Auto, "");
3171
3172 const result = self.builder.buildExtractValue(result_struct, 0, "");
3173 const overflow_bit = self.builder.buildExtractValue(result_struct, 1, "");
3174
3175 self.store(ptr, ptr_ty, result, .NotAtomic);
3176
3177 return overflow_bit;
3178 }
3179
3180 fn airShlWithOverflow(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
3181 if (self.liveness.isUnused(inst))
3182 return null;
3183
3184 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
3185 const extra = self.air.extraData(Air.Bin, pl_op.payload).data;
3186
3187 const ptr = try self.resolveInst(pl_op.operand);
3188 const lhs = try self.resolveInst(extra.lhs);
3189 const rhs = try self.resolveInst(extra.rhs);
3190
3191 const ptr_ty = self.air.typeOf(pl_op.operand);
3192 const lhs_ty = self.air.typeOf(extra.lhs);
3193 const rhs_ty = self.air.typeOf(extra.rhs);
3194
3195 const tg = self.dg.module.getTarget();
3196
3197 const casted_rhs = if (rhs_ty.bitSize(tg) < lhs_ty.bitSize(tg))
3198 self.builder.buildZExt(rhs, try self.dg.llvmType(lhs_ty), "")
3199 else
3200 rhs;
3201
3202 const result = self.builder.buildShl(lhs, casted_rhs, "");
3203 const reconstructed = if (lhs_ty.isSignedInt())
3204 self.builder.buildAShr(result, casted_rhs, "")
3205 else
3206 self.builder.buildLShr(result, casted_rhs, "");
3207
3208 const overflow_bit = self.builder.buildICmp(.NE, lhs, reconstructed, "");
3209
3210 self.store(ptr, ptr_ty, result, .NotAtomic);
3211
3212 return overflow_bit;
3213 }
3214
3136 fn airAnd(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {3215 fn airAnd(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
3137 if (self.liveness.isUnused(inst))3216 if (self.liveness.isUnused(inst))
3138 return null;3217 return null;
...@@ -3511,11 +3590,20 @@ pub const FuncGen = struct {...@@ -3511,11 +3590,20 @@ pub const FuncGen = struct {
35113590
3512 fn airBreakpoint(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {3591 fn airBreakpoint(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
3513 _ = inst;3592 _ = inst;
3514 const llvm_fn = self.getIntrinsic("llvm.debugtrap");3593 const llvm_fn = self.getIntrinsic("llvm.debugtrap", &.{});
3515 _ = self.builder.buildCall(llvm_fn, undefined, 0, .C, .Auto, "");3594 _ = self.builder.buildCall(llvm_fn, undefined, 0, .C, .Auto, "");
3516 return null;3595 return null;
3517 }3596 }
35183597
3598 fn airRetAddr(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
3599 _ = inst;
3600 const i32_zero = self.context.intType(32).constNull();
3601 const usize_llvm_ty = try self.dg.llvmType(Type.usize);
3602 const llvm_fn = self.getIntrinsic("llvm.returnaddress", &.{});
3603 const ptr_val = self.builder.buildCall(llvm_fn, &[_]*const llvm.Value{i32_zero}, 1, .Fast, .Auto, "");
3604 return self.builder.buildPtrToInt(ptr_val, usize_llvm_ty, "");
3605 }
3606
3519 fn airFence(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {3607 fn airFence(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
3520 const atomic_order = self.air.instructions.items(.data)[inst].fence;3608 const atomic_order = self.air.instructions.items(.data)[inst].fence;
3521 const llvm_memory_order = toLlvmAtomicOrdering(atomic_order);3609 const llvm_memory_order = toLlvmAtomicOrdering(atomic_order);
...@@ -3946,13 +4034,10 @@ pub const FuncGen = struct {...@@ -3946,13 +4034,10 @@ pub const FuncGen = struct {
3946 return self.builder.buildInBoundsGEP(base_ptr, &indices, indices.len, "");4034 return self.builder.buildInBoundsGEP(base_ptr, &indices, indices.len, "");
3947 }4035 }
39484036
3949 fn getIntrinsic(self: *FuncGen, name: []const u8) *const llvm.Value {4037 fn getIntrinsic(self: *FuncGen, name: []const u8, types: []*const llvm.Type) *const llvm.Value {
3950 const id = llvm.lookupIntrinsicID(name.ptr, name.len);4038 const id = llvm.lookupIntrinsicID(name.ptr, name.len);
3951 assert(id != 0);4039 assert(id != 0);
3952 // TODO: add support for overload intrinsics by passing the prefix of the intrinsic4040 return self.llvmModule().getIntrinsicDeclaration(id, types.ptr, types.len);
3953 // to `lookupIntrinsicID` and then passing the correct types to
3954 // `getIntrinsicDeclaration`
3955 return self.llvmModule().getIntrinsicDeclaration(id, null, 0);
3956 }4041 }
39574042
3958 fn load(self: *FuncGen, ptr: *const llvm.Value, ptr_ty: Type) ?*const llvm.Value {4043 fn load(self: *FuncGen, ptr: *const llvm.Value, ptr_ty: Type) ?*const llvm.Value {
src/print_air.zig+18
...@@ -159,6 +159,7 @@ const Writer = struct {...@@ -159,6 +159,7 @@ const Writer = struct {
159159
160 .breakpoint,160 .breakpoint,
161 .unreach,161 .unreach,
162 .ret_addr,
162 => try w.writeNoOp(s, inst),163 => try w.writeNoOp(s, inst),
163164
164 .const_ty,165 .const_ty,
...@@ -228,6 +229,12 @@ const Writer = struct {...@@ -228,6 +229,12 @@ const Writer = struct {
228 .atomic_rmw => try w.writeAtomicRmw(s, inst),229 .atomic_rmw => try w.writeAtomicRmw(s, inst),
229 .memcpy => try w.writeMemcpy(s, inst),230 .memcpy => try w.writeMemcpy(s, inst),
230 .memset => try w.writeMemset(s, inst),231 .memset => try w.writeMemset(s, inst),
232
233 .add_with_overflow,
234 .sub_with_overflow,
235 .mul_with_overflow,
236 .shl_with_overflow,
237 => try w.writeOverflow(s, inst),
231 }238 }
232 }239 }
233240
...@@ -348,6 +355,17 @@ const Writer = struct {...@@ -348,6 +355,17 @@ const Writer = struct {
348 try s.print(", {s}, {s}", .{ @tagName(extra.op()), @tagName(extra.ordering()) });355 try s.print(", {s}, {s}", .{ @tagName(extra.op()), @tagName(extra.ordering()) });
349 }356 }
350357
358 fn writeOverflow(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
359 const pl_op = w.air.instructions.items(.data)[inst].pl_op;
360 const extra = w.air.extraData(Air.Bin, pl_op.payload).data;
361
362 try w.writeOperand(s, inst, 0, pl_op.operand);
363 try s.writeAll(", ");
364 try w.writeOperand(s, inst, 1, extra.lhs);
365 try s.writeAll(", ");
366 try w.writeOperand(s, inst, 2, extra.rhs);
367 }
368
351 fn writeMemset(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {369 fn writeMemset(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
352 const pl_op = w.air.instructions.items(.data)[inst].pl_op;370 const pl_op = w.air.instructions.items(.data)[inst].pl_op;
353 const extra = w.air.extraData(Air.Bin, pl_op.payload).data;371 const extra = w.air.extraData(Air.Bin, pl_op.payload).data;
src/type.zig+39-52
...@@ -627,7 +627,7 @@ pub const Type = extern union {...@@ -627,7 +627,7 @@ pub const Type = extern union {
627 }627 }
628628
629 if (a.tag() == .error_set_inferred and b.tag() == .error_set_inferred) {629 if (a.tag() == .error_set_inferred and b.tag() == .error_set_inferred) {
630 return a.castTag(.error_set_inferred).?.data.func == b.castTag(.error_set_inferred).?.data.func;630 return a.castTag(.error_set_inferred).?.data == b.castTag(.error_set_inferred).?.data;
631 }631 }
632632
633 if (a.tag() == .error_set_single and b.tag() == .error_set_single) {633 if (a.tag() == .error_set_single and b.tag() == .error_set_single) {
...@@ -904,10 +904,11 @@ pub const Type = extern union {...@@ -904,10 +904,11 @@ pub const Type = extern union {
904 });904 });
905 },905 },
906 .error_set_merged => {906 .error_set_merged => {
907 const names = self.castTag(.error_set_merged).?.data;907 const names = self.castTag(.error_set_merged).?.data.keys();
908 const duped_names = try allocator.alloc([]const u8, names.len);908 var duped_names = Module.ErrorSet.NameMap{};
909 for (duped_names) |*name, i| {909 try duped_names.ensureTotalCapacity(allocator, names.len);
910 name.* = try allocator.dupe(u8, names[i]);910 for (names) |name| {
911 duped_names.putAssumeCapacityNoClobber(name, .{});
911 }912 }
912 return Tag.error_set_merged.create(allocator, duped_names);913 return Tag.error_set_merged.create(allocator, duped_names);
913 },914 },
...@@ -1206,7 +1207,7 @@ pub const Type = extern union {...@@ -1206,7 +1207,7 @@ pub const Type = extern union {
1206 return writer.print("(inferred error set of {s})", .{func.owner_decl.name});1207 return writer.print("(inferred error set of {s})", .{func.owner_decl.name});
1207 },1208 },
1208 .error_set_merged => {1209 .error_set_merged => {
1209 const names = ty.castTag(.error_set_merged).?.data;1210 const names = ty.castTag(.error_set_merged).?.data.keys();
1210 try writer.writeAll("error{");1211 try writer.writeAll("error{");
1211 for (names) |name, i| {1212 for (names) |name, i| {
1212 if (i != 0) try writer.writeByte(',');1213 if (i != 0) try writer.writeByte(',');
...@@ -1574,6 +1575,7 @@ pub const Type = extern union {...@@ -1574,6 +1575,7 @@ pub const Type = extern union {
1574 .extern_options,1575 .extern_options,
1575 .@"anyframe",1576 .@"anyframe",
1576 .anyframe_T,1577 .anyframe_T,
1578 .anyopaque,
1577 .@"opaque",1579 .@"opaque",
1578 .single_const_pointer,1580 .single_const_pointer,
1579 .single_mut_pointer,1581 .single_mut_pointer,
...@@ -1653,7 +1655,6 @@ pub const Type = extern union {...@@ -1653,7 +1655,6 @@ pub const Type = extern union {
1653 return payload.error_set.hasCodeGenBits() or payload.payload.hasCodeGenBits();1655 return payload.error_set.hasCodeGenBits() or payload.payload.hasCodeGenBits();
1654 },1656 },
16551657
1656 .anyopaque,
1657 .void,1658 .void,
1658 .type,1659 .type,
1659 .comptime_int,1660 .comptime_int,
...@@ -2873,6 +2874,35 @@ pub const Type = extern union {...@@ -2873,6 +2874,35 @@ pub const Type = extern union {
2873 };2874 };
2874 }2875 }
28752876
2877 /// Returns whether ty, which must be an error set, includes an error `name`.
2878 /// Might return a false negative if `ty` is an inferred error set and not fully
2879 /// resolved yet.
2880 pub fn errorSetHasField(ty: Type, name: []const u8) bool {
2881 if (ty.isAnyError()) {
2882 return true;
2883 }
2884
2885 switch (ty.tag()) {
2886 .error_set_single => {
2887 const data = ty.castTag(.error_set_single).?.data;
2888 return std.mem.eql(u8, data, name);
2889 },
2890 .error_set_inferred => {
2891 const data = ty.castTag(.error_set_inferred).?.data;
2892 return data.errors.contains(name);
2893 },
2894 .error_set_merged => {
2895 const data = ty.castTag(.error_set_merged).?.data;
2896 return data.contains(name);
2897 },
2898 .error_set => {
2899 const data = ty.castTag(.error_set).?.data;
2900 return data.names.contains(name);
2901 },
2902 else => unreachable,
2903 }
2904 }
2905
2876 /// Asserts the type is an array or vector.2906 /// Asserts the type is an array or vector.
2877 pub fn arrayLen(ty: Type) u64 {2907 pub fn arrayLen(ty: Type) u64 {
2878 return switch (ty.tag()) {2908 return switch (ty.tag()) {
...@@ -4148,57 +4178,14 @@ pub const Type = extern union {...@@ -4148,57 +4178,14 @@ pub const Type = extern union {
4148 pub const base_tag = Tag.error_set_merged;4178 pub const base_tag = Tag.error_set_merged;
41494179
4150 base: Payload = Payload{ .tag = base_tag },4180 base: Payload = Payload{ .tag = base_tag },
4151 data: []const []const u8,4181 data: Module.ErrorSet.NameMap,
4152 };4182 };
41534183
4154 pub const ErrorSetInferred = struct {4184 pub const ErrorSetInferred = struct {
4155 pub const base_tag = Tag.error_set_inferred;4185 pub const base_tag = Tag.error_set_inferred;
41564186
4157 base: Payload = Payload{ .tag = base_tag },4187 base: Payload = Payload{ .tag = base_tag },
4158 data: Data,4188 data: *Module.Fn.InferredErrorSet,
4159
4160 pub const Data = struct {
4161 func: *Module.Fn,
4162 /// Direct additions to the inferred error set via `return error.Foo;`.
4163 map: std.StringHashMapUnmanaged(void),
4164 /// Other functions with inferred error sets which this error set includes.
4165 functions: std.AutoHashMapUnmanaged(*Module.Fn, void),
4166 is_anyerror: bool,
4167
4168 pub fn addErrorSet(self: *Data, gpa: Allocator, err_set_ty: Type) !void {
4169 switch (err_set_ty.tag()) {
4170 .error_set => {
4171 const names = err_set_ty.castTag(.error_set).?.data.names();
4172 for (names) |name| {
4173 try self.map.put(gpa, name, {});
4174 }
4175 },
4176 .error_set_single => {
4177 const name = err_set_ty.castTag(.error_set_single).?.data;
4178 try self.map.put(gpa, name, {});
4179 },
4180 .error_set_inferred => {
4181 const func = err_set_ty.castTag(.error_set_inferred).?.data.func;
4182 try self.functions.put(gpa, func, {});
4183 var it = func.owner_decl.ty.fnReturnType().errorUnionSet()
4184 .castTag(.error_set_inferred).?.data.map.iterator();
4185 while (it.next()) |entry| {
4186 try self.map.put(gpa, entry.key_ptr.*, {});
4187 }
4188 },
4189 .error_set_merged => {
4190 const names = err_set_ty.castTag(.error_set_merged).?.data;
4191 for (names) |name| {
4192 try self.map.put(gpa, name, {});
4193 }
4194 },
4195 .anyerror => {
4196 self.is_anyerror = true;
4197 },
4198 else => unreachable,
4199 }
4200 }
4201 };
4202 };4189 };
42034190
4204 pub const Pointer = struct {4191 pub const Pointer = struct {
src/value.zig+121-37
...@@ -1969,20 +1969,18 @@ pub const Value = extern union {...@@ -1969,20 +1969,18 @@ pub const Value = extern union {
1969 return @divFloor(@floatToInt(std.math.big.Limb, std.math.log2(w_value)), @typeInfo(std.math.big.Limb).Int.bits) + 1;1969 return @divFloor(@floatToInt(std.math.big.Limb, std.math.log2(w_value)), @typeInfo(std.math.big.Limb).Int.bits) + 1;
1970 }1970 }
19711971
1972 /// Supports both floats and ints; handles undefined.1972 pub const OverflowArithmeticResult = struct {
1973 pub fn numberAddWrap(1973 overflowed: bool,
1974 wrapped_result: Value,
1975 };
1976
1977 pub fn intAddWithOverflow(
1974 lhs: Value,1978 lhs: Value,
1975 rhs: Value,1979 rhs: Value,
1976 ty: Type,1980 ty: Type,
1977 arena: Allocator,1981 arena: Allocator,
1978 target: Target,1982 target: Target,
1979 ) !Value {1983 ) !OverflowArithmeticResult {
1980 if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef);
1981
1982 if (ty.isAnyFloat()) {
1983 return floatAdd(lhs, rhs, ty, arena);
1984 }
1985
1986 const info = ty.intInfo(target);1984 const info = ty.intInfo(target);
19871985
1988 var lhs_space: Value.BigIntSpace = undefined;1986 var lhs_space: Value.BigIntSpace = undefined;
...@@ -1994,8 +1992,30 @@ pub const Value = extern union {...@@ -1994,8 +1992,30 @@ pub const Value = extern union {
1994 std.math.big.int.calcTwosCompLimbCount(info.bits),1992 std.math.big.int.calcTwosCompLimbCount(info.bits),
1995 );1993 );
1996 var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined };1994 var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined };
1997 result_bigint.addWrap(lhs_bigint, rhs_bigint, info.signedness, info.bits);1995 const overflowed = result_bigint.addWrap(lhs_bigint, rhs_bigint, info.signedness, info.bits);
1998 return fromBigInt(arena, result_bigint.toConst());1996 const result = try fromBigInt(arena, result_bigint.toConst());
1997 return OverflowArithmeticResult{
1998 .overflowed = overflowed,
1999 .wrapped_result = result,
2000 };
2001 }
2002
2003 /// Supports both floats and ints; handles undefined.
2004 pub fn numberAddWrap(
2005 lhs: Value,
2006 rhs: Value,
2007 ty: Type,
2008 arena: Allocator,
2009 target: Target,
2010 ) !Value {
2011 if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef);
2012
2013 if (ty.isAnyFloat()) {
2014 return floatAdd(lhs, rhs, ty, arena);
2015 }
2016
2017 const overflow_result = try intAddWithOverflow(lhs, rhs, ty, arena, target);
2018 return overflow_result.wrapped_result;
1999 }2019 }
20002020
2001 fn fromBigInt(arena: Allocator, big_int: BigIntConst) !Value {2021 fn fromBigInt(arena: Allocator, big_int: BigIntConst) !Value {
...@@ -2040,20 +2060,13 @@ pub const Value = extern union {...@@ -2040,20 +2060,13 @@ pub const Value = extern union {
2040 return fromBigInt(arena, result_bigint.toConst());2060 return fromBigInt(arena, result_bigint.toConst());
2041 }2061 }
20422062
2043 /// Supports both floats and ints; handles undefined.2063 pub fn intSubWithOverflow(
2044 pub fn numberSubWrap(
2045 lhs: Value,2064 lhs: Value,
2046 rhs: Value,2065 rhs: Value,
2047 ty: Type,2066 ty: Type,
2048 arena: Allocator,2067 arena: Allocator,
2049 target: Target,2068 target: Target,
2050 ) !Value {2069 ) !OverflowArithmeticResult {
2051 if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef);
2052
2053 if (ty.isAnyFloat()) {
2054 return floatSub(lhs, rhs, ty, arena);
2055 }
2056
2057 const info = ty.intInfo(target);2070 const info = ty.intInfo(target);
20582071
2059 var lhs_space: Value.BigIntSpace = undefined;2072 var lhs_space: Value.BigIntSpace = undefined;
...@@ -2065,8 +2078,30 @@ pub const Value = extern union {...@@ -2065,8 +2078,30 @@ pub const Value = extern union {
2065 std.math.big.int.calcTwosCompLimbCount(info.bits),2078 std.math.big.int.calcTwosCompLimbCount(info.bits),
2066 );2079 );
2067 var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined };2080 var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined };
2068 result_bigint.subWrap(lhs_bigint, rhs_bigint, info.signedness, info.bits);2081 const overflowed = result_bigint.subWrap(lhs_bigint, rhs_bigint, info.signedness, info.bits);
2069 return fromBigInt(arena, result_bigint.toConst());2082 const wrapped_result = try fromBigInt(arena, result_bigint.toConst());
2083 return OverflowArithmeticResult{
2084 .overflowed = overflowed,
2085 .wrapped_result = wrapped_result,
2086 };
2087 }
2088
2089 /// Supports both floats and ints; handles undefined.
2090 pub fn numberSubWrap(
2091 lhs: Value,
2092 rhs: Value,
2093 ty: Type,
2094 arena: Allocator,
2095 target: Target,
2096 ) !Value {
2097 if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef);
2098
2099 if (ty.isAnyFloat()) {
2100 return floatSub(lhs, rhs, ty, arena);
2101 }
2102
2103 const overflow_result = try intSubWithOverflow(lhs, rhs, ty, arena, target);
2104 return overflow_result.wrapped_result;
2070 }2105 }
20712106
2072 /// Supports integers only; asserts neither operand is undefined.2107 /// Supports integers only; asserts neither operand is undefined.
...@@ -2095,20 +2130,13 @@ pub const Value = extern union {...@@ -2095,20 +2130,13 @@ pub const Value = extern union {
2095 return fromBigInt(arena, result_bigint.toConst());2130 return fromBigInt(arena, result_bigint.toConst());
2096 }2131 }
20972132
2098 /// Supports both floats and ints; handles undefined.2133 pub fn intMulWithOverflow(
2099 pub fn numberMulWrap(
2100 lhs: Value,2134 lhs: Value,
2101 rhs: Value,2135 rhs: Value,
2102 ty: Type,2136 ty: Type,
2103 arena: Allocator,2137 arena: Allocator,
2104 target: Target,2138 target: Target,
2105 ) !Value {2139 ) !OverflowArithmeticResult {
2106 if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef);
2107
2108 if (ty.isAnyFloat()) {
2109 return floatMul(lhs, rhs, ty, arena);
2110 }
2111
2112 const info = ty.intInfo(target);2140 const info = ty.intInfo(target);
21132141
2114 var lhs_space: Value.BigIntSpace = undefined;2142 var lhs_space: Value.BigIntSpace = undefined;
...@@ -2117,16 +2145,42 @@ pub const Value = extern union {...@@ -2117,16 +2145,42 @@ pub const Value = extern union {
2117 const rhs_bigint = rhs.toBigInt(&rhs_space);2145 const rhs_bigint = rhs.toBigInt(&rhs_space);
2118 const limbs = try arena.alloc(2146 const limbs = try arena.alloc(
2119 std.math.big.Limb,2147 std.math.big.Limb,
2120 std.math.big.int.calcTwosCompLimbCount(info.bits),2148 lhs_bigint.limbs.len + rhs_bigint.limbs.len,
2121 );2149 );
2122 var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined };2150 var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined };
2123 var limbs_buffer = try arena.alloc(2151 var limbs_buffer = try arena.alloc(
2124 std.math.big.Limb,2152 std.math.big.Limb,
2125 std.math.big.int.calcMulWrapLimbsBufferLen(info.bits, lhs_bigint.limbs.len, rhs_bigint.limbs.len, 1),2153 std.math.big.int.calcMulLimbsBufferLen(lhs_bigint.limbs.len, rhs_bigint.limbs.len, 1),
2126 );2154 );
2127 defer arena.free(limbs_buffer);2155 result_bigint.mul(lhs_bigint, rhs_bigint, limbs_buffer, arena);
2128 result_bigint.mulWrap(lhs_bigint, rhs_bigint, info.signedness, info.bits, limbs_buffer, arena);2156
2129 return fromBigInt(arena, result_bigint.toConst());2157 const overflowed = !result_bigint.toConst().fitsInTwosComp(info.signedness, info.bits);
2158 if (overflowed) {
2159 result_bigint.truncate(result_bigint.toConst(), info.signedness, info.bits);
2160 }
2161
2162 return OverflowArithmeticResult{
2163 .overflowed = overflowed,
2164 .wrapped_result = try fromBigInt(arena, result_bigint.toConst()),
2165 };
2166 }
2167
2168 /// Supports both floats and ints; handles undefined.
2169 pub fn numberMulWrap(
2170 lhs: Value,
2171 rhs: Value,
2172 ty: Type,
2173 arena: Allocator,
2174 target: Target,
2175 ) !Value {
2176 if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef);
2177
2178 if (ty.isAnyFloat()) {
2179 return floatMul(lhs, rhs, ty, arena);
2180 }
2181
2182 const overflow_result = try intMulWithOverflow(lhs, rhs, ty, arena, target);
2183 return overflow_result.wrapped_result;
2130 }2184 }
21312185
2132 /// Supports integers only; asserts neither operand is undefined.2186 /// Supports integers only; asserts neither operand is undefined.
...@@ -2159,7 +2213,6 @@ pub const Value = extern union {...@@ -2159,7 +2213,6 @@ pub const Value = extern union {
2159 std.math.big.Limb,2213 std.math.big.Limb,
2160 std.math.big.int.calcMulLimbsBufferLen(lhs_bigint.limbs.len, rhs_bigint.limbs.len, 1),2214 std.math.big.int.calcMulLimbsBufferLen(lhs_bigint.limbs.len, rhs_bigint.limbs.len, 1),
2161 );2215 );
2162 defer arena.free(limbs_buffer);
2163 result_bigint.mul(lhs_bigint, rhs_bigint, limbs_buffer, arena);2216 result_bigint.mul(lhs_bigint, rhs_bigint, limbs_buffer, arena);
2164 result_bigint.saturate(result_bigint.toConst(), info.signedness, info.bits);2217 result_bigint.saturate(result_bigint.toConst(), info.signedness, info.bits);
2165 return fromBigInt(arena, result_bigint.toConst());2218 return fromBigInt(arena, result_bigint.toConst());
...@@ -2495,6 +2548,37 @@ pub const Value = extern union {...@@ -2495,6 +2548,37 @@ pub const Value = extern union {
2495 return fromBigInt(allocator, result_bigint.toConst());2548 return fromBigInt(allocator, result_bigint.toConst());
2496 }2549 }
24972550
2551 pub fn shlWithOverflow(
2552 lhs: Value,
2553 rhs: Value,
2554 ty: Type,
2555 allocator: Allocator,
2556 target: Target,
2557 ) !OverflowArithmeticResult {
2558 const info = ty.intInfo(target);
2559 var lhs_space: Value.BigIntSpace = undefined;
2560 const lhs_bigint = lhs.toBigInt(&lhs_space);
2561 const shift = @intCast(usize, rhs.toUnsignedInt());
2562 const limbs = try allocator.alloc(
2563 std.math.big.Limb,
2564 lhs_bigint.limbs.len + (shift / (@sizeOf(std.math.big.Limb) * 8)) + 1,
2565 );
2566 var result_bigint = BigIntMutable{
2567 .limbs = limbs,
2568 .positive = undefined,
2569 .len = undefined,
2570 };
2571 result_bigint.shiftLeft(lhs_bigint, shift);
2572 const overflowed = !result_bigint.toConst().fitsInTwosComp(info.signedness, info.bits);
2573 if (overflowed) {
2574 result_bigint.truncate(result_bigint.toConst(), info.signedness, info.bits);
2575 }
2576 return OverflowArithmeticResult{
2577 .overflowed = overflowed,
2578 .wrapped_result = try fromBigInt(allocator, result_bigint.toConst()),
2579 };
2580 }
2581
2498 pub fn shlSat(2582 pub fn shlSat(
2499 lhs: Value,2583 lhs: Value,
2500 rhs: Value,2584 rhs: Value,
test/behavior/eval.zig+16
...@@ -451,3 +451,19 @@ test "comptime bitwise operators" {...@@ -451,3 +451,19 @@ test "comptime bitwise operators" {
451 try expect(~@as(u128, 0) == 0xffffffffffffffffffffffffffffffff);451 try expect(~@as(u128, 0) == 0xffffffffffffffffffffffffffffffff);
452 }452 }
453}453}
454
455test "comptime shlWithOverflow" {
456 const ct_shifted: u64 = comptime amt: {
457 var amt = @as(u64, 0);
458 _ = @shlWithOverflow(u64, ~@as(u64, 0), 16, &amt);
459 break :amt amt;
460 };
461
462 const rt_shifted: u64 = amt: {
463 var amt = @as(u64, 0);
464 _ = @shlWithOverflow(u64, ~@as(u64, 0), 16, &amt);
465 break :amt amt;
466 };
467
468 try expect(ct_shifted == rt_shifted);
469}
test/behavior/eval_stage1.zig-16
...@@ -162,22 +162,6 @@ test "const ptr to comptime mutable data is not memoized" {...@@ -162,22 +162,6 @@ test "const ptr to comptime mutable data is not memoized" {
162 }162 }
163}163}
164164
165test "comptime shlWithOverflow" {
166 const ct_shifted: u64 = comptime amt: {
167 var amt = @as(u64, 0);
168 _ = @shlWithOverflow(u64, ~@as(u64, 0), 16, &amt);
169 break :amt amt;
170 };
171
172 const rt_shifted: u64 = amt: {
173 var amt = @as(u64, 0);
174 _ = @shlWithOverflow(u64, ~@as(u64, 0), 16, &amt);
175 break :amt amt;
176 };
177
178 try expect(ct_shifted == rt_shifted);
179}
180
181test "runtime 128 bit integer division" {165test "runtime 128 bit integer division" {
182 var a: u128 = 152313999999999991610955792383;166 var a: u128 = 152313999999999991610955792383;
183 var b: u128 = 10000000000000000000;167 var b: u128 = 10000000000000000000;
test/behavior/math.zig+95
...@@ -444,3 +444,98 @@ test "128-bit multiplication" {...@@ -444,3 +444,98 @@ test "128-bit multiplication" {
444 var c = a * b;444 var c = a * b;
445 try expect(c == 6);445 try expect(c == 6);
446}446}
447
448test "@addWithOverflow" {
449 var result: u8 = undefined;
450 try expect(@addWithOverflow(u8, 250, 100, &result));
451 try expect(result == 94);
452 try expect(!@addWithOverflow(u8, 100, 150, &result));
453 try expect(result == 250);
454
455 var a: u8 = 200;
456 var b: u8 = 99;
457 try expect(@addWithOverflow(u8, a, b, &result));
458 try expect(result == 43);
459 b = 55;
460 try expect(!@addWithOverflow(u8, a, b, &result));
461 try expect(result == 255);
462}
463
464test "small int addition" {
465 var x: u2 = 0;
466 try expect(x == 0);
467
468 x += 1;
469 try expect(x == 1);
470
471 x += 1;
472 try expect(x == 2);
473
474 x += 1;
475 try expect(x == 3);
476
477 var result: @TypeOf(x) = 3;
478 try expect(@addWithOverflow(@TypeOf(x), x, 1, &result));
479
480 try expect(result == 0);
481}
482
483test "@mulWithOverflow" {
484 var result: u8 = undefined;
485 try expect(@mulWithOverflow(u8, 86, 3, &result));
486 try expect(result == 2);
487 try expect(!@mulWithOverflow(u8, 85, 3, &result));
488 try expect(result == 255);
489
490 var a: u8 = 123;
491 var b: u8 = 2;
492 try expect(!@mulWithOverflow(u8, a, b, &result));
493 try expect(result == 246);
494 b = 4;
495 try expect(@mulWithOverflow(u8, a, b, &result));
496 try expect(result == 236);
497}
498
499test "@subWithOverflow" {
500 var result: u8 = undefined;
501 try expect(@subWithOverflow(u8, 1, 2, &result));
502 try expect(result == 255);
503 try expect(!@subWithOverflow(u8, 1, 1, &result));
504 try expect(result == 0);
505
506 var a: u8 = 1;
507 var b: u8 = 2;
508 try expect(@subWithOverflow(u8, a, b, &result));
509 try expect(result == 255);
510 b = 1;
511 try expect(!@subWithOverflow(u8, a, b, &result));
512 try expect(result == 0);
513}
514
515test "@shlWithOverflow" {
516 var result: u16 = undefined;
517 try expect(@shlWithOverflow(u16, 0b0010111111111111, 3, &result));
518 try expect(result == 0b0111111111111000);
519 try expect(!@shlWithOverflow(u16, 0b0010111111111111, 2, &result));
520 try expect(result == 0b1011111111111100);
521
522 var a: u16 = 0b0000_0000_0000_0011;
523 var b: u4 = 15;
524 try expect(@shlWithOverflow(u16, a, b, &result));
525 try expect(result == 0b1000_0000_0000_0000);
526 b = 14;
527 try expect(!@shlWithOverflow(u16, a, b, &result));
528 try expect(result == 0b1100_0000_0000_0000);
529}
530
531test "overflow arithmetic with u0 values" {
532 var result: u0 = undefined;
533 try expect(!@addWithOverflow(u0, 0, 0, &result));
534 try expect(result == 0);
535 try expect(!@subWithOverflow(u0, 0, 0, &result));
536 try expect(result == 0);
537 try expect(!@mulWithOverflow(u0, 0, 0, &result));
538 try expect(result == 0);
539 try expect(!@shlWithOverflow(u0, 0, 0, &result));
540 try expect(result == 0);
541}
test/behavior/math_stage1.zig-63
...@@ -6,50 +6,6 @@ const maxInt = std.math.maxInt;...@@ -6,50 +6,6 @@ const maxInt = std.math.maxInt;
6const minInt = std.math.minInt;6const minInt = std.math.minInt;
7const mem = std.mem;7const mem = std.mem;
88
9test "@addWithOverflow" {
10 var result: u8 = undefined;
11 try expect(@addWithOverflow(u8, 250, 100, &result));
12 try expect(result == 94);
13 try expect(!@addWithOverflow(u8, 100, 150, &result));
14 try expect(result == 250);
15}
16
17test "@mulWithOverflow" {
18 var result: u8 = undefined;
19 try expect(@mulWithOverflow(u8, 86, 3, &result));
20 try expect(result == 2);
21 try expect(!@mulWithOverflow(u8, 85, 3, &result));
22 try expect(result == 255);
23}
24
25test "@subWithOverflow" {
26 var result: u8 = undefined;
27 try expect(@subWithOverflow(u8, 1, 2, &result));
28 try expect(result == 255);
29 try expect(!@subWithOverflow(u8, 1, 1, &result));
30 try expect(result == 0);
31}
32
33test "@shlWithOverflow" {
34 var result: u16 = undefined;
35 try expect(@shlWithOverflow(u16, 0b0010111111111111, 3, &result));
36 try expect(result == 0b0111111111111000);
37 try expect(!@shlWithOverflow(u16, 0b0010111111111111, 2, &result));
38 try expect(result == 0b1011111111111100);
39}
40
41test "overflow arithmetic with u0 values" {
42 var result: u0 = undefined;
43 try expect(!@addWithOverflow(u0, 0, 0, &result));
44 try expect(result == 0);
45 try expect(!@subWithOverflow(u0, 0, 0, &result));
46 try expect(result == 0);
47 try expect(!@mulWithOverflow(u0, 0, 0, &result));
48 try expect(result == 0);
49 try expect(!@shlWithOverflow(u0, 0, 0, &result));
50 try expect(result == 0);
51}
52
53test "@clz vectors" {9test "@clz vectors" {
54 try testClzVectors();10 try testClzVectors();
55 comptime try testClzVectors();11 comptime try testClzVectors();
...@@ -90,25 +46,6 @@ fn testCtzVectors() !void {...@@ -90,25 +46,6 @@ fn testCtzVectors() !void {
90 try expectEqual(@ctz(u16, @splat(64, @as(u16, 0b00000000))), @splat(64, @as(u5, 16)));46 try expectEqual(@ctz(u16, @splat(64, @as(u16, 0b00000000))), @splat(64, @as(u5, 16)));
91}47}
9248
93test "small int addition" {
94 var x: u2 = 0;
95 try expect(x == 0);
96
97 x += 1;
98 try expect(x == 1);
99
100 x += 1;
101 try expect(x == 2);
102
103 x += 1;
104 try expect(x == 3);
105
106 var result: @TypeOf(x) = 3;
107 try expect(@addWithOverflow(@TypeOf(x), x, 1, &result));
108
109 try expect(result == 0);
110}
111
112test "allow signed integer division/remainder when values are comptime known and positive or exact" {49test "allow signed integer division/remainder when values are comptime known and positive or exact" {
113 try expect(5 / 3 == 1);50 try expect(5 / 3 == 1);
114 try expect(-5 / -3 == 1);51 try expect(-5 / -3 == 1);