| ... | ... | @@ -5550,16 +5550,12 @@ fn airMulWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5550 | 5550 | |
| 5551 | 5551 | const int_info = lhs_ty.intInfo(func.target); |
| 5552 | 5552 | const wasm_bits = toWasmBits(int_info.bits) orelse { |
| 5553 | | return func.fail("TODO: Implement overflow arithmetic for integer bitsize: {d}", .{int_info.bits}); |
| 5554 | | }; |
| 5555 | | |
| 5556 | | if (wasm_bits > 64) { |
| 5557 | 5553 | return func.fail("TODO: Implement `@mulWithOverflow` for integer bitsize: {d}", .{int_info.bits}); |
| 5558 | | } |
| 5554 | }; |
| 5559 | 5555 | |
| 5560 | 5556 | const zero = switch (wasm_bits) { |
| 5561 | 5557 | 32 => WValue{ .imm32 = 0 }, |
| 5562 | | 64 => WValue{ .imm64 = 0 }, |
| 5558 | 64, 128 => WValue{ .imm64 = 0 }, |
| 5563 | 5559 | else => unreachable, |
| 5564 | 5560 | }; |
| 5565 | 5561 | |
| ... | ... | @@ -5638,6 +5634,65 @@ fn airMulWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5638 | 5634 | _ = try func.cmp(lsb, msb_shifted, lhs_ty, .neq); |
| 5639 | 5635 | try func.addLabel(.local_set, overflow_bit.local.value); |
| 5640 | 5636 | break :blk res; |
| 5637 | } else if (int_info.bits == 128 and int_info.signedness == .unsigned) blk: { |
| 5638 | var lhs_msb = try (try func.load(lhs, Type.u64, 0)).toLocal(func, Type.u64); |
| 5639 | defer lhs_msb.free(func); |
| 5640 | var lhs_lsb = try (try func.load(lhs, Type.u64, 8)).toLocal(func, Type.u64); |
| 5641 | defer lhs_lsb.free(func); |
| 5642 | var rhs_msb = try (try func.load(rhs, Type.u64, 0)).toLocal(func, Type.u64); |
| 5643 | defer rhs_msb.free(func); |
| 5644 | var rhs_lsb = try (try func.load(rhs, Type.u64, 8)).toLocal(func, Type.u64); |
| 5645 | defer rhs_lsb.free(func); |
| 5646 | |
| 5647 | const mul1 = try func.callIntrinsic( |
| 5648 | "__multi3", |
| 5649 | &[_]Type{Type.i64} ** 4, |
| 5650 | Type.initTag(.i128), |
| 5651 | &.{ lhs_lsb, zero, rhs_msb, zero }, |
| 5652 | ); |
| 5653 | const mul2 = try func.callIntrinsic( |
| 5654 | "__multi3", |
| 5655 | &[_]Type{Type.i64} ** 4, |
| 5656 | Type.initTag(.i128), |
| 5657 | &.{ rhs_lsb, zero, lhs_msb, zero }, |
| 5658 | ); |
| 5659 | const mul3 = try func.callIntrinsic( |
| 5660 | "__multi3", |
| 5661 | &[_]Type{Type.i64} ** 4, |
| 5662 | Type.initTag(.i128), |
| 5663 | &.{ lhs_msb, zero, rhs_msb, zero }, |
| 5664 | ); |
| 5665 | |
| 5666 | const rhs_lsb_not_zero = try func.cmp(rhs_lsb, zero, Type.u64, .neq); |
| 5667 | const lhs_lsb_not_zero = try func.cmp(lhs_lsb, zero, Type.u64, .neq); |
| 5668 | const lsb_and = try func.binOp(rhs_lsb_not_zero, lhs_lsb_not_zero, Type.bool, .@"and"); |
| 5669 | const mul1_lsb = try func.load(mul1, Type.u64, 8); |
| 5670 | const mul1_lsb_not_zero = try func.cmp(mul1_lsb, zero, Type.u64, .neq); |
| 5671 | const lsb_or1 = try func.binOp(lsb_and, mul1_lsb_not_zero, Type.bool, .@"or"); |
| 5672 | const mul2_lsb = try func.load(mul2, Type.u64, 8); |
| 5673 | const mul2_lsb_not_zero = try func.cmp(mul2_lsb, zero, Type.u64, .neq); |
| 5674 | const lsb_or = try func.binOp(lsb_or1, mul2_lsb_not_zero, Type.bool, .@"or"); |
| 5675 | |
| 5676 | const mul1_msb = try func.load(mul1, Type.u64, 0); |
| 5677 | const mul2_msb = try func.load(mul2, Type.u64, 0); |
| 5678 | const mul_add1 = try func.binOp(mul1_msb, mul2_msb, Type.u64, .add); |
| 5679 | |
| 5680 | var mul3_lsb = try (try func.load(mul3, Type.u64, 8)).toLocal(func, Type.u64); |
| 5681 | defer mul3_lsb.free(func); |
| 5682 | var mul_add2 = try (try func.binOp(mul_add1, mul3_lsb, Type.u64, .add)).toLocal(func, Type.u64); |
| 5683 | defer mul_add2.free(func); |
| 5684 | const mul_add_lt = try func.cmp(mul_add2, mul3_lsb, Type.u64, .lt); |
| 5685 | |
| 5686 | // result for overflow bit |
| 5687 | _ = try func.binOp(lsb_or, mul_add_lt, Type.bool, .@"or"); |
| 5688 | try func.addLabel(.local_set, overflow_bit.local.value); |
| 5689 | |
| 5690 | const tmp_result = try func.allocStack(Type.initTag(.u128)); |
| 5691 | try func.emitWValue(tmp_result); |
| 5692 | const mul3_msb = try func.load(mul3, Type.u64, 0); |
| 5693 | try func.store(.stack, mul3_msb, Type.u64, tmp_result.offset()); |
| 5694 | try func.store(tmp_result, mul_add2, Type.u64, 8); |
| 5695 | break :blk tmp_result; |
| 5641 | 5696 | } else return func.fail("TODO: @mulWithOverflow for integers between 32 and 64 bits", .{}); |
| 5642 | 5697 | var bin_op_local = try bin_op.toLocal(func, lhs_ty); |
| 5643 | 5698 | defer bin_op_local.free(func); |