This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
FWD: FLOATING-POINT CONSISTENCY, -FFLOAT-STORE, AND X86 (MOS
- To: burley at gnu dot org, egcs at cygnus dot com
- Subject: FWD: FLOATING-POINT CONSISTENCY, -FFLOAT-STORE, AND X86 (MOS
- From: tprince at cat dot e-mail dot com
- Date: Wed, 02 Dec 1998 12:45:36 EST
-Reply
>>"And, my impression is that the "first solution" is to ensure that
any FP temporaries are spilled only to *like-sized* memory
locations."
At least, double-precision spills are desirable even when all the
variables are single precision. This could apply to some of the
Power-PC ports as well.
>>"In other words, the default for x86 code generation should
apparently
be that, when the compiler generates an intermediate result, it
*always* uses maximum available precision for that result, even
if
it has to spill the result to memory. (I *think* it can do this while
obeying the current FP mode, but don't have time to check right
now.)
Here's an example that illustrates some of the key points:
double a, b, c, d, e;
...
e = a*b + c*d;
The -ffloat-store option controls whether the store into `e'
includes
a "chopping" (truncation or, usually, rounding) to the exact type
specified -- in this case, 64-bit IEEE (double) format."
In the case where e is used in a subsequent calculation, we
don't want to force a store and reload unless -ffloat-store is
invoked. But I'm not sure you can always apply the same rules to
storage to a named variable (it might be stored in a structure or
COMMON block) as to register spills, which aren't visible in the
source code. We might even have a rare case where we are
doing some kind of remaindering, where we need to use the
form which is rounded to the declared format. This is a more
difficult question to solve and I'm confused about what
connection you are making between that and the spilled
temporaries.
The intermediate calculations -- t1=a*b, t2=c*d, and t1+t2 -- are
expressed here as computed in an unspecified precision and
stored into
an undeclared temporary of the same precision, for the
purposes of
discussion.
Typically, t1 and t2 end up as extended precision on the x86,
because
the code just uses the prevailing FP mode (which is set to
"extended",
normally) and the temporaries themselves reside on the x86 FP
stack,
which accommodates extended-precision results. These are, I
believe,
80-bit results (though when stored to memory, 96 bits are
written),
though those specifics are not pertinent to my points here."
I suspect the 96 bits must be written to a 128-bit aligned storage
location to minimize the performance hit.
>>"The problem seems to be that, sometimes, t1 and/or t2 end
up as
*double* precision, because the compiler realizes it can't keep
them on the stack while doing other pending calculations
(assuming
other stuff going on that isn't in the example).
In such a case, either (say) t1=a*b is computed entirely in double
precision, requiring chopping of `a' and `b' into 64-bit doubles
(think t3=(double)a, t4=(double)b, t1=t3*t4) or, more likely (on
the x86 anyway), a*b is computed in extended precision but the
result is chopped down into double when t1 is spilled to
memory.
In that more-likely latter case, at least, the problem is not just
that rounding happens *twice*, but that it happens without *any*
reasonable expectation, predictability, or control on the part of
the programmer who wrote the code."
"But, at least, I think we could make egcs take a big step forward
towards providing *some* degree of predictability by doing the
following:
Ensure that any spills of intermediate calculations are done
in such a way that the *complete* contents of the register being
spilled are preserved and, later, restored.
Right now, for a sample case I (laboriously ;-) made up, it seems
that the above is not currently being done. So, when egcs (g77)
decides it has to spill an FP register to make room for more
intermediate calculations, it chops it into a 64-bit double, which
leads to double roundings and other numerically suspicious
things
(again, especially a problem when the programmer has no
control
over this)."
Including the possibility that the results change as a side effect
of changes in optimization or nearby code.
>> tq vm, (burley)
If someone does manage to implement this, I would like to study
the effect on the complex math functions of libF77, using Cody's
CELEFUNT test suite. I have demonstrated already that the
extended double facility shows to good advantage in the double
complex functions. The single complex functions already
accomplish what we are talking about by using double
declarations for all locals, and that gives them a big advantage
over certain vendors' libraries.
I know I'll arouse the ire of some people again when I point out
that CELEFUNT shows only 4 decimal places accuracy from
some of the functions, when everything is done purely in single
precision, and that a few of the tests show the full gain of 11 bits
of accuracy from pure 53-bit double precision to extended
double.
But if there are people who really depend on the complex math
functions and can show a good reason why they should not be
more accurate, we'll have to pay attention to that. I don't consider
emulating one particular vendor's results a sufficient
consideration, when they all differ from each other, and we have
a recognized test suite as an arbitrator.
Dr. Timothy C. Prince
Consulting Engineer
Solar Turbines, a Caterpillar Company
alternate e-mail: tprince@computer.org
To: INTERNET - IBMMAIL
I5716149 - IBMMAIL