| ... | ... | @@ -78,6 +78,7 @@ post_hoc_blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, *LabeledBlock) = .{}, |
| 78 | 78 | err: ?*Module.ErrorMsg = null, |
| 79 | 79 | |
| 80 | 80 | const std = @import("std"); |
| 81 | const math = std.math; |
| 81 | 82 | const mem = std.mem; |
| 82 | 83 | const Allocator = std.mem.Allocator; |
| 83 | 84 | const assert = std.debug.assert; |
| ... | ... | @@ -11824,7 +11825,7 @@ fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. |
| 11824 | 11825 | return sema.failWithDivideByZero(block, rhs_src); |
| 11825 | 11826 | } |
| 11826 | 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 | 11829 | // If this answer could possibly be different by doing `intMod`, |
| 11829 | 11830 | // we must emit a compile error. Otherwise, it's OK. |
| 11830 | 11831 | 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 | 11887 | return block.addBinOp(air_tag, casted_lhs, casted_rhs); |
| 11887 | 11888 | } |
| 11888 | 11889 | |
| 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 | |
| 11889 | 11944 | fn zirMod(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 11890 | 11945 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 11891 | 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 | 12105 | if (maybe_lhs_val) |lhs_val| { |
| 12051 | 12106 | return sema.addConstant( |
| 12052 | 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 | 12111 | break :rs lhs_src; |