1 /**
2     Save/Restore floating-point control words, so that
3     rounding-mode doesn't change wildly in a shared library.
4 
5     Copyright: Guillaume Piolat 2015-2016.
6     License:   http://www.boost.org/LICENSE_1_0.txt
7 */
8 module dplug.core.fpcontrol;
9 
10 version(X86)
11     version = isX86;
12 version(X86_64)
13     version = isX86;
14 
15 import inteli.xmmintrin;
16 
17 nothrow @nogc:
18 
19 /**
20     This struct ensures that floating point is save/restored
21     and set consistently in plugin callbacks.
22 */
23 struct FPControl
24 {
25 nothrow @nogc:
26     void initialize()
27     {
28         // Save and set control word. This works because
29         // intel-intrinsics emulate that control word for
30         // ARM.
31         {
32             // Get current SSE control word
33             storedMXCSR = _mm_getcsr();
34 
35             // Set current SSE control word:
36             // - Flush denormals to zero
37             // - Denormals Are Zeros
38             // - all exception masked
39             _mm_setcsr(0x9fff);
40         }
41 
42         // There is a x86 specific path-here because x86 has
43         // a FPU control word in addition to the SSE control
44         // word.
45         version(isX86)
46         {
47             // store FPU control word
48             fpuState = getFPUControlState();
49 
50             // masks all floating-point exceptions,
51             // sets rounding to nearest,
52             // and sets the x87 FPU precision to 64 bits
53             ushort control = 0x037f;
54 
55             // Very rarely useful debug options below:
56 
57             // 1. Looking for problems? Unmask all errors.
58             //control = 0x0340;
59 
60             // 2. Looking for denormals only? This unmasks
61             // denormal creation and denormal use
62             // exceptions.
63             //control = 0x036d;
64 
65             setFPUControlState(control);
66         }
67     }
68 
69     ~this()
70     {
71         _mm_setcsr(storedMXCSR);
72 
73         version(isX86)
74         {
75             // restore FPU control word
76             setFPUControlState(fpuState);
77         }
78     }
79 
80     version(isX86)
81     {
82         ushort fpuState;
83     }
84     uint storedMXCSR;
85 }
86 
87 
88 version(isX86)
89 {
90     version(D_InlineAsm_X86)
91         version = InlineX86Asm;
92     else version(D_InlineAsm_X86_64)
93         version = InlineX86Asm;
94 
95     ushort getFPUControlState()
96     {
97         version (InlineX86Asm)
98         {
99             short cont;
100             asm nothrow @nogc
101             {
102                 xor EAX, EAX;
103                 fstcw cont;
104             }
105             return cont;
106         }
107         else
108             static assert(0);
109     }
110 
111     void setFPUControlState(ushort newState)
112     {
113         version (InlineX86Asm)
114         {
115             asm nothrow @nogc
116             {
117                 fclex;
118                 fldcw newState;
119             }
120         }
121         else
122             static assert(0);
123     }
124 }
125