| ... | @@ -2014,13 +2014,13 @@ fn binOpBigInt(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerErr | ... | @@ -2014,13 +2014,13 @@ fn binOpBigInt(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerErr |
| 2014 | const rhs_high_bit = try self.load(rhs, Type.u64, 0); | 2014 | const rhs_high_bit = try self.load(rhs, Type.u64, 0); |
| 2015 | const rhs_low_bit = try self.load(rhs, Type.u64, 8); | 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 | const high_op_res = try self.binOp(lhs_high_bit, rhs_high_bit, Type.u64, op); | 2018 | const high_op_res = try self.binOp(lhs_high_bit, rhs_high_bit, Type.u64, op); |
| 2019 | | 2019 | |
| 2020 | const lt = if (op == .add) blk: { | 2020 | const lt = if (op == .add) blk: { |
| 2021 | break :blk try self.cmp(high_op_res, rhs_high_bit, Type.u64, .lt); | 2021 | break :blk try self.cmp(high_op_res, rhs_high_bit, Type.u64, .lt); |
| 2022 | } else if (op == .sub) blk: { | 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 | } else unreachable; | 2024 | } else unreachable; |
| 2025 | const tmp = try self.intcast(lt, Type.u32, Type.u64); | 2025 | const tmp = try self.intcast(lt, Type.u32, Type.u64); |
| 2026 | const tmp_op = try self.binOp(low_op_res, tmp, Type.u64, op); | 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,6 +2078,7 @@ fn wrapOperand(self: *Self, operand: WValue, ty: Type) InnerError!WValue { |
| 2078 | const wasm_bits = toWasmBits(bitsize) orelse { | 2078 | const wasm_bits = toWasmBits(bitsize) orelse { |
| 2079 | return self.fail("TODO: Implement wrapOperand for bitsize '{d}'", .{bitsize}); | 2079 | return self.fail("TODO: Implement wrapOperand for bitsize '{d}'", .{bitsize}); |
| 2080 | }; | 2080 | }; |
| | 2081 | |
| 2081 | if (wasm_bits == bitsize) return operand; | 2082 | if (wasm_bits == bitsize) return operand; |
| 2082 | | 2083 | |
| 2083 | if (wasm_bits == 128) { | 2084 | if (wasm_bits == 128) { |
| ... | @@ -2424,15 +2425,16 @@ fn valueAsI32(self: Self, val: Value, ty: Type) i32 { | ... | @@ -2424,15 +2425,16 @@ fn valueAsI32(self: Self, val: Value, ty: Type) i32 { |
| 2424 | | 2425 | |
| 2425 | fn airBlock(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | 2426 | fn airBlock(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 2426 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 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 | const extra = self.air.extraData(Air.Block, ty_pl.payload); | 2430 | const extra = self.air.extraData(Air.Block, ty_pl.payload); |
| 2429 | const body = self.air.extra[extra.end..][0..extra.data.body_len]; | 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 | 2433 | // if wasm_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) | 2434 | const block_result: WValue = if (wasm_block_ty != wasm.block_empty) blk: { |
| 2433 | try self.allocLocal(self.air.getRefType(ty_pl.ty)) | 2435 | const ty: Type = if (isByRef(block_ty, self.target)) Type.u32 else block_ty; |
| 2434 | else | 2436 | break :blk try self.allocLocal(ty); |
| 2435 | WValue.none; | 2437 | } else WValue.none; |
| 2436 | | 2438 | |
| 2437 | try self.startBlock(.block, wasm.block_empty); | 2439 | try self.startBlock(.block, wasm.block_empty); |
| 2438 | // Here we set the current block idx, so breaks know the depth to jump | 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,16 +2602,43 @@ fn airNot(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 2600 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 2602 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2601 | | 2603 | |
| 2602 | const operand = try self.resolveInst(ty_op.operand); | 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 | 2607 | if (operand_ty.zigTypeTag() == .Bool) { |
| 2606 | // to create the same logic | 2608 | try self.emitWValue(operand); |
| 2607 | try self.addTag(.i32_eqz); | 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 | 2619 | switch (wasm_bits) { |
| 2610 | const not_tmp = try self.allocLocal(Type.initTag(.i32)); | 2620 | 32 => { |
| 2611 | try self.addLabel(.local_set, not_tmp.local); | 2621 | const bin_op = try self.binOp(operand, .{ .imm32 = ~@as(u32, 0) }, operand_ty, .xor); |
| 2612 | return not_tmp; | 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 | fn airBreakpoint(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | 2644 | fn airBreakpoint(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |