Skip to content

Commit b8330ea

Browse files
committed
stage2: Handle lazy values for the % operator
1 parent 85a3f9b commit b8330ea

File tree

3 files changed

+72
-40
lines changed

3 files changed

+72
-40
lines changed

src/Sema.zig

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ post_hoc_blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, *LabeledBlock) = .{},
7878
err: ?*Module.ErrorMsg = null,
7979

8080
const std = @import("std");
81+
const math = std.math;
8182
const mem = std.mem;
8283
const Allocator = std.mem.Allocator;
8384
const assert = std.debug.assert;
@@ -11753,7 +11754,7 @@ fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
1175311754
return sema.failWithDivideByZero(block, rhs_src);
1175411755
}
1175511756
if (maybe_lhs_val) |lhs_val| {
11756-
const rem_result = try lhs_val.intRem(rhs_val, resolved_type, sema.arena, target);
11757+
const rem_result = try sema.intRem(block, resolved_type, lhs_val, lhs_src, rhs_val, rhs_src);
1175711758
// If this answer could possibly be different by doing `intMod`,
1175811759
// we must emit a compile error. Otherwise, it's OK.
1175911760
if ((try rhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src))) != (try lhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src))) and
@@ -11815,6 +11816,60 @@ fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
1181511816
return block.addBinOp(air_tag, casted_lhs, casted_rhs);
1181611817
}
1181711818

11819+
fn intRem(
11820+
sema: *Sema,
11821+
block: *Block,
11822+
ty: Type,
11823+
lhs: Value,
11824+
lhs_src: LazySrcLoc,
11825+
rhs: Value,
11826+
rhs_src: LazySrcLoc,
11827+
) CompileError!Value {
11828+
if (ty.zigTypeTag() == .Vector) {
11829+
const result_data = try sema.arena.alloc(Value, ty.vectorLen());
11830+
for (result_data) |*scalar, i| {
11831+
scalar.* = try sema.intRemScalar(block, lhs.indexVectorlike(i), lhs_src, rhs.indexVectorlike(i), rhs_src);
11832+
}
11833+
return Value.Tag.aggregate.create(sema.arena, result_data);
11834+
}
11835+
return sema.intRemScalar(block, lhs, lhs_src, rhs, rhs_src);
11836+
}
11837+
11838+
fn intRemScalar(
11839+
sema: *Sema,
11840+
block: *Block,
11841+
lhs: Value,
11842+
lhs_src: LazySrcLoc,
11843+
rhs: Value,
11844+
rhs_src: LazySrcLoc,
11845+
) CompileError!Value {
11846+
const target = sema.mod.getTarget();
11847+
// TODO is this a performance issue? maybe we should try the operation without
11848+
// resorting to BigInt first.
11849+
var lhs_space: Value.BigIntSpace = undefined;
11850+
var rhs_space: Value.BigIntSpace = undefined;
11851+
const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, target, sema.kit(block, lhs_src));
11852+
const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, target, sema.kit(block, rhs_src));
11853+
const limbs_q = try sema.arena.alloc(
11854+
math.big.Limb,
11855+
lhs_bigint.limbs.len,
11856+
);
11857+
const limbs_r = try sema.arena.alloc(
11858+
math.big.Limb,
11859+
// TODO: consider reworking Sema to re-use Values rather than
11860+
// always producing new Value objects.
11861+
rhs_bigint.limbs.len,
11862+
);
11863+
const limbs_buffer = try sema.arena.alloc(
11864+
math.big.Limb,
11865+
math.big.int.calcDivLimbsBufferLen(lhs_bigint.limbs.len, rhs_bigint.limbs.len),
11866+
);
11867+
var result_q = math.big.int.Mutable{ .limbs = limbs_q, .positive = undefined, .len = undefined };
11868+
var result_r = math.big.int.Mutable{ .limbs = limbs_r, .positive = undefined, .len = undefined };
11869+
result_q.divTrunc(&result_r, lhs_bigint, rhs_bigint, limbs_buffer);
11870+
return Value.fromBigInt(sema.arena, result_r.toConst());
11871+
}
11872+
1181811873
fn zirMod(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
1181911874
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
1182011875
const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node };
@@ -11979,7 +12034,7 @@ fn zirRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
1197912034
if (maybe_lhs_val) |lhs_val| {
1198012035
return sema.addConstant(
1198112036
resolved_type,
11982-
try lhs_val.intRem(rhs_val, resolved_type, sema.arena, target),
12037+
try sema.intRem(block, resolved_type, lhs_val, lhs_src, rhs_val, rhs_src),
1198312038
);
1198412039
}
1198512040
break :rs lhs_src;

src/value.zig

Lines changed: 0 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -3472,44 +3472,6 @@ pub const Value = extern union {
34723472
return fromBigInt(allocator, result_q.toConst());
34733473
}
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-
35133475
pub fn intMod(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, target: Target) !Value {
35143476
if (ty.zigTypeTag() == .Vector) {
35153477
const result_data = try allocator.alloc(Value, ty.vectorLen());

test/behavior/math.zig

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1721,3 +1721,18 @@ fn testAbsFloat() !void {
17211721
fn testAbsFloatOne(in: f32, out: f32) !void {
17221722
try expect(@fabs(@as(f32, in)) == @as(f32, out));
17231723
}
1724+
1725+
test "mod lazy values" {
1726+
{
1727+
const X = struct { x: u32 };
1728+
const x = @sizeOf(Foo);
1729+
const y = 1 % x;
1730+
_ = y;
1731+
}
1732+
{
1733+
const X = struct { x: u32 };
1734+
const x = @sizeOf(Foo);
1735+
const y = x % 1;
1736+
_ = y;
1737+
}
1738+
}

0 commit comments

Comments
 (0)