Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement @depositBits and @extractBits #18680

Closed
wants to merge 28 commits into from
Closed
Changes from 1 commit
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
34ffb08
std.math.big.int: Implement depositBits and extractBits
ominitay Apr 9, 2023
32ff101
std.math.big.int: Conversion from 2's complement
ominitay Apr 11, 2023
a33d4f6
Write docs for `@depositBits` and `@extractBits`
ominitay Apr 12, 2023
9bd3bf7
Implement `@depositBits` and `@extractBits`
ominitay Apr 12, 2023
2de5fcc
LLVM: Implement emulation for `@depositBits`
ominitay Apr 13, 2023
a2850aa
LLVM: Implement emulation for `@extractBits`
ominitay Apr 13, 2023
9760841
std.math.big.int: Fix index out-of-bounds
ominitay Apr 14, 2023
566a888
Add behaviour tests for `@depositBits` and `@extractBits`
ominitay Apr 14, 2023
db280ce
zig fmt
ominitay Apr 15, 2023
9020b2f
Replace `u6` with `Log2Limb`
ominitay Apr 15, 2023
eecdf99
big.int.depositBits/extractBits: Remove limbs_buffer
ominitay Apr 17, 2023
13d4205
Disallow signed integer types for deposit/extract
ominitay Apr 18, 2023
313d258
Actually use deposit/extract behaviour test
ominitay Apr 19, 2023
5a42ecb
Enable langref tests for deposit and extract
ominitay Apr 19, 2023
fc8eadb
Allow use of `comptime_int` with deposit/extract
ominitay Apr 19, 2023
9c14b26
Improve compile errors for negative values
ominitay Apr 19, 2023
4eff831
update comments
ominitay Apr 21, 2023
69e893d
Bring branch up-to-date
ominitay Nov 9, 2023
71f8db4
x86: Implement `@depositBits` and `@extractBits`
ominitay Nov 12, 2023
5f66df1
update deposit/extract to master
ominitay Jan 25, 2024
e0b4630
zig fmt
ominitay Jan 25, 2024
4bcaab9
Don't compile tests for deposit/extract when unsupported
ominitay Jan 25, 2024
432e1cb
Bring branch up-to-date with llvm backend changes
ominitay Mar 15, 2024
725019e
Emulate pdep and pext in compiler-rt
ominitay Mar 26, 2024
e1915f9
Include depositBits/extractBits emulation in x86 backend
ominitay Mar 27, 2024
e80a4b2
Update behaviour tests for deposit/extractBits
ominitay Mar 28, 2024
b87e549
Bring fork up-to-date with master
ominitay Mar 29, 2024
726b436
Skip failing behaviour tests
ominitay Apr 17, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
std.math.big.int: Conversion from 2's complement
Implements std.math.big.int.Mutable.convertFromTwosComplement, to match
convertToTwosComplement.
ominitay committed Apr 16, 2024
commit 32ff10178028cb3de7e42848809f88c193367d59
34 changes: 34 additions & 0 deletions lib/std/math/big/int.zig
Original file line number Diff line number Diff line change
@@ -1844,6 +1844,40 @@ pub const Mutable = struct {
r.normalize(r.len);
}

/// Converts a twos-complement value to a magnitude, and sets the sign of `r` to match.
/// `a.positive` is ignored
/// r may alias a
///
/// Asserts `r` has enough storage to store the result.
/// The upper bound is `calcTwosCompLimbCount(bit_count)`
pub fn convertFromTwosComplement(r: *Mutable, a: Const, signedness: Signedness, bit_count: usize) void {
const req_limbs = calcTwosCompLimbCount(bit_count);
if (req_limbs == 0 or a.eqZero()) {
r.set(0);
return;
}

const bit = @truncate(Log2Limb, bit_count - 1);
const signmask = @as(Limb, 1) << bit;
const mask = (signmask << 1) -% 1;

if (signedness == .unsigned or req_limbs > a.limbs.len or a.limbs[req_limbs - 1] & signmask == 0) {
r.truncate(a, signedness, bit_count);
return;
}

r.copy(a);
assert(r.limbs.len >= req_limbs);
r.len = req_limbs;

r.addScalar(r.toConst(), -1);
llnot(r.limbs[0..r.len]);
r.limbs[r.len - 1] &= mask;

r.positive = false;
r.normalize(r.len);
}

/// Truncate an integer to a number of bits, following 2s-complement semantics.
/// r may alias a.
///
27 changes: 27 additions & 0 deletions lib/std/math/big/int_test.zig
Original file line number Diff line number Diff line change
@@ -2854,6 +2854,33 @@ fn depositBitsTest(comptime source: comptime_int, comptime mask: comptime_int, c
try testing.expectEqual(std.math.Order.eq, result.toConst().orderAgainstScalar(expected));
}

test "big int conversion to/from twos complement" {
var a = try Managed.initSet(testing.allocator, maxInt(u64));
defer a.deinit();
var b = try Managed.initSet(testing.allocator, maxInt(u32));
defer b.deinit();
var c = try Managed.initSet(testing.allocator, maxInt(u493));
defer c.deinit();

var m_a = a.toMutable();
m_a.convertToTwosComplement(m_a.toConst(), .unsigned, 64);
try testing.expectEqual(m_a.toConst().orderAgainstScalar(maxInt(u64)), .eq);
m_a.convertFromTwosComplement(m_a.toConst(), .signed, 64);
try testing.expectEqual(m_a.toConst().orderAgainstScalar(-1), .eq);

var m_b = b.toMutable();
m_b.convertToTwosComplement(m_b.toConst(), .unsigned, 32);
try testing.expectEqual(m_b.toConst().orderAgainstScalar(maxInt(u32)), .eq);
m_b.convertFromTwosComplement(m_b.toConst(), .signed, 32);
try testing.expectEqual(m_b.toConst().orderAgainstScalar(-1), .eq);

var m_c = c.toMutable();
m_c.convertToTwosComplement(m_c.toConst(), .unsigned, 493);
try testing.expectEqual(m_c.toConst().orderAgainstScalar(maxInt(u493)), .eq);
m_c.convertFromTwosComplement(m_c.toConst(), .signed, 493);
try testing.expectEqual(m_c.toConst().orderAgainstScalar(-1), .eq);
}

test "big int conversion read/write twos complement" {
var a = try Managed.initSet(testing.allocator, (1 << 493) - 1);
defer a.deinit();