Thread overview
Setting the FPU control word?
Mar 10, 2008
Bill Baxter
Mar 10, 2008
Neil Vice
Mar 11, 2008
Bill Baxter
Mar 11, 2008
Bill Baxter
Mar 11, 2008
Neil Vice
Mar 11, 2008
Bill Baxter
Mar 11, 2008
Bill Baxter
Mar 12, 2008
Don Clugston
March 10, 2008
Anyone know how to translate these instructions to D? (specifically DMD/Win flavor of D, but GDC/Win also appreciated if different):

   http://www.cs.cmu.edu/~quake/robust.pc.html

--bb
March 10, 2008
"Bill Baxter" <dnewsgroup@billbaxter.com> wrote in message news:fr3k2f$30b5$1@digitalmars.com...
> Anyone know how to translate these instructions to D? (specifically DMD/Win flavor of D, but GDC/Win also appreciated if different):
>
>    http://www.cs.cmu.edu/~quake/robust.pc.html
>
> --bb

Something along the following lines seems to do the trick, by which I mean it compiles in 2.012 though I believe the syntax should be compatible with D1:

enum FPPrecision : short
{
    Single = 4210,
    Double = 4722
}

void setFPCtrlWord(FPPrecision precision)
{
    asm
    {
        fldcw precision;
    }
}

Having said that it might be advisable to use 'fstcw' and bitwise operations to alter the specifics of the control-word that you require:

http://www.website.masmforum.com/tutorials/fptute/fpuchap3.htm#fldcw


March 10, 2008
"Bill Baxter" <dnewsgroup@billbaxter.com> wrote in message news:fr3k2f$30b5$1@digitalmars.com...
> Anyone know how to translate these instructions to D? (specifically DMD/Win flavor of D, but GDC/Win also appreciated if different):
>
>    http://www.cs.cmu.edu/~quake/robust.pc.html
>
> --bb

Would std.c.fenv (or tango.stdc.fenv, same module) be of any use here?


March 11, 2008
Jarrett Billingsley wrote:
> "Bill Baxter" <dnewsgroup@billbaxter.com> wrote in message news:fr3k2f$30b5$1@digitalmars.com...
>> Anyone know how to translate these instructions to D? (specifically DMD/Win flavor of D, but GDC/Win also appreciated if different):
>>
>>    http://www.cs.cmu.edu/~quake/robust.pc.html
>>
>> --bb
> 
> Would std.c.fenv (or tango.stdc.fenv, same module) be of any use here? 

Ah, fsetprec(FE_DOUBLE) does indeed seem to be intended to be the thing.

Except, it doesn't work.  The asm fldcw thing does seem to work though.


----
module fpctrl;
import std.c.fenv;
import std.stdio;

enum FPPrecision : short
{
    Single = 0x0000,
    Double = 0x0200,
    Real = 0x0300,
    Mask = 0x0300,
}

void setFPControlWord(FPPrecision precision)
{
    FPPrecision oldcw;

    asm
    {
        fstcw oldcw;
        fwait;
        fldcw precision;
    }
    writefln("oldcw was: 0x%x", oldcw);


}

void main()
{
    fesetround(FE_FLTPREC); // should set ctrl word to 0x_2__

    setFPControlWord(FPPrecision.Double); // prints 0x_3__, the default
}


--bb
March 11, 2008
Neil Vice wrote:
> "Bill Baxter" <dnewsgroup@billbaxter.com> wrote in message news:fr3k2f$30b5$1@digitalmars.com...
>> Anyone know how to translate these instructions to D? (specifically DMD/Win flavor of D, but GDC/Win also appreciated if different):
>>
>>    http://www.cs.cmu.edu/~quake/robust.pc.html
>>
>> --bb
> 
> Something along the following lines seems to do the trick, by which I mean it compiles in 2.012 though I believe the syntax should be compatible with D1:
> 
> enum FPPrecision : short
> {
>     Single = 4210,
>     Double = 4722
> }
> 
> void setFPCtrlWord(FPPrecision precision)
> {
>     asm
>     {
>         fldcw precision;
>     }
> }

Ooh, thanks!

> Having said that it might be advisable to use 'fstcw' and bitwise operations to alter the specifics of the control-word that you require:
> 
> http://www.website.masmforum.com/tutorials/fptute/fpuchap3.htm#fldcw 

Hmm, yeh.  Those crazy computational geometry guys always assume you're writing a command line program whose only purpose in life is to calculate a Delaunay triangulation or something.  Oh, you want to use this algorithm in a what?? an application??  What's that?

True to form, that page from Shewchuk says nothing about how to put things back the way you found them when you're done with robust predicate happy-fun-time.

That page you linked to was great though.  Thanks.

--bb
March 11, 2008
Here's a more cleaned up version.  If you see anything that could be improved, let me know.  This is my first asm{}.

module fpctrl;
//import std.c.fenv;
import std.stdio;

enum FPPrecision : short
{
    Single = 0x0000,
    Double = 0x0200,
    Real = 0x0300,
    Mask = 0x0300,
    InvMask = ~Mask
}

version(X86) { version = DO_FPU_CONTROL; }
version(X86_64) { version = DO_FPU_CONTROL; }


FPPrecision setFPControlWord(FPPrecision precision)
{
    FPPrecision oldcw;

    version(DO_FPU_CONTROL) {
        FPPrecision newcw;
        asm
        {
            fstcw oldcw;
            fwait;
            mov AX, oldcw;
            and AX,FPPrecision.InvMask;
            or AX,precision;
            mov newcw,AX;
            fldcw newcw;
        }
        debug
        {
            writefln("oldcw was: 0x%x", oldcw);
            asm
            {
                fstcw newcw;
            }
            writefln("new is: 0x%x", newcw);
        }

        oldcw &= FPPrecision.Mask;
    }

    return oldcw;
}

void main()
{
    auto orig = setFPControlWord(FPPrecision.Double);

    setFPControlWord(FPPrecision.Single);

    setFPControlWord(orig);
}
March 11, 2008
Well short of the method return value being undefined if DO_FPU_CONTROL is not set and the fact that storing the new control word in a variable is unnecessary with the exception of the debug, output it looks fine. If you didn't require the debug output I believe you could simply use AX as the operand to fldcw.

Happy to help =) Incidently it was my first use of asm in D also.

Neil


"Bill Baxter" <dnewsgroup@billbaxter.com> wrote in message news:fr4pb3$1f97$1@digitalmars.com...
> Here's a more cleaned up version.  If you see anything that could be improved, let me know.  This is my first asm{}.
>
> module fpctrl;
> //import std.c.fenv;
> import std.stdio;
>
> enum FPPrecision : short
> {
>     Single = 0x0000,
>     Double = 0x0200,
>     Real = 0x0300,
>     Mask = 0x0300,
>     InvMask = ~Mask
> }
>
> version(X86) { version = DO_FPU_CONTROL; }
> version(X86_64) { version = DO_FPU_CONTROL; }
>
>
> FPPrecision setFPControlWord(FPPrecision precision)
> {
>     FPPrecision oldcw;
>
>     version(DO_FPU_CONTROL) {
>         FPPrecision newcw;
>         asm
>         {
>             fstcw oldcw;
>             fwait;
>             mov AX, oldcw;
>             and AX,FPPrecision.InvMask;
>             or AX,precision;
>             mov newcw,AX;
>             fldcw newcw;
>         }
>         debug
>         {
>             writefln("oldcw was: 0x%x", oldcw);
>             asm
>             {
>                 fstcw newcw;
>             }
>             writefln("new is: 0x%x", newcw);
>         }
>
>         oldcw &= FPPrecision.Mask;
>     }
>
>     return oldcw;
> }
>
> void main()
> {
>     auto orig = setFPControlWord(FPPrecision.Double);
>
>     setFPControlWord(FPPrecision.Single);
>
>     setFPControlWord(orig);
> }


March 11, 2008
Neil Vice wrote:
> Well short of the method return value being undefined if DO_FPU_CONTROL is not set 

It is defined (http://www.digitalmars.com/d/1.0/enum.html)
to be the first value of the enum.  I decided to add an Undefined FPPrecision flag in my current version, and put that as the first thing in the enum to serve as a "this is bogus/uninitialized" indicator.

> and the fact that storing the new control word in a variable is unnecessary with the exception of the debug, output it looks fine. If you didn't require the debug output I believe you could simply use AX as the operand to fldcw.

I see.  The code on the page you linked to used push EAX, and [SP] to access it, but the [SP] bit wouldn't compile ("invalid addressing mode").  That's why I went for the variable.  I'm not too worried about the extra cost of the mov.  :-)

> Happy to help =) Incidently it was my first use of asm in D also.

Funny.  :-)

The main thing I was worried about was the portability of those version statements.  Does the same FPU mojo work on X86_64?  Does it work with GDC?  I've heard GDC doesn't quite implement the inline asm spec.

--bb

> Neil
> 
> 
> "Bill Baxter" <dnewsgroup@billbaxter.com> wrote in message news:fr4pb3$1f97$1@digitalmars.com...
>> Here's a more cleaned up version.  If you see anything that could be improved, let me know.  This is my first asm{}.
>>
>> module fpctrl;
>> //import std.c.fenv;
>> import std.stdio;
>>
>> enum FPPrecision : short
>> {
>>     Single = 0x0000,
>>     Double = 0x0200,
>>     Real = 0x0300,
>>     Mask = 0x0300,
>>     InvMask = ~Mask
>> }
>>
>> version(X86) { version = DO_FPU_CONTROL; }
>> version(X86_64) { version = DO_FPU_CONTROL; }
>>
>>
>> FPPrecision setFPControlWord(FPPrecision precision)
>> {
>>     FPPrecision oldcw;
>>
>>     version(DO_FPU_CONTROL) {
>>         FPPrecision newcw;
>>         asm
>>         {
>>             fstcw oldcw;
>>             fwait;
>>             mov AX, oldcw;
>>             and AX,FPPrecision.InvMask;
>>             or AX,precision;
>>             mov newcw,AX;
>>             fldcw newcw;
>>         }
>>         debug
>>         {
>>             writefln("oldcw was: 0x%x", oldcw);
>>             asm
>>             {
>>                 fstcw newcw;
>>             }
>>             writefln("new is: 0x%x", newcw);
>>         }
>>
>>         oldcw &= FPPrecision.Mask;
>>     }
>>
>>     return oldcw;
>> }
>>
>> void main()
>> {
>>     auto orig = setFPControlWord(FPPrecision.Double);
>>
>>     setFPControlWord(FPPrecision.Single);
>>
>>     setFPControlWord(orig);
>> } 
> 
> 
March 12, 2008
Bill Baxter wrote:
> Jarrett Billingsley wrote:
>> "Bill Baxter" <dnewsgroup@billbaxter.com> wrote in message news:fr3k2f$30b5$1@digitalmars.com...
>>> Anyone know how to translate these instructions to D? (specifically DMD/Win flavor of D, but GDC/Win also appreciated if different):
>>>
>>>    http://www.cs.cmu.edu/~quake/robust.pc.html
>>>
>>> --bb
>>
>> Would std.c.fenv (or tango.stdc.fenv, same module) be of any use here? 
> 
> Ah, fsetprec(FE_DOUBLE) does indeed seem to be intended to be the thing.
> 
> Except, it doesn't work.  The asm fldcw thing does seem to work though.
> 
> 
> ----
> module fpctrl;
> import std.c.fenv;
> import std.stdio;
> 
> enum FPPrecision : short
> {
>     Single = 0x0000,
>     Double = 0x0200,
>     Real = 0x0300,
>     Mask = 0x0300,
> }
> 
> void setFPControlWord(FPPrecision precision)
> {
>     FPPrecision oldcw;
> 
>     asm
>     {
>         fstcw oldcw;
>         fwait;
>         fldcw precision;
>     }
>     writefln("oldcw was: 0x%x", oldcw);
> 
> 
> }
> 
> void main()
> {
>     fesetround(FE_FLTPREC); // should set ctrl word to 0x_2__
> 
>     setFPControlWord(FPPrecision.Double); // prints 0x_3__, the default
> }
> 
> 
> --bb

I've got something similar in tango.math.IEEE.

reduceRealPrecision()
setIeeeRounding()
ieeeFlags();

Mostly only works for x86 (no inline asm yet for other CPUs?)