diff options
author | Chris Robinson <[email protected]> | 2012-09-16 03:19:53 -0700 |
---|---|---|
committer | Chris Robinson <[email protected]> | 2012-09-16 05:35:38 -0700 |
commit | df2e82da78a70a8929ed4bd065515eab7d1db336 (patch) | |
tree | ba821abe9e86617206f8ad8625ea4fc2f7ddd096 /Alc | |
parent | a1daec66e29cf90132d4a5e51e00b04a162f15be (diff) |
Properly handle the SSE control word
Diffstat (limited to 'Alc')
-rw-r--r-- | Alc/helpers.c | 53 |
1 files changed, 37 insertions, 16 deletions
diff --git a/Alc/helpers.c b/Alc/helpers.c index 625c9c96..d074c52b 100644 --- a/Alc/helpers.c +++ b/Alc/helpers.c @@ -175,23 +175,36 @@ void al_free(void *ptr) void SetMixerFPUMode(FPUCtl *ctl) { -#if defined(_FPU_GETCW) && defined(_FPU_SETCW) && (defined(__i386__) || defined(__x86_64__)) - fpu_control_t fpuState, newState; - _FPU_GETCW(fpuState); +#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) + unsigned short fpuState; + __asm__ __volatile__("fnstcw %0" : "=m" (*&fpuState)); ctl->state = fpuState; - newState = fpuState&~(_FPU_EXTENDED|_FPU_DOUBLE|_FPU_SINGLE | - _FPU_RC_NEAREST|_FPU_RC_DOWN|_FPU_RC_UP|_FPU_RC_ZERO); - newState |= _FPU_SINGLE | _FPU_RC_ZERO; + fpuState &= ~0x300; /* clear precision to single */ + fpuState |= 0xC00; /* set round-to-zero */ + __asm__ __volatile__("fldcw %0" : : "m" (*&fpuState)); +#ifdef HAVE_SSE if((CPUCapFlags&CPU_CAP_SSE)) - newState |= 0x8000; /* flush-to-zero */ - _FPU_SETCW(newState); + { + int sseState; + __asm__ __volatile__("stmxcsr %0" : "=m" (*&sseState)); + ctl->sse_state = sseState; + sseState &= ~0x300; /* clear precision to single */ + sseState |= 0xC00; /* set round-to-zero */ + sseState |= 0x8000; /* set flush-to-zero */ + __asm__ __volatile__("ldmxcsr %0" : : "m" (*&sseState)); + } +#endif #elif defined(HAVE___CONTROL87_2) int mode; - __control87_2(0, 0, &ctl->state, NULL); - __control87_2(_RC_CHOP|_DN_FLUSH|_PC_24, _MCW_RC|_MCW_DN|_MCW_PC, &mode, NULL); + __control87_2(0, 0, &ctl->state, &ctl->sse_state); + __control87_2(_RC_CHOP|_PC_24, _MCW_RC|_MCW_PC, &mode, NULL); +#ifdef HAVE_SSE + if((CPUCapFlags&CPU_CAP_SSE)) + __control87_2(_RC_CHOP|_PC_24|_DN_FLUSH, _MCW_RC|_MCW_PC|_MCW_DN, NULL, &mode); +#endif #elif defined(HAVE__CONTROLFP) ctl->state = _controlfp(0, 0); - (void)_controlfp(_RC_CHOP|_DN_FLUSH|_PC_24, _MCW_RC|_MCW_DN|_MCW_PC); + (void)_controlfp(_RC_CHOP|_PC_24, _MCW_RC|_MCW_PC); #elif defined(HAVE_FESETROUND) ctl->state = fegetround(); #ifdef FE_TOWARDZERO @@ -202,14 +215,22 @@ void SetMixerFPUMode(FPUCtl *ctl) void RestoreFPUMode(const FPUCtl *ctl) { -#if defined(_FPU_GETCW) && defined(_FPU_SETCW) && (defined(__i386__) || defined(__x86_64__)) - fpu_control_t fpuState = ctl->state; - _FPU_SETCW(fpuState); +#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) + unsigned short fpuState = ctl->state; + __asm__ __volatile__("fldcw %0" : : "m" (*&fpuState)); +#ifdef HAVE_SSE + if((CPUCapFlags&CPU_CAP_SSE)) + __asm__ __volatile__("ldmxcsr %0" : : "m" (*&ctl->sse_state)); +#endif #elif defined(HAVE___CONTROL87_2) int mode; - __control87_2(ctl->state, _MCW_RC|_MCW_DN|_MCW_PC, &mode, NULL); + __control87_2(ctl->state, _MCW_RC|_MCW_PC, &mode, NULL); +#ifdef HAVE_SSE + if((CPUCapFlags&CPU_CAP_SSE)) + __control87_2(ctl->sse_state, _MCW_DN, NULL, &mode); +#endif #elif defined(HAVE__CONTROLFP) - _controlfp(ctl->state, _MCW_RC|_MCW_DN|_MCW_PC); + _controlfp(ctl->state, _MCW_RC|_MCW_PC); #elif defined(HAVE_FESETROUND) fesetround(ctl->state); #endif |