[Mono-list] Concerns regarding interpreter implementation of Compare and Branching instructions w/ Floating Point values

Tom Guinther tomguinther@hotmail.com
Sun, 20 Oct 2002 17:37:40 -0400


This is a multi-part message in MIME format.

------=_NextPart_000_008C_01C2785F.63377400
Content-Type: text/plain;
	charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable

The other day while reading the CLI specification I became a bit =
confused regarding the exact implementation of the compare and branching =
instructions when floating point values are being evaluated.  Being =
aware of, but completely uninvolved with, this project I thought it =
would be interesting to review the "mono" interpretation of the =
specification. Surprisingly I found an implementation that seems =
relatively inconsistent and somewhat bizarre in relation to my (naive?) =
interpretation of the specification. This simply leads me to wonder =
whether the spec is grossly inaccurate, my interpretation is =
off-the-wall, or the Mono implementation is lacking in =
detail/correctness in this area.

Their two fundamental  issues that I wanted to bring up for discussion:
    1) The proper interpretation of CGT.UN(.S) and CLT.UN(.S)
    2) The overall implementation of compare and branching instructions =
w/ floating point values

    Note: The answer to question #1 has little or no bearing on my =
questions related to the existing implementation of the compare and =
branching instructions w/
        floating point values

Just to be explicit, my entire discussion is only related to floating =
point values and therefore I only talk about implementation of the =
instructions with regard to floating-point values and I am extracting =
implementation information from the mono/interpreter/interp.c (which I =
am assuming is not a DEAD file.)


Part 1 - The proper interpretation of CGT.UN(.S) and CLT.UN(.S):

The original question I was pondering was related to implementations of =
CGT.UN(.S) and CLT.UN(.S) where the spec uses the following type of =
wording:
    "for floating-point numbers, either value1 is strictly greater than =
value2, or value1 is not ordered with respect to value2"
contrasted with the wording for the non UN version(s) which explicitly =
state the following:
    "... If value1 is strictly greater than value2, ... for =
floating-point numbers, CGT returns 0 [false] if the numbers are =
unordered (that is, if one or both of the arguments are NaN)"

The explicit wording of the CGT instruction leads to me to the following =
pseudo implementation (CLT is the same, just change the > operator to < =
operator):

    CGT
    ..., F1, F2 =3D> Int32(true=3D1 or false=3D0)

    if isunordered(F1) or isunordered(F2)
        result =3D false ;
    else
        result =3D F1 > F2 ;

    Given the different "wordage" for CGT.UN I concluded that the =
following pseudo implementation was correct. If it is not correct I =
would be extremely happy to receive the correct interpretation. Also, =
the implementation of CLT.UN would be the same except for replacing the =
> operator with the < operator.

    CGT.UN
    ..., F1, F2 =3D> Int32(true=3D1, false=3D0)

    if (isunordered(F1))
        result =3D false ;
    else
        result =3D isunordered(F2) or (F1 > F2)


    Part 2: The overall implementation of compare and branching =
instructions w/ floating point values

    The correct interpretation and implementation of the compare =
instructions is critical to successfully implementing the branch =
instructions. This is because the branch instructions are defined in =
terms of the compare instructions. For completeness sake I want to =
explicitly define pseudo implementation for the remaining compare =
instruction CEQ.

CEQ
..., F1, F2 =3D> Int32(true=3D1, false=3D0)

if isunordered(F1) or isunordered(F2)
    result =3D false ;
else
    result =3D F1 =3D=3D F2 ;


As you might expect, the Mono implementation of CEQ is as follows (and =
seems correct to me):
CEQ:
    if (isnan(F1) || isnan(F2))
        result =3D 0 ;
    else
        result =3D F1 =3D=3D F2

The Mono implementation for CGT(.S), CLT(.S), CGT.UN(.S), CLT.UN(.S) =
follows:
CGT:
CGT.S:
    if (isnan(F1) || isnan(F2))
        result =3D 0 ;
    else
        result =3D F1 > F2

CLT:
CLT.S:
    if (isnan(F1) || isnan(F2))
        result =3D 0 ;
    else
        result =3D F1 < F2

CGT.UN:
    result =3D isnan(F1) || isnan(F2)

CLT.UN:
    result =3D isnan(F1) || isnan(F2)

You may notice that the implementations of CGT.UN and CLT.UN are exactly =
the same and involve NO comparisons. This may be intentional, and if so, =
the CLI specification for these instructions is written very poorly. I =
don't see how the Mono implementation can be correct assuming that the =
designers would not define two opcodes that do the exact same thing and =
imply that some type of comparison is involved when it isn't. Hmmm...

Now to the branching instructions:
    BEQ(.S) is defined as equivalent to:
        CEQ
        BRTRUE

    Which is the equivalent of:
        if isunordered(F1) or isunordered(F2)
            branch =3D false
        else
            branch =3D F1 =3D=3D F2

The Mono implementation of BEQ(.S) is:
    result =3D F1 =3D=3D F2

Clearly, unordered values are not taken into consideration as the =
specification requires.
    BGE(.S) is defined as equivalent to:
        CLT.UN
        BRTRUE

    Which is the equivalent of (according to my possibly errant =
interpretation):
        if isunordered(F1)
            branch =3D true ;
        else
            branch =3D !isunordered(F2) and (F1 >=3D F2)

    The Mono implementation of BGE(.S) is:
        result =3D F1 >=3D F2 ;

   Regardless of interpretation of CLT.UN, Mono is not accounting for =
unordered values.

    And so the list goes on for the branch instructions that are not of =
the .UN form. Unordered values are not properly taken into account =
(based on my understanding).

    The implementation of the B??.UN(.S) instructions are generally of =
the form:
        !isunordered(F1) && !isunordered(F2) and (F1 op F2)

    This may not be the correct implementation (depending on correct =
interpretation of CGT.UN(.S) and CLT.UN(.S)) for:
        BGT.UN(.S) and BLT.UN(.S) since there equivalency is defined in =
terms of CGT.UN(.S) and CLT.UN(.S) respectively while
        BGE.UN(.S) and BLE.UN(.S) are defined in terms of CLT and CGT =
(respectively)


Apologies in advance for the long, incoherent e-mail, but any =
thoughts/answers would be much appreciated.

Tom Guinther



   =20

------=_NextPart_000_008C_01C2785F.63377400
Content-Type: text/html;
	charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML><HEAD>
<META http-equiv=3DContent-Type content=3D"text/html; =
charset=3Diso-8859-1">
<META content=3D"MSHTML 6.00.2600.0" name=3DGENERATOR>
<STYLE></STYLE>
</HEAD>
<BODY bgColor=3D#ffffff>
<DIV><FONT face=3DArial size=3D2>The other day while reading the CLI =
specification I=20
became a bit confused regarding the exact implementation of the compare =
and=20
branching instructions when floating point values are being =
evaluated.&nbsp;=20
Being aware of, but completely uninvolved with, this project I thought =
it would=20
be interesting to review the "mono" interpretation of the specification. =

Surprisingly I found an implementation that seems relatively =
inconsistent and=20
somewhat bizarre in relation to my (naive?) interpretation of the =
specification.=20
This simply leads me to wonder whether the spec is grossly inaccurate, =
my=20
interpretation is off-the-wall, or the Mono implementation is lacking in =

detail/correctness in this area.</FONT></DIV>
<DIV><FONT face=3DArial size=3D2></FONT>&nbsp;</DIV>
<DIV><FONT face=3DArial size=3D2>Their two fundamental&nbsp; issues that =
I wanted to=20
bring up for discussion:</FONT></DIV>
<DIV><FONT face=3DArial size=3D2>&nbsp;&nbsp;&nbsp; 1) The proper =
interpretation of=20
CGT.UN(.S) and CLT.UN(.S)</FONT></DIV>
<DIV><FONT face=3DArial size=3D2>&nbsp;&nbsp;&nbsp; 2) The overall =
implementation of=20
compare and branching instructions w/ floating point values</FONT></DIV>
<DIV><FONT face=3DArial size=3D2></FONT>&nbsp;</DIV>
<DIV><FONT face=3DArial size=3D2>&nbsp;&nbsp;&nbsp; Note: The answer to =
question #1=20
has little or no bearing on my questions related to the existing =
implementation=20
of the compare and branching instructions w/</FONT></DIV>
<DIV><FONT face=3DArial size=3D2>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; =
floating=20
point values</FONT></DIV>
<DIV><FONT face=3DArial size=3D2></FONT>&nbsp;</DIV>
<DIV><FONT face=3DArial size=3D2>Just to be explicit, my entire =
discussion is only=20
related to floating point values and therefore I only talk about =
implementation=20
of the instructions with regard to floating-point values and I am =
extracting=20
implementation information from the mono/interpreter/interp.c (which I =
am=20
assuming is not a DEAD file.)</FONT></DIV>
<DIV>&nbsp;</DIV>
<DIV><FONT face=3DArial size=3D2></FONT>&nbsp;</DIV>
<DIV><FONT face=3DArial size=3D2>Part 1 - The proper interpretation of =
CGT.UN(.S)=20
and CLT.UN(.S):</FONT></DIV>
<DIV><FONT face=3DArial size=3D2></FONT>&nbsp;</DIV>
<DIV><FONT face=3DArial size=3D2>The original question I was pondering =
was related=20
to implementations of CGT.UN(.S) and CLT.UN(.S) where the spec uses the=20
following type of wording:</FONT></DIV>
<DIV><FONT face=3DArial size=3D2>&nbsp;&nbsp;&nbsp; "for floating-point =
numbers,=20
either value1 is strictly greater than value2, or value1 is not ordered =
with=20
respect to value2"</FONT></DIV>
<DIV><FONT face=3DArial size=3D2>contrasted with the wording for the non =
UN=20
version(s) which explicitly state the following:</FONT></DIV>
<DIV><FONT face=3DArial size=3D2>&nbsp;&nbsp;&nbsp; "... If value1 is =
strictly=20
greater than value2, ... for floating-point numbers, CGT returns 0 =
[false] if=20
the numbers are unordered (that is, if one or both of the arguments are=20
NaN)"</FONT></DIV>
<DIV><FONT face=3DArial size=3D2></FONT>&nbsp;</DIV>
<DIV><FONT face=3DArial size=3D2>The explicit wording of the CGT =
instruction leads=20
to me to the following pseudo implementation (CLT is the same, just =
change the=20
&gt; operator to &lt; operator):</FONT></DIV>
<DIV><FONT face=3DArial size=3D2></FONT>&nbsp;</DIV>
<DIV><FONT face=3DArial size=3D2>&nbsp;&nbsp;&nbsp; CGT</FONT></DIV>
<DIV><FONT face=3DArial size=3D2>&nbsp;&nbsp;&nbsp; ..., F1, F2 =3D&gt;=20
Int32(true=3D1&nbsp;or false=3D0)</FONT></DIV>
<DIV><FONT face=3DArial size=3D2></FONT>&nbsp;</DIV>
<DIV><FONT face=3DArial size=3D2>&nbsp;&nbsp;&nbsp; if isunordered(F1) =
or=20
isunordered(F2)</FONT></DIV>
<DIV><FONT face=3DArial size=3D2>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; =
result =3D=20
false ;</FONT></DIV>
<DIV><FONT face=3DArial size=3D2>&nbsp;&nbsp;&nbsp; else</FONT></DIV>
<DIV><FONT face=3DArial size=3D2>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; =
result =3D F1=20
&gt; F2 ;</FONT></DIV>
<DIV><FONT face=3DArial size=3D2></FONT>&nbsp;</DIV>
<DIV><FONT face=3DArial size=3D2>&nbsp;&nbsp;&nbsp; Given the different =
"wordage"=20
for CGT.UN I concluded that the following pseudo implementation was =
correct. If=20
it is not correct I would be extremely happy to receive the correct=20
interpretation. Also, the implementation of CLT.UN would be the same =
except for=20
replacing the &gt; operator with the &lt; operator.</FONT></DIV>
<DIV><FONT face=3DArial size=3D2></FONT>&nbsp;</DIV>
<DIV><FONT face=3DArial size=3D2>&nbsp;&nbsp;&nbsp; CGT.UN</FONT></DIV>
<DIV><FONT face=3DArial size=3D2>&nbsp;&nbsp;&nbsp; ..., F1, F2 =3D&gt; =
Int32(true=3D1,=20
false=3D0)</FONT></DIV>
<DIV><FONT face=3DArial size=3D2></FONT>&nbsp;</DIV>
<DIV><FONT face=3DArial size=3D2>&nbsp;&nbsp;&nbsp; if=20
(isunordered(F1))</FONT></DIV>
<DIV><FONT face=3DArial size=3D2>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; =
result =3D=20
false ;</FONT></DIV>
<DIV><FONT face=3DArial size=3D2>&nbsp;&nbsp;&nbsp; else</FONT></DIV>
<DIV><FONT face=3DArial size=3D2>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; =
result =3D=20
isunordered(F2) or (F1 &gt; F2)</FONT></DIV>
<DIV><FONT face=3DArial size=3D2></FONT>&nbsp;</DIV>
<DIV><FONT face=3DArial size=3D2></FONT>&nbsp;</DIV>
<DIV><FONT face=3DArial size=3D2>&nbsp;&nbsp;&nbsp; Part 2: The overall=20
implementation of compare and branching instructions w/ floating point=20
values</FONT></DIV>
<DIV><FONT face=3DArial size=3D2></FONT>&nbsp;</DIV>
<DIV><FONT face=3DArial size=3D2>&nbsp;&nbsp;&nbsp; The correct =
interpretation and=20
implementation of the compare instructions is critical to successfully=20
implementing the branch instructions. This is because the branch =
instructions=20
are defined in terms of the compare instructions. For completeness sake =
I want=20
to explicitly define pseudo implementation for the remaining compare =
instruction=20
CEQ.</FONT></DIV>
<DIV><FONT face=3DArial size=3D2></FONT>&nbsp;</DIV>
<DIV><FONT face=3DArial size=3D2>CEQ</FONT></DIV>
<DIV><FONT face=3DArial size=3D2>..., F1, F2 =3D&gt; Int32(true=3D1,=20
false=3D0)</FONT></DIV>
<DIV><FONT face=3DArial size=3D2></FONT>&nbsp;</DIV>
<DIV><FONT face=3DArial size=3D2>if isunordered(F1) or =
isunordered(F2)</FONT></DIV>
<DIV><FONT face=3DArial size=3D2>&nbsp;&nbsp;&nbsp; result =3D false =
;</FONT></DIV>
<DIV><FONT face=3DArial size=3D2>else</FONT></DIV>
<DIV><FONT face=3DArial size=3D2>&nbsp;&nbsp;&nbsp; result =3D F1 =3D=3D =
F2 ;</FONT></DIV>
<DIV><FONT face=3DArial size=3D2></FONT>&nbsp;</DIV>
<DIV><FONT face=3DArial size=3D2></FONT>&nbsp;</DIV>
<DIV><FONT face=3DArial size=3D2>As you might expect, the Mono =
implementation of CEQ=20
is as follows (<FONT face=3DArial size=3D2>and seems correct to=20
me)</FONT>:</FONT></DIV>
<DIV><FONT face=3DArial size=3D2>CEQ:</FONT></DIV>
<DIV><FONT face=3DArial size=3D2>&nbsp;&nbsp;&nbsp; if (isnan(F1) ||=20
isnan(F2))</FONT></DIV>
<DIV><FONT face=3DArial size=3D2>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; =
result =3D 0=20
;</FONT></DIV>
<DIV><FONT face=3DArial size=3D2>&nbsp;&nbsp;&nbsp; else</FONT></DIV>
<DIV><FONT face=3DArial size=3D2>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; =
result =3D F1=20
=3D=3D F2</FONT></DIV>
<DIV><FONT face=3DArial size=3D2></FONT>&nbsp;</DIV>
<DIV><FONT face=3DArial size=3D2>The Mono implementation for CGT(.S), =
CLT(.S),=20
CGT.UN(.S), CLT.UN(.S) follows:</FONT></DIV>
<DIV><FONT face=3DArial size=3D2>CGT:</FONT></DIV>
<DIV><FONT face=3DArial size=3D2>CGT.S:</FONT></DIV><FONT face=3DArial =
size=3D2>
<DIV><FONT face=3DArial size=3D2>&nbsp;&nbsp;&nbsp; if (isnan(F1) ||=20
isnan(F2))</FONT></DIV>
<DIV><FONT face=3DArial size=3D2>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; =
result =3D 0=20
;</FONT></DIV>
<DIV><FONT face=3DArial size=3D2>&nbsp;&nbsp;&nbsp; else</FONT></DIV>
<DIV><FONT face=3DArial size=3D2>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; =
result =3D=20
F1&nbsp;&gt; F2</FONT></DIV>
<DIV>&nbsp;</DIV>
<DIV>CLT:</DIV>
<DIV>CLT.S:</DIV>
<DIV>
<DIV><FONT face=3DArial size=3D2>&nbsp;&nbsp;&nbsp; if (isnan(F1) ||=20
isnan(F2))</FONT></DIV>
<DIV><FONT face=3DArial size=3D2>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; =
result =3D 0=20
;</FONT></DIV>
<DIV><FONT face=3DArial size=3D2>&nbsp;&nbsp;&nbsp; else</FONT></DIV>
<DIV><FONT face=3DArial size=3D2>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; =
result =3D=20
F1&nbsp;&lt; F2</FONT></DIV></DIV>
<DIV>&nbsp;</DIV>
<DIV>CGT.UN:</DIV>
<DIV>&nbsp;&nbsp;&nbsp; result =3D isnan(F1) || isnan(F2)</DIV>
<DIV>&nbsp;</DIV>
<DIV>CLT.UN:</DIV>
<DIV>&nbsp;&nbsp;&nbsp; result =3D isnan(F1) || isnan(F2)</DIV>
<DIV>&nbsp;</DIV>
<DIV>You may notice that the implementations of CGT.UN and CLT.UN are =
exactly=20
the same and involve NO comparisons. This may be intentional, and if so, =
the CLI=20
specification for these instructions is written very poorly. I don't see =
how the=20
Mono implementation can be correct assuming that the designers would not =
define=20
two opcodes that do the exact same thing and imply that some type of =
comparison=20
is involved when it isn't. Hmmm...</DIV>
<DIV>&nbsp;</DIV>
<DIV>Now to the branching instructions:</DIV>
<DIV>&nbsp;&nbsp;&nbsp; BEQ(.S) is defined as equivalent to:</DIV>
<DIV>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CEQ</DIV>
<DIV>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; BRTRUE</DIV>
<DIV>&nbsp;</DIV>
<DIV>&nbsp;&nbsp;&nbsp; Which is the equivalent of:</DIV>
<DIV>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if isunordered(F1) or=20
isunordered(F2)</DIV>
<DIV>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; =
branch =3D=20
false</DIV>
<DIV>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; else</DIV>
<DIV>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; branch =3D =
F1 =3D=3D=20
F2</DIV>
<DIV>&nbsp;</DIV>
<DIV>The Mono implementation of BEQ(.S) is:</DIV>
<DIV>&nbsp;&nbsp;&nbsp; result =3D F1 =3D=3D F2</DIV>
<DIV>&nbsp;</DIV>
<DIV>Clearly, unordered values are not taken into consideration as the=20
specification requires.</DIV>
<DIV>&nbsp;&nbsp;&nbsp; BGE(.S) is defined as equivalent to:</DIV>
<DIV>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; CLT.UN</DIV>
<DIV>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; BRTRUE</DIV>
<DIV>&nbsp;</DIV>
<DIV>&nbsp;&nbsp;&nbsp; Which is the equivalent of (according to my =
possibly=20
errant interpretation):</DIV>
<DIV>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if isunordered(F1)</DIV>
<DIV>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; branch =3D =
true=20
;</DIV>
<DIV>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; else</DIV>
<DIV>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; branch =3D =

!isunordered(F2)&nbsp;and (F1 &gt;=3D F2)</DIV>
<DIV>&nbsp;</DIV>
<DIV>&nbsp;&nbsp;&nbsp; The Mono implementation of BGE(.S) is:</DIV>
<DIV>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; result =3D F1 &gt;=3D F2 =
;</DIV>
<DIV>&nbsp;</DIV>
<DIV>&nbsp;&nbsp;&nbsp;Regardless of interpretation of CLT.UN, Mono is =
not=20
accounting for unordered values.</DIV>
<DIV>&nbsp;</DIV>
<DIV>&nbsp;&nbsp;&nbsp; And so the list goes on for the branch =
instructions that=20
are not of the .UN form. Unordered values are not properly taken into =
account=20
(based on my understanding).</DIV>
<DIV>&nbsp;</DIV>
<DIV>&nbsp;&nbsp;&nbsp; The implementation of the B??.UN(.S) =
instructions are=20
generally of the form:</DIV>
<DIV>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; !isunordered(F1) &amp;&amp;=20
!isunordered(F2) and (F1 op F2)</DIV>
<DIV>&nbsp;</DIV>
<DIV>&nbsp;&nbsp;&nbsp; This may not be the correct implementation =
(depending on=20
correct interpretation of&nbsp;CGT.UN(.S) and CLT.UN(.S)) for:</DIV>
<DIV>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BGT.UN(.S) and =
BLT.UN(.S) since=20
there equivalency is defined in terms of CGT.UN(.S) and CLT.UN(.S) =
respectively=20
while</DIV>
<DIV>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; BGE.UN(.S) and BLE.UN(.S) are =
defined=20
in terms of CLT and CGT (respectively)</DIV>
<DIV>&nbsp;</DIV>
<DIV>&nbsp;</DIV>
<DIV>Apologies in advance for the long, incoherent e-mail, but any=20
thoughts/answers would be much appreciated.</DIV>
<DIV>&nbsp;</DIV>
<DIV>Tom Guinther</DIV>
<DIV>&nbsp;</DIV>
<DIV>&nbsp;</DIV>
<DIV>&nbsp;</DIV>
<DIV>&nbsp;&nbsp;&nbsp; </FONT></DIV></BODY></HTML>

------=_NextPart_000_008C_01C2785F.63377400--