authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2023-04-29 17:02:50+02:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2023-05-19 20:18:59+02:00
log8236a26c605c8c4276f2062b3b6f55497cd45e53
treecac3c26ab3354d1c5e8a4ee689235c38237dfa7b
parenteb77e3381fac5f5bba2254cf5a7369aaea930e4e
signaturelock-open Commit is signed but in an unrecognized format.

wasm: implement mul, shl and xor for big ints

Uses compiler-rt for multiplication and shifting left, while lowers it down using regular instructions for xor.

1 files changed, 45 insertions(+), 27 deletions(-)

src/arch/wasm/CodeGen.zig+45-27
...@@ -2565,37 +2565,55 @@ fn binOp(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!...@@ -2565,37 +2565,55 @@ fn binOp(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!
25652565
2566fn binOpBigInt(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!WValue {2566fn binOpBigInt(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!WValue {
2567 if (ty.intInfo(func.target).bits > 128) {2567 if (ty.intInfo(func.target).bits > 128) {
2568 return func.fail("TODO: Implement binary operation for big integer", .{});2568 return func.fail("TODO: Implement binary operation for big integers larger than 128 bits", .{});
2569 }2569 }
25702570
2571 if (op != .add and op != .sub) {2571 switch (op) {
2572 return func.fail("TODO: Implement binary operation for big integers", .{});2572 .mul => return func.callIntrinsic("__multi3", &.{ ty, ty }, ty, &.{ lhs, rhs }),
2573 }2573 .shr => return func.callIntrinsic("__lshrti3", &.{ ty, Type.i32 }, ty, &.{ lhs, rhs }),
25742574 .xor => {
2575 const result = try func.allocStack(ty);2575 const result = try func.allocStack(ty);
2576 var lhs_high_bit = try (try func.load(lhs, Type.u64, 0)).toLocal(func, Type.u64);2576 try func.emitWValue(result);
2577 defer lhs_high_bit.free(func);2577 const lhs_high_bit = try func.load(lhs, Type.u64, 0);
2578 var rhs_high_bit = try (try func.load(rhs, Type.u64, 0)).toLocal(func, Type.u64);2578 const rhs_high_bit = try func.load(rhs, Type.u64, 0);
2579 defer rhs_high_bit.free(func);2579 const xor_high_bit = try func.binOp(lhs_high_bit, rhs_high_bit, Type.u64, .xor);
2580 var high_op_res = try (try func.binOp(lhs_high_bit, rhs_high_bit, Type.u64, op)).toLocal(func, Type.u64);2580 try func.store(.stack, xor_high_bit, Type.u64, result.offset());
2581 defer high_op_res.free(func);
2582
2583 const lhs_low_bit = try func.load(lhs, Type.u64, 8);
2584 const rhs_low_bit = try func.load(rhs, Type.u64, 8);
2585 const low_op_res = try func.binOp(lhs_low_bit, rhs_low_bit, Type.u64, op);
25862581
2587 const lt = if (op == .add) blk: {2582 try func.emitWValue(result);
2588 break :blk try func.cmp(high_op_res, rhs_high_bit, Type.u64, .lt);2583 const lhs_low_bit = try func.load(lhs, Type.u64, 8);
2589 } else if (op == .sub) blk: {2584 const rhs_low_bit = try func.load(rhs, Type.u64, 8);
2590 break :blk try func.cmp(lhs_high_bit, rhs_high_bit, Type.u64, .lt);2585 const xor_low_bit = try func.binOp(lhs_low_bit, rhs_low_bit, Type.u64, .xor);
2591 } else unreachable;2586 try func.store(.stack, xor_low_bit, Type.u64, result.offset() + 8);
2592 const tmp = try func.intcast(lt, Type.u32, Type.u64);2587 return result;
2593 var tmp_op = try (try func.binOp(low_op_res, tmp, Type.u64, op)).toLocal(func, Type.u64);2588 },
2594 defer tmp_op.free(func);2589 .add, .sub => {
2590 const result = try func.allocStack(ty);
2591 var lhs_high_bit = try (try func.load(lhs, Type.u64, 0)).toLocal(func, Type.u64);
2592 defer lhs_high_bit.free(func);
2593 var rhs_high_bit = try (try func.load(rhs, Type.u64, 0)).toLocal(func, Type.u64);
2594 defer rhs_high_bit.free(func);
2595 var high_op_res = try (try func.binOp(lhs_high_bit, rhs_high_bit, Type.u64, op)).toLocal(func, Type.u64);
2596 defer high_op_res.free(func);
25952597
2596 try func.store(result, high_op_res, Type.u64, 0);2598 const lhs_low_bit = try func.load(lhs, Type.u64, 8);
2597 try func.store(result, tmp_op, Type.u64, 8);2599 const rhs_low_bit = try func.load(rhs, Type.u64, 8);
2598 return result;2600 const low_op_res = try func.binOp(lhs_low_bit, rhs_low_bit, Type.u64, op);
2601
2602 const lt = if (op == .add) blk: {
2603 break :blk try func.cmp(high_op_res, rhs_high_bit, Type.u64, .lt);
2604 } else if (op == .sub) blk: {
2605 break :blk try func.cmp(lhs_high_bit, rhs_high_bit, Type.u64, .lt);
2606 } else unreachable;
2607 const tmp = try func.intcast(lt, Type.u32, Type.u64);
2608 var tmp_op = try (try func.binOp(low_op_res, tmp, Type.u64, op)).toLocal(func, Type.u64);
2609 defer tmp_op.free(func);
2610
2611 try func.store(result, high_op_res, Type.u64, 0);
2612 try func.store(result, tmp_op, Type.u64, 8);
2613 return result;
2614 },
2615 else => return func.fail("TODO: Implement binary operation for big integers: '{s}'", .{@tagName(op)}),
2616 }
2599}2617}
26002618
2601const FloatOp = enum {2619const FloatOp = enum {