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