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 }