authorgravatar for paul.verigo@gmail.comPavel Verigo <paul.verigo@gmail.com> 2024-06-13 19:15:31+02:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2024-06-16 11:53:33+02:00
log17f14e1d65b59ebb1a8b5b617cc31fb2614f0c6a
treef6fea0e60a5f86508bf49a5eb318a21fd7c1c758
parent8f27a43701118f4c713629dfc61b3e63a805851f

stage2-wasm: bit_reverse


7 files changed, 235 insertions(+), 4 deletions(-)

lib/compiler_rt.zig+1
...@@ -7,6 +7,7 @@ comptime {...@@ -7,6 +7,7 @@ comptime {
7 _ = @import("compiler_rt/count0bits.zig");7 _ = @import("compiler_rt/count0bits.zig");
8 _ = @import("compiler_rt/parity.zig");8 _ = @import("compiler_rt/parity.zig");
9 _ = @import("compiler_rt/popcount.zig");9 _ = @import("compiler_rt/popcount.zig");
10 _ = @import("compiler_rt/bitreverse.zig");
10 _ = @import("compiler_rt/bswap.zig");11 _ = @import("compiler_rt/bswap.zig");
11 _ = @import("compiler_rt/cmp.zig");12 _ = @import("compiler_rt/cmp.zig");
1213
lib/compiler_rt/bitreverse.zig created+65
...@@ -0,0 +1,65 @@
1const std = @import("std");
2const builtin = @import("builtin");
3const common = @import("common.zig");
4
5pub const panic = common.panic;
6
7comptime {
8 @export(__bitreversesi2, .{ .name = "__bitreversesi2", .linkage = common.linkage, .visibility = common.visibility });
9 @export(__bitreversedi2, .{ .name = "__bitreversedi2", .linkage = common.linkage, .visibility = common.visibility });
10 @export(__bitreverseti2, .{ .name = "__bitreverseti2", .linkage = common.linkage, .visibility = common.visibility });
11}
12
13inline fn bitreverseXi2(comptime T: type, a: T) T {
14 switch (@bitSizeOf(T)) {
15 32 => {
16 var t: T = a;
17 t = ((t >> 1) & 0x55555555) | ((t & 0x55555555) << 1);
18 t = ((t >> 2) & 0x33333333) | ((t & 0x33333333) << 2);
19 t = ((t >> 4) & 0x0F0F0F0F) | ((t & 0x0F0F0F0F) << 4);
20 t = ((t >> 8) & 0x00FF00FF) | ((t & 0x00FF00FF) << 8);
21 t = (t >> 16) | (t << 16);
22 return t;
23 },
24 64 => {
25 var t: T = a;
26 t = ((t >> 1) & 0x5555555555555555) | ((t & 0x5555555555555555) << 1);
27 t = ((t >> 2) & 0x3333333333333333) | ((t & 0x3333333333333333) << 2);
28 t = ((t >> 4) & 0x0F0F0F0F0F0F0F0F) | ((t & 0x0F0F0F0F0F0F0F0F) << 4);
29 t = ((t >> 8) & 0x00FF00FF00FF00FF) | ((t & 0x00FF00FF00FF00FF) << 8);
30 t = ((t >> 16) & 0x0000FFFF0000FFFF) | ((t & 0x0000FFFF0000FFFF) << 16);
31 t = (t >> 32) | (t << 32);
32 return t;
33 },
34 128 => {
35 var t: T = a;
36 t = ((t >> 1) & 0x55555555555555555555555555555555) | ((t & 0x55555555555555555555555555555555) << 1);
37 t = ((t >> 2) & 0x33333333333333333333333333333333) | ((t & 0x33333333333333333333333333333333) << 2);
38 t = ((t >> 4) & 0x0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F) | ((t & 0x0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F) << 4);
39 t = ((t >> 8) & 0x00FF00FF00FF00FF00FF00FF00FF00FF) | ((t & 0x00FF00FF00FF00FF00FF00FF00FF00FF) << 8);
40 t = ((t >> 16) & 0x0000FFFF0000FFFF0000FFFF0000FFFF) | ((t & 0x0000FFFF0000FFFF0000FFFF0000FFFF) << 16);
41 t = ((t >> 32) & 0x00000000FFFFFFFF00000000FFFFFFFF) | ((t & 0x00000000FFFFFFFF00000000FFFFFFFF) << 32);
42 t = (t >> 64) | (t << 64);
43 return t;
44 },
45 else => unreachable,
46 }
47}
48
49pub fn __bitreversesi2(a: u32) callconv(.C) u32 {
50 return bitreverseXi2(u32, a);
51}
52
53pub fn __bitreversedi2(a: u64) callconv(.C) u64 {
54 return bitreverseXi2(u64, a);
55}
56
57pub fn __bitreverseti2(a: u128) callconv(.C) u128 {
58 return bitreverseXi2(u128, a);
59}
60
61test {
62 _ = @import("bitreversesi2_test.zig");
63 _ = @import("bitreversedi2_test.zig");
64 _ = @import("bitreverseti2_test.zig");
65}
lib/compiler_rt/bitreversedi2_test.zig created+22
...@@ -0,0 +1,22 @@
1const bitreverse = @import("bitreverse.zig");
2const testing = @import("std").testing;
3
4fn test__bitreversedi2(input: u64, expected: u64) !void {
5 const result = bitreverse.__bitreversedi2(input);
6 try testing.expectEqual(expected, result);
7}
8
9test "bitreversedi2" {
10 try test__bitreversedi2(0x0123456789abcdef, 0xf7b3d591e6a2c480);
11 try test__bitreversedi2(0xf7b3d591e6a2c480, 0x0123456789abcdef);
12 try test__bitreversedi2(0x89abcdef00000000, 0x00000000f7b3d591);
13 try test__bitreversedi2(0x00000000f7b3d591, 0x89abcdef00000000);
14 try test__bitreversedi2(0x0000c0da23000000, 0x000000c45b030000);
15 try test__bitreversedi2(0x000000c45b030000, 0x0000c0da23000000);
16 try test__bitreversedi2(0x000000000000032f, 0xf4c0000000000000);
17 try test__bitreversedi2(0xf4c0000000000000, 0x000000000000032f);
18 try test__bitreversedi2(0xaaaaaaaaaaaaaaaa, 0x5555555555555555);
19 try test__bitreversedi2(0x5555555555555555, 0xaaaaaaaaaaaaaaaa);
20 try test__bitreversedi2(0x0000000000000000, 0x0000000000000000);
21 try test__bitreversedi2(0xffffffffffffffff, 0xffffffffffffffff);
22}
lib/compiler_rt/bitreversesi2_test.zig created+22
...@@ -0,0 +1,22 @@
1const bitreverse = @import("bitreverse.zig");
2const testing = @import("std").testing;
3
4fn test__bitreversesi2(input: u32, expected: u32) !void {
5 const result = bitreverse.__bitreversesi2(input);
6 try testing.expectEqual(expected, result);
7}
8
9test "bitreversesi2" {
10 try test__bitreversesi2(0x01234567, 0xe6a2c480);
11 try test__bitreversesi2(0xe6a2c480, 0x01234567);
12 try test__bitreversesi2(0x89abcdef, 0xf7b3d591);
13 try test__bitreversesi2(0xf7b3d591, 0x89abcdef);
14 try test__bitreversesi2(0xc0da2300, 0x00c45b03);
15 try test__bitreversesi2(0x00c45b03, 0xc0da2300);
16 try test__bitreversesi2(0x0000032f, 0xf4c00000);
17 try test__bitreversesi2(0xf4c00000, 0x0000032f);
18 try test__bitreversesi2(0xaaaaaaaa, 0x55555555);
19 try test__bitreversesi2(0x55555555, 0xaaaaaaaa);
20 try test__bitreversesi2(0x00000000, 0x00000000);
21 try test__bitreversesi2(0xffffffff, 0xffffffff);
22}
lib/compiler_rt/bitreverseti2_test.zig created+22
...@@ -0,0 +1,22 @@
1const bitreverse = @import("bitreverse.zig");
2const testing = @import("std").testing;
3
4fn test__bitreverseti2(input: u128, expected: u128) !void {
5 const result = bitreverse.__bitreverseti2(input);
6 try testing.expectEqual(expected, result);
7}
8
9test "bitreverseti2" {
10 try test__bitreverseti2(0x0123456789abcdef0123456789abcdef, 0xf7b3d591e6a2c480f7b3d591e6a2c480);
11 try test__bitreverseti2(0xf7b3d591e6a2c480f7b3d591e6a2c480, 0x0123456789abcdef0123456789abcdef);
12 try test__bitreverseti2(0x89abcdef000000000000000000000000, 0x000000000000000000000000f7b3d591);
13 try test__bitreverseti2(0x000000000000000000000000f7b3d591, 0x89abcdef000000000000000000000000);
14 try test__bitreverseti2(0x000000000000c0da2300000000000000, 0x00000000000000c45b03000000000000);
15 try test__bitreverseti2(0x00000000000000c45b03000000000000, 0x000000000000c0da2300000000000000);
16 try test__bitreverseti2(0x0000000000000000000000000000032f, 0xf4c00000000000000000000000000000);
17 try test__bitreverseti2(0xf4c00000000000000000000000000000, 0x0000000000000000000000000000032f);
18 try test__bitreverseti2(0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, 0x55555555555555555555555555555555);
19 try test__bitreverseti2(0x55555555555555555555555555555555, 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);
20 try test__bitreverseti2(0x00000000000000000000000000000000, 0x00000000000000000000000000000000);
21 try test__bitreverseti2(0xffffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffffff);
22}
src/arch/wasm/CodeGen.zig+94-1
...@@ -1953,6 +1953,7 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -1953,6 +1953,7 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
1953 .prefetch => func.airPrefetch(inst),1953 .prefetch => func.airPrefetch(inst),
1954 .popcount => func.airPopcount(inst),1954 .popcount => func.airPopcount(inst),
1955 .byte_swap => func.airByteSwap(inst),1955 .byte_swap => func.airByteSwap(inst),
1956 .bit_reverse => func.airBitReverse(inst),
19561957
1957 .slice => func.airSlice(inst),1958 .slice => func.airSlice(inst),
1958 .slice_len => func.airSliceLen(inst),1959 .slice_len => func.airSliceLen(inst),
...@@ -2000,7 +2001,6 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -2000,7 +2001,6 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
20002001
2001 .mul_sat,2002 .mul_sat,
2002 .assembly,2003 .assembly,
2003 .bit_reverse,
2004 .is_err_ptr,2004 .is_err_ptr,
2005 .is_non_err_ptr,2005 .is_non_err_ptr,
20062006
...@@ -5819,6 +5819,99 @@ fn airPopcount(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -5819,6 +5819,99 @@ fn airPopcount(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5819 func.finishAir(inst, result, &.{ty_op.operand});5819 func.finishAir(inst, result, &.{ty_op.operand});
5820}5820}
58215821
5822fn airBitReverse(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5823 const mod = func.bin_file.base.comp.module.?;
5824 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
5825
5826 const operand = try func.resolveInst(ty_op.operand);
5827 const ty = func.typeOf(ty_op.operand);
5828
5829 if (ty.zigTypeTag(mod) == .Vector) {
5830 return func.fail("TODO: Implement @bitReverse for vectors", .{});
5831 }
5832
5833 const int_info = ty.intInfo(mod);
5834 const bits = int_info.bits;
5835 const wasm_bits = toWasmBits(bits) orelse {
5836 return func.fail("TODO: Implement @bitReverse for integers with bitsize '{d}'", .{bits});
5837 };
5838
5839 switch (wasm_bits) {
5840 32 => {
5841 const intrin_ret = try func.callIntrinsic(
5842 "__bitreversesi2",
5843 &.{.u32_type},
5844 Type.u32,
5845 &.{operand},
5846 );
5847 const reversed = if (bits == 32)
5848 intrin_ret
5849 else
5850 try func.binOp(intrin_ret, .{ .imm32 = 32 - bits }, Type.u32, .shr);
5851 const result = try reversed.toLocal(func, ty);
5852 func.finishAir(inst, result, &.{ty_op.operand});
5853 },
5854 64 => {
5855 const intrin_ret = try func.callIntrinsic(
5856 "__bitreversedi2",
5857 &.{.u64_type},
5858 Type.u64,
5859 &.{operand},
5860 );
5861 const reversed = if (bits == 64)
5862 intrin_ret
5863 else
5864 try func.binOp(intrin_ret, .{ .imm64 = 64 - bits }, Type.u64, .shr);
5865 const result = try reversed.toLocal(func, ty);
5866 func.finishAir(inst, result, &.{ty_op.operand});
5867 },
5868 128 => {
5869 const result = try func.allocStack(ty);
5870
5871 try func.emitWValue(result);
5872 const first_half = try func.load(operand, Type.u64, 8);
5873 const intrin_ret_first = try func.callIntrinsic(
5874 "__bitreversedi2",
5875 &.{.u64_type},
5876 Type.u64,
5877 &.{first_half},
5878 );
5879 try func.emitWValue(intrin_ret_first);
5880 if (bits < 128) {
5881 try func.emitWValue(.{ .imm64 = 128 - bits });
5882 try func.addTag(.i64_shr_u);
5883 }
5884 try func.emitWValue(result);
5885 const second_half = try func.load(operand, Type.u64, 0);
5886 const intrin_ret_second = try func.callIntrinsic(
5887 "__bitreversedi2",
5888 &.{.u64_type},
5889 Type.u64,
5890 &.{second_half},
5891 );
5892 try func.emitWValue(intrin_ret_second);
5893 if (bits == 128) {
5894 try func.store(.stack, .stack, Type.u64, result.offset() + 8);
5895 try func.store(.stack, .stack, Type.u64, result.offset());
5896 } else {
5897 var tmp = try func.allocLocal(Type.u64);
5898 defer tmp.free(func);
5899 try func.addLabel(.local_tee, tmp.local.value);
5900 try func.emitWValue(.{ .imm64 = 128 - bits });
5901 try func.addTag(.i64_shr_u);
5902 try func.store(.stack, .stack, Type.u64, result.offset() + 8);
5903 try func.addLabel(.local_get, tmp.local.value);
5904 try func.emitWValue(.{ .imm64 = bits - 64 });
5905 try func.addTag(.i64_shl);
5906 try func.addTag(.i64_or);
5907 try func.store(.stack, .stack, Type.u64, result.offset());
5908 }
5909 func.finishAir(inst, result, &.{ty_op.operand});
5910 },
5911 else => unreachable,
5912 }
5913}
5914
5822fn airErrorName(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {5915fn airErrorName(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5823 const un_op = func.air.instructions.items(.data)[@intFromEnum(inst)].un_op;5916 const un_op = func.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
58245917
test/behavior/bitreverse.zig+9-3
...@@ -4,13 +4,10 @@ const expect = std.testing.expect;...@@ -4,13 +4,10 @@ const expect = std.testing.expect;
4const minInt = std.math.minInt;4const minInt = std.math.minInt;
55
6test "@bitReverse large exotic integer" {6test "@bitReverse large exotic integer" {
7 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
8
9 try expect(@bitReverse(@as(u95, 0x123456789abcdef111213141)) == 0x4146424447bd9eac8f351624);7 try expect(@bitReverse(@as(u95, 0x123456789abcdef111213141)) == 0x4146424447bd9eac8f351624);
10}8}
119
12test "@bitReverse" {10test "@bitReverse" {
13 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
14 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;11 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
15 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;12 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
16 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO13 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -58,6 +55,12 @@ fn testBitReverse() !void {...@@ -58,6 +55,12 @@ fn testBitReverse() !void {
58 try expect(@bitReverse(num56) == 0x7b3d591e6a2c48);55 try expect(@bitReverse(num56) == 0x7b3d591e6a2c48);
59 var num64: u64 = 0x123456789abcdef1;56 var num64: u64 = 0x123456789abcdef1;
60 try expect(@bitReverse(num64) == 0x8f7b3d591e6a2c48);57 try expect(@bitReverse(num64) == 0x8f7b3d591e6a2c48);
58 var num95: u95 = 0x123456789abcdef111213141;
59 try expect(@bitReverse(num95) == 0x4146424447bd9eac8f351624);
60 var num96: u96 = 0x123456789abcdef111213141;
61 try expect(@bitReverse(num96) == 0x828c84888f7b3d591e6a2c48);
62 var num97: u97 = 0x1123456789abcdef111213141;
63 try expect(@bitReverse(num97) == 0x1051909111ef67ab23cd45891);
61 var num128: u128 = 0x123456789abcdef11121314151617181;64 var num128: u128 = 0x123456789abcdef11121314151617181;
62 try expect(@bitReverse(num128) == 0x818e868a828c84888f7b3d591e6a2c48);65 try expect(@bitReverse(num128) == 0x818e868a828c84888f7b3d591e6a2c48);
6366
...@@ -99,6 +102,9 @@ fn testBitReverse() !void {...@@ -99,6 +102,9 @@ fn testBitReverse() !void {
99 &num48,102 &num48,
100 &num56,103 &num56,
101 &num64,104 &num64,
105 &num95,
106 &num96,
107 &num97,
102 &num128,108 &num128,
103 &neg8,109 &neg8,
104 &neg16,110 &neg16,