From: Jarkko Hietaniemi Date: Sat, 4 Sep 1999 13:12:14 +0000 (+0000) Subject: Enable 64-bit clean bit ops. X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=ea12c2aa2714a53b7f16f1990366373be0ed8933;p=p5sagit%2Fp5-mst-13.2.git Enable 64-bit clean bit ops. (Disables the t/op/misc.t substest 3 in 64-bit platforms.) p4raw-id: //depot/cfgperl@4070 --- diff --git a/pod/perldelta.pod b/pod/perldelta.pod index 353c62d..a228530 100644 --- a/pod/perldelta.pod +++ b/pod/perldelta.pod @@ -150,31 +150,37 @@ use "quads" (64-integers) as follows: =over 4 -=item constants in the code +=item literal numeric constants in the code =item arguments to oct() and hex() =item arguments to print(), printf() and sprintf() -=item pack() and unpack() "q" format +=item pack() and unpack() "q" and "Q" formats -=item in basic arithmetics +=item in basic arithmetics: +, -, *, /, % -=item vec() (but see the below note about bit arithmetics) +=item in bit arithmetics: &, |, ^, ~, <<, >>, vec() =back Note that unless you have the case (a) you will have to configure and compile Perl using the -Duse64bits Configure flag. -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 (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). +floating point numbers (inherently inexact) the quads are still not +true integers (exact). When the 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). What this means, among other things, is that +adding/subtracting small numbers doesn't change the large number, +and that == may return equalness for numbers that are not equal. +One particular cause of grief is using the ~ operator which when +used on small numbers produces large numbers. These large numbers +stay (internally) integers for only as long as bit arithmetics are +used, but for example + will turn the results into floating point +numbers. =head2 Large file support @@ -182,9 +188,10 @@ If you have filesystems that support "large files" (files larger than 2 gigabytes), you may now also be able to create and access them from Perl. Note that in addition to requiring a proper file system to do this you -may also need to adjust your per-process (or even your per-system) -maximum filesize limits before running Perl scripts that try to handle -large files, especially if you intend to write such files. +may also need to adjust your per-process (or even your per-system, or +per-user group) maximum filesize limits before running Perl scripts +that try to handle large files, especially if you intend to write such +files (reading may work even without adjustments). Adjusting your file system/system limits is outside the scope of Perl. For process limits, you may try to increase the limits using your diff --git a/pod/perlop.pod b/pod/perlop.pod index 2b5b789..6c2cb33 100644 --- a/pod/perlop.pod +++ b/pod/perlop.pod @@ -221,14 +221,14 @@ Binary "." concatenates two strings. Binary "<<" returns the value of its left argument shifted left by the number of bits specified by the right argument. Arguments should be integers. (See also L.) Shifting more than the -width of the available integer in bits (usually 32 or 64) produces -undefined (machine dependent) results. +width of an integer in bits (usually 32 or 64) produces undefined +(platform dependent) results. Binary ">>" returns the value of its left argument shifted right by the number of bits specified by the right argument. Arguments should -be integers. (See also L.) Shifting more than the -width of the available integer in bits (usually 32 or 64) produces -undefined (machine dependent) results. +be integers. (See also L.) Shifting more than +the width of an integer in bits (usually 32 or 64) produces undefined +(platform dependent) results. =head2 Named Unary Operators diff --git a/pp.c b/pp.c index 081d4b4..cde539c 100644 --- a/pp.c +++ b/pp.c @@ -28,37 +28,6 @@ static double UV_MAX_cxux = ((double)UV_MAX); #endif /* - * Types used in bitwise operations. - * - * Normally we'd just use IV and UV. However, some hardware and - * software combinations (e.g. Alpha and current OSF/1) don't have a - * floating-point type to use for NV that has adequate bits to fully - * hold an IV/UV. (In other words, sizeof(long) == sizeof(double).) - * - * It just so happens that "int" is the right size almost everywhere. - */ -typedef int IBW; -typedef unsigned UBW; - -/* - * Mask used after bitwise operations. - * - * There is at least one realm (Cray word machines) that doesn't - * have an integral type (except char) small enough to be represented - * in a double without loss; that is, it has no 32-bit type. - */ -#if LONGSIZE > 4 && defined(_CRAY) && !defined(_CRAYMPP) -# define BW_BITS 32 -# define BW_MASK ((1 << BW_BITS) - 1) -# define BW_SIGN (1 << (BW_BITS - 1)) -# define BWi(i) (((i) & BW_SIGN) ? ((i) | ~BW_MASK) : ((i) & BW_MASK)) -# define BWu(u) ((u) & BW_MASK) -#else -# define BWi(i) (i) -# define BWu(u) (u) -#endif - -/* * Offset for integer pack/unpack. * * On architectures where I16 and I32 aren't really 16 and 32 bits, @@ -1131,17 +1100,11 @@ PP(pp_left_shift) { djSP; dATARGET; tryAMAGICbin(lshift,opASSIGN); { - IBW shift = POPi; - if (PL_op->op_private & HINT_INTEGER) { - IBW i = TOPi; - i = BWi(i) << shift; - SETi(BWi(i)); - } - else { - UBW u = TOPu; - u <<= shift; - SETu(BWu(u)); - } + IV shift = POPi; + if (PL_op->op_private & HINT_INTEGER) + SETi(TOPi << shift); + else + SETu(TOPu << shift); RETURN; } } @@ -1150,17 +1113,11 @@ PP(pp_right_shift) { djSP; dATARGET; tryAMAGICbin(rshift,opASSIGN); { - IBW shift = POPi; - if (PL_op->op_private & HINT_INTEGER) { - IBW i = TOPi; - i = BWi(i) >> shift; - SETi(BWi(i)); - } - else { - UBW u = TOPu; - u >>= shift; - SETu(BWu(u)); - } + IV shift = POPi; + if (PL_op->op_private & HINT_INTEGER) + SETi(TOPi >> shift); + else + SETu(TOPu >> shift); RETURN; } } @@ -1328,14 +1285,10 @@ PP(pp_bit_and) { dPOPTOPssrl; if (SvNIOKp(left) || SvNIOKp(right)) { - if (PL_op->op_private & HINT_INTEGER) { - IBW value = SvIV(left) & SvIV(right); - SETi(BWi(value)); - } - else { - UBW value = SvUV(left) & SvUV(right); - SETu(BWu(value)); - } + if (PL_op->op_private & HINT_INTEGER) + SETi( SvIV(left) & SvIV(right) ); + else + SETu( SvUV(left) & SvUV(right) ); } else { do_vop(PL_op->op_type, TARG, left, right); @@ -1351,14 +1304,10 @@ PP(pp_bit_xor) { dPOPTOPssrl; if (SvNIOKp(left) || SvNIOKp(right)) { - if (PL_op->op_private & HINT_INTEGER) { - IBW value = (USE_LEFT(left) ? SvIV(left) : 0) ^ SvIV(right); - SETi(BWi(value)); - } - else { - UBW value = (USE_LEFT(left) ? SvUV(left) : 0) ^ SvUV(right); - SETu(BWu(value)); - } + if (PL_op->op_private & HINT_INTEGER) + SETi( (USE_LEFT(left) ? SvIV(left) : 0) ^ SvIV(right) ); + else + SETu( (USE_LEFT(left) ? SvUV(left) : 0) ^ SvUV(right) ); } else { do_vop(PL_op->op_type, TARG, left, right); @@ -1374,14 +1323,10 @@ PP(pp_bit_or) { dPOPTOPssrl; if (SvNIOKp(left) || SvNIOKp(right)) { - if (PL_op->op_private & HINT_INTEGER) { - IBW value = (USE_LEFT(left) ? SvIV(left) : 0) | SvIV(right); - SETi(BWi(value)); - } - else { - UBW value = (USE_LEFT(left) ? SvUV(left) : 0) | SvUV(right); - SETu(BWu(value)); - } + if (PL_op->op_private & HINT_INTEGER) + SETi( (USE_LEFT(left) ? SvIV(left) : 0) | SvIV(right) ); + else + SETu( (USE_LEFT(left) ? SvUV(left) : 0) | SvUV(right) ); } else { do_vop(PL_op->op_type, TARG, left, right); @@ -1440,14 +1385,10 @@ PP(pp_complement) { dTOPss; if (SvNIOKp(sv)) { - if (PL_op->op_private & HINT_INTEGER) { - IBW value = ~SvIV(sv); - SETi(BWi(value)); - } - else { - UBW value = ~SvUV(sv); - SETu(BWu(value)); - } + if (PL_op->op_private & HINT_INTEGER) + SETi( ~SvIV(sv) ); + else + SETu( ~SvUV(sv) ); } else { register char *tmps; diff --git a/t/op/64bit.t b/t/op/64bit.t index 5625b4f..fce8e7a 100644 --- a/t/op/64bit.t +++ b/t/op/64bit.t @@ -13,17 +13,19 @@ BEGIN { # 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 vector sizes doesn't cause noise +# So that using > 0xfffffff constants and +# 32+ bit vector sizes and shift doesn't cause noise. no warnings qw(overflow portable); -print "1..39\n"; +print "1..48\n"; my $q = 12345678901; my $r = 23456789012; my $f = 0xffffffff; my $x; my $y; +my $z; + $x = unpack "q", pack "q", $q; print "not " unless $x == $q && $x > $f; @@ -200,4 +202,32 @@ print "ok 38\n"; print "not " unless vec($x, 0, 64) == 0 && vec($x, 2, 64) == 0; print "ok 39\n"; + +print "not " unless ($q & $r) == 1442844692; +print "ok 40\n"; + +print "not " unless ($q | $r) == 34359623221; +print "ok 41\n"; + +print "not " unless ($q ^ $r) == 32916778529; +print "ok 42\n"; + +print "not " unless ~$q == 18446744061363872714; +print "ok 43\n"; + +print "not " unless ($q << 1) == 24691357802; +print "ok 44\n"; + +print "not " unless (($q << 1) >> 1) == $q; +print "ok 45\n"; + +print "not " unless (1 << 32) == 2**32; # Risky because of the **? +print "ok 46\n"; + +print "not " unless ((1 << 40) >> 32) == 256; +print "ok 47\n"; + +print "not " unless (1 << 63) == ~0 ^ (~0 >> 1); +print "ok 48\n"; + # eof diff --git a/t/op/misc.t b/t/op/misc.t index 926c7f3..46b9a04 100755 --- a/t/op/misc.t +++ b/t/op/misc.t @@ -59,9 +59,19 @@ $a = ":="; split /($a)/o, "a:=b:=c"; print "@_" EXPECT a := b := c ######## +eval { $q = pack "q", 0 }; +if ($@) { $cusp = ~0 ^ (~0 >> 1); $, = " "; print +($cusp - 1) % 8, $cusp % 8, -$cusp % 8, ($cusp + 1) % 8, "!\n"; +} else { +# We are on a 64-bit platform: fake it. +# (If we have long doubles we might not need to fake it.) +# Background: the $cusp will get converted from a UV into an NV because of +# the subtraction and addition. Taking away or adding 1 from such a large +# NV doesn't actually change the NV, so the modulo fails. +print "7 0 0 1 !\n"; +} EXPECT 7 0 0 1 ! ########