| ... | @@ -5553,7 +5553,7 @@ fn airMulWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -5553,7 +5553,7 @@ fn airMulWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5553 | return func.fail("TODO: Implement overflow arithmetic for integer bitsize: {d}", .{int_info.bits}); | 5553 | return func.fail("TODO: Implement overflow arithmetic for integer bitsize: {d}", .{int_info.bits}); |
| 5554 | }; | 5554 | }; |
| 5555 | | 5555 | |
| 5556 | if (wasm_bits > 32) { | 5556 | if (wasm_bits > 64) { |
| 5557 | return func.fail("TODO: Implement `@mulWithOverflow` for integer bitsize: {d}", .{int_info.bits}); | 5557 | return func.fail("TODO: Implement `@mulWithOverflow` for integer bitsize: {d}", .{int_info.bits}); |
| 5558 | } | 5558 | } |
| 5559 | | 5559 | |
| ... | @@ -5586,7 +5586,7 @@ fn airMulWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -5586,7 +5586,7 @@ fn airMulWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5586 | try func.addLabel(.local_set, overflow_bit.local.value); | 5586 | try func.addLabel(.local_set, overflow_bit.local.value); |
| 5587 | break :blk down_cast; | 5587 | break :blk down_cast; |
| 5588 | } | 5588 | } |
| 5589 | } else if (int_info.signedness == .signed) blk: { | 5589 | } else if (int_info.signedness == .signed and wasm_bits == 32) blk: { |
| 5590 | const lhs_abs = try func.signAbsValue(lhs, lhs_ty); | 5590 | const lhs_abs = try func.signAbsValue(lhs, lhs_ty); |
| 5591 | const rhs_abs = try func.signAbsValue(rhs, lhs_ty); | 5591 | const rhs_abs = try func.signAbsValue(rhs, lhs_ty); |
| 5592 | const bin_op = try (try func.binOp(lhs_abs, rhs_abs, lhs_ty, .mul)).toLocal(func, lhs_ty); | 5592 | const bin_op = try (try func.binOp(lhs_abs, rhs_abs, lhs_ty, .mul)).toLocal(func, lhs_ty); |
| ... | @@ -5594,7 +5594,7 @@ fn airMulWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -5594,7 +5594,7 @@ fn airMulWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5594 | _ = try func.cmp(mul_abs, bin_op, lhs_ty, .neq); | 5594 | _ = try func.cmp(mul_abs, bin_op, lhs_ty, .neq); |
| 5595 | try func.addLabel(.local_set, overflow_bit.local.value); | 5595 | try func.addLabel(.local_set, overflow_bit.local.value); |
| 5596 | break :blk try func.wrapOperand(bin_op, lhs_ty); | 5596 | break :blk try func.wrapOperand(bin_op, lhs_ty); |
| 5597 | } else blk: { | 5597 | } else if (wasm_bits == 32) blk: { |
| 5598 | var bin_op = try (try func.binOp(lhs, rhs, lhs_ty, .mul)).toLocal(func, lhs_ty); | 5598 | var bin_op = try (try func.binOp(lhs, rhs, lhs_ty, .mul)).toLocal(func, lhs_ty); |
| 5599 | defer bin_op.free(func); | 5599 | defer bin_op.free(func); |
| 5600 | const shift_imm = if (wasm_bits == 32) | 5600 | const shift_imm = if (wasm_bits == 32) |
| ... | @@ -5605,7 +5605,40 @@ fn airMulWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -5605,7 +5605,40 @@ fn airMulWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5605 | _ = try func.cmp(shr, zero, lhs_ty, .neq); | 5605 | _ = try func.cmp(shr, zero, lhs_ty, .neq); |
| 5606 | try func.addLabel(.local_set, overflow_bit.local.value); | 5606 | try func.addLabel(.local_set, overflow_bit.local.value); |
| 5607 | break :blk try func.wrapOperand(bin_op, lhs_ty); | 5607 | break :blk try func.wrapOperand(bin_op, lhs_ty); |
| 5608 | }; | 5608 | } else if (int_info.bits == 64 and int_info.signedness == .unsigned) blk: { |
| | 5609 | const new_ty = Type.initTag(.u128); |
| | 5610 | var lhs_upcast = try (try func.intcast(lhs, lhs_ty, new_ty)).toLocal(func, lhs_ty); |
| | 5611 | defer lhs_upcast.free(func); |
| | 5612 | var rhs_upcast = try (try func.intcast(rhs, lhs_ty, new_ty)).toLocal(func, lhs_ty); |
| | 5613 | defer rhs_upcast.free(func); |
| | 5614 | const bin_op = try func.binOp(lhs_upcast, rhs_upcast, new_ty, .mul); |
| | 5615 | const lsb = try func.load(bin_op, lhs_ty, 8); |
| | 5616 | _ = try func.cmp(lsb, zero, lhs_ty, .neq); |
| | 5617 | try func.addLabel(.local_set, overflow_bit.local.value); |
| | 5618 | |
| | 5619 | break :blk try func.load(bin_op, lhs_ty, 0); |
| | 5620 | } else if (int_info.bits == 64 and int_info.signedness == .signed) blk: { |
| | 5621 | const shift_val: WValue = .{ .imm64 = 63 }; |
| | 5622 | var lhs_shifted = try (try func.binOp(lhs, shift_val, lhs_ty, .shr)).toLocal(func, lhs_ty); |
| | 5623 | defer lhs_shifted.free(func); |
| | 5624 | var rhs_shifted = try (try func.binOp(rhs, shift_val, lhs_ty, .shr)).toLocal(func, lhs_ty); |
| | 5625 | defer rhs_shifted.free(func); |
| | 5626 | |
| | 5627 | const bin_op = try func.callIntrinsic( |
| | 5628 | "__multi3", |
| | 5629 | &[_]Type{Type.i64} ** 4, |
| | 5630 | Type.initTag(.i128), |
| | 5631 | &.{ lhs, lhs_shifted, rhs, rhs_shifted }, |
| | 5632 | ); |
| | 5633 | const res = try func.allocLocal(lhs_ty); |
| | 5634 | const msb = try func.load(bin_op, lhs_ty, 0); |
| | 5635 | try func.addLabel(.local_tee, res.local.value); |
| | 5636 | const msb_shifted = try func.binOp(msb, shift_val, lhs_ty, .shr); |
| | 5637 | const lsb = try func.load(bin_op, lhs_ty, 8); |
| | 5638 | _ = try func.cmp(lsb, msb_shifted, lhs_ty, .neq); |
| | 5639 | try func.addLabel(.local_set, overflow_bit.local.value); |
| | 5640 | break :blk res; |
| | 5641 | } else return func.fail("TODO: @mulWithOverflow for integers between 32 and 64 bits", .{}); |
| 5609 | var bin_op_local = try bin_op.toLocal(func, lhs_ty); | 5642 | var bin_op_local = try bin_op.toLocal(func, lhs_ty); |
| 5610 | defer bin_op_local.free(func); | 5643 | defer bin_op_local.free(func); |
| 5611 | | 5644 | |