mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 06:13:07 +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);
|
||||
while (i != 0) {
|
||||
i -= 1;
|
||||
const limb = a.limbs[i];
|
||||
const this_limb_lz = @clz(limb);
|
||||
const this_limb_lz = @clz(a.limbs[i]);
|
||||
total_limb_lz += this_limb_lz;
|
||||
if (this_limb_lz != bits_per_limb) break;
|
||||
}
|
||||
@ -2557,6 +2556,7 @@ pub const Const = struct {
|
||||
pub fn ctz(a: Const, bits: Limb) Limb {
|
||||
// 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.
|
||||
if (a.eqlZero()) return bits;
|
||||
var result: Limb = 0;
|
||||
for (a.limbs) |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, 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();
|
||||
}
|
||||
|
||||
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) {
|
||||
return @byteSwap(@as(RoundBitsUp(Type, 8), rhs));
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user