Real.maxFinite and friends

Matthew Fluet fluet@CS.Cornell.EDU
Fri, 5 Oct 2001 08:53:53 -0400 (EDT)


I made Real.maxFinite and friends constants stored in
src/runtime/basis/Real_const.S.  Now the
src/basis-library/misc/primitive.sml has declarations of the form
val maxFinite = _ffi "Real_maxFinite": real;
and src/basis-library/real/real.sml just inherits the values from
Primitive.Real.  I copied the code to calculated these constants into
src/regression/real7.sml.  The only hackery in that move is that outside
the pre-basis, I don't have access to isPositive as an ffi (although I
guess I could explicitly import it with _ffi "isPositive").  So I
implemented it as
val isPositive = fn r => (isNormal r; r > 0,0)
which is a total hack, but works.  Interestingly, SML/NJ suffers from the
same problem and the same hack works for them.  Also, compiling with
-ieee-fp true produces the correct result, so at least that is working.

So, this leads to some questions about what happens when isNormal and
isFinite are made primitives.  I currently don't have a natural way of
forcing a value out of a register at the point where I translate
primitives.  And, for the most part, that isn't completely necessary.
What I imagine I would do would be to translate isNormal(X) is to copy X
to a temporary location then access the high word of the temporary
location.  That will force the float to be written to memory and then read
into a gpr; but it may well leave X in the floating point register if
there are future uses.  This means I could imagine the following program:

val r = Real.minNormalPos / 3.0
val b1 = Real.isNormal r
val b2 = Real.>(r, 0.0)
val b3 = Real.<(r, Real.minNormalPos)
val b = b1 andalso b2 andalso b3
val _ = print ((Bool.toString b) ^ "\n")

would print true.  It currently prints true if you move Real.isNormal to
be the last test.

Here is an even stranger example:

val r = Real.minNormalPos / 3.0
val b1 = Real.==(0.0, r)
val _ = print ((Bool.toString b1) ^ "\n")
val b2 = Real.==(0.0, r)
val _ = print ((Bool.toString b2) ^ "\n")

I can justify outputs of (true, true), (false, true), (false, false).
(true, true) is the correct result, according to the Basis Library, which
MLton produces with -ieee-fp.  (false, true) is what MLton (and SML/NJ)
currently produces, which is explained by the fact that the value r is
stored to memory during the non-tail and C calls that make up the print
expression, and is fetched back for the second Real.==.  I would expect
(false, false) to be reasonable output of MLton after commonSubexp has
been moved to SSA, because the second Real.== will just inherit the value
computed by the first.  (This isn't done by the current commonSubexp
because the two Real.== are in different scopes.)

Thoughts?  Comments?