stage2: Handle lazy values for the % operator
This commit is contained in:
59
src/Sema.zig
59
src/Sema.zig
@@ -78,6 +78,7 @@ post_hoc_blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, *LabeledBlock) = .{},
|
||||
err: ?*Module.ErrorMsg = null,
|
||||
|
||||
const std = @import("std");
|
||||
const math = std.math;
|
||||
const mem = std.mem;
|
||||
const Allocator = std.mem.Allocator;
|
||||
const assert = std.debug.assert;
|
||||
@@ -11824,7 +11825,7 @@ fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
|
||||
return sema.failWithDivideByZero(block, rhs_src);
|
||||
}
|
||||
if (maybe_lhs_val) |lhs_val| {
|
||||
const rem_result = try lhs_val.intRem(rhs_val, resolved_type, sema.arena, target);
|
||||
const rem_result = try sema.intRem(block, resolved_type, lhs_val, lhs_src, rhs_val, rhs_src);
|
||||
// If this answer could possibly be different by doing `intMod`,
|
||||
// we must emit a compile error. Otherwise, it's OK.
|
||||
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.
|
||||
return block.addBinOp(air_tag, casted_lhs, casted_rhs);
|
||||
}
|
||||
|
||||
fn intRem(
|
||||
sema: *Sema,
|
||||
block: *Block,
|
||||
ty: Type,
|
||||
lhs: Value,
|
||||
lhs_src: LazySrcLoc,
|
||||
rhs: Value,
|
||||
rhs_src: LazySrcLoc,
|
||||
) CompileError!Value {
|
||||
if (ty.zigTypeTag() == .Vector) {
|
||||
const result_data = try sema.arena.alloc(Value, ty.vectorLen());
|
||||
for (result_data) |*scalar, i| {
|
||||
scalar.* = try sema.intRemScalar(block, lhs.indexVectorlike(i), lhs_src, rhs.indexVectorlike(i), rhs_src);
|
||||
}
|
||||
return Value.Tag.aggregate.create(sema.arena, result_data);
|
||||
}
|
||||
return sema.intRemScalar(block, lhs, lhs_src, rhs, rhs_src);
|
||||
}
|
||||
|
||||
fn intRemScalar(
|
||||
sema: *Sema,
|
||||
block: *Block,
|
||||
lhs: Value,
|
||||
lhs_src: LazySrcLoc,
|
||||
rhs: Value,
|
||||
rhs_src: LazySrcLoc,
|
||||
) CompileError!Value {
|
||||
const target = sema.mod.getTarget();
|
||||
// TODO is this a performance issue? maybe we should try the operation without
|
||||
// resorting to BigInt first.
|
||||
var lhs_space: Value.BigIntSpace = undefined;
|
||||
var rhs_space: Value.BigIntSpace = undefined;
|
||||
const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, target, sema.kit(block, lhs_src));
|
||||
const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, target, sema.kit(block, rhs_src));
|
||||
const limbs_q = try sema.arena.alloc(
|
||||
math.big.Limb,
|
||||
lhs_bigint.limbs.len,
|
||||
);
|
||||
const limbs_r = try sema.arena.alloc(
|
||||
math.big.Limb,
|
||||
// TODO: consider reworking Sema to re-use Values rather than
|
||||
// always producing new Value objects.
|
||||
rhs_bigint.limbs.len,
|
||||
);
|
||||
const limbs_buffer = try sema.arena.alloc(
|
||||
math.big.Limb,
|
||||
math.big.int.calcDivLimbsBufferLen(lhs_bigint.limbs.len, rhs_bigint.limbs.len),
|
||||
);
|
||||
var result_q = math.big.int.Mutable{ .limbs = limbs_q, .positive = undefined, .len = undefined };
|
||||
var result_r = math.big.int.Mutable{ .limbs = limbs_r, .positive = undefined, .len = undefined };
|
||||
result_q.divTrunc(&result_r, lhs_bigint, rhs_bigint, limbs_buffer);
|
||||
return Value.fromBigInt(sema.arena, result_r.toConst());
|
||||
}
|
||||
|
||||
fn zirMod(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
|
||||
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
|
||||
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
|
||||
if (maybe_lhs_val) |lhs_val| {
|
||||
return sema.addConstant(
|
||||
resolved_type,
|
||||
try lhs_val.intRem(rhs_val, resolved_type, sema.arena, target),
|
||||
try sema.intRem(block, resolved_type, lhs_val, lhs_src, rhs_val, rhs_src),
|
||||
);
|
||||
}
|
||||
break :rs lhs_src;
|
||||
|
||||
@@ -3472,44 +3472,6 @@ pub const Value = extern union {
|
||||
return fromBigInt(allocator, result_q.toConst());
|
||||
}
|
||||
|
||||
pub fn intRem(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, target: Target) !Value {
|
||||
if (ty.zigTypeTag() == .Vector) {
|
||||
const result_data = try allocator.alloc(Value, ty.vectorLen());
|
||||
for (result_data) |*scalar, i| {
|
||||
scalar.* = try intRemScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), allocator, target);
|
||||
}
|
||||
return Value.Tag.aggregate.create(allocator, result_data);
|
||||
}
|
||||
return intRemScalar(lhs, rhs, allocator, target);
|
||||
}
|
||||
|
||||
pub fn intRemScalar(lhs: Value, rhs: Value, allocator: Allocator, target: Target) !Value {
|
||||
// TODO is this a performance issue? maybe we should try the operation without
|
||||
// resorting to BigInt first.
|
||||
var lhs_space: Value.BigIntSpace = undefined;
|
||||
var rhs_space: Value.BigIntSpace = undefined;
|
||||
const lhs_bigint = lhs.toBigInt(&lhs_space, target);
|
||||
const rhs_bigint = rhs.toBigInt(&rhs_space, target);
|
||||
const limbs_q = try allocator.alloc(
|
||||
std.math.big.Limb,
|
||||
lhs_bigint.limbs.len,
|
||||
);
|
||||
const limbs_r = try allocator.alloc(
|
||||
std.math.big.Limb,
|
||||
// TODO: consider reworking Sema to re-use Values rather than
|
||||
// always producing new Value objects.
|
||||
rhs_bigint.limbs.len,
|
||||
);
|
||||
const limbs_buffer = try allocator.alloc(
|
||||
std.math.big.Limb,
|
||||
std.math.big.int.calcDivLimbsBufferLen(lhs_bigint.limbs.len, rhs_bigint.limbs.len),
|
||||
);
|
||||
var result_q = BigIntMutable{ .limbs = limbs_q, .positive = undefined, .len = undefined };
|
||||
var result_r = BigIntMutable{ .limbs = limbs_r, .positive = undefined, .len = undefined };
|
||||
result_q.divTrunc(&result_r, lhs_bigint, rhs_bigint, limbs_buffer);
|
||||
return fromBigInt(allocator, result_r.toConst());
|
||||
}
|
||||
|
||||
pub fn intMod(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, target: Target) !Value {
|
||||
if (ty.zigTypeTag() == .Vector) {
|
||||
const result_data = try allocator.alloc(Value, ty.vectorLen());
|
||||
|
||||
@@ -1721,3 +1721,18 @@ fn testAbsFloat() !void {
|
||||
fn testAbsFloatOne(in: f32, out: f32) !void {
|
||||
try expect(@fabs(@as(f32, in)) == @as(f32, out));
|
||||
}
|
||||
|
||||
test "mod lazy values" {
|
||||
{
|
||||
const X = struct { x: u32 };
|
||||
const x = @sizeOf(X);
|
||||
const y = 1 % x;
|
||||
_ = y;
|
||||
}
|
||||
{
|
||||
const X = struct { x: u32 };
|
||||
const x = @sizeOf(X);
|
||||
const y = x % 1;
|
||||
_ = y;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user