| ... | ... | @@ -2523,10 +2523,34 @@ fn airBinOp(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void { |
| 2523 | 2523 | const bin_op = func.air.instructions.items(.data)[inst].bin_op; |
| 2524 | 2524 | const lhs = try func.resolveInst(bin_op.lhs); |
| 2525 | 2525 | const rhs = try func.resolveInst(bin_op.rhs); |
| 2526 | | const ty = func.air.typeOf(bin_op.lhs); |
| 2526 | const lhs_ty = func.air.typeOf(bin_op.lhs); |
| 2527 | const rhs_ty = func.air.typeOf(bin_op.rhs); |
| 2528 | |
| 2529 | // For certain operations, such as shifting, the types are different. |
| 2530 | // When converting this to a WebAssembly type, they *must* match to perform |
| 2531 | // an operation. For this reason we verify if the WebAssembly type is different, in which |
| 2532 | // case we first coerce the operands to the same type before performing the operation. |
| 2533 | // For big integers we can ignore this as we will call into compiler-rt which handles this. |
| 2534 | const result = switch (op) { |
| 2535 | .shr, .shl => res: { |
| 2536 | const lhs_wasm_bits = toWasmBits(@intCast(u16, lhs_ty.bitSize(func.target))) orelse { |
| 2537 | return func.fail("TODO: implement '{s}' for types larger than 128 bits", .{@tagName(op)}); |
| 2538 | }; |
| 2539 | const rhs_wasm_bits = toWasmBits(@intCast(u16, rhs_ty.bitSize(func.target))).?; |
| 2540 | const new_rhs = if (lhs_wasm_bits != rhs_wasm_bits and lhs_wasm_bits != 128) blk: { |
| 2541 | const tmp = try func.intcast(rhs, rhs_ty, lhs_ty); |
| 2542 | break :blk try tmp.toLocal(func, lhs_ty); |
| 2543 | } else rhs; |
| 2544 | const stack_result = try func.binOp(lhs, new_rhs, lhs_ty, op); |
| 2545 | break :res try stack_result.toLocal(func, lhs_ty); |
| 2546 | }, |
| 2547 | else => res: { |
| 2548 | const stack_result = try func.binOp(lhs, rhs, lhs_ty, op); |
| 2549 | break :res try stack_result.toLocal(func, lhs_ty); |
| 2550 | }, |
| 2551 | }; |
| 2527 | 2552 | |
| 2528 | | const stack_value = try func.binOp(lhs, rhs, ty, op); |
| 2529 | | func.finishAir(inst, try stack_value.toLocal(func, ty), &.{ bin_op.lhs, bin_op.rhs }); |
| 2553 | func.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs }); |
| 2530 | 2554 | } |
| 2531 | 2555 | |
| 2532 | 2556 | /// Performs a binary operation on the given `WValue`'s |
| ... | ... | @@ -2769,14 +2793,38 @@ fn airWrapBinOp(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void { |
| 2769 | 2793 | |
| 2770 | 2794 | const lhs = try func.resolveInst(bin_op.lhs); |
| 2771 | 2795 | const rhs = try func.resolveInst(bin_op.rhs); |
| 2772 | | const ty = func.air.typeOf(bin_op.lhs); |
| 2796 | const lhs_ty = func.air.typeOf(bin_op.lhs); |
| 2797 | const rhs_ty = func.air.typeOf(bin_op.rhs); |
| 2773 | 2798 | |
| 2774 | | if (ty.zigTypeTag() == .Vector) { |
| 2799 | if (lhs_ty.zigTypeTag() == .Vector or rhs_ty.zigTypeTag() == .Vector) { |
| 2775 | 2800 | return func.fail("TODO: Implement wrapping arithmetic for vectors", .{}); |
| 2776 | 2801 | } |
| 2777 | 2802 | |
| 2778 | | const result = try (try func.wrapBinOp(lhs, rhs, ty, op)).toLocal(func, ty); |
| 2779 | | func.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs }); |
| 2803 | // For certain operations, such as shifting, the types are different. |
| 2804 | // When converting this to a WebAssembly type, they *must* match to perform |
| 2805 | // an operation. For this reason we verify if the WebAssembly type is different, in which |
| 2806 | // case we first coerce the operands to the same type before performing the operation. |
| 2807 | // For big integers we can ignore this as we will call into compiler-rt which handles this. |
| 2808 | const result = switch (op) { |
| 2809 | .shr, .shl => res: { |
| 2810 | const lhs_wasm_bits = toWasmBits(@intCast(u16, lhs_ty.bitSize(func.target))) orelse { |
| 2811 | return func.fail("TODO: implement '{s}' for types larger than 128 bits", .{@tagName(op)}); |
| 2812 | }; |
| 2813 | const rhs_wasm_bits = toWasmBits(@intCast(u16, rhs_ty.bitSize(func.target))).?; |
| 2814 | const new_rhs = if (lhs_wasm_bits != rhs_wasm_bits and lhs_wasm_bits != 128) blk: { |
| 2815 | const tmp = try func.intcast(rhs, rhs_ty, lhs_ty); |
| 2816 | break :blk try tmp.toLocal(func, lhs_ty); |
| 2817 | } else rhs; |
| 2818 | const stack_result = try func.wrapBinOp(lhs, new_rhs, lhs_ty, op); |
| 2819 | break :res try stack_result.toLocal(func, lhs_ty); |
| 2820 | }, |
| 2821 | else => res: { |
| 2822 | const stack_result = try func.wrapBinOp(lhs, rhs, lhs_ty, op); |
| 2823 | break :res try stack_result.toLocal(func, lhs_ty); |
| 2824 | }, |
| 2825 | }; |
| 2826 | |
| 2827 | return func.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs }); |
| 2780 | 2828 | } |
| 2781 | 2829 | |
| 2782 | 2830 | /// Performs a wrapping binary operation. |