mirror of
https://github.com/ziglang/zig.git
synced 2025-12-16 03:03:09 +00:00
Merge pull request #22932 from jacobly0/x86_64-rewrite
x86_64: start rewriting bit counting operations
This commit is contained in:
commit
bd237bced4
@ -2544,8 +2544,7 @@ pub const Const = struct {
|
|||||||
const bits_per_limb = @bitSizeOf(Limb);
|
const bits_per_limb = @bitSizeOf(Limb);
|
||||||
while (i != 0) {
|
while (i != 0) {
|
||||||
i -= 1;
|
i -= 1;
|
||||||
const limb = a.limbs[i];
|
const this_limb_lz = @clz(a.limbs[i]);
|
||||||
const this_limb_lz = @clz(limb);
|
|
||||||
total_limb_lz += this_limb_lz;
|
total_limb_lz += this_limb_lz;
|
||||||
if (this_limb_lz != bits_per_limb) break;
|
if (this_limb_lz != bits_per_limb) break;
|
||||||
}
|
}
|
||||||
@ -2557,6 +2556,7 @@ pub const Const = struct {
|
|||||||
pub fn ctz(a: Const, bits: Limb) Limb {
|
pub fn ctz(a: Const, bits: Limb) Limb {
|
||||||
// Limbs are stored in little-endian order. Converting a negative number to twos-complement
|
// Limbs are stored in little-endian order. Converting a negative number to twos-complement
|
||||||
// flips all bits above the lowest set bit, which does not affect the trailing zero count.
|
// flips all bits above the lowest set bit, which does not affect the trailing zero count.
|
||||||
|
if (a.eqlZero()) return bits;
|
||||||
var result: Limb = 0;
|
var result: Limb = 0;
|
||||||
for (a.limbs) |limb| {
|
for (a.limbs) |limb| {
|
||||||
const limb_tz = @ctz(limb);
|
const limb_tz = @ctz(limb);
|
||||||
|
|||||||
@ -3332,3 +3332,227 @@ test "(BigInt) negative" {
|
|||||||
try testing.expect(mem.eql(u8, a_fmt, "(BigInt)"));
|
try testing.expect(mem.eql(u8, a_fmt, "(BigInt)"));
|
||||||
try testing.expect(!mem.eql(u8, b_fmt, "(BigInt)"));
|
try testing.expect(!mem.eql(u8, b_fmt, "(BigInt)"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "clz" {
|
||||||
|
const neg_limb_max_squared: std.math.big.int.Const = .{
|
||||||
|
.limbs = &.{ 1, maxInt(Limb) - 1 },
|
||||||
|
.positive = false,
|
||||||
|
};
|
||||||
|
try testing.expect(neg_limb_max_squared.clz(@bitSizeOf(Limb) * 2 + 1) == 0);
|
||||||
|
|
||||||
|
const neg_limb_max_squared_plus_one: std.math.big.int.Const = .{
|
||||||
|
.limbs = &.{ 0, maxInt(Limb) - 1 },
|
||||||
|
.positive = false,
|
||||||
|
};
|
||||||
|
try testing.expect(neg_limb_max_squared_plus_one.clz(@bitSizeOf(Limb) * 2 + 1) == 0);
|
||||||
|
|
||||||
|
const neg_limb_msb_squared: std.math.big.int.Const = .{
|
||||||
|
.limbs = &.{ 0, 1 << @bitSizeOf(Limb) - 2 },
|
||||||
|
.positive = false,
|
||||||
|
};
|
||||||
|
try testing.expect(neg_limb_msb_squared.clz(@bitSizeOf(Limb) * 2) == 0);
|
||||||
|
try testing.expect(neg_limb_msb_squared.clz(@bitSizeOf(Limb) * 2 + 1) == 0);
|
||||||
|
|
||||||
|
const neg_limb_max: std.math.big.int.Const = .{
|
||||||
|
.limbs = &.{maxInt(Limb)},
|
||||||
|
.positive = false,
|
||||||
|
};
|
||||||
|
try testing.expect(neg_limb_max.clz(@bitSizeOf(Limb) + 1) == 0);
|
||||||
|
try testing.expect(neg_limb_max.clz(@bitSizeOf(Limb) * 2 - 1) == 0);
|
||||||
|
try testing.expect(neg_limb_max.clz(@bitSizeOf(Limb) * 2) == 0);
|
||||||
|
try testing.expect(neg_limb_max.clz(@bitSizeOf(Limb) * 2 + 1) == 0);
|
||||||
|
|
||||||
|
const neg_limb_msb: std.math.big.int.Const = .{
|
||||||
|
.limbs = &.{1 << @bitSizeOf(Limb) - 1},
|
||||||
|
.positive = false,
|
||||||
|
};
|
||||||
|
try testing.expect(neg_limb_msb.clz(@bitSizeOf(Limb)) == 0);
|
||||||
|
try testing.expect(neg_limb_msb.clz(@bitSizeOf(Limb) + 1) == 0);
|
||||||
|
try testing.expect(neg_limb_msb.clz(@bitSizeOf(Limb) * 2 - 1) == 0);
|
||||||
|
try testing.expect(neg_limb_msb.clz(@bitSizeOf(Limb) * 2) == 0);
|
||||||
|
try testing.expect(neg_limb_msb.clz(@bitSizeOf(Limb) * 2 + 1) == 0);
|
||||||
|
|
||||||
|
const neg_one: std.math.big.int.Const = .{
|
||||||
|
.limbs = &.{1},
|
||||||
|
.positive = false,
|
||||||
|
};
|
||||||
|
try testing.expect(neg_one.clz(@bitSizeOf(Limb)) == 0);
|
||||||
|
try testing.expect(neg_one.clz(@bitSizeOf(Limb) + 1) == 0);
|
||||||
|
try testing.expect(neg_one.clz(@bitSizeOf(Limb) * 2 - 1) == 0);
|
||||||
|
try testing.expect(neg_one.clz(@bitSizeOf(Limb) * 2) == 0);
|
||||||
|
try testing.expect(neg_one.clz(@bitSizeOf(Limb) * 2 + 1) == 0);
|
||||||
|
|
||||||
|
const zero: std.math.big.int.Const = .{
|
||||||
|
.limbs = &.{0},
|
||||||
|
.positive = true,
|
||||||
|
};
|
||||||
|
try testing.expect(zero.clz(@bitSizeOf(Limb)) == @bitSizeOf(Limb));
|
||||||
|
try testing.expect(zero.clz(@bitSizeOf(Limb) + 1) == @bitSizeOf(Limb) + 1);
|
||||||
|
try testing.expect(zero.clz(@bitSizeOf(Limb) * 2 - 1) == @bitSizeOf(Limb) * 2 - 1);
|
||||||
|
try testing.expect(zero.clz(@bitSizeOf(Limb) * 2) == @bitSizeOf(Limb) * 2);
|
||||||
|
try testing.expect(zero.clz(@bitSizeOf(Limb) * 2 + 1) == @bitSizeOf(Limb) * 2 + 1);
|
||||||
|
|
||||||
|
const one: std.math.big.int.Const = .{
|
||||||
|
.limbs = &.{1},
|
||||||
|
.positive = true,
|
||||||
|
};
|
||||||
|
try testing.expect(one.clz(@bitSizeOf(Limb)) == @bitSizeOf(Limb) - 1);
|
||||||
|
try testing.expect(one.clz(@bitSizeOf(Limb) + 1) == @bitSizeOf(Limb));
|
||||||
|
try testing.expect(one.clz(@bitSizeOf(Limb) * 2 - 1) == @bitSizeOf(Limb) * 2 - 2);
|
||||||
|
try testing.expect(one.clz(@bitSizeOf(Limb) * 2) == @bitSizeOf(Limb) * 2 - 1);
|
||||||
|
try testing.expect(one.clz(@bitSizeOf(Limb) * 2 + 1) == @bitSizeOf(Limb) * 2);
|
||||||
|
|
||||||
|
const limb_msb: std.math.big.int.Const = .{
|
||||||
|
.limbs = &.{1 << @bitSizeOf(Limb) - 1},
|
||||||
|
.positive = true,
|
||||||
|
};
|
||||||
|
try testing.expect(limb_msb.clz(@bitSizeOf(Limb)) == 0);
|
||||||
|
try testing.expect(limb_msb.clz(@bitSizeOf(Limb) + 1) == 1);
|
||||||
|
try testing.expect(limb_msb.clz(@bitSizeOf(Limb) * 2 - 1) == @bitSizeOf(Limb) - 1);
|
||||||
|
try testing.expect(limb_msb.clz(@bitSizeOf(Limb) * 2) == @bitSizeOf(Limb));
|
||||||
|
try testing.expect(limb_msb.clz(@bitSizeOf(Limb) * 2 + 1) == @bitSizeOf(Limb) + 1);
|
||||||
|
|
||||||
|
const limb_max: std.math.big.int.Const = .{
|
||||||
|
.limbs = &.{maxInt(Limb)},
|
||||||
|
.positive = true,
|
||||||
|
};
|
||||||
|
try testing.expect(limb_max.clz(@bitSizeOf(Limb)) == 0);
|
||||||
|
try testing.expect(limb_max.clz(@bitSizeOf(Limb) + 1) == 1);
|
||||||
|
try testing.expect(limb_max.clz(@bitSizeOf(Limb) * 2 - 1) == @bitSizeOf(Limb) - 1);
|
||||||
|
try testing.expect(limb_max.clz(@bitSizeOf(Limb) * 2) == @bitSizeOf(Limb));
|
||||||
|
try testing.expect(limb_max.clz(@bitSizeOf(Limb) * 2 + 1) == @bitSizeOf(Limb) + 1);
|
||||||
|
|
||||||
|
const limb_msb_squared: std.math.big.int.Const = .{
|
||||||
|
.limbs = &.{ 0, 1 << @bitSizeOf(Limb) - 2 },
|
||||||
|
.positive = true,
|
||||||
|
};
|
||||||
|
try testing.expect(limb_msb_squared.clz(@bitSizeOf(Limb) * 2 - 1) == 0);
|
||||||
|
try testing.expect(limb_msb_squared.clz(@bitSizeOf(Limb) * 2) == 1);
|
||||||
|
try testing.expect(limb_msb_squared.clz(@bitSizeOf(Limb) * 2 + 1) == 2);
|
||||||
|
|
||||||
|
const limb_max_squared_minus_one: std.math.big.int.Const = .{
|
||||||
|
.limbs = &.{ 0, maxInt(Limb) - 1 },
|
||||||
|
.positive = true,
|
||||||
|
};
|
||||||
|
try testing.expect(limb_max_squared_minus_one.clz(@bitSizeOf(Limb) * 2) == 0);
|
||||||
|
try testing.expect(limb_max_squared_minus_one.clz(@bitSizeOf(Limb) * 2 + 1) == 1);
|
||||||
|
|
||||||
|
const limb_max_squared: std.math.big.int.Const = .{
|
||||||
|
.limbs = &.{ 1, maxInt(Limb) - 1 },
|
||||||
|
.positive = true,
|
||||||
|
};
|
||||||
|
try testing.expect(limb_max_squared.clz(@bitSizeOf(Limb) * 2) == 0);
|
||||||
|
try testing.expect(limb_max_squared.clz(@bitSizeOf(Limb) * 2 + 1) == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "ctz" {
|
||||||
|
const neg_limb_max_squared: std.math.big.int.Const = .{
|
||||||
|
.limbs = &.{ 1, maxInt(Limb) - 1 },
|
||||||
|
.positive = false,
|
||||||
|
};
|
||||||
|
try testing.expect(neg_limb_max_squared.ctz(@bitSizeOf(Limb) * 2 + 1) == 0);
|
||||||
|
|
||||||
|
const neg_limb_max_squared_plus_one: std.math.big.int.Const = .{
|
||||||
|
.limbs = &.{ 0, maxInt(Limb) - 1 },
|
||||||
|
.positive = false,
|
||||||
|
};
|
||||||
|
try testing.expect(neg_limb_max_squared_plus_one.ctz(@bitSizeOf(Limb) * 2 + 1) == @bitSizeOf(Limb) + 1);
|
||||||
|
|
||||||
|
const neg_limb_msb_squared: std.math.big.int.Const = .{
|
||||||
|
.limbs = &.{ 0, 1 << @bitSizeOf(Limb) - 2 },
|
||||||
|
.positive = false,
|
||||||
|
};
|
||||||
|
try testing.expect(neg_limb_msb_squared.ctz(@bitSizeOf(Limb) * 2) == @bitSizeOf(Limb) * 2 - 2);
|
||||||
|
try testing.expect(neg_limb_msb_squared.ctz(@bitSizeOf(Limb) * 2 + 1) == @bitSizeOf(Limb) * 2 - 2);
|
||||||
|
|
||||||
|
const neg_limb_max: std.math.big.int.Const = .{
|
||||||
|
.limbs = &.{maxInt(Limb)},
|
||||||
|
.positive = false,
|
||||||
|
};
|
||||||
|
try testing.expect(neg_limb_max.ctz(@bitSizeOf(Limb) + 1) == 0);
|
||||||
|
try testing.expect(neg_limb_max.ctz(@bitSizeOf(Limb) * 2 - 1) == 0);
|
||||||
|
try testing.expect(neg_limb_max.ctz(@bitSizeOf(Limb) * 2) == 0);
|
||||||
|
try testing.expect(neg_limb_max.ctz(@bitSizeOf(Limb) * 2 + 1) == 0);
|
||||||
|
|
||||||
|
const neg_limb_msb: std.math.big.int.Const = .{
|
||||||
|
.limbs = &.{1 << @bitSizeOf(Limb) - 1},
|
||||||
|
.positive = false,
|
||||||
|
};
|
||||||
|
try testing.expect(neg_limb_msb.ctz(@bitSizeOf(Limb)) == @bitSizeOf(Limb) - 1);
|
||||||
|
try testing.expect(neg_limb_msb.ctz(@bitSizeOf(Limb) + 1) == @bitSizeOf(Limb) - 1);
|
||||||
|
try testing.expect(neg_limb_msb.ctz(@bitSizeOf(Limb) * 2 - 1) == @bitSizeOf(Limb) - 1);
|
||||||
|
try testing.expect(neg_limb_msb.ctz(@bitSizeOf(Limb) * 2) == @bitSizeOf(Limb) - 1);
|
||||||
|
try testing.expect(neg_limb_msb.ctz(@bitSizeOf(Limb) * 2 + 1) == @bitSizeOf(Limb) - 1);
|
||||||
|
|
||||||
|
const neg_one: std.math.big.int.Const = .{
|
||||||
|
.limbs = &.{1},
|
||||||
|
.positive = false,
|
||||||
|
};
|
||||||
|
try testing.expect(neg_one.ctz(@bitSizeOf(Limb)) == 0);
|
||||||
|
try testing.expect(neg_one.ctz(@bitSizeOf(Limb) + 1) == 0);
|
||||||
|
try testing.expect(neg_one.ctz(@bitSizeOf(Limb) * 2 - 1) == 0);
|
||||||
|
try testing.expect(neg_one.ctz(@bitSizeOf(Limb) * 2) == 0);
|
||||||
|
try testing.expect(neg_one.ctz(@bitSizeOf(Limb) * 2 + 1) == 0);
|
||||||
|
|
||||||
|
const zero: std.math.big.int.Const = .{
|
||||||
|
.limbs = &.{0},
|
||||||
|
.positive = true,
|
||||||
|
};
|
||||||
|
try testing.expect(zero.ctz(@bitSizeOf(Limb)) == @bitSizeOf(Limb));
|
||||||
|
try testing.expect(zero.ctz(@bitSizeOf(Limb) + 1) == @bitSizeOf(Limb) + 1);
|
||||||
|
try testing.expect(zero.ctz(@bitSizeOf(Limb) * 2 - 1) == @bitSizeOf(Limb) * 2 - 1);
|
||||||
|
try testing.expect(zero.ctz(@bitSizeOf(Limb) * 2) == @bitSizeOf(Limb) * 2);
|
||||||
|
try testing.expect(zero.ctz(@bitSizeOf(Limb) * 2 + 1) == @bitSizeOf(Limb) * 2 + 1);
|
||||||
|
|
||||||
|
const one: std.math.big.int.Const = .{
|
||||||
|
.limbs = &.{1},
|
||||||
|
.positive = true,
|
||||||
|
};
|
||||||
|
try testing.expect(one.ctz(@bitSizeOf(Limb)) == 0);
|
||||||
|
try testing.expect(one.ctz(@bitSizeOf(Limb) + 1) == 0);
|
||||||
|
try testing.expect(one.ctz(@bitSizeOf(Limb) * 2 - 1) == 0);
|
||||||
|
try testing.expect(one.ctz(@bitSizeOf(Limb) * 2) == 0);
|
||||||
|
try testing.expect(one.ctz(@bitSizeOf(Limb) * 2 + 1) == 0);
|
||||||
|
|
||||||
|
const limb_msb: std.math.big.int.Const = .{
|
||||||
|
.limbs = &.{1 << @bitSizeOf(Limb) - 1},
|
||||||
|
.positive = true,
|
||||||
|
};
|
||||||
|
try testing.expect(limb_msb.ctz(@bitSizeOf(Limb)) == @bitSizeOf(Limb) - 1);
|
||||||
|
try testing.expect(limb_msb.ctz(@bitSizeOf(Limb) + 1) == @bitSizeOf(Limb) - 1);
|
||||||
|
try testing.expect(limb_msb.ctz(@bitSizeOf(Limb) * 2 - 1) == @bitSizeOf(Limb) - 1);
|
||||||
|
try testing.expect(limb_msb.ctz(@bitSizeOf(Limb) * 2) == @bitSizeOf(Limb) - 1);
|
||||||
|
try testing.expect(limb_msb.ctz(@bitSizeOf(Limb) * 2 + 1) == @bitSizeOf(Limb) - 1);
|
||||||
|
|
||||||
|
const limb_max: std.math.big.int.Const = .{
|
||||||
|
.limbs = &.{maxInt(Limb)},
|
||||||
|
.positive = true,
|
||||||
|
};
|
||||||
|
try testing.expect(limb_max.ctz(@bitSizeOf(Limb)) == 0);
|
||||||
|
try testing.expect(limb_max.ctz(@bitSizeOf(Limb) + 1) == 0);
|
||||||
|
try testing.expect(limb_max.ctz(@bitSizeOf(Limb) * 2 - 1) == 0);
|
||||||
|
try testing.expect(limb_max.ctz(@bitSizeOf(Limb) * 2) == 0);
|
||||||
|
try testing.expect(limb_max.ctz(@bitSizeOf(Limb) * 2 + 1) == 0);
|
||||||
|
|
||||||
|
const limb_msb_squared: std.math.big.int.Const = .{
|
||||||
|
.limbs = &.{ 0, 1 << @bitSizeOf(Limb) - 2 },
|
||||||
|
.positive = true,
|
||||||
|
};
|
||||||
|
try testing.expect(limb_msb_squared.ctz(@bitSizeOf(Limb) * 2 - 1) == @bitSizeOf(Limb) * 2 - 2);
|
||||||
|
try testing.expect(limb_msb_squared.ctz(@bitSizeOf(Limb) * 2) == @bitSizeOf(Limb) * 2 - 2);
|
||||||
|
try testing.expect(limb_msb_squared.ctz(@bitSizeOf(Limb) * 2 + 1) == @bitSizeOf(Limb) * 2 - 2);
|
||||||
|
|
||||||
|
const limb_max_squared_minus_one: std.math.big.int.Const = .{
|
||||||
|
.limbs = &.{ 0, maxInt(Limb) - 1 },
|
||||||
|
.positive = true,
|
||||||
|
};
|
||||||
|
try testing.expect(limb_max_squared_minus_one.ctz(@bitSizeOf(Limb) * 2) == @bitSizeOf(Limb) + 1);
|
||||||
|
try testing.expect(limb_max_squared_minus_one.ctz(@bitSizeOf(Limb) * 2 + 1) == @bitSizeOf(Limb) + 1);
|
||||||
|
|
||||||
|
const limb_max_squared: std.math.big.int.Const = .{
|
||||||
|
.limbs = &.{ 1, maxInt(Limb) - 1 },
|
||||||
|
.positive = true,
|
||||||
|
};
|
||||||
|
try testing.expect(limb_max_squared.ctz(@bitSizeOf(Limb) * 2) == 0);
|
||||||
|
try testing.expect(limb_max_squared.ctz(@bitSizeOf(Limb) * 2 + 1) == 0);
|
||||||
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -19273,6 +19273,22 @@ test clz {
|
|||||||
try test_clz.testIntVectors();
|
try test_clz.testIntVectors();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline fn ctz(comptime Type: type, rhs: Type) @TypeOf(@ctz(rhs)) {
|
||||||
|
return @ctz(rhs);
|
||||||
|
}
|
||||||
|
test ctz {
|
||||||
|
const test_ctz = unary(ctz, .{});
|
||||||
|
try test_ctz.testInts();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fn popCount(comptime Type: type, rhs: Type) @TypeOf(@popCount(rhs)) {
|
||||||
|
return @popCount(rhs);
|
||||||
|
}
|
||||||
|
test popCount {
|
||||||
|
const test_pop_count = unary(popCount, .{});
|
||||||
|
try test_pop_count.testInts();
|
||||||
|
}
|
||||||
|
|
||||||
inline fn byteSwap(comptime Type: type, rhs: Type) RoundBitsUp(Type, 8) {
|
inline fn byteSwap(comptime Type: type, rhs: Type) RoundBitsUp(Type, 8) {
|
||||||
return @byteSwap(@as(RoundBitsUp(Type, 8), rhs));
|
return @byteSwap(@as(RoundBitsUp(Type, 8), rhs));
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user