mirror of
https://github.com/ziglang/zig.git
synced 2025-12-29 01:23:17 +00:00
wasm: implement @mulWithOverflow for big ints
Currently we only support exact 128 bit *unsigned* integers
This commit is contained in:
parent
992de8e617
commit
d353d208e2
@ -5550,16 +5550,12 @@ fn airMulWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
|
||||
const int_info = lhs_ty.intInfo(func.target);
|
||||
const wasm_bits = toWasmBits(int_info.bits) orelse {
|
||||
return func.fail("TODO: Implement overflow arithmetic for integer bitsize: {d}", .{int_info.bits});
|
||||
};
|
||||
|
||||
if (wasm_bits > 64) {
|
||||
return func.fail("TODO: Implement `@mulWithOverflow` for integer bitsize: {d}", .{int_info.bits});
|
||||
}
|
||||
};
|
||||
|
||||
const zero = switch (wasm_bits) {
|
||||
32 => WValue{ .imm32 = 0 },
|
||||
64 => WValue{ .imm64 = 0 },
|
||||
64, 128 => WValue{ .imm64 = 0 },
|
||||
else => unreachable,
|
||||
};
|
||||
|
||||
@ -5638,6 +5634,65 @@ fn airMulWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
_ = try func.cmp(lsb, msb_shifted, lhs_ty, .neq);
|
||||
try func.addLabel(.local_set, overflow_bit.local.value);
|
||||
break :blk res;
|
||||
} else if (int_info.bits == 128 and int_info.signedness == .unsigned) blk: {
|
||||
var lhs_msb = try (try func.load(lhs, Type.u64, 0)).toLocal(func, Type.u64);
|
||||
defer lhs_msb.free(func);
|
||||
var lhs_lsb = try (try func.load(lhs, Type.u64, 8)).toLocal(func, Type.u64);
|
||||
defer lhs_lsb.free(func);
|
||||
var rhs_msb = try (try func.load(rhs, Type.u64, 0)).toLocal(func, Type.u64);
|
||||
defer rhs_msb.free(func);
|
||||
var rhs_lsb = try (try func.load(rhs, Type.u64, 8)).toLocal(func, Type.u64);
|
||||
defer rhs_lsb.free(func);
|
||||
|
||||
const mul1 = try func.callIntrinsic(
|
||||
"__multi3",
|
||||
&[_]Type{Type.i64} ** 4,
|
||||
Type.initTag(.i128),
|
||||
&.{ lhs_lsb, zero, rhs_msb, zero },
|
||||
);
|
||||
const mul2 = try func.callIntrinsic(
|
||||
"__multi3",
|
||||
&[_]Type{Type.i64} ** 4,
|
||||
Type.initTag(.i128),
|
||||
&.{ rhs_lsb, zero, lhs_msb, zero },
|
||||
);
|
||||
const mul3 = try func.callIntrinsic(
|
||||
"__multi3",
|
||||
&[_]Type{Type.i64} ** 4,
|
||||
Type.initTag(.i128),
|
||||
&.{ lhs_msb, zero, rhs_msb, zero },
|
||||
);
|
||||
|
||||
const rhs_lsb_not_zero = try func.cmp(rhs_lsb, zero, Type.u64, .neq);
|
||||
const lhs_lsb_not_zero = try func.cmp(lhs_lsb, zero, Type.u64, .neq);
|
||||
const lsb_and = try func.binOp(rhs_lsb_not_zero, lhs_lsb_not_zero, Type.bool, .@"and");
|
||||
const mul1_lsb = try func.load(mul1, Type.u64, 8);
|
||||
const mul1_lsb_not_zero = try func.cmp(mul1_lsb, zero, Type.u64, .neq);
|
||||
const lsb_or1 = try func.binOp(lsb_and, mul1_lsb_not_zero, Type.bool, .@"or");
|
||||
const mul2_lsb = try func.load(mul2, Type.u64, 8);
|
||||
const mul2_lsb_not_zero = try func.cmp(mul2_lsb, zero, Type.u64, .neq);
|
||||
const lsb_or = try func.binOp(lsb_or1, mul2_lsb_not_zero, Type.bool, .@"or");
|
||||
|
||||
const mul1_msb = try func.load(mul1, Type.u64, 0);
|
||||
const mul2_msb = try func.load(mul2, Type.u64, 0);
|
||||
const mul_add1 = try func.binOp(mul1_msb, mul2_msb, Type.u64, .add);
|
||||
|
||||
var mul3_lsb = try (try func.load(mul3, Type.u64, 8)).toLocal(func, Type.u64);
|
||||
defer mul3_lsb.free(func);
|
||||
var mul_add2 = try (try func.binOp(mul_add1, mul3_lsb, Type.u64, .add)).toLocal(func, Type.u64);
|
||||
defer mul_add2.free(func);
|
||||
const mul_add_lt = try func.cmp(mul_add2, mul3_lsb, Type.u64, .lt);
|
||||
|
||||
// result for overflow bit
|
||||
_ = try func.binOp(lsb_or, mul_add_lt, Type.bool, .@"or");
|
||||
try func.addLabel(.local_set, overflow_bit.local.value);
|
||||
|
||||
const tmp_result = try func.allocStack(Type.initTag(.u128));
|
||||
try func.emitWValue(tmp_result);
|
||||
const mul3_msb = try func.load(mul3, Type.u64, 0);
|
||||
try func.store(.stack, mul3_msb, Type.u64, tmp_result.offset());
|
||||
try func.store(tmp_result, mul_add2, Type.u64, 8);
|
||||
break :blk tmp_result;
|
||||
} 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);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user