2 * Copyright Andrey Semashev 2007 - 2021.
3 * Distributed under the Boost Software License, Version 1.0.
4 * (See accompanying file LICENSE_1_0.txt or copy at
5 * http://www.boost.org/LICENSE_1_0.txt)
9 * \author Andrey Semashev
12 * \brief This header is the Boost.Log library implementation, see the library documentation
13 * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
16 #include <boost/log/detail/config.hpp>
18 #include <boost/cstdint.hpp>
19 #include <boost/log/utility/manipulators/dump.hpp>
20 #if defined(_MSC_VER) && (defined(BOOST_LOG_USE_SSSE3) || defined(BOOST_LOG_USE_AVX2))
21 #include <boost/winapi/dll.hpp>
22 #include <intrin.h> // __cpuid
24 #include <boost/log/detail/header.hpp>
28 BOOST_LOG_OPEN_NAMESPACE
32 #if defined(BOOST_LOG_USE_SSSE3)
33 extern dump_data_char_t dump_data_char_ssse3
;
34 extern dump_data_wchar_t dump_data_wchar_ssse3
;
35 #if !defined(BOOST_NO_CXX11_CHAR16_T)
36 extern dump_data_char16_t dump_data_char16_ssse3
;
38 #if !defined(BOOST_NO_CXX11_CHAR32_T)
39 extern dump_data_char32_t dump_data_char32_ssse3
;
41 extern dump_data_char_t dump_data_char_ssse3_slow_pshufb
;
42 extern dump_data_wchar_t dump_data_wchar_ssse3_slow_pshufb
;
43 #if !defined(BOOST_NO_CXX11_CHAR16_T)
44 extern dump_data_char16_t dump_data_char16_ssse3_slow_pshufb
;
46 #if !defined(BOOST_NO_CXX11_CHAR32_T)
47 extern dump_data_char32_t dump_data_char32_ssse3_slow_pshufb
;
50 #if defined(BOOST_LOG_USE_AVX2)
51 extern dump_data_char_t dump_data_char_avx2
;
52 extern dump_data_wchar_t dump_data_wchar_avx2
;
53 #if !defined(BOOST_NO_CXX11_CHAR16_T)
54 extern dump_data_char16_t dump_data_char16_avx2
;
56 #if !defined(BOOST_NO_CXX11_CHAR32_T)
57 extern dump_data_char32_t dump_data_char32_avx2
;
61 enum { stride
= 256 };
63 BOOST_ALIGNMENT(16) extern const char g_hex_char_table
[2][16] =
65 { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' },
66 { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }
69 template< typename CharT
>
70 void dump_data_generic(const void* data
, std::size_t size
, std::basic_ostream
< CharT
>& strm
)
72 typedef CharT char_type
;
74 char_type buf
[stride
* 3u];
76 const char* const char_table
= g_hex_char_table
[(strm
.flags() & std::ios_base::uppercase
) != 0];
77 const std::size_t stride_count
= size
/ stride
, tail_size
= size
% stride
;
79 const uint8_t* p
= static_cast< const uint8_t* >(data
);
80 char_type
* buf_begin
= buf
+ 1u; // skip the first space of the first chunk
81 char_type
* buf_end
= buf
+ sizeof(buf
) / sizeof(*buf
);
83 for (std::size_t i
= 0; i
< stride_count
; ++i
)
86 for (unsigned int j
= 0; j
< stride
; ++j
, b
+= 3u, ++p
)
89 b
[0] = static_cast< char_type
>(' ');
90 b
[1] = static_cast< char_type
>(char_table
[n
>> 4]);
91 b
[2] = static_cast< char_type
>(char_table
[n
& 0x0F]);
94 strm
.write(buf_begin
, buf_end
- buf_begin
);
105 b
[0] = static_cast< char_type
>(' ');
106 b
[1] = static_cast< char_type
>(char_table
[n
>> 4]);
107 b
[2] = static_cast< char_type
>(char_table
[n
& 0x0F]);
112 while (i
< tail_size
);
114 strm
.write(buf_begin
, b
- buf_begin
);
118 BOOST_LOG_API dump_data_char_t
* dump_data_char
= &dump_data_generic
< char >;
119 BOOST_LOG_API dump_data_wchar_t
* dump_data_wchar
= &dump_data_generic
< wchar_t >;
120 #if !defined(BOOST_NO_CXX11_CHAR16_T)
121 BOOST_LOG_API dump_data_char16_t
* dump_data_char16
= &dump_data_generic
< char16_t
>;
123 #if !defined(BOOST_NO_CXX11_CHAR32_T)
124 BOOST_LOG_API dump_data_char32_t
* dump_data_char32
= &dump_data_generic
< char32_t
>;
127 #if defined(BOOST_LOG_USE_SSSE3) || defined(BOOST_LOG_USE_AVX2)
129 BOOST_LOG_ANONYMOUS_NAMESPACE
{
131 struct function_pointer_initializer
133 function_pointer_initializer()
135 // First, let's check for the max supported cpuid function
136 uint32_t eax
= 0, ebx
= 0, ecx
= 0, edx
= 0;
137 cpuid(eax
, ebx
, ecx
, edx
);
139 const uint32_t max_cpuid_function
= eax
;
140 const uint32_t cpu_vendor
[3u] = { ebx
, edx
, ecx
};
141 if (max_cpuid_function
>= 1)
145 cpuid(eax
, ebx
, ecx
, edx
);
147 // Check for SSSE3 support
150 const uint32_t family
= ((eax
>> 8) & 0x0000000F) + ((eax
>> 20) & 0x000000FF);
151 const uint32_t model
= ((eax
>> 4) & 0x0000000F) | ((eax
>> 12) & 0x000000F0);
153 // Check if the CPU has slow pshufb. Some old Intel Atoms prior to Silvermont.
154 if (cpu_vendor
[0] == 0x756e6547 && cpu_vendor
[1] == 0x49656e69 && cpu_vendor
[2] == 0x6c65746e &&
155 family
== 6 && (model
== 28 || model
== 38 || model
== 39 || model
== 53 || model
== 54))
157 enable_ssse3_slow_pshufb();
165 #if defined(BOOST_LOG_USE_AVX2)
166 if (max_cpuid_function
>= 7)
168 // To check for AVX2 availability we also need to verify that OS supports it
169 // Check that OSXSAVE is supported by CPU
170 if (ecx
& (1u << 27))
172 // Check that it is used by the OS
173 bool mmstate
= false;
174 #if defined(__GNUC__)
175 // Get the XFEATURE_ENABLED_MASK register
179 : "=a" (eax
), "=d" (edx
)
182 mmstate
= (eax
& 6u) == 6u;
183 #elif defined(BOOST_WINDOWS)
184 // MSVC does not have an intrinsic for xgetbv, we have to query OS
185 boost::winapi::HMODULE_ hKernel32
= boost::winapi::GetModuleHandleW(L
"kernel32.dll");
188 typedef uint64_t (BOOST_WINAPI_WINAPI_CC
* get_enabled_extended_features_t
)(uint64_t);
189 get_enabled_extended_features_t get_enabled_extended_features
= (get_enabled_extended_features_t
)boost::winapi::get_proc_address(hKernel32
, "GetEnabledExtendedFeatures");
190 if (get_enabled_extended_features
)
192 // XSTATE_MASK_LEGACY_SSE | XSTATE_MASK_GSSE == 6
193 mmstate
= get_enabled_extended_features(6u) == 6u;
200 // Finally, check for AVX2 support in CPU
203 cpuid(eax
, ebx
, ecx
, edx
);
210 #endif // defined(BOOST_LOG_USE_AVX2)
215 static void cpuid(uint32_t& eax
, uint32_t& ebx
, uint32_t& ecx
, uint32_t& edx
)
217 #if defined(__GNUC__)
218 #if (defined(__i386__) || defined(__VXWORKS__)) && (defined(__PIC__) || defined(__PIE__)) && !(defined(__clang__) || (defined(BOOST_GCC) && BOOST_GCC >= 50100))
219 // Unless the compiler can do it automatically, we have to backup ebx in 32-bit PIC/PIE code because it is reserved by the ABI.
220 // For VxWorks ebx is reserved on 64-bit as well.
221 #if defined(__x86_64__)
225 "xchgq %%rbx, %0\n\t"
227 "xchgq %%rbx, %0\n\t"
228 : "+DS" (rbx
), "+a" (eax
), "+c" (ecx
), "+d" (edx
)
230 ebx
= static_cast< uint32_t >(rbx
);
231 #else // defined(__x86_64__)
234 "xchgl %%ebx, %0\n\t"
236 "xchgl %%ebx, %0\n\t"
237 : "+DS" (ebx
), "+a" (eax
), "+c" (ecx
), "+d" (edx
)
239 #endif // defined(__x86_64__)
244 : "+a" (eax
), "+b" (ebx
), "+c" (ecx
), "+d" (edx
)
247 #elif defined(_MSC_VER)
255 #error Boost.Log: Unexpected compiler
259 static void enable_ssse3_slow_pshufb()
261 dump_data_char
= &dump_data_char_ssse3_slow_pshufb
;
262 dump_data_wchar
= &dump_data_wchar_ssse3_slow_pshufb
;
263 #if !defined(BOOST_NO_CXX11_CHAR16_T)
264 dump_data_char16
= &dump_data_char16_ssse3_slow_pshufb
;
266 #if !defined(BOOST_NO_CXX11_CHAR32_T)
267 dump_data_char32
= &dump_data_char32_ssse3_slow_pshufb
;
271 static void enable_ssse3()
273 dump_data_char
= &dump_data_char_ssse3
;
274 dump_data_wchar
= &dump_data_wchar_ssse3
;
275 #if !defined(BOOST_NO_CXX11_CHAR16_T)
276 dump_data_char16
= &dump_data_char16_ssse3
;
278 #if !defined(BOOST_NO_CXX11_CHAR32_T)
279 dump_data_char32
= &dump_data_char32_ssse3
;
283 #if defined(BOOST_LOG_USE_AVX2)
284 static void enable_avx2()
286 dump_data_char
= &dump_data_char_avx2
;
287 dump_data_wchar
= &dump_data_wchar_avx2
;
288 #if !defined(BOOST_NO_CXX11_CHAR16_T)
289 dump_data_char16
= &dump_data_char16_avx2
;
291 #if !defined(BOOST_NO_CXX11_CHAR32_T)
292 dump_data_char32
= &dump_data_char32_avx2
;
295 #endif // defined(BOOST_LOG_USE_AVX2)
298 static function_pointer_initializer g_function_pointer_initializer
;
302 #endif // defined(BOOST_LOG_USE_SSSE3) || defined(BOOST_LOG_USE_AVX2)
306 BOOST_LOG_CLOSE_NAMESPACE
// namespace log
310 #include <boost/log/detail/footer.hpp>