Skip to content

Commit 8e7d9af

Browse files
SuperAugusteLuukdegram
authored andcommitted
Add 64bit byteswap case, use fewer locals
1 parent cbeab67 commit 8e7d9af

File tree

2 files changed

+66
-16
lines changed

2 files changed

+66
-16
lines changed

src/arch/wasm/CodeGen.zig

Lines changed: 36 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6641,21 +6641,42 @@ fn airByteSwap(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
66416641
break :result try (try func.binOp(tmp, lsb, ty, .@"or")).toLocal(func, ty);
66426642
},
66436643
32 => {
6644-
const shl_tmp = try func.binOp(operand, .{ .imm32 = 8 }, ty, .shl);
6645-
var lhs = try (try func.binOp(shl_tmp, .{ .imm32 = 0xFF00FF00 }, ty, .@"and")).toLocal(func, ty);
6646-
defer lhs.free(func);
6647-
const shr_tmp = try func.binOp(operand, .{ .imm32 = 8 }, ty, .shr);
6648-
var rhs = try (try func.binOp(shr_tmp, .{ .imm32 = 0xFF00FF }, ty, .@"and")).toLocal(func, ty);
6649-
defer rhs.free(func);
6650-
var tmp_or = try (try func.binOp(lhs, rhs, ty, .@"or")).toLocal(func, ty);
6651-
defer tmp_or.free(func);
6652-
6653-
const shl = try func.binOp(tmp_or, .{ .imm32 = 16 }, ty, .shl);
6654-
const shr = try func.binOp(tmp_or, .{ .imm32 = 16 }, ty, .shr);
6655-
const res = if (int_info.signedness == .signed) blk: {
6656-
break :blk try func.wrapOperand(shr, Type.u16);
6657-
} else shr;
6658-
break :result try (try func.binOp(shl, res, ty, .@"or")).toLocal(func, ty);
6644+
const shl_tmp = try func.binOp(operand, .{ .imm32 = 8 }, Type.u32, .shl);
6645+
const lhs = try func.binOp(shl_tmp, .{ .imm32 = 0xFF00FF00 }, Type.u32, .@"and");
6646+
const shr_tmp = try func.binOp(operand, .{ .imm32 = 8 }, Type.u32, .shr);
6647+
const rhs = try func.binOp(shr_tmp, .{ .imm32 = 0x00FF00FF }, Type.u32, .@"and");
6648+
var tmp_or = try (try func.binOp(lhs, rhs, Type.u32, .@"or")).toLocal(func, Type.u32);
6649+
6650+
const shl = try func.binOp(tmp_or, .{ .imm32 = 16 }, Type.u32, .shl);
6651+
const shr = try func.binOp(tmp_or, .{ .imm32 = 16 }, Type.u32, .shr);
6652+
6653+
tmp_or.free(func);
6654+
6655+
break :result try (try func.binOp(shl, shr, Type.u32, .@"or")).toLocal(func, Type.u32);
6656+
},
6657+
64 => {
6658+
const shl_tmp_1 = try func.binOp(operand, .{ .imm64 = 8 }, Type.u64, .shl);
6659+
const lhs_1 = try func.binOp(shl_tmp_1, .{ .imm64 = 0xFF00FF00FF00FF00 }, Type.u64, .@"and");
6660+
6661+
const shr_tmp_1 = try func.binOp(operand, .{ .imm64 = 8 }, Type.u64, .shr);
6662+
const rhs_1 = try func.binOp(shr_tmp_1, .{ .imm64 = 0x00FF00FF00FF00FF }, Type.u64, .@"and");
6663+
6664+
var tmp_or_1 = try (try func.binOp(lhs_1, rhs_1, Type.u64, .@"or")).toLocal(func, Type.u64);
6665+
6666+
const shl_tmp_2 = try func.binOp(tmp_or_1, .{ .imm64 = 16 }, Type.u64, .shl);
6667+
const lhs_2 = try func.binOp(shl_tmp_2, .{ .imm64 = 0xFFFF0000FFFF0000 }, Type.u64, .@"and");
6668+
6669+
const shr_tmp_2 = try func.binOp(tmp_or_1, .{ .imm64 = 16 }, Type.u64, .shr);
6670+
tmp_or_1.free(func);
6671+
const rhs_2 = try func.binOp(shr_tmp_2, .{ .imm64 = 0x0000FFFF0000FFFF }, Type.u64, .@"and");
6672+
6673+
var tmp_or_2 = try (try func.binOp(lhs_2, rhs_2, Type.u64, .@"or")).toLocal(func, Type.u64);
6674+
6675+
const shl = try func.binOp(tmp_or_2, .{ .imm64 = 32 }, Type.u64, .shl);
6676+
const shr = try func.binOp(tmp_or_2, .{ .imm64 = 32 }, Type.u64, .shr);
6677+
tmp_or_2.free(func);
6678+
6679+
break :result try (try func.binOp(shl, shr, Type.u64, .@"or")).toLocal(func, Type.u64);
66596680
},
66606681
else => return func.fail("TODO: @byteSwap for integers with bitsize {d}", .{int_info.bits}),
66616682
}

test/behavior/byteswap.zig

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,36 @@ const builtin = @import("builtin");
33
const expect = std.testing.expect;
44

55
test "@byteSwap integers" {
6-
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
6+
if (builtin.zig_backend == .stage2_wasm) {
7+
// TODO: Remove when self-hosted wasm supports more types for byteswap
8+
const ByteSwapIntTest = struct {
9+
fn run() !void {
10+
try t(u8, 0x12, 0x12);
11+
try t(u16, 0x1234, 0x3412);
12+
try t(u24, 0x123456, 0x563412);
13+
try t(i24, @as(i24, @bitCast(@as(u24, 0xf23456))), 0x5634f2);
14+
try t(i24, 0x1234f6, @as(i24, @bitCast(@as(u24, 0xf63412))));
15+
try t(u32, 0x12345678, 0x78563412);
16+
try t(i32, @as(i32, @bitCast(@as(u32, 0xf2345678))), 0x785634f2);
17+
try t(i32, 0x123456f8, @as(i32, @bitCast(@as(u32, 0xf8563412))));
18+
try t(u64, 0x123456789abcdef1, 0xf1debc9a78563412);
19+
20+
try t(u0, @as(u0, 0), 0);
21+
try t(i8, @as(i8, -50), -50);
22+
try t(i16, @as(i16, @bitCast(@as(u16, 0x1234))), @as(i16, @bitCast(@as(u16, 0x3412))));
23+
try t(i24, @as(i24, @bitCast(@as(u24, 0x123456))), @as(i24, @bitCast(@as(u24, 0x563412))));
24+
try t(i32, @as(i32, @bitCast(@as(u32, 0x12345678))), @as(i32, @bitCast(@as(u32, 0x78563412))));
25+
try t(i64, @as(i64, @bitCast(@as(u64, 0x123456789abcdef1))), @as(i64, @bitCast(@as(u64, 0xf1debc9a78563412))));
26+
}
27+
fn t(comptime I: type, input: I, expected_output: I) !void {
28+
try std.testing.expect(expected_output == @byteSwap(input));
29+
}
30+
};
31+
try comptime ByteSwapIntTest.run();
32+
try ByteSwapIntTest.run();
33+
return;
34+
}
35+
736
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
837
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
938
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;

0 commit comments

Comments
 (0)