Intel(R) Threading Building Blocks Doxygen Documentation  version 4.2.3
msvc_ia32_common.h
Go to the documentation of this file.
1 /*
2  Copyright (c) 2005-2019 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 
18 
19 */
20 
21 #if !defined(__TBB_machine_H) || defined(__TBB_machine_msvc_ia32_common_H)
22 #error Do not #include this internal file directly; use public TBB headers instead.
23 #endif
24 
25 #define __TBB_machine_msvc_ia32_common_H
26 
27 #include <intrin.h>
28 
29 //TODO: consider moving this macro to tbb_config.h and using where MSVC asm is used
30 #if !_M_X64 || __INTEL_COMPILER
31  #define __TBB_X86_MSVC_INLINE_ASM_AVAILABLE 1
32 #else
33  //MSVC in x64 mode does not accept inline assembler
34  #define __TBB_X86_MSVC_INLINE_ASM_AVAILABLE 0
35  #define __TBB_NO_X86_MSVC_INLINE_ASM_MSG "The compiler being used is not supported (outdated?)"
36 #endif
37 
38 #if _M_X64
39  #define __TBB_r(reg_name) r##reg_name
40  #define __TBB_W(name) name##64
41  namespace tbb { namespace internal { namespace msvc_intrinsics {
42  typedef __int64 word;
43  }}}
44 #else
45  #define __TBB_r(reg_name) e##reg_name
46  #define __TBB_W(name) name
47  namespace tbb { namespace internal { namespace msvc_intrinsics {
48  typedef long word;
49  }}}
50 #endif
51 
52 #if __TBB_MSVC_PART_WORD_INTERLOCKED_INTRINSICS_PRESENT
53  // S is the operand size in bytes, B is the suffix for intrinsics for that size
54  #define __TBB_MACHINE_DEFINE_ATOMICS(S,B,T,U) \
55  __pragma(intrinsic( _InterlockedCompareExchange##B )) \
56  static inline T __TBB_machine_cmpswp##S ( volatile void * ptr, U value, U comparand ) { \
57  return _InterlockedCompareExchange##B ( (T*)ptr, value, comparand ); \
58  } \
59  __pragma(intrinsic( _InterlockedExchangeAdd##B )) \
60  static inline T __TBB_machine_fetchadd##S ( volatile void * ptr, U addend ) { \
61  return _InterlockedExchangeAdd##B ( (T*)ptr, addend ); \
62  } \
63  __pragma(intrinsic( _InterlockedExchange##B )) \
64  static inline T __TBB_machine_fetchstore##S ( volatile void * ptr, U value ) { \
65  return _InterlockedExchange##B ( (T*)ptr, value ); \
66  }
67 
68  // Atomic intrinsics for 1, 2, and 4 bytes are available for x86 & x64
69  __TBB_MACHINE_DEFINE_ATOMICS(1,8,char,__int8)
70  __TBB_MACHINE_DEFINE_ATOMICS(2,16,short,__int16)
71  __TBB_MACHINE_DEFINE_ATOMICS(4,,long,__int32)
72 
73  #if __TBB_WORDSIZE==8
74  __TBB_MACHINE_DEFINE_ATOMICS(8,64,__int64,__int64)
75  #endif
76 
77  #undef __TBB_MACHINE_DEFINE_ATOMICS
78 #endif /* __TBB_MSVC_PART_WORD_INTERLOCKED_INTRINSICS_PRESENT */
79 
80 #if _MSC_VER>=1300 || __INTEL_COMPILER>=1100
81  #pragma intrinsic(_ReadWriteBarrier)
82  #pragma intrinsic(_mm_mfence)
83  #define __TBB_compiler_fence() _ReadWriteBarrier()
84  #define __TBB_full_memory_fence() _mm_mfence()
85 #elif __TBB_X86_MSVC_INLINE_ASM_AVAILABLE
86  #define __TBB_compiler_fence() __asm { __asm nop }
87  #define __TBB_full_memory_fence() __asm { __asm mfence }
88 #else
89  #error Unsupported compiler; define __TBB_{control,acquire,release}_consistency_helper to support it
90 #endif
91 
92 #define __TBB_control_consistency_helper() __TBB_compiler_fence()
93 #define __TBB_acquire_consistency_helper() __TBB_compiler_fence()
94 #define __TBB_release_consistency_helper() __TBB_compiler_fence()
95 
96 #if (_MSC_VER>=1300) || (__INTEL_COMPILER)
97  #pragma intrinsic(_mm_pause)
98  namespace tbb { namespace internal { namespace msvc_intrinsics {
99  static inline void pause (uintptr_t delay ) {
100  for (;delay>0; --delay )
101  _mm_pause();
102  }
103  }}}
104  #define __TBB_Pause(V) tbb::internal::msvc_intrinsics::pause(V)
105  #define __TBB_SINGLE_PAUSE _mm_pause()
106 #else
107  #if !__TBB_X86_MSVC_INLINE_ASM_AVAILABLE
108  #error __TBB_NO_X86_MSVC_INLINE_ASM_MSG
109  #endif
110  namespace tbb { namespace internal { namespace msvc_inline_asm
111  static inline void pause (uintptr_t delay ) {
112  _asm
113  {
114  mov __TBB_r(ax), delay
115  __TBB_L1:
116  pause
117  add __TBB_r(ax), -1
118  jne __TBB_L1
119  }
120  return;
121  }
122  }}}
123  #define __TBB_Pause(V) tbb::internal::msvc_inline_asm::pause(V)
124  #define __TBB_SINGLE_PAUSE __asm pause
125 #endif
126 
127 #if (_MSC_VER>=1400 && !__INTEL_COMPILER) || (__INTEL_COMPILER>=1200)
128 // MSVC did not have this intrinsic prior to VC8.
129 // ICL 11.1 fails to compile a TBB example if __TBB_Log2 uses the intrinsic.
130  #pragma intrinsic(__TBB_W(_BitScanReverse))
131  namespace tbb { namespace internal { namespace msvc_intrinsics {
132  static inline uintptr_t lg_bsr( uintptr_t i ){
133  unsigned long j;
134  __TBB_W(_BitScanReverse)( &j, i );
135  return j;
136  }
137  }}}
138  #define __TBB_Log2(V) tbb::internal::msvc_intrinsics::lg_bsr(V)
139 #else
140  #if !__TBB_X86_MSVC_INLINE_ASM_AVAILABLE
141  #error __TBB_NO_X86_MSVC_INLINE_ASM_MSG
142  #endif
143  namespace tbb { namespace internal { namespace msvc_inline_asm {
144  static inline uintptr_t lg_bsr( uintptr_t i ){
145  uintptr_t j;
146  __asm
147  {
148  bsr __TBB_r(ax), i
149  mov j, __TBB_r(ax)
150  }
151  return j;
152  }
153  }}}
154  #define __TBB_Log2(V) tbb::internal::msvc_inline_asm::lg_bsr(V)
155 #endif
156 
157 #if _MSC_VER>=1400
158  #pragma intrinsic(__TBB_W(_InterlockedOr))
159  #pragma intrinsic(__TBB_W(_InterlockedAnd))
160  namespace tbb { namespace internal { namespace msvc_intrinsics {
161  static inline void lock_or( volatile void *operand, intptr_t addend ){
162  __TBB_W(_InterlockedOr)((volatile word*)operand, addend);
163  }
164  static inline void lock_and( volatile void *operand, intptr_t addend ){
165  __TBB_W(_InterlockedAnd)((volatile word*)operand, addend);
166  }
167  }}}
168  #define __TBB_AtomicOR(P,V) tbb::internal::msvc_intrinsics::lock_or(P,V)
169  #define __TBB_AtomicAND(P,V) tbb::internal::msvc_intrinsics::lock_and(P,V)
170 #else
171  #if !__TBB_X86_MSVC_INLINE_ASM_AVAILABLE
172  #error __TBB_NO_X86_MSVC_INLINE_ASM_MSG
173  #endif
174  namespace tbb { namespace internal { namespace msvc_inline_asm {
175  static inline void lock_or( volatile void *operand, __int32 addend ) {
176  __asm
177  {
178  mov eax, addend
179  mov edx, [operand]
180  lock or [edx], eax
181  }
182  }
183  static inline void lock_and( volatile void *operand, __int32 addend ) {
184  __asm
185  {
186  mov eax, addend
187  mov edx, [operand]
188  lock and [edx], eax
189  }
190  }
191  }}}
192  #define __TBB_AtomicOR(P,V) tbb::internal::msvc_inline_asm::lock_or(P,V)
193  #define __TBB_AtomicAND(P,V) tbb::internal::msvc_inline_asm::lock_and(P,V)
194 #endif
195 
196 #pragma intrinsic(__rdtsc)
197 namespace tbb { namespace internal { typedef uint64_t machine_tsc_t; } }
199  return __rdtsc();
200 }
201 #define __TBB_time_stamp() __TBB_machine_time_stamp()
202 
203 // API to retrieve/update FPU control setting
204 #define __TBB_CPU_CTL_ENV_PRESENT 1
205 
206 namespace tbb { namespace internal { class cpu_ctl_env; } }
207 #if __TBB_X86_MSVC_INLINE_ASM_AVAILABLE
209  __asm {
210  __asm mov __TBB_r(ax), ctl
211  __asm stmxcsr [__TBB_r(ax)]
212  __asm fstcw [__TBB_r(ax)+4]
213  }
214  }
216  __asm {
217  __asm mov __TBB_r(ax), ctl
218  __asm ldmxcsr [__TBB_r(ax)]
219  __asm fldcw [__TBB_r(ax)+4]
220  }
221  }
222 #else
223  extern "C" {
226  }
227 #endif
228 
229 namespace tbb {
230 namespace internal {
231 class cpu_ctl_env {
232 private:
233  int mxcsr;
234  short x87cw;
235  static const int MXCSR_CONTROL_MASK = ~0x3f; /* all except last six status bits */
236 public:
237  bool operator!=( const cpu_ctl_env& ctl ) const { return mxcsr != ctl.mxcsr || x87cw != ctl.x87cw; }
238  void get_env() {
239  __TBB_get_cpu_ctl_env( this );
241  }
242  void set_env() const { __TBB_set_cpu_ctl_env( this ); }
243 };
244 } // namespace internal
245 } // namespace tbb
246 
247 #if !__TBB_WIN8UI_SUPPORT
248 extern "C" __declspec(dllimport) int __stdcall SwitchToThread( void );
249 #define __TBB_Yield() SwitchToThread()
250 #else
251 #include<thread>
252 #define __TBB_Yield() std::this_thread::yield()
253 #endif
254 
255 #undef __TBB_r
256 #undef __TBB_W
257 #undef __TBB_word
258 
259 extern "C" {
260  __int8 __TBB_EXPORTED_FUNC __TBB_machine_try_lock_elided (volatile void* ptr);
261  void __TBB_EXPORTED_FUNC __TBB_machine_unlock_elided (volatile void* ptr);
262 
263  // 'pause' instruction aborts HLE/RTM transactions
265 
266 #if __TBB_TSX_INTRINSICS_PRESENT
267  #define __TBB_machine_is_in_transaction _xtest
268  #define __TBB_machine_begin_transaction _xbegin
269  #define __TBB_machine_end_transaction _xend
270  // The value (0xFF) below comes from the
271  // Intel(R) 64 and IA-32 Architectures Optimization Reference Manual 12.4.5 lock not free
272  #define __TBB_machine_transaction_conflict_abort() _xabort(0xFF)
273 #else
278 #endif /* __TBB_TSX_INTRINSICS_PRESENT */
279 }
__int8 __TBB_EXPORTED_FUNC __TBB_machine_is_in_transaction()
static const int MXCSR_CONTROL_MASK
static void lock_or(volatile void *operand, __int32 addend)
static void __TBB_machine_try_lock_elided_cancel()
static uintptr_t lg_bsr(uintptr_t i)
void const char const char int ITT_FORMAT __itt_group_sync x void const char ITT_FORMAT __itt_group_sync s void ITT_FORMAT __itt_group_sync p void ITT_FORMAT p void ITT_FORMAT p no args __itt_suppress_mode_t unsigned int void size_t ITT_FORMAT d void ITT_FORMAT p void ITT_FORMAT p __itt_model_site __itt_model_site_instance ITT_FORMAT p __itt_model_task __itt_model_task_instance ITT_FORMAT p void * lock
void __TBB_EXPORTED_FUNC __TBB_machine_end_transaction()
uint64_t machine_tsc_t
void __TBB_EXPORTED_FUNC __TBB_machine_unlock_elided(volatile void *ptr)
The graph class.
bool operator!=(const cpu_ctl_env &ctl) const
__declspec(dllimport) int __stdcall SwitchToThread(void)
namespace msvc_inline_asm static inline void pause(uintptr_t delay)
#define __TBB_EXPORTED_FUNC
#define __TBB_r(reg_name)
unsigned __int32 __TBB_EXPORTED_FUNC __TBB_machine_begin_transaction()
void __TBB_set_cpu_ctl_env(const tbb::internal::cpu_ctl_env *ctl)
void __TBB_get_cpu_ctl_env(tbb::internal::cpu_ctl_env *ctl)
static tbb::internal::machine_tsc_t __TBB_machine_time_stamp()
#define __TBB_MACHINE_DEFINE_ATOMICS(S, T)
Definition: gcc_generic.h:66
#define __TBB_W(name)
void __TBB_EXPORTED_FUNC __TBB_machine_transaction_conflict_abort()
__int8 __TBB_EXPORTED_FUNC __TBB_machine_try_lock_elided(volatile void *ptr)
static void lock_and(volatile void *operand, __int32 addend)
#define __TBB_SINGLE_PAUSE

Copyright © 2005-2019 Intel Corporation. All Rights Reserved.

Intel, Pentium, Intel Xeon, Itanium, Intel XScale and VTune are registered trademarks or trademarks of Intel Corporation or its subsidiaries in the United States and other countries.

* Other names and brands may be claimed as the property of others.