1 /* 2 Copyright (c) 2005-2021 Intel Corporation 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 #ifndef __TBB_test_common_fp_control_H_ 18 #define __TBB_test_common_fp_control_H_ 19 20 #include "common/test.h" 21 #include "oneapi/tbb/detail/_machine.h" 22 23 #if ( __TBB_x86_32 || __TBB_x86_64 ) 24 25 const int 26 #if _WIN32 || _WIN64 27 FE_TONEAREST = _RC_NEAR, 28 FE_DOWNWARD = _RC_DOWN, 29 FE_UPWARD = _RC_UP, 30 FE_TOWARDZERO = _RC_CHOP, 31 SSE_SHIFT = 5, 32 #else 33 FE_TONEAREST = 0x0000, 34 FE_DOWNWARD = 0x0400, 35 FE_UPWARD = 0x0800, 36 FE_TOWARDZERO = 0x0c00, 37 SSE_SHIFT = 3, 38 #endif 39 FE_RND_MODE_MASK = FE_TOWARDZERO, 40 SSE_RND_MODE_MASK = FE_RND_MODE_MASK << SSE_SHIFT, 41 SSE_DAZ = 0x0040, 42 SSE_FTZ = 0x8000, 43 SSE_MODE_MASK = SSE_DAZ | SSE_FTZ, 44 SSE_STATUS_MASK = 0x3F; 45 46 const int NumSseModes = 4; 47 const int SseModes[NumSseModes] = { 0, SSE_DAZ, SSE_FTZ, SSE_DAZ | SSE_FTZ }; 48 49 inline int GetRoundingMode ( bool checkConsistency = true ) { 50 tbb::detail::d1::cpu_ctl_env ctl; 51 ctl.get_env(); 52 if (checkConsistency) { 53 auto sse_rnd_mode = (ctl.mxcsr & SSE_RND_MODE_MASK) >> SSE_SHIFT; 54 auto x87_rnd_mode = (ctl.x87cw & FE_RND_MODE_MASK); 55 CHECK(sse_rnd_mode == x87_rnd_mode); 56 } 57 return ctl.x87cw & FE_RND_MODE_MASK; 58 } 59 60 inline void SetRoundingMode ( int mode ) { 61 tbb::detail::d1::cpu_ctl_env ctl; 62 ctl.get_env(); 63 ctl.mxcsr = (ctl.mxcsr & ~SSE_RND_MODE_MASK) | (mode & FE_RND_MODE_MASK) << SSE_SHIFT; 64 ctl.x87cw = ((ctl.x87cw & ~FE_RND_MODE_MASK) | (mode & FE_RND_MODE_MASK)); 65 66 if (true) { 67 auto sse_rnd_mode = (ctl.mxcsr & SSE_RND_MODE_MASK) >> SSE_SHIFT; 68 auto x87_rnd_mode = (ctl.x87cw & FE_RND_MODE_MASK); 69 CHECK(sse_rnd_mode == x87_rnd_mode); 70 } 71 72 ctl.set_env(); 73 } 74 75 inline int GetSseMode () { 76 tbb::detail::d1::cpu_ctl_env ctl; 77 ctl.get_env(); 78 return ctl.mxcsr & SSE_MODE_MASK; 79 } 80 81 inline void SetSseMode ( int mode ) { 82 tbb::detail::d1::cpu_ctl_env ctl; 83 ctl.get_env(); 84 ctl.mxcsr = (ctl.mxcsr & ~SSE_MODE_MASK) | (mode & SSE_MODE_MASK); 85 ctl.set_env(); 86 } 87 88 #elif defined(_M_ARM) 89 const int NumSseModes = 1; 90 const int SseModes[NumSseModes] = { 0 }; 91 92 inline int GetSseMode () { return 0; } 93 inline void SetSseMode ( int ) {} 94 95 const int FE_TONEAREST = _RC_NEAR, 96 FE_DOWNWARD = _RC_DOWN, 97 FE_UPWARD = _RC_UP, 98 FE_TOWARDZERO = _RC_CHOP; 99 100 inline int GetRoundingMode ( bool = true ) { 101 tbb::detail::d1::cpu_ctl_env ctl; 102 ctl.get_env(); 103 return ctl.my_ctl; 104 } 105 inline void SetRoundingMode ( int mode ) { 106 tbb::detail::d1::cpu_ctl_env ctl; 107 ctl.my_ctl = mode; 108 ctl.set_env(); 109 } 110 111 #else /* Other archs */ 112 113 #include <fenv.h> 114 115 const int RND_MODE_MASK = FE_TONEAREST | FE_DOWNWARD | FE_UPWARD | FE_TOWARDZERO; 116 117 const int NumSseModes = 1; 118 const int SseModes[NumSseModes] = { 0 }; 119 120 inline int GetRoundingMode ( bool = true ) { return fegetround(); } 121 inline void SetRoundingMode ( int rnd ) { fesetround(rnd); } 122 123 inline int GetSseMode () { return 0; } 124 inline void SetSseMode ( int ) {} 125 126 #endif /* Other archs */ 127 128 const int NumRoundingModes = 4; 129 const int RoundingModes[NumRoundingModes] = { FE_TONEAREST, FE_DOWNWARD, FE_UPWARD, FE_TOWARDZERO }; 130 const int numFPModes = NumRoundingModes*NumSseModes; 131 132 inline void SetFPMode( int mode ) { 133 SetRoundingMode( RoundingModes[mode/NumSseModes%NumRoundingModes] ); 134 SetSseMode( SseModes[mode%NumSseModes] ); 135 } 136 137 #define AssertFPMode( mode ) { \ 138 CHECK_MESSAGE( GetRoundingMode() == RoundingModes[mode/NumSseModes%NumRoundingModes], "FPU control state has not been set correctly." ); \ 139 CHECK_MESSAGE( GetSseMode() == SseModes[mode%NumSseModes], "SSE control state has not been set correctly." ); \ 140 } 141 142 inline int SetNextFPMode( int mode, int step = 1 ) { 143 const int nextMode = (mode+step)%numFPModes; 144 SetFPMode( nextMode ); 145 return nextMode; 146 } 147 148 class FPModeContext { 149 int origSse, origRounding; 150 int currentMode; 151 public: 152 FPModeContext(int newMode) { 153 origSse = GetSseMode(); 154 origRounding = GetRoundingMode(); 155 SetFPMode(currentMode = newMode); 156 } 157 ~FPModeContext() { 158 assertFPMode(); 159 SetRoundingMode(origRounding); 160 SetSseMode(origSse); 161 } 162 int setNextFPMode() { 163 assertFPMode(); 164 return currentMode = SetNextFPMode(currentMode); 165 } 166 void assertFPMode() { 167 AssertFPMode(currentMode); 168 } 169 }; 170 #endif // __TBB_test_common_memory_usagae_H_ 171