Skip to content

Commit bb1c3e8

Browse files
committed
stage2: Handle lazy values for the % operator
1 parent 49a270b commit bb1c3e8

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;
@@ -11824,7 +11825,7 @@ fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
1182411825
return sema.failWithDivideByZero(block, rhs_src);
1182511826
}
1182611827
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);
1182811829
// If this answer could possibly be different by doing `intMod`,
1182911830
// we must emit a compile error. Otherwise, it's OK.
1183011831
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.
1188611887
return block.addBinOp(air_tag, casted_lhs, casted_rhs);
1188711888
}
1188811889

11890+
fn 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+
11909+
fn 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+
1188911944
fn zirMod(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
1189011945
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
1189111946
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
1205012105
if (maybe_lhs_val) |lhs_val| {
1205112106
return sema.addConstant(
1205212107
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),
1205412109
);
1205512110
}
1205612111
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(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+
}

0 commit comments

Comments
 (0)