| ... | @@ -1852,6 +1852,7 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -1852,6 +1852,7 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 1852 | .bool_and => func.airBinOp(inst, .@"and"), | 1852 | .bool_and => func.airBinOp(inst, .@"and"), |
| 1853 | .bool_or => func.airBinOp(inst, .@"or"), | 1853 | .bool_or => func.airBinOp(inst, .@"or"), |
| 1854 | .rem => func.airBinOp(inst, .rem), | 1854 | .rem => func.airBinOp(inst, .rem), |
| | 1855 | .mod => func.airMod(inst), |
| 1855 | .shl => func.airWrapBinOp(inst, .shl), | 1856 | .shl => func.airWrapBinOp(inst, .shl), |
| 1856 | .shl_exact => func.airBinOp(inst, .shl), | 1857 | .shl_exact => func.airBinOp(inst, .shl), |
| 1857 | .shl_sat => func.airShlSat(inst), | 1858 | .shl_sat => func.airShlSat(inst), |
| ... | @@ -2012,7 +2013,6 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -2012,7 +2013,6 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 2012 | .frame_addr => func.airFrameAddress(inst), | 2013 | .frame_addr => func.airFrameAddress(inst), |
| 2013 | | 2014 | |
| 2014 | .mul_sat, | 2015 | .mul_sat, |
| 2015 | .mod, | | |
| 2016 | .assembly, | 2016 | .assembly, |
| 2017 | .bit_reverse, | 2017 | .bit_reverse, |
| 2018 | .is_err_ptr, | 2018 | .is_err_ptr, |
| ... | @@ -4151,7 +4151,7 @@ fn intcast(func: *CodeGen, operand: WValue, given: Type, wanted: Type) InnerErro | ... | @@ -4151,7 +4151,7 @@ fn intcast(func: *CodeGen, operand: WValue, given: Type, wanted: Type) InnerErro |
| 4151 | // when we upcast from a smaller integer to larger | 4151 | // when we upcast from a smaller integer to larger |
| 4152 | // integers, we must get its absolute value similar to | 4152 | // integers, we must get its absolute value similar to |
| 4153 | // i64_extend_i32_s instruction. | 4153 | // i64_extend_i32_s instruction. |
| 4154 | return func.signAbsValue(operand, given); | 4154 | return func.signExtendInt(operand, given); |
| 4155 | } | 4155 | } |
| 4156 | return func.wrapOperand(operand, wanted); | 4156 | return func.wrapOperand(operand, wanted); |
| 4157 | } | 4157 | } |
| ... | @@ -5649,13 +5649,13 @@ fn airAddSubWithOverflow(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerErro | ... | @@ -5649,13 +5649,13 @@ fn airAddSubWithOverflow(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerErro |
| 5649 | // for signed integers, we first apply signed shifts by the difference in bits | 5649 | // for signed integers, we first apply signed shifts by the difference in bits |
| 5650 | // to get the signed value, as we store it internally as 2's complement. | 5650 | // to get the signed value, as we store it internally as 2's complement. |
| 5651 | var lhs = if (wasm_bits != int_info.bits and is_signed) blk: { | 5651 | var lhs = if (wasm_bits != int_info.bits and is_signed) blk: { |
| 5652 | break :blk try (try func.signAbsValue(lhs_op, lhs_ty)).toLocal(func, lhs_ty); | 5652 | break :blk try (try func.signExtendInt(lhs_op, lhs_ty)).toLocal(func, lhs_ty); |
| 5653 | } else lhs_op; | 5653 | } else lhs_op; |
| 5654 | var rhs = if (wasm_bits != int_info.bits and is_signed) blk: { | 5654 | var rhs = if (wasm_bits != int_info.bits and is_signed) blk: { |
| 5655 | break :blk try (try func.signAbsValue(rhs_op, lhs_ty)).toLocal(func, lhs_ty); | 5655 | break :blk try (try func.signExtendInt(rhs_op, lhs_ty)).toLocal(func, lhs_ty); |
| 5656 | } else rhs_op; | 5656 | } else rhs_op; |
| 5657 | | 5657 | |
| 5658 | // in this case, we performed a signAbsValue which created a temporary local | 5658 | // in this case, we performed a signExtendInt which created a temporary local |
| 5659 | // so let's free this so it can be re-used instead. | 5659 | // so let's free this so it can be re-used instead. |
| 5660 | // In the other case we do not want to free it, because that would free the | 5660 | // In the other case we do not want to free it, because that would free the |
| 5661 | // resolved instructions which may be referenced by other instructions. | 5661 | // resolved instructions which may be referenced by other instructions. |
| ... | @@ -5677,7 +5677,7 @@ fn airAddSubWithOverflow(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerErro | ... | @@ -5677,7 +5677,7 @@ fn airAddSubWithOverflow(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerErro |
| 5677 | const lt = try func.cmp(bin_op, lhs, lhs_ty, .lt); | 5677 | const lt = try func.cmp(bin_op, lhs, lhs_ty, .lt); |
| 5678 | break :blk try func.binOp(cmp_zero, lt, Type.u32, .xor); | 5678 | break :blk try func.binOp(cmp_zero, lt, Type.u32, .xor); |
| 5679 | } | 5679 | } |
| 5680 | const abs = try func.signAbsValue(bin_op, lhs_ty); | 5680 | const abs = try func.signExtendInt(bin_op, lhs_ty); |
| 5681 | break :blk try func.cmp(abs, bin_op, lhs_ty, .neq); | 5681 | break :blk try func.cmp(abs, bin_op, lhs_ty, .neq); |
| 5682 | } else if (wasm_bits == int_info.bits) | 5682 | } else if (wasm_bits == int_info.bits) |
| 5683 | try func.cmp(bin_op, lhs, lhs_ty, cmp_op) | 5683 | try func.cmp(bin_op, lhs, lhs_ty, cmp_op) |
| ... | @@ -5797,7 +5797,7 @@ fn airShlWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -5797,7 +5797,7 @@ fn airShlWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5797 | const overflow_bit = if (wasm_bits != int_info.bits and is_signed) blk: { | 5797 | const overflow_bit = if (wasm_bits != int_info.bits and is_signed) blk: { |
| 5798 | // emit lhs to stack to we can keep 'wrapped' on the stack also | 5798 | // emit lhs to stack to we can keep 'wrapped' on the stack also |
| 5799 | try func.emitWValue(lhs); | 5799 | try func.emitWValue(lhs); |
| 5800 | const abs = try func.signAbsValue(shl, lhs_ty); | 5800 | const abs = try func.signExtendInt(shl, lhs_ty); |
| 5801 | const wrapped = try func.wrapBinOp(abs, rhs_final, lhs_ty, .shr); | 5801 | const wrapped = try func.wrapBinOp(abs, rhs_final, lhs_ty, .shr); |
| 5802 | break :blk try func.cmp(.{ .stack = {} }, wrapped, lhs_ty, .neq); | 5802 | break :blk try func.cmp(.{ .stack = {} }, wrapped, lhs_ty, .neq); |
| 5803 | } else blk: { | 5803 | } else blk: { |
| ... | @@ -5869,10 +5869,10 @@ fn airMulWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -5869,10 +5869,10 @@ fn airMulWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5869 | break :blk down_cast; | 5869 | break :blk down_cast; |
| 5870 | } | 5870 | } |
| 5871 | } else if (int_info.signedness == .signed and wasm_bits == 32) blk: { | 5871 | } else if (int_info.signedness == .signed and wasm_bits == 32) blk: { |
| 5872 | const lhs_abs = try func.signAbsValue(lhs, lhs_ty); | 5872 | const lhs_abs = try func.signExtendInt(lhs, lhs_ty); |
| 5873 | const rhs_abs = try func.signAbsValue(rhs, lhs_ty); | 5873 | const rhs_abs = try func.signExtendInt(rhs, lhs_ty); |
| 5874 | const bin_op = try (try func.binOp(lhs_abs, rhs_abs, lhs_ty, .mul)).toLocal(func, lhs_ty); | 5874 | const bin_op = try (try func.binOp(lhs_abs, rhs_abs, lhs_ty, .mul)).toLocal(func, lhs_ty); |
| 5875 | const mul_abs = try func.signAbsValue(bin_op, lhs_ty); | 5875 | const mul_abs = try func.signExtendInt(bin_op, lhs_ty); |
| 5876 | _ = try func.cmp(mul_abs, bin_op, lhs_ty, .neq); | 5876 | _ = try func.cmp(mul_abs, bin_op, lhs_ty, .neq); |
| 5877 | try func.addLabel(.local_set, overflow_bit.local.value); | 5877 | try func.addLabel(.local_set, overflow_bit.local.value); |
| 5878 | break :blk try func.wrapOperand(bin_op, lhs_ty); | 5878 | break :blk try func.wrapOperand(bin_op, lhs_ty); |
| ... | @@ -6405,19 +6405,26 @@ fn airDivFloor(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -6405,19 +6405,26 @@ fn airDivFloor(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6405 | const rhs = try func.resolveInst(bin_op.rhs); | 6405 | const rhs = try func.resolveInst(bin_op.rhs); |
| 6406 | | 6406 | |
| 6407 | if (ty.isUnsignedInt(mod)) { | 6407 | if (ty.isUnsignedInt(mod)) { |
| 6408 | const result = try (try func.binOp(lhs, rhs, ty, .div)).toLocal(func, ty); | 6408 | _ = try func.binOp(lhs, rhs, ty, .div); |
| 6409 | return func.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs }); | | |
| 6410 | } else if (ty.isSignedInt(mod)) { | 6409 | } else if (ty.isSignedInt(mod)) { |
| 6411 | const int_bits = ty.intInfo(mod).bits; | 6410 | const int_bits = ty.intInfo(mod).bits; |
| 6412 | const wasm_bits = toWasmBits(int_bits) orelse { | 6411 | const wasm_bits = toWasmBits(int_bits) orelse { |
| 6413 | return func.fail("TODO: `@divFloor` for signed integers larger than '{d}' bits", .{int_bits}); | 6412 | return func.fail("TODO: `@divFloor` for signed integers larger than 64 bits ({d} bits requested)", .{int_bits}); |
| 6414 | }; | 6413 | }; |
| 6415 | const lhs_res = if (wasm_bits != int_bits) blk: { | 6414 | |
| 6416 | break :blk try (try func.signAbsValue(lhs, ty)).toLocal(func, ty); | 6415 | if (wasm_bits > 64) { |
| 6417 | } else lhs; | 6416 | return func.fail("TODO: `@divFloor` for signed integers larger than 64 bits ({d} bits requested)", .{int_bits}); |
| 6418 | const rhs_res = if (wasm_bits != int_bits) blk: { | 6417 | } |
| 6419 | break :blk try (try func.signAbsValue(rhs, ty)).toLocal(func, ty); | 6418 | |
| 6420 | } else rhs; | 6419 | const lhs_wasm = if (wasm_bits != int_bits) |
| | 6420 | try (try func.signExtendInt(lhs, ty)).toLocal(func, ty) |
| | 6421 | else |
| | 6422 | lhs; |
| | 6423 | |
| | 6424 | const rhs_wasm = if (wasm_bits != int_bits) |
| | 6425 | try (try func.signExtendInt(rhs, ty)).toLocal(func, ty) |
| | 6426 | else |
| | 6427 | rhs; |
| 6421 | | 6428 | |
| 6422 | const zero = switch (wasm_bits) { | 6429 | const zero = switch (wasm_bits) { |
| 6423 | 32 => WValue{ .imm32 = 0 }, | 6430 | 32 => WValue{ .imm32 = 0 }, |
| ... | @@ -6425,27 +6432,50 @@ fn airDivFloor(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -6425,27 +6432,50 @@ fn airDivFloor(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6425 | else => unreachable, | 6432 | else => unreachable, |
| 6426 | }; | 6433 | }; |
| 6427 | | 6434 | |
| 6428 | const div_result = try func.allocLocal(ty); | 6435 | // tee leaves the value on the stack and stores it in a local. |
| 6429 | // leave on stack | 6436 | const quotient = try func.allocLocal(ty); |
| 6430 | _ = try func.binOp(lhs_res, rhs_res, ty, .div); | 6437 | _ = try func.binOp(lhs_wasm, rhs_wasm, ty, .div); |
| 6431 | try func.addLabel(.local_tee, div_result.local.value); | 6438 | try func.addLabel(.local_tee, quotient.local.value); |
| 6432 | _ = try func.cmp(lhs_res, zero, ty, .lt); | 6439 | |
| 6433 | _ = try func.cmp(rhs_res, zero, ty, .lt); | 6440 | // select takes a 32 bit value as the condition, so in the 64 bit case we use eqz to narrow |
| | 6441 | // the 64 bit value we want to use as the condition to 32 bits. |
| | 6442 | // This also inverts the condition (non 0 => 0, 0 => 1), so we put the adjusted and |
| | 6443 | // non-adjusted quotients on the stack in the opposite order for 32 vs 64 bits. |
| | 6444 | if (wasm_bits == 64) { |
| | 6445 | try func.emitWValue(quotient); |
| | 6446 | } |
| | 6447 | |
| | 6448 | // 0 if the signs of rhs_wasm and lhs_wasm are the same, 1 otherwise. |
| | 6449 | _ = try func.binOp(lhs_wasm, rhs_wasm, ty, .xor); |
| | 6450 | _ = try func.cmp(.stack, zero, ty, .lt); |
| | 6451 | |
| 6434 | switch (wasm_bits) { | 6452 | switch (wasm_bits) { |
| 6435 | 32 => { | 6453 | 32 => { |
| 6436 | try func.addTag(.i32_xor); | | |
| 6437 | try func.addTag(.i32_sub); | 6454 | try func.addTag(.i32_sub); |
| | 6455 | try func.emitWValue(quotient); |
| 6438 | }, | 6456 | }, |
| 6439 | 64 => { | 6457 | 64 => { |
| 6440 | try func.addTag(.i64_xor); | 6458 | try func.addTag(.i64_extend_i32_u); |
| 6441 | try func.addTag(.i64_sub); | 6459 | try func.addTag(.i64_sub); |
| 6442 | }, | 6460 | }, |
| 6443 | else => unreachable, | 6461 | else => unreachable, |
| 6444 | } | 6462 | } |
| 6445 | try func.emitWValue(div_result); | 6463 | |
| 6446 | // leave value on the stack | 6464 | _ = try func.binOp(lhs_wasm, rhs_wasm, ty, .rem); |
| 6447 | _ = try func.binOp(lhs_res, rhs_res, ty, .rem); | 6465 | |
| | 6466 | if (wasm_bits == 64) { |
| | 6467 | try func.addTag(.i64_eqz); |
| | 6468 | } |
| | 6469 | |
| 6448 | try func.addTag(.select); | 6470 | try func.addTag(.select); |
| | 6471 | |
| | 6472 | // We need to zero the high bits because N bit comparisons consider all 32 or 64 bits, and |
| | 6473 | // expect all but the lowest N bits to be 0. |
| | 6474 | // TODO: Should we be zeroing the high bits here or should we be ignoring the high bits |
| | 6475 | // when performing comparisons? |
| | 6476 | if (int_bits != wasm_bits) { |
| | 6477 | _ = try func.wrapOperand(.{ .stack = {} }, ty); |
| | 6478 | } |
| 6449 | } else { | 6479 | } else { |
| 6450 | const float_bits = ty.floatBits(func.target); | 6480 | const float_bits = ty.floatBits(func.target); |
| 6451 | if (float_bits > 64) { | 6481 | if (float_bits > 64) { |
| ... | @@ -6453,15 +6483,11 @@ fn airDivFloor(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -6453,15 +6483,11 @@ fn airDivFloor(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6453 | } | 6483 | } |
| 6454 | const is_f16 = float_bits == 16; | 6484 | const is_f16 = float_bits == 16; |
| 6455 | | 6485 | |
| 6456 | const lhs_operand = if (is_f16) blk: { | 6486 | const lhs_wasm = if (is_f16) try func.fpext(lhs, Type.f16, Type.f32) else lhs; |
| 6457 | break :blk try func.fpext(lhs, Type.f16, Type.f32); | 6487 | const rhs_wasm = if (is_f16) try func.fpext(rhs, Type.f16, Type.f32) else rhs; |
| 6458 | } else lhs; | | |
| 6459 | const rhs_operand = if (is_f16) blk: { | | |
| 6460 | break :blk try func.fpext(rhs, Type.f16, Type.f32); | | |
| 6461 | } else rhs; | | |
| 6462 | | 6488 | |
| 6463 | try func.emitWValue(lhs_operand); | 6489 | try func.emitWValue(lhs_wasm); |
| 6464 | try func.emitWValue(rhs_operand); | 6490 | try func.emitWValue(rhs_wasm); |
| 6465 | | 6491 | |
| 6466 | switch (float_bits) { | 6492 | switch (float_bits) { |
| 6467 | 16, 32 => { | 6493 | 16, 32 => { |
| ... | @@ -6498,8 +6524,8 @@ fn divSigned(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type) InnerError!WVal | ... | @@ -6498,8 +6524,8 @@ fn divSigned(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type) InnerError!WVal |
| 6498 | | 6524 | |
| 6499 | if (wasm_bits != int_bits) { | 6525 | if (wasm_bits != int_bits) { |
| 6500 | // Leave both values on the stack | 6526 | // Leave both values on the stack |
| 6501 | _ = try func.signAbsValue(lhs, ty); | 6527 | _ = try func.signExtendInt(lhs, ty); |
| 6502 | _ = try func.signAbsValue(rhs, ty); | 6528 | _ = try func.signExtendInt(rhs, ty); |
| 6503 | } else { | 6529 | } else { |
| 6504 | try func.emitWValue(lhs); | 6530 | try func.emitWValue(lhs); |
| 6505 | try func.emitWValue(rhs); | 6531 | try func.emitWValue(rhs); |
| ... | @@ -6511,19 +6537,68 @@ fn divSigned(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type) InnerError!WVal | ... | @@ -6511,19 +6537,68 @@ fn divSigned(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type) InnerError!WVal |
| 6511 | return result; | 6537 | return result; |
| 6512 | } | 6538 | } |
| 6513 | | 6539 | |
| 6514 | /// Retrieves the absolute value of a signed integer | 6540 | /// Remainder after floor division, defined by: |
| 6515 | /// NOTE: Leaves the result value on the stack. | 6541 | /// @divFloor(a, b) * b + @mod(a, b) = a |
| 6516 | fn signAbsValue(func: *CodeGen, operand: WValue, ty: Type) InnerError!WValue { | 6542 | fn airMod(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| | 6543 | const bin_op = func.air.instructions.items(.data)[inst].bin_op; |
| | 6544 | |
| | 6545 | const mod = func.bin_file.base.options.module.?; |
| | 6546 | const ty = func.typeOfIndex(inst); |
| | 6547 | const lhs = try func.resolveInst(bin_op.lhs); |
| | 6548 | const rhs = try func.resolveInst(bin_op.rhs); |
| | 6549 | |
| | 6550 | if (ty.isUnsignedInt(mod)) { |
| | 6551 | _ = try func.binOp(lhs, rhs, ty, .rem); |
| | 6552 | } else if (ty.isSignedInt(mod)) { |
| | 6553 | // The wasm rem instruction gives the remainder after truncating division (rounding towards |
| | 6554 | // 0), equivalent to @rem. |
| | 6555 | // We make use of the fact that: |
| | 6556 | // @mod(a, b) = @rem(@rem(a, b) + b, b) |
| | 6557 | const int_bits = ty.intInfo(mod).bits; |
| | 6558 | const wasm_bits = toWasmBits(int_bits) orelse { |
| | 6559 | return func.fail("TODO: `@mod` for signed integers larger than 64 bits ({d} bits requested)", .{int_bits}); |
| | 6560 | }; |
| | 6561 | |
| | 6562 | if (wasm_bits > 64) { |
| | 6563 | return func.fail("TODO: `@mod` for signed integers larger than 64 bits ({d} bits requested)", .{int_bits}); |
| | 6564 | } |
| | 6565 | |
| | 6566 | const lhs_wasm = if (wasm_bits != int_bits) |
| | 6567 | try (try func.signExtendInt(lhs, ty)).toLocal(func, ty) |
| | 6568 | else |
| | 6569 | lhs; |
| | 6570 | |
| | 6571 | const rhs_wasm = if (wasm_bits != int_bits) |
| | 6572 | try (try func.signExtendInt(rhs, ty)).toLocal(func, ty) |
| | 6573 | else |
| | 6574 | rhs; |
| | 6575 | |
| | 6576 | _ = try func.binOp(lhs_wasm, rhs_wasm, ty, .rem); |
| | 6577 | _ = try func.binOp(.stack, rhs_wasm, ty, .add); |
| | 6578 | _ = try func.binOp(.stack, rhs_wasm, ty, .rem); |
| | 6579 | } else { |
| | 6580 | return func.fail("TODO: implement `@mod` on floating point types for {}", .{func.target.cpu.arch}); |
| | 6581 | } |
| | 6582 | |
| | 6583 | const result = try func.allocLocal(ty); |
| | 6584 | try func.addLabel(.local_set, result.local.value); |
| | 6585 | func.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs }); |
| | 6586 | } |
| | 6587 | |
| | 6588 | /// Sign extends an N bit signed integer and pushes the result to the stack. |
| | 6589 | /// The result will be sign extended to 32 bits if N <= 32 or 64 bits if N <= 64. |
| | 6590 | /// Support for integers wider than 64 bits has not yet been implemented. |
| | 6591 | fn signExtendInt(func: *CodeGen, operand: WValue, ty: Type) InnerError!WValue { |
| 6517 | const mod = func.bin_file.base.options.module.?; | 6592 | const mod = func.bin_file.base.options.module.?; |
| 6518 | const int_bits = ty.intInfo(mod).bits; | 6593 | const int_bits = ty.intInfo(mod).bits; |
| 6519 | const wasm_bits = toWasmBits(int_bits) orelse { | 6594 | const wasm_bits = toWasmBits(int_bits) orelse { |
| 6520 | return func.fail("TODO: signAbsValue for signed integers larger than '{d}' bits", .{int_bits}); | 6595 | return func.fail("TODO: signExtendInt for signed integers larger than '{d}' bits", .{int_bits}); |
| 6521 | }; | 6596 | }; |
| 6522 | | 6597 | |
| 6523 | const shift_val = switch (wasm_bits) { | 6598 | const shift_val = switch (wasm_bits) { |
| 6524 | 32 => WValue{ .imm32 = wasm_bits - int_bits }, | 6599 | 32 => WValue{ .imm32 = wasm_bits - int_bits }, |
| 6525 | 64 => WValue{ .imm64 = wasm_bits - int_bits }, | 6600 | 64 => WValue{ .imm64 = wasm_bits - int_bits }, |
| 6526 | else => return func.fail("TODO: signAbsValue for i128", .{}), | 6601 | else => return func.fail("TODO: signExtendInt for i128", .{}), |
| 6527 | }; | 6602 | }; |
| 6528 | | 6603 | |
| 6529 | try func.emitWValue(operand); | 6604 | try func.emitWValue(operand); |
| ... | @@ -6604,10 +6679,10 @@ fn signedSat(func: *CodeGen, lhs_operand: WValue, rhs_operand: WValue, ty: Type, | ... | @@ -6604,10 +6679,10 @@ fn signedSat(func: *CodeGen, lhs_operand: WValue, rhs_operand: WValue, ty: Type, |
| 6604 | const is_wasm_bits = wasm_bits == int_info.bits; | 6679 | const is_wasm_bits = wasm_bits == int_info.bits; |
| 6605 | | 6680 | |
| 6606 | var lhs = if (!is_wasm_bits) lhs: { | 6681 | var lhs = if (!is_wasm_bits) lhs: { |
| 6607 | break :lhs try (try func.signAbsValue(lhs_operand, ty)).toLocal(func, ty); | 6682 | break :lhs try (try func.signExtendInt(lhs_operand, ty)).toLocal(func, ty); |
| 6608 | } else lhs_operand; | 6683 | } else lhs_operand; |
| 6609 | var rhs = if (!is_wasm_bits) rhs: { | 6684 | var rhs = if (!is_wasm_bits) rhs: { |
| 6610 | break :rhs try (try func.signAbsValue(rhs_operand, ty)).toLocal(func, ty); | 6685 | break :rhs try (try func.signExtendInt(rhs_operand, ty)).toLocal(func, ty); |
| 6611 | } else rhs_operand; | 6686 | } else rhs_operand; |
| 6612 | | 6687 | |
| 6613 | const max_val: u64 = @as(u64, @intCast((@as(u65, 1) << @as(u7, @intCast(int_info.bits - 1))) - 1)); | 6688 | const max_val: u64 = @as(u64, @intCast((@as(u65, 1) << @as(u7, @intCast(int_info.bits - 1))) - 1)); |