summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doop.c98
-rw-r--r--pod/perldelta.pod13
-rw-r--r--pod/perldiag.pod6
-rw-r--r--pod/perlfunc.pod9
-rw-r--r--pp.h6
-rw-r--r--t/op/64bit.t21
6 files changed, 128 insertions, 25 deletions
diff --git a/doop.c b/doop.c
index 36fb6b37f8..3e40d92d4f 100644
--- a/doop.c
+++ b/doop.c
@@ -737,6 +737,58 @@ Perl_do_vecget(pTHX_ SV *sv, I32 offset, I32 size)
((UV) s[offset + 1] << 16) +
( s[offset + 2] << 8);
}
+#ifdef HAS_QUAD
+ else if (size == 64) {
+ dTHR;
+ if (ckWARN(WARN_PORTABLE))
+ Perl_warner(aTHX_ WARN_PORTABLE,
+ "Bit vector size > 32 non-portable");
+ if (offset >= srclen)
+ retnum = 0;
+ else if (offset + 1 >= srclen)
+ retnum =
+ (UV) s[offset ] << 56;
+ else if (offset + 2 >= srclen)
+ retnum =
+ ((UV) s[offset ] << 56) +
+ ((UV) s[offset + 1] << 48);
+ else if (offset + 3 >= srclen)
+ retnum =
+ ((UV) s[offset ] << 56) +
+ ((UV) s[offset + 1] << 48) +
+ ((UV) s[offset + 2] << 40);
+ else if (offset + 4 >= srclen)
+ retnum =
+ ((UV) s[offset ] << 56) +
+ ((UV) s[offset + 1] << 48) +
+ ((UV) s[offset + 2] << 40) +
+ ((UV) s[offset + 3] << 32);
+ else if (offset + 5 >= srclen)
+ retnum =
+ ((UV) s[offset ] << 56) +
+ ((UV) s[offset + 1] << 48) +
+ ((UV) s[offset + 2] << 40) +
+ ((UV) s[offset + 3] << 32) +
+ ( s[offset + 4] << 24);
+ else if (offset + 6 >= srclen)
+ retnum =
+ ((UV) s[offset ] << 56) +
+ ((UV) s[offset + 1] << 48) +
+ ((UV) s[offset + 2] << 40) +
+ ((UV) s[offset + 3] << 32) +
+ ((UV) s[offset + 4] << 24) +
+ ((UV) s[offset + 5] << 16);
+ else
+ retnum =
+ ((UV) s[offset ] << 56) +
+ ((UV) s[offset + 1] << 48) +
+ ((UV) s[offset + 2] << 40) +
+ ((UV) s[offset + 3] << 32) +
+ ((UV) s[offset + 4] << 24) +
+ ((UV) s[offset + 5] << 16) +
+ ( s[offset + 6] << 8);
+ }
+#endif
}
}
else if (size < 8)
@@ -755,6 +807,23 @@ Perl_do_vecget(pTHX_ SV *sv, I32 offset, I32 size)
((UV) s[offset + 1] << 16) +
( s[offset + 2] << 8) +
s[offset + 3];
+#ifdef HAS_QUAD
+ else if (size == 64) {
+ dTHR;
+ if (ckWARN(WARN_PORTABLE))
+ Perl_warner(aTHX_ WARN_PORTABLE,
+ "Bit vector size > 32 non-portable");
+ retnum =
+ ((UV) s[offset ] << 56) +
+ ((UV) s[offset + 1] << 48) +
+ ((UV) s[offset + 2] << 40) +
+ ((UV) s[offset + 3] << 32) +
+ ((UV) s[offset + 4] << 24) +
+ ((UV) s[offset + 5] << 16) +
+ ( s[offset + 6] << 8) +
+ s[offset + 7];
+ }
+#endif
}
return retnum;
@@ -800,16 +869,31 @@ Perl_do_vecset(pTHX_ SV *sv)
else {
offset >>= 3; /* turn into byte offset */
if (size == 8)
- s[offset] = lval & 255;
+ s[offset ] = lval & 0xff;
else if (size == 16) {
- s[offset] = (lval >> 8) & 255;
- s[offset+1] = lval & 255;
+ s[offset ] = (lval >> 8) & 0xff;
+ s[offset+1] = lval & 0xff;
}
else if (size == 32) {
- s[offset] = (lval >> 24) & 255;
- s[offset+1] = (lval >> 16) & 255;
- s[offset+2] = (lval >> 8) & 255;
- s[offset+3] = lval & 255;
+ s[offset ] = (lval >> 24) & 0xff;
+ s[offset+1] = (lval >> 16) & 0xff;
+ s[offset+2] = (lval >> 8) & 0xff;
+ s[offset+3] = lval & 0xff;
+ }
+#ifdef HAS_QUAD
+ else if (size == 64) {
+ dTHR;
+ if (ckWARN(WARN_PORTABLE))
+ Perl_warner(aTHX_ WARN_PORTABLE,
+ "Bit vector size > 32 non-portable");
+ s[offset ] = (lval >> 56) & 0xff;
+ s[offset+1] = (lval >> 48) & 0xff;
+ s[offset+2] = (lval >> 40) & 0xff;
+ s[offset+3] = (lval >> 32) & 0xff;
+ s[offset+4] = (lval >> 24) & 0xff;
+ s[offset+5] = (lval >> 16) & 0xff;
+ s[offset+6] = (lval >> 8) & 0xff;
+ s[offset+7] = lval & 0xff;
}
}
SvSETMAGIC(targ);
diff --git a/pod/perldelta.pod b/pod/perldelta.pod
index 90f1729020..26a6450c6b 100644
--- a/pod/perldelta.pod
+++ b/pod/perldelta.pod
@@ -161,19 +161,20 @@ use "quads" (64-integers) as follows:
=item in basic arithmetics
+=item vec() (but see the below note about bit arithmetics)
+
=back
Note that unless you have the case (a) you will have to configure
and compile Perl using the -Duse64bits Configure flag.
-Unfortunately, bit operations (&, <<, ...) and vec() do not work,
-they are limited to 32 bits.
+Unfortunately bit arithmetics (&, |, ^, ~, <<, >>) are not 64-bit clean.
Last but not least: note that due to Perl's habit of always using
-floating point numbers the quads are still not true integers. When
-quads overflow their limits (18446744073709551615 unsigned,
--9223372036854775808...9223372036854775807 signed), they are silently
-promoted to floating point numbers, after which they will
+floating point numbers the quads are still not true integers.
+When quads overflow their limits (0...18_446_744_073_709_551_615 unsigned,
+-9_223_372_036_854_775_808...9_223_372_036_854_775_807 signed), they
+are silently promoted to floating point numbers, after which they will
start losing precision (their lower digits).
=head2 Large file support
diff --git a/pod/perldiag.pod b/pod/perldiag.pod
index 49e654afb5..90439402a8 100644
--- a/pod/perldiag.pod
+++ b/pod/perldiag.pod
@@ -488,6 +488,10 @@ L<perlport> for more on portability concerns.
(W) You tried to do a bind on a closed socket. Did you forget to check
the return value of your socket() call? See L<perlfunc/bind>.
+=item Bit vector size > 32 non-portable
+
+(W) Using bit vector sizes larger than 32 is non-portable.
+
=item Bizarre copy of %s in %s
(P) Perl detected an attempt to copy an internal value that is not copiable.
@@ -1522,7 +1526,7 @@ before the illegal character.
=item Illegal number of bits in vec
(F) The number of bits in vec() (the third argument) must be a power of
-two from 1 to 32.
+two from 1 to 32 (or 64, if your platform supports that).
=item Illegal switch in PERL5OPT: %s
diff --git a/pod/perlfunc.pod b/pod/perlfunc.pod
index 0e4b7c7cc3..25c8efe27c 100644
--- a/pod/perlfunc.pod
+++ b/pod/perlfunc.pod
@@ -4990,15 +4990,18 @@ See also C<keys>, C<each>, and C<sort>.
Treats the string in EXPR as a vector of unsigned integers, and
returns the value of the bit field specified by OFFSET. BITS
specifies the number of bits that are reserved for each entry in the
-bit vector. This must be a power of two from 1 to 32.
+bit vector. This must be a power of two from 1 to 32 (or 64, if your
+platform supports that).
+
C<vec> may also be assigned to, in which case parentheses are needed
to give the expression the correct precedence as in
vec($image, $max_x * $x + $y, 8) = 3;
Vectors created with C<vec> can also be manipulated with the logical
-operators C<|>, C<&>, and C<^>, which will assume a bit vector operation is
-desired when both operands are strings. See L<perlop/"Bitwise String Operators">.
+operators C<|>, C<&>, and C<^>, which will assume a bit vector
+operation is desired when both operands are strings.
+See L<perlop/"Bitwise String Operators">.
The following code will build up an ASCII string saying C<'PerlPerlPerl'>.
The comments show the string after each step. Note that this code works
diff --git a/pp.h b/pp.h
index c35f9677d4..ec701f3054 100644
--- a/pp.h
+++ b/pp.h
@@ -67,7 +67,7 @@
#define POPul ((unsigned long)SvIVx(POPs))
#ifdef HAS_QUAD
#define POPq ((Quad_t)SvIVx(POPs))
-#define POPuq ((Uquad_t)SvIVx(POPs))
+#define POPuq ((Uquad_t)SvUVx(POPs))
#endif
#define TOPs (*sp)
@@ -77,10 +77,10 @@
#define TOPi ((IV)SvIV(TOPs))
#define TOPu ((UV)SvUV(TOPs))
#define TOPl ((long)SvIV(TOPs))
-#define TOPul ((unsigned long)SvIV(TOPs))
+#define TOPul ((unsigned long)SvUV(TOPs))
#ifdef HAS_QUAD
#define TOPq ((Quad_t)SvIV(TOPs))
-#define TOPuq ((Uquad_t)SvIV(TOPs))
+#define TOPuq ((Uquad_t)SvUV(TOPs))
#endif
/* Go to some pains in the rare event that we must extend the stack. */
diff --git a/t/op/64bit.t b/t/op/64bit.t
index 4da3a9e2e8..d35254be24 100644
--- a/t/op/64bit.t
+++ b/t/op/64bit.t
@@ -10,14 +10,14 @@ BEGIN {
# This could use a lot of more tests.
#
-# Nota bene: bit operations (&, |, ^, ~, <<, >>, vec) are not 64-bit clean.
+# Nota bene: bit operations (&, |, ^, ~, <<, >>) are not 64-bit clean.
# See the beginning of pp.c and the explanation next to IBW/UBW.
-# so that using > 0xfffffff constants and 32+ bit
-# shifts and vector sizes doesn't cause noise
-no warning 'overflow';
+# so that using > 0xfffffff constants and
+# 32+ bit vector sizes doesn't cause noise
+no warning qw(overflow portable);
-print "1..36\n";
+print "1..39\n";
my $q = 12345678901;
my $r = 23456789012;
@@ -190,3 +190,14 @@ print "not " unless $a == -9223372036854775809;
print "ok 36\n";
+$x = '';
+print "not " unless (vec($x, 1, 64) = $q) == $q;
+print "ok 37\n";
+
+print "not " unless vec($x, 1, 64) == $q && vec($x, 1, 64) > $f;
+print "ok 38\n";
+
+print "not " unless vec($x, 0, 64) == 0 && vec($x, 2, 64) == 0;
+print "ok 39\n";
+
+# eof