| ... | ... | @@ -2014,13 +2014,13 @@ fn binOpBigInt(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerErr |
| 2014 | 2014 | const rhs_high_bit = try self.load(rhs, Type.u64, 0); |
| 2015 | 2015 | const rhs_low_bit = try self.load(rhs, Type.u64, 8); |
| 2016 | 2016 | |
| 2017 | | const low_op_res = try self.binOp(rhs_low_bit, lhs_low_bit, Type.u64, op); |
| 2017 | const low_op_res = try self.binOp(lhs_low_bit, rhs_low_bit, Type.u64, op); |
| 2018 | 2018 | const high_op_res = try self.binOp(lhs_high_bit, rhs_high_bit, Type.u64, op); |
| 2019 | 2019 | |
| 2020 | 2020 | const lt = if (op == .add) blk: { |
| 2021 | 2021 | break :blk try self.cmp(high_op_res, rhs_high_bit, Type.u64, .lt); |
| 2022 | 2022 | } else if (op == .sub) blk: { |
| 2023 | | break :blk try self.cmp(rhs_high_bit, lhs_high_bit, Type.u64, .lt); |
| 2023 | break :blk try self.cmp(lhs_high_bit, rhs_high_bit, Type.u64, .lt); |
| 2024 | 2024 | } else unreachable; |
| 2025 | 2025 | const tmp = try self.intcast(lt, Type.u32, Type.u64); |
| 2026 | 2026 | const tmp_op = try self.binOp(low_op_res, tmp, Type.u64, op); |
| ... | ... | @@ -2078,6 +2078,7 @@ fn wrapOperand(self: *Self, operand: WValue, ty: Type) InnerError!WValue { |
| 2078 | 2078 | const wasm_bits = toWasmBits(bitsize) orelse { |
| 2079 | 2079 | return self.fail("TODO: Implement wrapOperand for bitsize '{d}'", .{bitsize}); |
| 2080 | 2080 | }; |
| 2081 | |
| 2081 | 2082 | if (wasm_bits == bitsize) return operand; |
| 2082 | 2083 | |
| 2083 | 2084 | if (wasm_bits == 128) { |
| ... | ... | @@ -2424,15 +2425,16 @@ fn valueAsI32(self: Self, val: Value, ty: Type) i32 { |
| 2424 | 2425 | |
| 2425 | 2426 | fn airBlock(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 2426 | 2427 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 2427 | | const block_ty = genBlockType(self.air.getRefType(ty_pl.ty), self.target); |
| 2428 | const block_ty = self.air.getRefType(ty_pl.ty); |
| 2429 | const wasm_block_ty = genBlockType(block_ty, self.target); |
| 2428 | 2430 | const extra = self.air.extraData(Air.Block, ty_pl.payload); |
| 2429 | 2431 | const body = self.air.extra[extra.end..][0..extra.data.body_len]; |
| 2430 | 2432 | |
| 2431 | | // if block_ty is non-empty, we create a register to store the temporary value |
| 2432 | | const block_result: WValue = if (block_ty != wasm.block_empty) |
| 2433 | | try self.allocLocal(self.air.getRefType(ty_pl.ty)) |
| 2434 | | else |
| 2435 | | WValue.none; |
| 2433 | // if wasm_block_ty is non-empty, we create a register to store the temporary value |
| 2434 | const block_result: WValue = if (wasm_block_ty != wasm.block_empty) blk: { |
| 2435 | const ty: Type = if (isByRef(block_ty, self.target)) Type.u32 else block_ty; |
| 2436 | break :blk try self.allocLocal(ty); |
| 2437 | } else WValue.none; |
| 2436 | 2438 | |
| 2437 | 2439 | try self.startBlock(.block, wasm.block_empty); |
| 2438 | 2440 | // Here we set the current block idx, so breaks know the depth to jump |
| ... | ... | @@ -2600,16 +2602,43 @@ fn airNot(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 2600 | 2602 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2601 | 2603 | |
| 2602 | 2604 | const operand = try self.resolveInst(ty_op.operand); |
| 2603 | | try self.emitWValue(operand); |
| 2605 | const operand_ty = self.air.typeOf(ty_op.operand); |
| 2604 | 2606 | |
| 2605 | | // wasm does not have booleans nor the `not` instruction, therefore compare with 0 |
| 2606 | | // to create the same logic |
| 2607 | | try self.addTag(.i32_eqz); |
| 2607 | if (operand_ty.zigTypeTag() == .Bool) { |
| 2608 | try self.emitWValue(operand); |
| 2609 | try self.addTag(.i32_eqz); |
| 2610 | const not_tmp = try self.allocLocal(operand_ty); |
| 2611 | try self.addLabel(.local_set, not_tmp.local); |
| 2612 | return not_tmp; |
| 2613 | } else { |
| 2614 | const operand_bits = operand_ty.intInfo(self.target).bits; |
| 2615 | const wasm_bits = toWasmBits(operand_bits) orelse { |
| 2616 | return self.fail("TODO: Implement binary NOT for integer with bitsize '{d}'", .{operand_bits}); |
| 2617 | }; |
| 2608 | 2618 | |
| 2609 | | // save the result in the local |
| 2610 | | const not_tmp = try self.allocLocal(Type.initTag(.i32)); |
| 2611 | | try self.addLabel(.local_set, not_tmp.local); |
| 2612 | | return not_tmp; |
| 2619 | switch (wasm_bits) { |
| 2620 | 32 => { |
| 2621 | const bin_op = try self.binOp(operand, .{ .imm32 = ~@as(u32, 0) }, operand_ty, .xor); |
| 2622 | return self.wrapOperand(bin_op, operand_ty); |
| 2623 | }, |
| 2624 | 64 => { |
| 2625 | const bin_op = try self.binOp(operand, .{ .imm64 = ~@as(u64, 0) }, operand_ty, .xor); |
| 2626 | return self.wrapOperand(bin_op, operand_ty); |
| 2627 | }, |
| 2628 | 128 => { |
| 2629 | const result_ptr = try self.allocStack(operand_ty); |
| 2630 | const msb = try self.load(operand, Type.u64, 0); |
| 2631 | const lsb = try self.load(operand, Type.u64, 8); |
| 2632 | |
| 2633 | const msb_xor = try self.binOp(msb, .{ .imm64 = ~@as(u64, 0) }, Type.u64, .xor); |
| 2634 | const lsb_xor = try self.binOp(lsb, .{ .imm64 = ~@as(u64, 0) }, Type.u64, .xor); |
| 2635 | try self.store(result_ptr, msb_xor, Type.u64, 0); |
| 2636 | try self.store(result_ptr, lsb_xor, Type.u64, 8); |
| 2637 | return result_ptr; |
| 2638 | }, |
| 2639 | else => unreachable, |
| 2640 | } |
| 2641 | } |
| 2613 | 2642 | } |
| 2614 | 2643 | |
| 2615 | 2644 | fn airBreakpoint(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |