CBE: split {clz,ctz,mod,popCount,byteSwap,bitReverse} by type

This also surfaces the fact that clz, ctz and popCount didn't actually
support 128 bit integers, despite what was claimed by
226fcd7c709ec664c5d883042cf7beb3026f66cb. This was partially hidden by
the fact that the test code for popCount only exercised 128 bit integers
in a comptime context. This commit duplicates that test case for runtime
ints too.
This commit is contained in:
Daniele Cocca 2022-03-14 14:10:52 +00:00
parent d912699e08
commit 8643591c9a
4 changed files with 245 additions and 101 deletions

View File

@ -1709,11 +1709,11 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
.memcpy => try airMemcpy(f, inst),
.set_union_tag => try airSetUnionTag(f, inst),
.get_union_tag => try airGetUnionTag(f, inst),
.clz => try airBuiltinCall(f, inst, "clz", .{}),
.ctz => try airBuiltinCall(f, inst, "ctz", .{}),
.popcount => try airBuiltinCall(f, inst, "popcount", .{}),
.byte_swap => try airBuiltinCall(f, inst, "byte_swap", .{ .needs_signedness_info = true }),
.bit_reverse => try airBuiltinCall(f, inst, "bit_reverse", .{ .needs_signedness_info = true }),
.clz => try airBuiltinCall(f, inst, "clz"),
.ctz => try airBuiltinCall(f, inst, "ctz"),
.popcount => try airBuiltinCall(f, inst, "popcount"),
.byte_swap => try airBuiltinCall(f, inst, "byte_swap"),
.bit_reverse => try airBuiltinCall(f, inst, "bit_reverse"),
.tag_name => try airTagName(f, inst),
.error_name => try airErrorName(f, inst),
.splat => try airSplat(f, inst),
@ -3351,7 +3351,7 @@ fn airPtrToInt(f: *Function, inst: Air.Inst.Index) !CValue {
return local;
}
fn airBuiltinCall(f: *Function, inst: Air.Inst.Index, fn_name: [*:0]const u8, options: struct { needs_signedness_info: bool = false }) !CValue {
fn airBuiltinCall(f: *Function, inst: Air.Inst.Index, fn_name: [*:0]const u8) !CValue {
if (f.liveness.isUnused(inst)) return CValue.none;
const inst_ty = f.air.typeOfIndex(inst);
@ -3362,20 +3362,17 @@ fn airBuiltinCall(f: *Function, inst: Air.Inst.Index, fn_name: [*:0]const u8, op
const writer = f.object.writer();
const int_info = operand_ty.intInfo(target);
_ = toCIntBits(int_info.bits) orelse
const c_bits = toCIntBits(int_info.bits) orelse
return f.fail("TODO: C backend: implement integer types larger than 128 bits", .{});
try writer.print(" = zig_{s}(", .{fn_name});
try writer.print(" = zig_{s}_", .{fn_name});
const prefix_byte: u8 = switch (int_info.signedness) {
.signed => 'i',
.unsigned => 'u',
};
try writer.print("{c}{d}(", .{ prefix_byte, c_bits });
try f.writeCValue(writer, try f.resolveInst(operand));
try writer.print(", {d}", .{int_info.bits});
if (options.needs_signedness_info) {
const signed_type = switch (int_info.signedness) {
.signed => "true",
.unsigned => "false",
};
try writer.print(", {s}", .{signed_type});
}
try writer.writeAll(");\n");
try writer.print(", {d});\n", .{int_info.bits});
return local;
}

View File

@ -503,104 +503,248 @@ zig_shl_sat_s(long, long, ((sizeof(long )) * CHAR_BIT - 1))
#define zig_bitsizeof(T) (CHAR_BIT * sizeof(T))
#define zig_bit_mask(T, bit_width) \
((bit_width) == 128 \
? ((T)(((uint128_t) 0xffffffffffffffff) << 64 | \
(uint128_t) 0xffffffffffffffff)) \
((bit_width) == zig_bitsizeof(T) \
? ((T)-1) \
: (((T)1 << (T)(bit_width)) - 1))
static inline uint128_t zig_sign_extend(uint128_t value, uint128_t zig_type_bit_width) {
const uint128_t m = (uint128_t)1 << (zig_type_bit_width - 1);
return (value ^ m) - m;
}
static inline int zig_clz(unsigned long long value, uint8_t zig_type_bit_width) {
static inline int zig_clz(unsigned int value, uint8_t zig_type_bit_width) {
if (value == 0) return zig_type_bit_width;
if (zig_type_bit_width <= zig_bitsizeof(unsigned int))
return (__builtin_clz(value) - zig_bitsizeof(unsigned int) + zig_type_bit_width);
if (zig_type_bit_width <= zig_bitsizeof(unsigned long))
return (__builtin_clzl(value) - zig_bitsizeof(unsigned long) + zig_type_bit_width);
return (__builtin_clzll(value) - zig_bitsizeof(unsigned long long) + zig_type_bit_width);
return __builtin_clz(value) - zig_bitsizeof(unsigned int) + zig_type_bit_width;
}
static inline int zig_ctz(unsigned long long value, uint8_t zig_type_bit_width) {
static inline int zig_clzl(unsigned long value, uint8_t zig_type_bit_width) {
if (value == 0) return zig_type_bit_width;
if (zig_type_bit_width <= zig_bitsizeof(unsigned int)) return __builtin_ctz(value);
if (zig_type_bit_width <= zig_bitsizeof(unsigned long)) return __builtin_ctzl(value);
return __builtin_ctzll(value);
return __builtin_clzl(value) - zig_bitsizeof(unsigned long) + zig_type_bit_width;
}
static inline int zig_popcount(unsigned long long value, uint8_t zig_type_bit_width) {
const unsigned long long mask = zig_bit_mask(unsigned long long, zig_type_bit_width);
if (zig_type_bit_width <= zig_bitsizeof(unsigned int))
return __builtin_popcount(value & mask);
if (zig_type_bit_width <= zig_bitsizeof(unsigned long))
return __builtin_popcountl(value & mask);
return __builtin_popcountll(value & mask);
static inline int zig_clzll(unsigned long long value, uint8_t zig_type_bit_width) {
if (value == 0) return zig_type_bit_width;
return __builtin_clzll(value) - zig_bitsizeof(unsigned long long) + zig_type_bit_width;
}
static inline uint128_t zig_byte_swap(uint128_t value, uint8_t zig_type_bit_width, bool signed_type) {
if (zig_type_bit_width <= 8) return value;
if (zig_type_bit_width <= 16) return __builtin_bswap16(value);
if (zig_type_bit_width <= 32) {
const uint32_t swapped = __builtin_bswap32(value) >> (32 - zig_type_bit_width);
return (signed_type ? zig_sign_extend(swapped, zig_type_bit_width) : swapped);
#define zig_clz_u8 zig_clz
#define zig_clz_i8 zig_clz
#define zig_clz_u16 zig_clz
#define zig_clz_i16 zig_clz
#define zig_clz_u32 zig_clzl
#define zig_clz_i32 zig_clzl
#define zig_clz_u64 zig_clzll
#define zig_clz_i64 zig_clzll
static inline int zig_clz_u128(uint128_t value, uint8_t zig_type_bit_width) {
if (value == 0) return zig_type_bit_width;
const uint128_t mask = zig_bit_mask(uint128_t, zig_type_bit_width);
const uint64_t hi = (value & mask) >> 64;
const uint64_t lo = (value & mask);
const int leading_zeroes = (
hi != 0 ? __builtin_clzll(hi) : 64 + (lo != 0 ? __builtin_clzll(lo) : 64));
return leading_zeroes - zig_bitsizeof(uint128_t) + zig_type_bit_width;
}
#define zig_clz_i128 zig_clz_u128
static inline int zig_ctz(unsigned int value, uint8_t zig_type_bit_width) {
if (value == 0) return zig_type_bit_width;
return __builtin_ctz(value & zig_bit_mask(unsigned int, zig_type_bit_width));
}
static inline int zig_ctzl(unsigned long value, uint8_t zig_type_bit_width) {
if (value == 0) return zig_type_bit_width;
return __builtin_ctzl(value & zig_bit_mask(unsigned long, zig_type_bit_width));
}
static inline int zig_ctzll(unsigned long value, uint8_t zig_type_bit_width) {
if (value == 0) return zig_type_bit_width;
return __builtin_ctzll(value & zig_bit_mask(unsigned long, zig_type_bit_width));
}
#define zig_ctz_u8 zig_ctz
#define zig_ctz_i8 zig_ctz
#define zig_ctz_u16 zig_ctz
#define zig_ctz_i16 zig_ctz
#define zig_ctz_u32 zig_ctzl
#define zig_ctz_i32 zig_ctzl
#define zig_ctz_u64 zig_ctzll
#define zig_ctz_i64 zig_ctzll
static inline int zig_ctz_u128(uint128_t value, uint8_t zig_type_bit_width) {
const uint128_t mask = zig_bit_mask(uint128_t, zig_type_bit_width);
const uint64_t hi = (value & mask) >> 64;
const uint64_t lo = (value & mask);
return (lo != 0 ? __builtin_ctzll(lo) : 64 + (hi != 0 ? __builtin_ctzll(hi) : 64));
}
#define zig_ctz_i128 zig_ctz_u128
static inline int zig_popcount(unsigned int value, uint8_t zig_type_bit_width) {
return __builtin_popcount(value & zig_bit_mask(unsigned int, zig_type_bit_width));
}
static inline int zig_popcountl(unsigned long value, uint8_t zig_type_bit_width) {
return __builtin_popcountl(value & zig_bit_mask(unsigned long, zig_type_bit_width));
}
static inline int zig_popcountll(unsigned long value, uint8_t zig_type_bit_width) {
return __builtin_popcountll(value & zig_bit_mask(unsigned long, zig_type_bit_width));
}
#define zig_popcount_u8 zig_popcount
#define zig_popcount_i8 zig_popcount
#define zig_popcount_u16 zig_popcount
#define zig_popcount_i16 zig_popcount
#define zig_popcount_u32 zig_popcountl
#define zig_popcount_i32 zig_popcountl
#define zig_popcount_u64 zig_popcountll
#define zig_popcount_i64 zig_popcountll
static inline int zig_popcount_u128(uint128_t value, uint8_t zig_type_bit_width) {
const uint128_t mask = zig_bit_mask(uint128_t, zig_type_bit_width);
const uint64_t hi = (value & mask) >> 64;
const uint64_t lo = (value & mask);
return __builtin_popcountll(hi) + __builtin_popcountll(lo);
}
#define zig_popcount_i128 zig_popcount_u128
#define zig_sign_extend(T) \
static inline T zig_sign_extend_##T(T value, uint8_t zig_type_bit_width) { \
const T m = (T)1 << (T)(zig_type_bit_width - 1); \
return (value ^ m) - m; \
}
if (zig_type_bit_width <= 64) {
const uint64_t swapped = __builtin_bswap64(value) >> (64 - zig_type_bit_width);
return (signed_type ? zig_sign_extend(swapped, zig_type_bit_width) : swapped);
zig_sign_extend(uint8_t)
zig_sign_extend(uint16_t)
zig_sign_extend(uint32_t)
zig_sign_extend(uint64_t)
zig_sign_extend(uint128_t)
#define zig_byte_swap_u(ZigTypeBits, CTypeBits) \
static inline uint##CTypeBits##_t zig_byte_swap_u##ZigTypeBits(uint##CTypeBits##_t value, uint8_t zig_type_bit_width) { \
return __builtin_bswap##CTypeBits(value) >> (CTypeBits - zig_type_bit_width); \
}
#define zig_byte_swap_s(ZigTypeBits, CTypeBits) \
static inline int##CTypeBits##_t zig_byte_swap_i##ZigTypeBits(int##CTypeBits##_t value, uint8_t zig_type_bit_width) { \
const uint##CTypeBits##_t swapped = zig_byte_swap_u##ZigTypeBits(value, zig_type_bit_width); \
return zig_sign_extend_uint##CTypeBits##_t(swapped, zig_type_bit_width); \
}
#define zig_byte_swap(ZigTypeBits, CTypeBits) \
zig_byte_swap_u(ZigTypeBits, CTypeBits) \
zig_byte_swap_s(ZigTypeBits, CTypeBits)
zig_byte_swap( 8, 16)
zig_byte_swap(16, 16)
zig_byte_swap(32, 32)
zig_byte_swap(64, 64)
static inline uint128_t zig_byte_swap_u128(uint128_t value, uint8_t zig_type_bit_width) {
const uint128_t mask = zig_bit_mask(uint128_t, zig_type_bit_width);
const uint128_t hi = __builtin_bswap64((uint64_t)(value >> 64));
const uint128_t lo = __builtin_bswap64((uint64_t)value);
const uint128_t swapped = (((lo << 64 | hi) >> (128 - zig_type_bit_width))) & mask;
return (signed_type ? zig_sign_extend(swapped, zig_type_bit_width) : swapped);
return (((lo << 64 | hi) >> (128 - zig_type_bit_width))) & mask;
}
static inline uint128_t zig_bit_reverse(uint128_t value, uint8_t zig_type_bit_width, bool signed_type) {
static const uint128_t reverse_lut[256] = {
0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, 0x50, 0xd0,
0x30, 0xb0, 0x70, 0xf0, 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, 0x04, 0x84, 0x44, 0xc4,
0x24, 0xa4, 0x64, 0xe4, 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, 0x1c, 0x9c, 0x5c, 0xdc,
0x3c, 0xbc, 0x7c, 0xfc, 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, 0x0a, 0x8a, 0x4a, 0xca,
0x2a, 0xaa, 0x6a, 0xea, 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, 0x16, 0x96, 0x56, 0xd6,
0x36, 0xb6, 0x76, 0xf6, 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, 0x01, 0x81, 0x41, 0xc1,
0x21, 0xa1, 0x61, 0xe1, 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 0x19, 0x99, 0x59, 0xd9,
0x39, 0xb9, 0x79, 0xf9, 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, 0x0d, 0x8d, 0x4d, 0xcd,
0x2d, 0xad, 0x6d, 0xed, 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, 0x13, 0x93, 0x53, 0xd3,
0x33, 0xb3, 0x73, 0xf3, 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, 0x07, 0x87, 0x47, 0xc7,
0x27, 0xa7, 0x67, 0xe7, 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 0x1f, 0x9f, 0x5f, 0xdf,
0x3f, 0xbf, 0x7f, 0xff
};
const uint128_t mask = zig_bit_mask(uint128_t, zig_type_bit_width);
const uint128_t swapped = zig_byte_swap(value, zig_type_bit_width, signed_type);
const uint128_t reversed = (
(reverse_lut[(swapped >> 0x78) & 0xff] << 0x78) |
(reverse_lut[(swapped >> 0x70) & 0xff] << 0x70) |
(reverse_lut[(swapped >> 0x68) & 0xff] << 0x68) |
(reverse_lut[(swapped >> 0x60) & 0xff] << 0x60) |
(reverse_lut[(swapped >> 0x58) & 0xff] << 0x58) |
(reverse_lut[(swapped >> 0x50) & 0xff] << 0x50) |
(reverse_lut[(swapped >> 0x48) & 0xff] << 0x48) |
(reverse_lut[(swapped >> 0x40) & 0xff] << 0x40) |
(reverse_lut[(swapped >> 0x38) & 0xff] << 0x38) |
(reverse_lut[(swapped >> 0x30) & 0xff] << 0x30) |
(reverse_lut[(swapped >> 0x28) & 0xff] << 0x28) |
(reverse_lut[(swapped >> 0x20) & 0xff] << 0x20) |
(reverse_lut[(swapped >> 0x18) & 0xff] << 0x18) |
(reverse_lut[(swapped >> 0x10) & 0xff] << 0x10) |
(reverse_lut[(swapped >> 0x08) & 0xff] << 0x08) |
(reverse_lut[(swapped >> 0x00) & 0xff] << 0x00));
const uint128_t result =
(reversed >> (zig_type_bit_width < 8 ? 8 - zig_type_bit_width : 0)) & mask;
return (signed_type ? zig_sign_extend(result, zig_type_bit_width) : result);
zig_byte_swap_s(128, 128)
static const uint8_t zig_bit_reverse_lut[256] = {
0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, 0x50, 0xd0,
0x30, 0xb0, 0x70, 0xf0, 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, 0x04, 0x84, 0x44, 0xc4,
0x24, 0xa4, 0x64, 0xe4, 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, 0x1c, 0x9c, 0x5c, 0xdc,
0x3c, 0xbc, 0x7c, 0xfc, 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, 0x0a, 0x8a, 0x4a, 0xca,
0x2a, 0xaa, 0x6a, 0xea, 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, 0x16, 0x96, 0x56, 0xd6,
0x36, 0xb6, 0x76, 0xf6, 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, 0x01, 0x81, 0x41, 0xc1,
0x21, 0xa1, 0x61, 0xe1, 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 0x19, 0x99, 0x59, 0xd9,
0x39, 0xb9, 0x79, 0xf9, 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, 0x0d, 0x8d, 0x4d, 0xcd,
0x2d, 0xad, 0x6d, 0xed, 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, 0x13, 0x93, 0x53, 0xd3,
0x33, 0xb3, 0x73, 0xf3, 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, 0x07, 0x87, 0x47, 0xc7,
0x27, 0xa7, 0x67, 0xe7, 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 0x1f, 0x9f, 0x5f, 0xdf,
0x3f, 0xbf, 0x7f, 0xff
};
static inline uint8_t zig_bit_reverse_u8(uint8_t value, uint8_t zig_type_bit_width) {
const uint8_t reversed = zig_bit_reverse_lut[value] >> (8 - zig_type_bit_width);
return zig_sign_extend_uint8_t(reversed, zig_type_bit_width);
}
#define zig_bit_reverse_i8 zig_bit_reverse_u8
static inline uint16_t zig_bit_reverse_u16(uint16_t value, uint8_t zig_type_bit_width) {
const uint16_t swapped = zig_byte_swap_u16(value, zig_type_bit_width);
const uint16_t reversed = (
((uint16_t)zig_bit_reverse_lut[(swapped >> 0x08) & 0xff] << 0x08) |
((uint16_t)zig_bit_reverse_lut[(swapped >> 0x00) & 0xff] << 0x00));
return zig_sign_extend_uint16_t(
reversed & zig_bit_mask(uint16_t, zig_type_bit_width),
zig_type_bit_width);
}
#define zig_bit_reverse_i16 zig_bit_reverse_u16
static inline uint32_t zig_bit_reverse_u32(uint32_t value, uint8_t zig_type_bit_width) {
const uint32_t swapped = zig_byte_swap_u32(value, zig_type_bit_width);
const uint32_t reversed = (
((uint32_t)zig_bit_reverse_lut[(swapped >> 0x18) & 0xff] << 0x18) |
((uint32_t)zig_bit_reverse_lut[(swapped >> 0x10) & 0xff] << 0x10) |
((uint32_t)zig_bit_reverse_lut[(swapped >> 0x08) & 0xff] << 0x08) |
((uint32_t)zig_bit_reverse_lut[(swapped >> 0x00) & 0xff] << 0x00));
return zig_sign_extend_uint32_t(
reversed & zig_bit_mask(uint32_t, zig_type_bit_width),
zig_type_bit_width);
}
#define zig_bit_reverse_i32 zig_bit_reverse_u32
static inline uint64_t zig_bit_reverse_u64(uint64_t value, uint8_t zig_type_bit_width) {
const uint64_t swapped = zig_byte_swap_u64(value, zig_type_bit_width);
const uint64_t reversed = (
((uint64_t)zig_bit_reverse_lut[(swapped >> 0x38) & 0xff] << 0x38) |
((uint64_t)zig_bit_reverse_lut[(swapped >> 0x30) & 0xff] << 0x30) |
((uint64_t)zig_bit_reverse_lut[(swapped >> 0x28) & 0xff] << 0x28) |
((uint64_t)zig_bit_reverse_lut[(swapped >> 0x20) & 0xff] << 0x20) |
((uint64_t)zig_bit_reverse_lut[(swapped >> 0x18) & 0xff] << 0x18) |
((uint64_t)zig_bit_reverse_lut[(swapped >> 0x10) & 0xff] << 0x10) |
((uint64_t)zig_bit_reverse_lut[(swapped >> 0x08) & 0xff] << 0x08) |
((uint64_t)zig_bit_reverse_lut[(swapped >> 0x00) & 0xff] << 0x00));
return zig_sign_extend_uint64_t(
reversed & zig_bit_mask(uint64_t, zig_type_bit_width),
zig_type_bit_width);
}
#define zig_bit_reverse_i64 zig_bit_reverse_u64
static inline uint128_t zig_bit_reverse_u128(uint128_t value, uint8_t zig_type_bit_width) {
const uint128_t swapped = zig_byte_swap_u128(value, zig_type_bit_width);
const uint128_t reversed = (
((uint128_t)zig_bit_reverse_lut[(swapped >> 0x78) & 0xff] << 0x78) |
((uint128_t)zig_bit_reverse_lut[(swapped >> 0x70) & 0xff] << 0x70) |
((uint128_t)zig_bit_reverse_lut[(swapped >> 0x68) & 0xff] << 0x68) |
((uint128_t)zig_bit_reverse_lut[(swapped >> 0x60) & 0xff] << 0x60) |
((uint128_t)zig_bit_reverse_lut[(swapped >> 0x58) & 0xff] << 0x58) |
((uint128_t)zig_bit_reverse_lut[(swapped >> 0x50) & 0xff] << 0x50) |
((uint128_t)zig_bit_reverse_lut[(swapped >> 0x48) & 0xff] << 0x48) |
((uint128_t)zig_bit_reverse_lut[(swapped >> 0x40) & 0xff] << 0x40) |
((uint128_t)zig_bit_reverse_lut[(swapped >> 0x38) & 0xff] << 0x38) |
((uint128_t)zig_bit_reverse_lut[(swapped >> 0x30) & 0xff] << 0x30) |
((uint128_t)zig_bit_reverse_lut[(swapped >> 0x28) & 0xff] << 0x28) |
((uint128_t)zig_bit_reverse_lut[(swapped >> 0x20) & 0xff] << 0x20) |
((uint128_t)zig_bit_reverse_lut[(swapped >> 0x18) & 0xff] << 0x18) |
((uint128_t)zig_bit_reverse_lut[(swapped >> 0x10) & 0xff] << 0x10) |
((uint128_t)zig_bit_reverse_lut[(swapped >> 0x08) & 0xff] << 0x08) |
((uint128_t)zig_bit_reverse_lut[(swapped >> 0x00) & 0xff] << 0x00));
return zig_sign_extend_uint128_t(
reversed & zig_bit_mask(uint128_t, zig_type_bit_width),
zig_type_bit_width);
}
#define zig_bit_reverse_i128 zig_bit_reverse_u128

View File

@ -82,7 +82,6 @@ test "@clz big ints" {
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
try testClzBigInts();
comptime try testClzBigInts();

View File

@ -37,6 +37,10 @@ fn testPopCountIntegers() !void {
var x: i8 = -120;
try expect(@popCount(i8, x) == 2);
}
{
var x: u128 = 0b11111111000110001100010000100001000011000011100101010001;
try expect(@popCount(u128, x) == 24);
}
comptime {
try expect(@popCount(u8, @bitCast(u8, @as(i8, -120))) == 2);
}