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 {...@@ -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 };
55555555
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 }
55595559
...@@ -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);
56115644