www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Setting the FPU control word?

reply Bill Baxter <dnewsgroup billbaxter.com> writes:
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
Mar 10 2008
next sibling parent reply "Neil Vice" <psgdg swiftdsl.com.au> writes:
"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
Mar 10 2008
parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
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
Mar 10 2008
parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
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);
}
Mar 10 2008
parent reply "Neil Vice" <sardonicpresence gmail.com> writes:
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);
 } 

Mar 10 2008
parent Bill Baxter <dnewsgroup billbaxter.com> writes:
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);
 } 


Mar 10 2008
prev sibling parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"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?
Mar 10 2008
parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
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
Mar 10 2008
parent Don Clugston <dac nospam.com.au> writes:
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?)
Mar 12 2008