1 /**
2 * Copyright: Copyright Auburn Sounds 2015-2016
3 * License:   $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
4 * Authors:   Guillaume Piolat
5 */
6 module dplug.core.fpcontrol;
7 
8 version(X86)
9     version = isX86;
10 version(X86_64)
11     version = isX86;
12 
13 /// This struct ensures that floating point is save/restored and set consistently in plugin callbacks.
14 struct FPControl
15 {
16     void initialize() nothrow @nogc
17     {
18         version(isX86)
19         {
20             // store SSE control word
21             sseState = getSSEControlState();
22             setSSEControlState(0x9fff); // Flush denormals to zero + Denormals Are Zeros + all exception masked
23 
24             // store FPU control word
25             fpuState = getFPUControlState();
26 
27 
28             // masks all floating-point exceptions, sets rounding to nearest, and sets the x87 FPU precision to 64 bits
29             ushort control = 0x037f;
30 
31             // Looking for problems? Unmask all errors.
32             //control = 0x0340;
33 
34             // Looking for denormals only? This unmasks denormal creation and denormal use exceptions.
35             //control = 0x036d;
36 
37             setFPUControlState(control);
38         }
39     }
40 
41     ~this() nothrow @nogc
42     {
43         version(isX86)
44         {
45             // restore SSE2 LDMXCSR and STMXCSR load and write the MXCSR
46             setSSEControlState(sseState);
47 
48             // restore FPU control word
49             setFPUControlState(fpuState);
50         }
51     }
52 
53     version(isX86)
54     {
55         ushort fpuState;
56         uint sseState;
57     }
58 }
59 
60 
61 version(isX86)
62 {
63     version(D_InlineAsm_X86)
64         version = InlineX86Asm;
65     else version(D_InlineAsm_X86_64)
66         version = InlineX86Asm;
67 
68     /// Gets FPU control register
69     ushort getFPUControlState() nothrow @nogc
70     {
71         version (InlineX86Asm)
72         {
73             short cont;
74             asm nothrow @nogc
75             {
76                 xor EAX, EAX;
77                 fstcw cont;
78             }
79             return cont;
80         }
81         else
82             static assert(0, "Unsupported");
83     }
84 
85     /// Sets FPU control register
86     void setFPUControlState(ushort newState) nothrow @nogc
87     {
88         // MAYDO: report that the naked version in Phobos is buggy on OSX
89         // it fills the control word with a random word which can create
90         // FP exceptions.
91         version (InlineX86Asm)
92         {
93             asm nothrow @nogc
94             {
95                 fclex;
96                 fldcw newState;
97             }
98         }
99         else
100             static assert(0, "Unsupported");
101     }
102 
103     /// Get SSE control register
104     uint getSSEControlState() @trusted nothrow @nogc
105     {
106         version (InlineX86Asm)
107         {
108             uint controlWord;
109             asm nothrow @nogc 
110             {
111                 stmxcsr controlWord; 
112             }
113             return controlWord;
114         }
115         else
116             assert(0, "Not yet supported");
117     }
118 
119     /// Sets SSE control register
120     void setSSEControlState(uint controlWord) @trusted nothrow @nogc
121     {
122         version (InlineX86Asm)
123         {
124             asm nothrow @nogc 
125             { 
126                 ldmxcsr controlWord; 
127             }
128         }
129         else
130             assert(0, "Not yet supported");
131     }
132 }
133 
134 unittest
135 {
136 
137     FPControl control;
138     control.initialize();
139 
140 
141 }