diff options
| author | Luuk de Gram <luuk@degram.dev> | 2022-06-06 21:20:51 +0200 |
|---|---|---|
| committer | Luuk de Gram <luuk@degram.dev> | 2022-06-11 19:38:00 +0200 |
| commit | bc499de328f0d0110a8eaf3de7be55e05595f598 (patch) | |
| tree | 9201e8aa976df79899c18abad64c14dc7a48d7b3 /src | |
| parent | c1eb6c30e84b0b161b634f7410088f44c80caa90 (diff) | |
| download | zig-bc499de328f0d0110a8eaf3de7be55e05595f598.tar.gz zig-bc499de328f0d0110a8eaf3de7be55e05595f598.zip | |
wasm: implement `@byteSwap` for 16/32bit integers
Diffstat (limited to 'src')
| -rw-r--r-- | src/arch/wasm/CodeGen.zig | 49 |
1 files changed, 48 insertions, 1 deletions
diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index 33cf5422f2..1c9fe192d7 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -1541,6 +1541,7 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue { .union_init => self.airUnionInit(inst), .prefetch => self.airPrefetch(inst), .popcount => self.airPopcount(inst), + .byte_swap => self.airByteSwap(inst), .slice => self.airSlice(inst), .slice_len => self.airSliceLen(inst), @@ -1590,7 +1591,6 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue { .shl_sat, .ret_addr, .frame_addr, - .byte_swap, .bit_reverse, .is_err_ptr, .is_non_err_ptr, @@ -4691,3 +4691,50 @@ fn lowerTry( } return self.load(err_union, pl_ty, pl_offset); } + +fn airByteSwap(self: *Self, inst: Air.Inst.Index) InnerError!WValue { + if (self.liveness.isUnused(inst)) { + return WValue{ .none = {} }; + } + + const ty_op = self.air.instructions.items(.data)[inst].ty_op; + const ty = self.air.typeOfIndex(inst); + const operand = try self.resolveInst(ty_op.operand); + + if (ty.zigTypeTag() == .Vector) { + return self.fail("TODO: @byteSwap for vectors", .{}); + } + const int_info = ty.intInfo(self.target); + + // bytes are no-op + if (int_info.bits == 8) { + return operand; + } + + switch (int_info.bits) { + 16 => { + const shl_res = try self.binOp(operand, .{ .imm32 = 8 }, ty, .shl); + const tmp = try self.binOp(operand, .{ .imm32 = 0xFF00 }, ty, .@"and"); + const shr_res = try self.binOp(tmp, .{ .imm32 = 8 }, ty, .shr); + const res = if (int_info.signedness == .signed) blk: { + break :blk try self.wrapOperand(shr_res, Type.u8); + } else shr_res; + return self.binOp(shl_res, res, ty, .@"or"); + }, + 32 => { + const shl_tmp = try self.binOp(operand, .{ .imm32 = 8 }, ty, .shl); + const lhs = try self.binOp(shl_tmp, .{ .imm32 = 0xFF00FF00 }, ty, .@"and"); + const shr_tmp = try self.binOp(operand, .{ .imm32 = 8 }, ty, .shr); + const rhs = try self.binOp(shr_tmp, .{ .imm32 = 0xFF00FF }, ty, .@"and"); + const tmp_or = try self.binOp(lhs, rhs, ty, .@"or"); + + const shl = try self.binOp(tmp_or, .{ .imm32 = 16 }, ty, .shl); + const shr = try self.binOp(tmp_or, .{ .imm32 = 16 }, ty, .shr); + const res = if (int_info.signedness == .signed) blk: { + break :blk try self.wrapOperand(shr, Type.u16); + } else shr; + return self.binOp(shl, res, ty, .@"or"); + }, + else => return self.fail("TODO: @byteSwap for integers with bitsize {d}", .{int_info.bits}), + } +} |
