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