diff options
| author | Isaac Freund <mail@isaacfreund.com> | 2022-08-10 13:21:47 +0200 |
|---|---|---|
| committer | Isaac Freund <mail@isaacfreund.com> | 2022-08-10 14:48:27 +0200 |
| commit | bb1c3e8b7e2be201221e14719d2d39e6298cc66c (patch) | |
| tree | d4d5800c280beea171fdb4028553a7107aa21891 /src | |
| parent | 49a270b2038709a6a0c1f4de604696278769257b (diff) | |
| download | zig-bb1c3e8b7e2be201221e14719d2d39e6298cc66c.tar.gz zig-bb1c3e8b7e2be201221e14719d2d39e6298cc66c.zip | |
stage2: Handle lazy values for the % operator
Diffstat (limited to 'src')
| -rw-r--r-- | src/Sema.zig | 59 | ||||
| -rw-r--r-- | src/value.zig | 38 |
2 files changed, 57 insertions, 40 deletions
diff --git a/src/Sema.zig b/src/Sema.zig index acdce0e9b0..6d95b46c7c 100644 --- a/src/Sema.zig +++ b/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; diff --git a/src/value.zig b/src/value.zig index 3994040ba6..f156651eaa 100644 --- a/src/value.zig +++ b/src/value.zig @@ -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()); |
