@@ -1096,7 +1096,7 @@ pub const Mutable = struct {
1096
1096
/// Asserts there is enough memory to fit the result. The upper bound Limb count is
1097
1097
/// `a.limbs.len + (shift / (@sizeOf(Limb) * 8))`.
1098
1098
pub fn shiftLeft (r : * Mutable , a : Const , shift : usize ) void {
1099
- llshl (r .limbs [0 .. ] , a .limbs [0 .. a . limbs . len ] , shift );
1099
+ llshl (r .limbs , a .limbs , shift );
1100
1100
r .normalize (a .limbs .len + (shift / limb_bits ) + 1 );
1101
1101
r .positive = a .positive ;
1102
1102
}
@@ -1165,7 +1165,7 @@ pub const Mutable = struct {
1165
1165
1166
1166
// This shift should not be able to overflow, so invoke llshl and normalize manually
1167
1167
// to avoid the extra required limb.
1168
- llshl (r .limbs [0 .. ] , a .limbs [0 .. a . limbs . len ] , shift );
1168
+ llshl (r .limbs , a .limbs , shift );
1169
1169
r .normalize (a .limbs .len + (shift / limb_bits ));
1170
1170
r .positive = a .positive ;
1171
1171
}
@@ -1202,17 +1202,11 @@ pub const Mutable = struct {
1202
1202
break :nonzero a .limbs [full_limbs_shifted_out ] << not_covered != 0 ;
1203
1203
};
1204
1204
1205
- llshr (r .limbs [0 .. ] , a .limbs [0 .. a . limbs . len ] , shift );
1205
+ llshr (r .limbs , a .limbs , shift );
1206
1206
1207
1207
r .len = a .limbs .len - full_limbs_shifted_out ;
1208
1208
r .positive = a .positive ;
1209
- if (nonzero_negative_shiftout ) {
1210
- if (full_limbs_shifted_out > 0 ) {
1211
- r .limbs [a .limbs .len - full_limbs_shifted_out ] = 0 ;
1212
- r .len += 1 ;
1213
- }
1214
- r .addScalar (r .toConst (), -1 );
1215
- }
1209
+ if (nonzero_negative_shiftout ) r .addScalar (r .toConst (), -1 );
1216
1210
r .normalize (r .len );
1217
1211
}
1218
1212
@@ -1755,119 +1749,60 @@ pub const Mutable = struct {
1755
1749
y .shiftRight (y .toConst (), norm_shift );
1756
1750
}
1757
1751
1758
- /// If a is positive, this passes through to truncate.
1759
- /// If a is negative, then r is set to positive with the bit pattern ~(a - 1).
1760
- /// r may alias a.
1761
- ///
1762
- /// Asserts `r` has enough storage to store the result.
1763
- /// The upper bound is `calcTwosCompLimbCount(a.len)`.
1764
- pub fn convertToTwosComplement (r : * Mutable , a : Const , signedness : Signedness , bit_count : usize ) void {
1765
- if (a .positive ) {
1766
- r .truncate (a , signedness , bit_count );
1767
- return ;
1768
- }
1769
-
1770
- const req_limbs = calcTwosCompLimbCount (bit_count );
1771
- if (req_limbs == 0 or a .eqlZero ()) {
1772
- r .set (0 );
1773
- return ;
1774
- }
1775
-
1776
- const bit = @as (Log2Limb , @truncate (bit_count - 1 ));
1777
- const signmask = @as (Limb , 1 ) << bit ;
1778
- const mask = (signmask << 1 ) -% 1 ;
1779
-
1780
- r .addScalar (a .abs (), -1 );
1781
- if (req_limbs > r .len ) {
1782
- @memset (r .limbs [r .len .. req_limbs ], 0 );
1783
- }
1784
-
1785
- assert (r .limbs .len >= req_limbs );
1786
- r .len = req_limbs ;
1787
-
1788
- llnot (r .limbs [0.. r .len ]);
1789
- r .limbs [r .len - 1 ] &= mask ;
1790
- r .normalize (r .len );
1791
- }
1792
-
1793
1752
/// Truncate an integer to a number of bits, following 2s-complement semantics.
1794
- /// r may alias a .
1753
+ /// `r` may alias `a` .
1795
1754
///
1796
- /// Asserts `r` has enough storage to store the result.
1755
+ /// Asserts `r` has enough storage to compute the result.
1797
1756
/// The upper bound is `calcTwosCompLimbCount(a.len)`.
1798
1757
pub fn truncate (r : * Mutable , a : Const , signedness : Signedness , bit_count : usize ) void {
1799
- const req_limbs = calcTwosCompLimbCount (bit_count );
1800
- const abs_trunc_a : Const = .{
1801
- .positive = true ,
1802
- .limbs = a .limbs [0.. @min (a .limbs .len , req_limbs )],
1803
- };
1804
-
1805
1758
// Handle 0-bit integers.
1806
- if (req_limbs == 0 or abs_trunc_a .eqlZero ()) {
1759
+ if (bit_count == 0 ) {
1760
+ @branchHint (.unlikely );
1807
1761
r .set (0 );
1808
1762
return ;
1809
1763
}
1810
1764
1811
- const bit = @as (Log2Limb , @truncate (bit_count - 1 ));
1812
- const signmask = @as (Limb , 1 ) << bit ; // 0b0..010...0 where 1 is the sign bit.
1813
- const mask = (signmask << 1 ) -% 1 ; // 0b0..01..1 where the leftmost 1 is the sign bit.
1814
-
1815
- if (! a .positive ) {
1816
- // Convert the integer from sign-magnitude into twos-complement.
1817
- // -x = ~(x - 1)
1818
- // Note, we simply take req_limbs * @bitSizeOf(Limb) as the
1819
- // target bit count.
1820
-
1821
- r .addScalar (abs_trunc_a , -1 );
1765
+ const max_limbs = calcTwosCompLimbCount (bit_count );
1766
+ const sign_bit = @as (Limb , 1 ) << @truncate (bit_count - 1 );
1767
+ const mask = @as (Limb , maxInt (Limb )) >> @truncate (-% bit_count );
1768
+
1769
+ // Guess whether the result will have the same sign as `a`.
1770
+ // * If the result will be signed zero, the guess is `true`.
1771
+ // * If the result will be the minimum signed integer, the guess is `false`.
1772
+ // * If the result will be unsigned zero, the guess is `a.positive`.
1773
+ // * Otherwise the guess is correct.
1774
+ const same_sign_guess = switch (signedness ) {
1775
+ .signed = > max_limbs > a .limbs .len or a .limbs [max_limbs - 1 ] & sign_bit == 0 ,
1776
+ .unsigned = > a .positive ,
1777
+ };
1822
1778
1823
- // Zero-extend the result
1824
- @memset (r .limbs [r .len .. req_limbs ], 0 );
1825
- r .len = req_limbs ;
1826
-
1827
- // Without truncating, we can already peek at the sign bit of the result here.
1828
- // Note that it will be 0 if the result is negative, as we did not apply the flip here.
1829
- // If the result is negative, we have
1830
- // -(-x & mask)
1831
- // = ~(~(x - 1) & mask) + 1
1832
- // = ~(~((x - 1) | ~mask)) + 1
1833
- // = ((x - 1) | ~mask)) + 1
1834
- // Note, this is only valid for the target bits and not the upper bits
1835
- // of the most significant limb. Those still need to be cleared.
1836
- // Also note that `mask` is zero for all other bits, reducing to the identity.
1837
- // This means that we still need to use & mask to clear off the upper bits.
1838
-
1839
- if (signedness == .signed and r .limbs [r .len - 1 ] & signmask == 0 ) {
1840
- // Re-add the one and negate to get the result.
1841
- r .limbs [r .len - 1 ] &= mask ;
1842
- // Note, addition cannot require extra limbs here as we did a subtraction before.
1843
- r .addScalar (r .toConst (), 1 );
1844
- r .normalize (r .len );
1845
- r .positive = false ;
1846
- } else {
1847
- llnot (r .limbs [0.. r .len ]);
1848
- r .limbs [r .len - 1 ] &= mask ;
1849
- r .normalize (r .len );
1850
- }
1851
- } else {
1779
+ const abs_trunc_a : Const = .{
1780
+ .positive = true ,
1781
+ .limbs = a .limbs [0.. llnormalize (a .limbs [0.. @min (a .limbs .len , max_limbs )])],
1782
+ };
1783
+ if (same_sign_guess or abs_trunc_a .eqlZero ()) {
1784
+ // One of the following is true:
1785
+ // * The result is zero.
1786
+ // * The result is non-zero and has the same sign as `a`.
1852
1787
r .copy (abs_trunc_a );
1853
- // If the integer fits within target bits, no wrapping is required.
1854
- if (r .len < req_limbs ) return ;
1855
-
1856
- r .limbs [r .len - 1 ] &= mask ;
1788
+ if (max_limbs <= r .len ) r .limbs [max_limbs - 1 ] &= mask ;
1857
1789
r .normalize (r .len );
1858
-
1859
- if (signedness == .signed and r .limbs [r .len - 1 ] & signmask != 0 ) {
1860
- // Convert 2s-complement back to sign-magnitude.
1861
- // Sign-extend the upper bits so that they are inverted correctly.
1862
- r .limbs [r .len - 1 ] |= ~ mask ;
1863
- llnot (r .limbs [0.. r .len ]);
1864
-
1865
- // Note, can only overflow if r holds 0xFFF...F which can only happen if
1866
- // a holds 0.
1867
- r .addScalar (r .toConst (), 1 );
1868
-
1869
- r .positive = false ;
1870
- }
1790
+ r .positive = a .positive or r .eqlZero ();
1791
+ } else {
1792
+ // One of the following is true:
1793
+ // * The result is the minimum signed integer.
1794
+ // * The result is unsigned zero.
1795
+ // * The result is non-zero and has the opposite sign as `a`.
1796
+ r .addScalar (abs_trunc_a , -1 );
1797
+ llnot (r .limbs [0.. r .len ]);
1798
+ @memset (r .limbs [r .len .. max_limbs ], maxInt (Limb ));
1799
+ r .limbs [max_limbs - 1 ] &= mask ;
1800
+ r .normalize (max_limbs );
1801
+ r .positive = switch (signedness ) {
1802
+ // The only value with the sign bit still set is the minimum signed integer.
1803
+ .signed = > ! a .positive and r .limbs [max_limbs - 1 ] & sign_bit == 0 ,
1804
+ .unsigned = > ! a .positive or r .eqlZero (),
1805
+ };
1871
1806
}
1872
1807
}
1873
1808
0 commit comments