diff options
| author | Luuk de Gram <luuk@degram.dev> | 2022-05-16 17:14:15 +0200 |
|---|---|---|
| committer | Luuk de Gram <luuk@degram.dev> | 2022-05-18 07:43:33 +0200 |
| commit | fd081c74f10de71eaf00b0ccd7c4e4a0c0c5c3ad (patch) | |
| tree | 1f53091dcbcb960a615a7361af1787caf36fc268 /src/arch/wasm/CodeGen.zig | |
| parent | 10fe24c043c95180f658c3eb4d7fbbfd0388c14e (diff) | |
| download | zig-fd081c74f10de71eaf00b0ccd7c4e4a0c0c5c3ad.tar.gz zig-fd081c74f10de71eaf00b0ccd7c4e4a0c0c5c3ad.zip | |
wasm: Support `not` instruction for 128 bit integers
This also fixes the instruction for all other integer bitsizes,
as it was previously assuming to always be a bool.
128 bit substraction was also fixed as it contained a bug where it swapped
lhs with rhs.
Diffstat (limited to 'src/arch/wasm/CodeGen.zig')
| -rw-r--r-- | src/arch/wasm/CodeGen.zig | 61 |
1 files changed, 45 insertions, 16 deletions
diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index 06682e096f..feaa1cf145 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -2014,13 +2014,13 @@ fn binOpBigInt(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerErr const rhs_high_bit = try self.load(rhs, Type.u64, 0); const rhs_low_bit = try self.load(rhs, Type.u64, 8); - const low_op_res = try self.binOp(rhs_low_bit, lhs_low_bit, Type.u64, op); + const low_op_res = try self.binOp(lhs_low_bit, rhs_low_bit, Type.u64, op); const high_op_res = try self.binOp(lhs_high_bit, rhs_high_bit, Type.u64, op); const lt = if (op == .add) blk: { break :blk try self.cmp(high_op_res, rhs_high_bit, Type.u64, .lt); } else if (op == .sub) blk: { - break :blk try self.cmp(rhs_high_bit, lhs_high_bit, Type.u64, .lt); + break :blk try self.cmp(lhs_high_bit, rhs_high_bit, Type.u64, .lt); } else unreachable; const tmp = try self.intcast(lt, Type.u32, Type.u64); 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 { const wasm_bits = toWasmBits(bitsize) orelse { return self.fail("TODO: Implement wrapOperand for bitsize '{d}'", .{bitsize}); }; + if (wasm_bits == bitsize) return operand; if (wasm_bits == 128) { @@ -2424,15 +2425,16 @@ fn valueAsI32(self: Self, val: Value, ty: Type) i32 { fn airBlock(self: *Self, inst: Air.Inst.Index) InnerError!WValue { const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; - const block_ty = genBlockType(self.air.getRefType(ty_pl.ty), self.target); + const block_ty = self.air.getRefType(ty_pl.ty); + const wasm_block_ty = genBlockType(block_ty, self.target); const extra = self.air.extraData(Air.Block, ty_pl.payload); const body = self.air.extra[extra.end..][0..extra.data.body_len]; - // if block_ty is non-empty, we create a register to store the temporary value - const block_result: WValue = if (block_ty != wasm.block_empty) - try self.allocLocal(self.air.getRefType(ty_pl.ty)) - else - WValue.none; + // if wasm_block_ty is non-empty, we create a register to store the temporary value + const block_result: WValue = if (wasm_block_ty != wasm.block_empty) blk: { + const ty: Type = if (isByRef(block_ty, self.target)) Type.u32 else block_ty; + break :blk try self.allocLocal(ty); + } else WValue.none; try self.startBlock(.block, wasm.block_empty); // 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 { const ty_op = self.air.instructions.items(.data)[inst].ty_op; const operand = try self.resolveInst(ty_op.operand); - try self.emitWValue(operand); + const operand_ty = self.air.typeOf(ty_op.operand); - // wasm does not have booleans nor the `not` instruction, therefore compare with 0 - // to create the same logic - try self.addTag(.i32_eqz); + if (operand_ty.zigTypeTag() == .Bool) { + try self.emitWValue(operand); + try self.addTag(.i32_eqz); + const not_tmp = try self.allocLocal(operand_ty); + try self.addLabel(.local_set, not_tmp.local); + return not_tmp; + } else { + const operand_bits = operand_ty.intInfo(self.target).bits; + const wasm_bits = toWasmBits(operand_bits) orelse { + return self.fail("TODO: Implement binary NOT for integer with bitsize '{d}'", .{operand_bits}); + }; - // save the result in the local - const not_tmp = try self.allocLocal(Type.initTag(.i32)); - try self.addLabel(.local_set, not_tmp.local); - return not_tmp; + switch (wasm_bits) { + 32 => { + const bin_op = try self.binOp(operand, .{ .imm32 = ~@as(u32, 0) }, operand_ty, .xor); + return self.wrapOperand(bin_op, operand_ty); + }, + 64 => { + const bin_op = try self.binOp(operand, .{ .imm64 = ~@as(u64, 0) }, operand_ty, .xor); + return self.wrapOperand(bin_op, operand_ty); + }, + 128 => { + const result_ptr = try self.allocStack(operand_ty); + const msb = try self.load(operand, Type.u64, 0); + const lsb = try self.load(operand, Type.u64, 8); + + const msb_xor = try self.binOp(msb, .{ .imm64 = ~@as(u64, 0) }, Type.u64, .xor); + const lsb_xor = try self.binOp(lsb, .{ .imm64 = ~@as(u64, 0) }, Type.u64, .xor); + try self.store(result_ptr, msb_xor, Type.u64, 0); + try self.store(result_ptr, lsb_xor, Type.u64, 8); + return result_ptr; + }, + else => unreachable, + } + } } fn airBreakpoint(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
