authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2023-05-01 19:39:40+02:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2023-05-19 20:18:59+02:00
log992de8e61718a1a77666e473dc37872afbb80c98
treedc7c1c845f3332b6cb870461833c2fde608f2aac
parent8236a26c605c8c4276f2062b3b6f55497cd45e53
signaturelock-open Commit is signed but in an unrecognized format.

wasm: implement `@addWithOverflow` for 64bit ints


1 files changed, 37 insertions(+), 4 deletions(-)

src/arch/wasm/CodeGen.zig+37-4
......@@ -5553,7 +5553,7 @@ fn airMulWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
55535553 return func.fail("TODO: Implement overflow arithmetic for integer bitsize: {d}", .{int_info.bits});
55545554 };
55555555
5556 if (wasm_bits > 32) {
5556 if (wasm_bits > 64) {
55575557 return func.fail("TODO: Implement `@mulWithOverflow` for integer bitsize: {d}", .{int_info.bits});
55585558 }
55595559
......@@ -5586,7 +5586,7 @@ fn airMulWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
55865586 try func.addLabel(.local_set, overflow_bit.local.value);
55875587 break :blk down_cast;
55885588 }
5589 } else if (int_info.signedness == .signed) blk: {
5589 } else if (int_info.signedness == .signed and wasm_bits == 32) blk: {
55905590 const lhs_abs = try func.signAbsValue(lhs, lhs_ty);
55915591 const rhs_abs = try func.signAbsValue(rhs, lhs_ty);
55925592 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 {
55945594 _ = try func.cmp(mul_abs, bin_op, lhs_ty, .neq);
55955595 try func.addLabel(.local_set, overflow_bit.local.value);
55965596 break :blk try func.wrapOperand(bin_op, lhs_ty);
5597 } else blk: {
5597 } else if (wasm_bits == 32) blk: {
55985598 var bin_op = try (try func.binOp(lhs, rhs, lhs_ty, .mul)).toLocal(func, lhs_ty);
55995599 defer bin_op.free(func);
56005600 const shift_imm = if (wasm_bits == 32)
......@@ -5605,7 +5605,40 @@ fn airMulWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
56055605 _ = try func.cmp(shr, zero, lhs_ty, .neq);
56065606 try func.addLabel(.local_set, overflow_bit.local.value);
56075607 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", .{});
56095642 var bin_op_local = try bin_op.toLocal(func, lhs_ty);
56105643 defer bin_op_local.free(func);
56115644