From: David Mitchell Date: Mon, 21 Mar 2011 14:14:52 +0000 (+0000) Subject: pack test failures with long doubles on x86/gcc X-Git-Tag: accepted/trunk/20130322.191538~4842 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=cd07c537987a76c934f141ca5bc0309e5a6b2609;p=platform%2Fupstream%2Fperl.git 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. --- diff --git a/pp_pack.c b/pp_pack.c index be9b115..5229fc3 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)); }