summaryrefslogtreecommitdiff
path: root/pp_pack.c
diff options
context:
space:
mode:
authorDavid Mitchell <davem@iabyn.com>2011-03-21 14:14:52 +0000
committerDavid Mitchell <davem@iabyn.com>2011-03-21 14:30:20 +0000
commitcd07c537987a76c934f141ca5bc0309e5a6b2609 (patch)
treee874b1968d5f287ff655a6517abeabff306926ab /pp_pack.c
parentc34fab5fe3b5d2b8932d2f199a30b80c85950b75 (diff)
downloadperl-cd07c537987a76c934f141ca5bc0309e5a6b2609.tar.gz
pack test failures with long doubles on x86/gcc
[perl #86534] When using 80-bit extended precision floats, gcc-generated code can sometimes copy 10 bytes and sometimes 12. This can lead to 2 random bytes something appearing in the output of pack('F') and pack('D'). Work around this by using sv_2nv() rather than SvNV() (which expands to (SvNOK(sv) ? SvNVX(sv) : sv_2nv(sv) ) The basic issue is that the NV return value of a function is returned in a floating point register, which is then written to memory as 10 bytes, whereas a direct assignment, e.g. NV nv1 = nv2, is done by a 12-byte memory copy. However, when the sv_2nv() function is called as part of the ?: expression, its returned value is written as *10* bytes to a temp location on the stack, which is then copied as a *12* byte value to its final destination, picking up 2 bytes of random data from the stack, which then appears in the output of pack(), and ultimately leads to a test failure.
Diffstat (limited to 'pp_pack.c')
-rw-r--r--pp_pack.c10
1 files changed, 10 insertions, 0 deletions
diff --git a/pp_pack.c b/pp_pack.c
index be9b11580b..5229fc345e 100644
--- a/pp_pack.c
+++ b/pp_pack.c
@@ -3184,7 +3184,12 @@ extern const double _double_constants[];
Zero(&anv, 1, NV); /* can be long double with unused bits */
while (len-- > 0) {
fromstr = NEXTFROM;
+#ifdef __GNUC__
+ /* to work round a gcc/x86 bug; don't use SvNV */
+ anv.nv = sv_2nv(fromstr);
+#else
anv.nv = SvNV(fromstr);
+#endif
DO_BO_PACK_N(anv, NV);
PUSH_BYTES(utf8, cur, anv.bytes, sizeof(anv.bytes));
}
@@ -3197,7 +3202,12 @@ extern const double _double_constants[];
Zero(&aldouble, 1, long double);
while (len-- > 0) {
fromstr = NEXTFROM;
+# ifdef __GNUC__
+ /* to work round a gcc/x86 bug; don't use SvNV */
+ aldouble.ld = (long double)sv_2nv(fromstr);
+# else
aldouble.ld = (long double)SvNV(fromstr);
+# endif
DO_BO_PACK_N(aldouble, long double);
PUSH_BYTES(utf8, cur, aldouble.bytes, sizeof(aldouble.bytes));
}