authorgravatar for mail@isaacfreund.comIsaac Freund <mail@isaacfreund.com> 2022-08-10 13:21:47+02:00
committergravatar for mail@isaacfreund.comIsaac Freund <mail@isaacfreund.com> 2022-08-10 14:48:27+02:00
logbb1c3e8b7e2be201221e14719d2d39e6298cc66c
treed4d5800c280beea171fdb4028553a7107aa21891
parent49a270b2038709a6a0c1f4de604696278769257b
signaturelock-open Commit is signed but in an unrecognized format.

stage2: Handle lazy values for the % operator


3 files changed, 72 insertions(+), 40 deletions(-)

src/Sema.zig+57-2
...@@ -78,6 +78,7 @@ post_hoc_blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, *LabeledBlock) = .{},...@@ -78,6 +78,7 @@ post_hoc_blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, *LabeledBlock) = .{},
78err: ?*Module.ErrorMsg = null,78err: ?*Module.ErrorMsg = null,
7979
80const std = @import("std");80const std = @import("std");
81const math = std.math;
81const mem = std.mem;82const mem = std.mem;
82const Allocator = std.mem.Allocator;83const Allocator = std.mem.Allocator;
83const assert = std.debug.assert;84const assert = std.debug.assert;
...@@ -11824,7 +11825,7 @@ fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air....@@ -11824,7 +11825,7 @@ fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
11824 return sema.failWithDivideByZero(block, rhs_src);11825 return sema.failWithDivideByZero(block, rhs_src);
11825 }11826 }
11826 if (maybe_lhs_val) |lhs_val| {11827 if (maybe_lhs_val) |lhs_val| {
11827 const rem_result = try lhs_val.intRem(rhs_val, resolved_type, sema.arena, target);11828 const rem_result = try sema.intRem(block, resolved_type, lhs_val, lhs_src, rhs_val, rhs_src);
11828 // If this answer could possibly be different by doing `intMod`,11829 // If this answer could possibly be different by doing `intMod`,
11829 // we must emit a compile error. Otherwise, it's OK.11830 // we must emit a compile error. Otherwise, it's OK.
11830 if ((try rhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src))) != (try lhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src))) and11831 if ((try rhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src))) != (try lhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src))) and
...@@ -11886,6 +11887,60 @@ fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air....@@ -11886,6 +11887,60 @@ fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
11886 return block.addBinOp(air_tag, casted_lhs, casted_rhs);11887 return block.addBinOp(air_tag, casted_lhs, casted_rhs);
11887}11888}
1188811889
11890fn intRem(
11891 sema: *Sema,
11892 block: *Block,
11893 ty: Type,
11894 lhs: Value,
11895 lhs_src: LazySrcLoc,
11896 rhs: Value,
11897 rhs_src: LazySrcLoc,
11898) CompileError!Value {
11899 if (ty.zigTypeTag() == .Vector) {
11900 const result_data = try sema.arena.alloc(Value, ty.vectorLen());
11901 for (result_data) |*scalar, i| {
11902 scalar.* = try sema.intRemScalar(block, lhs.indexVectorlike(i), lhs_src, rhs.indexVectorlike(i), rhs_src);
11903 }
11904 return Value.Tag.aggregate.create(sema.arena, result_data);
11905 }
11906 return sema.intRemScalar(block, lhs, lhs_src, rhs, rhs_src);
11907}
11908
11909fn intRemScalar(
11910 sema: *Sema,
11911 block: *Block,
11912 lhs: Value,
11913 lhs_src: LazySrcLoc,
11914 rhs: Value,
11915 rhs_src: LazySrcLoc,
11916) CompileError!Value {
11917 const target = sema.mod.getTarget();
11918 // TODO is this a performance issue? maybe we should try the operation without
11919 // resorting to BigInt first.
11920 var lhs_space: Value.BigIntSpace = undefined;
11921 var rhs_space: Value.BigIntSpace = undefined;
11922 const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, target, sema.kit(block, lhs_src));
11923 const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, target, sema.kit(block, rhs_src));
11924 const limbs_q = try sema.arena.alloc(
11925 math.big.Limb,
11926 lhs_bigint.limbs.len,
11927 );
11928 const limbs_r = try sema.arena.alloc(
11929 math.big.Limb,
11930 // TODO: consider reworking Sema to re-use Values rather than
11931 // always producing new Value objects.
11932 rhs_bigint.limbs.len,
11933 );
11934 const limbs_buffer = try sema.arena.alloc(
11935 math.big.Limb,
11936 math.big.int.calcDivLimbsBufferLen(lhs_bigint.limbs.len, rhs_bigint.limbs.len),
11937 );
11938 var result_q = math.big.int.Mutable{ .limbs = limbs_q, .positive = undefined, .len = undefined };
11939 var result_r = math.big.int.Mutable{ .limbs = limbs_r, .positive = undefined, .len = undefined };
11940 result_q.divTrunc(&result_r, lhs_bigint, rhs_bigint, limbs_buffer);
11941 return Value.fromBigInt(sema.arena, result_r.toConst());
11942}
11943
11889fn zirMod(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {11944fn zirMod(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
11890 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;11945 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
11891 const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node };11946 const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node };
...@@ -12050,7 +12105,7 @@ fn zirRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins...@@ -12050,7 +12105,7 @@ fn zirRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
12050 if (maybe_lhs_val) |lhs_val| {12105 if (maybe_lhs_val) |lhs_val| {
12051 return sema.addConstant(12106 return sema.addConstant(
12052 resolved_type,12107 resolved_type,
12053 try lhs_val.intRem(rhs_val, resolved_type, sema.arena, target),12108 try sema.intRem(block, resolved_type, lhs_val, lhs_src, rhs_val, rhs_src),
12054 );12109 );
12055 }12110 }
12056 break :rs lhs_src;12111 break :rs lhs_src;
src/value.zig-38
...@@ -3472,44 +3472,6 @@ pub const Value = extern union {...@@ -3472,44 +3472,6 @@ pub const Value = extern union {
3472 return fromBigInt(allocator, result_q.toConst());3472 return fromBigInt(allocator, result_q.toConst());
3473 }3473 }
34743474
3475 pub fn intRem(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, target: Target) !Value {
3476 if (ty.zigTypeTag() == .Vector) {
3477 const result_data = try allocator.alloc(Value, ty.vectorLen());
3478 for (result_data) |*scalar, i| {
3479 scalar.* = try intRemScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), allocator, target);
3480 }
3481 return Value.Tag.aggregate.create(allocator, result_data);
3482 }
3483 return intRemScalar(lhs, rhs, allocator, target);
3484 }
3485
3486 pub fn intRemScalar(lhs: Value, rhs: Value, allocator: Allocator, target: Target) !Value {
3487 // TODO is this a performance issue? maybe we should try the operation without
3488 // resorting to BigInt first.
3489 var lhs_space: Value.BigIntSpace = undefined;
3490 var rhs_space: Value.BigIntSpace = undefined;
3491 const lhs_bigint = lhs.toBigInt(&lhs_space, target);
3492 const rhs_bigint = rhs.toBigInt(&rhs_space, target);
3493 const limbs_q = try allocator.alloc(
3494 std.math.big.Limb,
3495 lhs_bigint.limbs.len,
3496 );
3497 const limbs_r = try allocator.alloc(
3498 std.math.big.Limb,
3499 // TODO: consider reworking Sema to re-use Values rather than
3500 // always producing new Value objects.
3501 rhs_bigint.limbs.len,
3502 );
3503 const limbs_buffer = try allocator.alloc(
3504 std.math.big.Limb,
3505 std.math.big.int.calcDivLimbsBufferLen(lhs_bigint.limbs.len, rhs_bigint.limbs.len),
3506 );
3507 var result_q = BigIntMutable{ .limbs = limbs_q, .positive = undefined, .len = undefined };
3508 var result_r = BigIntMutable{ .limbs = limbs_r, .positive = undefined, .len = undefined };
3509 result_q.divTrunc(&result_r, lhs_bigint, rhs_bigint, limbs_buffer);
3510 return fromBigInt(allocator, result_r.toConst());
3511 }
3512
3513 pub fn intMod(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, target: Target) !Value {3475 pub fn intMod(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, target: Target) !Value {
3514 if (ty.zigTypeTag() == .Vector) {3476 if (ty.zigTypeTag() == .Vector) {
3515 const result_data = try allocator.alloc(Value, ty.vectorLen());3477 const result_data = try allocator.alloc(Value, ty.vectorLen());
test/behavior/math.zig+15
...@@ -1721,3 +1721,18 @@ fn testAbsFloat() !void {...@@ -1721,3 +1721,18 @@ fn testAbsFloat() !void {
1721fn testAbsFloatOne(in: f32, out: f32) !void {1721fn testAbsFloatOne(in: f32, out: f32) !void {
1722 try expect(@fabs(@as(f32, in)) == @as(f32, out));1722 try expect(@fabs(@as(f32, in)) == @as(f32, out));
1723}1723}
1724
1725test "mod lazy values" {
1726 {
1727 const X = struct { x: u32 };
1728 const x = @sizeOf(X);
1729 const y = 1 % x;
1730 _ = y;
1731 }
1732 {
1733 const X = struct { x: u32 };
1734 const x = @sizeOf(X);
1735 const y = x % 1;
1736 _ = y;
1737 }
1738}