| author | |
| committer | |
| log | 17f14e1d65b59ebb1a8b5b617cc31fb2614f0c6a |
| tree | f6fea0e60a5f86508bf49a5eb318a21fd7c1c758 |
| parent | 8f27a43701118f4c713629dfc61b3e63a805851f |
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"); |
| 12 | 13 |
lib/compiler_rt/bitreverse.zig created+65| ... | @@ -0,0 +1,65 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const builtin = @import("builtin"); | ||
| 3 | const common = @import("common.zig"); | ||
| 4 | |||
| 5 | pub const panic = common.panic; | ||
| 6 | |||
| 7 | comptime { | ||
| 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 | |||
| 13 | inline 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 | |||
| 49 | pub fn __bitreversesi2(a: u32) callconv(.C) u32 { | ||
| 50 | return bitreverseXi2(u32, a); | ||
| 51 | } | ||
| 52 | |||
| 53 | pub fn __bitreversedi2(a: u64) callconv(.C) u64 { | ||
| 54 | return bitreverseXi2(u64, a); | ||
| 55 | } | ||
| 56 | |||
| 57 | pub fn __bitreverseti2(a: u128) callconv(.C) u128 { | ||
| 58 | return bitreverseXi2(u128, a); | ||
| 59 | } | ||
| 60 | |||
| 61 | test { | ||
| 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 @@ | ||
| 1 | const bitreverse = @import("bitreverse.zig"); | ||
| 2 | const testing = @import("std").testing; | ||
| 3 | |||
| 4 | fn test__bitreversedi2(input: u64, expected: u64) !void { | ||
| 5 | const result = bitreverse.__bitreversedi2(input); | ||
| 6 | try testing.expectEqual(expected, result); | ||
| 7 | } | ||
| 8 | |||
| 9 | test "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 @@ | ||
| 1 | const bitreverse = @import("bitreverse.zig"); | ||
| 2 | const testing = @import("std").testing; | ||
| 3 | |||
| 4 | fn test__bitreversesi2(input: u32, expected: u32) !void { | ||
| 5 | const result = bitreverse.__bitreversesi2(input); | ||
| 6 | try testing.expectEqual(expected, result); | ||
| 7 | } | ||
| 8 | |||
| 9 | test "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 @@ | ||
| 1 | const bitreverse = @import("bitreverse.zig"); | ||
| 2 | const testing = @import("std").testing; | ||
| 3 | |||
| 4 | fn test__bitreverseti2(input: u128, expected: u128) !void { | ||
| 5 | const result = bitreverse.__bitreverseti2(input); | ||
| 6 | try testing.expectEqual(expected, result); | ||
| 7 | } | ||
| 8 | |||
| 9 | test "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), | ||
| 1956 | 1957 | ||
| 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 { |
| 2000 | 2001 | ||
| 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, |
| 2006 | 2006 | ||
| ... | @@ -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 | } |
| 5821 | 5821 | ||
| 5822 | fn 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 | |||
| 5822 | fn airErrorName(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 5915 | fn 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; |
| 5824 | 5917 |
test/behavior/bitreverse.zig+9-3| ... | @@ -4,13 +4,10 @@ const expect = std.testing.expect; | ... | @@ -4,13 +4,10 @@ const expect = std.testing.expect; |
| 4 | const minInt = std.math.minInt; | 4 | const minInt = std.math.minInt; |
| 5 | 5 | ||
| 6 | test "@bitReverse large exotic integer" { | 6 | test "@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 | } |
| 11 | 9 | ||
| 12 | test "@bitReverse" { | 10 | test "@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; // TODO | 13 | 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); |
| 63 | 66 | ||
| ... | @@ -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, |