This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: FLOATING-POINT CONSISTENCY, -FFLOAT-STORE, AND X86


>T: For a single-precision calculation, performing the register spills in
>double would provide enough extra precision, without significant impact on
>performance, if aligned storage can be used.

Perhaps, though I'm still concerned about *any* "visible" effects
on the results of computations resulting from internal compiler
decisions about whether and when to spill values.  So if spilling
80-bit values to 64-bit values cannot possibly change the resulting
calculations (of a reasonably working program of course!), fine,
otherwise, I'd rather have it played safe as a default.

>T: There's some uncertainty here, where the desire to maintain performance
>causes us to keep the extra precision, although the programmer might
>conceivably not want it.  In order to turn it off in a "fine-grained" manner,
>the programmer must program in a "float-store" which I do by invoking an
>external function which returns the rounded-off value (can't be in-lined).

Yup, and it'd be nice to offer more formal, documented facilities for
this sort of thing someday.

>T: I think what you are getting at is that it's usually acceptable for the
>results to be calculated in the declared precision; extra precision is usually
>desirable, but unpredictable combinations of extra precision and no extra
>precision may be disastrous.  See Kahan's writings about the quadratic
>formula.  Your proposal would make an improvement here.

That feedback is helpful, and does seem to reflect what I was trying to
say originally.  (I haven't seen Kahan's writings, or at least very little
of them, at this point.)

>>C: REAL*16 seems to be asked for fairly often.)
>
>T:  Probably by people who don' t recognize how much performance hit the Intel
>processors will take going from REAL*10 to REAL*16.  If the Lahey/Fuji f95
>compiler gets the alignment problems fixed so that REAL(kind=8) returns to
>good performance, I think this will become more evident.

I think a substantial portion of the audience asking for REAL*16 is
*non-Intel*.  SPARC and Alpha people come to mind.  I agree that those
who want enough extra precision to more reliably compute 64-bit results
from 64-bit inputs would likely prefer the faster, native support
provided by REAL*10 on Intel, and ideally "we" (g77/egcs/whatever) would
be able to provide REAL*10 somewhat faster than REAL*16 on other machines
as well, even though, unlike on Intels, the REAL*10 would be emulated.

>>C:  Probably.  But we're not even at 64-bit aligned storage for stack
> variables (which is where spills must happen, for the most part) yet,
> and IMO code that requires FP spills, on the x86 anyway, is probably
> not going to notice the lack of alignment due to its complexity.
>
>T:  I believe that i686-pc-linux-gnulibc1 is trying with some success to do
>aligned spills, and that that's the reason why -O2 is often faster running
>than -Os on that target, while -O2 is slower than -Os on the same code on the
>targets which don't have double alignments on the stack.

I don't think aligned spills happen reliably at all on any *released*
version of egcs or gcc yet (well, except maybe for old versions of
gcc patched with those big g77 patches that *seemed* to do most of the
aligned-double thing).  But it looks like egcs 1.2 or 1.3 will align
doubles on the stack, covering spills, at or near a rock-solid level
of reliability.

>T: The improvement in accuracy depends on getting extended precision results
>from built-in math functions, so it would require a math-inline option as well
>as the 80-bit register spills.  I don't know whether it can be done
>effectively say by taking care to make the math-inline headers of libc6 more
>reliable.

That's definitely off my radar at the moment, but, certainly, if the
compiler decides to call library (or inline) functions for constructs
not explicitly, in the code, involving such calls, and those functions
are not 80-bit, the result might indeed be similar to spilling to 64-bit
values in that the programmer doesn't expect a sudden loss of precision
there.

I'm thinking, for example, of complex divides, which g77 implements
by avoiding the back end's version and going straight for c_div (or
whatever) in libF77, to support a larger domain of inputs with
greater accuracy.

Though, in this example, the loss of precision is a bit easier to
predict: it currently happens for complex divides.  Someday, though,
we might decide to have it apply to complex multiplies, and/or it
might be desirable to have the compiler choose, based on less visible
data (than the source code) to do a call rather than in-line the code.
It's important to preserve the precision in such cases.

(I think most of the above was hand-waved by me, originally, when
I said something like "There's probably *lots* of things not quite
right with how the Intel does floating point", but if I didn't include
egcs/gcc/g77 along with the Intel as at least *possible* culprits, I
should have.)

>T:  That might be too much to expect.  It's true that there could be
>situations where adding code might cause a named variable to be spilled to its
>declared precision where a simpler version used extended precision, but I
>doubt it's feasible to prevent that.  I'll suggest a less ambitious goal:
>that the recognition of common sub-expressions should not lead to reduced
>precision:
>
>	a = b*c + d*e
>	f = d*e*g + h
>
>If the compiler decides to treat d*e as a common sub-expression, in order to
>save an operation, but then finds that this expression needs to spill, that
>spill and restore should be full precision.  Otherwise, we get back to the
>unpredictable situations.

Nothing about the above sounds wrong to me, but I don't really know enough
to say for sure whether I think it all makes sense, I'm afraid.

> >C: P.S. Most, if not all of this, is the result of widespread disagreement
> over what a simple type declaration like `REAL*8 A' or `double a;' really
> means.  The simple view is "it means that the variable must be capable
> of holding the specified precision", but so many people really expect
> it to mean so much more, in terms of whether operations on the variable
> may, might, or must involve more precision, etc.  And, since the
> predominant languages give those people no straightforward way to express
> what they *do* really want, how surprising is it that they "overload" the
> "simple" view of what a type definition really means?
>  >>
>
>T: This is getting off-topic.  I might think that f90 declarations like
>
>	a = REAL(selected_real_kind(15))
>	b = REAL(selected_real_kind(18))
>
>could allow the programmer to express intent in more detail while retaining
>portability, but I don't think any existing compilers implement this in a
>useful way.

It is a bit off-topic in this particular thread, but I was pointing out
a general rule about how we design languages and features.  If we don't
give users an *explicit* way to say *exactly* what they mean, they will
tend to discover ways to *effect* that meaning and, not only that, will
grow to define those ways as *meaning* what we didn't give them in
the first place.  That's usually a problem, because those ways usually
mean something *else* as well, and separating those meanings, once
established in the minds of the user base, becomes very difficult.

We should remember this when designing new features, new option names,
and so on.  Either focus on the *intent* consistently, or the
*implementation* consistently, but don't mush them together (as
was incorrectly done when naming the `-ffloat-store' option, IMO),
for example.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]