diff options
| author | Luuk de Gram <luuk@degram.dev> | 2023-05-01 19:39:40 +0200 |
|---|---|---|
| committer | Luuk de Gram <luuk@degram.dev> | 2023-05-19 20:18:59 +0200 |
| commit | 992de8e61718a1a77666e473dc37872afbb80c98 (patch) | |
| tree | dc7c1c845f3332b6cb870461833c2fde608f2aac /src/arch/wasm/CodeGen.zig | |
| parent | 8236a26c605c8c4276f2062b3b6f55497cd45e53 (diff) | |
| download | zig-992de8e61718a1a77666e473dc37872afbb80c98.tar.gz zig-992de8e61718a1a77666e473dc37872afbb80c98.zip | |
wasm: implement `@addWithOverflow` for 64bit ints
Diffstat (limited to 'src/arch/wasm/CodeGen.zig')
| -rw-r--r-- | src/arch/wasm/CodeGen.zig | 41 |
1 files changed, 37 insertions, 4 deletions
diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index 4296cc557f..53c537c463 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -5553,7 +5553,7 @@ fn airMulWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { return func.fail("TODO: Implement overflow arithmetic for integer bitsize: {d}", .{int_info.bits}); }; - if (wasm_bits > 32) { + if (wasm_bits > 64) { return func.fail("TODO: Implement `@mulWithOverflow` for integer bitsize: {d}", .{int_info.bits}); } @@ -5586,7 +5586,7 @@ fn airMulWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { try func.addLabel(.local_set, overflow_bit.local.value); break :blk down_cast; } - } else if (int_info.signedness == .signed) blk: { + } else if (int_info.signedness == .signed and wasm_bits == 32) blk: { const lhs_abs = try func.signAbsValue(lhs, lhs_ty); const rhs_abs = try func.signAbsValue(rhs, lhs_ty); 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 { _ = try func.cmp(mul_abs, bin_op, lhs_ty, .neq); try func.addLabel(.local_set, overflow_bit.local.value); break :blk try func.wrapOperand(bin_op, lhs_ty); - } else blk: { + } else if (wasm_bits == 32) blk: { var bin_op = try (try func.binOp(lhs, rhs, lhs_ty, .mul)).toLocal(func, lhs_ty); defer bin_op.free(func); const shift_imm = if (wasm_bits == 32) @@ -5605,7 +5605,40 @@ fn airMulWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { _ = try func.cmp(shr, zero, lhs_ty, .neq); try func.addLabel(.local_set, overflow_bit.local.value); break :blk try func.wrapOperand(bin_op, lhs_ty); - }; + } else if (int_info.bits == 64 and int_info.signedness == .unsigned) blk: { + const new_ty = Type.initTag(.u128); + var lhs_upcast = try (try func.intcast(lhs, lhs_ty, new_ty)).toLocal(func, lhs_ty); + defer lhs_upcast.free(func); + var rhs_upcast = try (try func.intcast(rhs, lhs_ty, new_ty)).toLocal(func, lhs_ty); + defer rhs_upcast.free(func); + const bin_op = try func.binOp(lhs_upcast, rhs_upcast, new_ty, .mul); + const lsb = try func.load(bin_op, lhs_ty, 8); + _ = try func.cmp(lsb, zero, lhs_ty, .neq); + try func.addLabel(.local_set, overflow_bit.local.value); + + break :blk try func.load(bin_op, lhs_ty, 0); + } else if (int_info.bits == 64 and int_info.signedness == .signed) blk: { + const shift_val: WValue = .{ .imm64 = 63 }; + var lhs_shifted = try (try func.binOp(lhs, shift_val, lhs_ty, .shr)).toLocal(func, lhs_ty); + defer lhs_shifted.free(func); + var rhs_shifted = try (try func.binOp(rhs, shift_val, lhs_ty, .shr)).toLocal(func, lhs_ty); + defer rhs_shifted.free(func); + + const bin_op = try func.callIntrinsic( + "__multi3", + &[_]Type{Type.i64} ** 4, + Type.initTag(.i128), + &.{ lhs, lhs_shifted, rhs, rhs_shifted }, + ); + const res = try func.allocLocal(lhs_ty); + const msb = try func.load(bin_op, lhs_ty, 0); + try func.addLabel(.local_tee, res.local.value); + const msb_shifted = try func.binOp(msb, shift_val, lhs_ty, .shr); + const lsb = try func.load(bin_op, lhs_ty, 8); + _ = try func.cmp(lsb, msb_shifted, lhs_ty, .neq); + try func.addLabel(.local_set, overflow_bit.local.value); + break :blk res; + } else return func.fail("TODO: @mulWithOverflow for integers between 32 and 64 bits", .{}); var bin_op_local = try bin_op.toLocal(func, lhs_ty); defer bin_op_local.free(func); |
