1 /*
2  * Distributed under the Boost Software License, Version 1.0.
3  * (See accompanying file LICENSE_1_0.txt or copy at
4  * http://www.boost.org/LICENSE_1_0.txt)
5  *
6  * Copyright (c) 2020 Andrey Semashev
7  */
8 /*!
9  * \file   cpuid.hpp
10  *
11  * This file contains declaration of \c cpuid function
12  */
13 
14 #ifndef BOOST_ATOMIC_CPUID_HPP_INCLUDED_
15 #define BOOST_ATOMIC_CPUID_HPP_INCLUDED_
16 
17 #include <boost/predef/architecture/x86.h>
18 
19 #if BOOST_ARCH_X86
20 
21 #if defined(_MSC_VER)
22 #include <intrin.h> // __cpuid
23 #endif
24 #include <boost/cstdint.hpp>
25 #include <boost/atomic/detail/config.hpp>
26 
27 #include <boost/atomic/detail/header.hpp>
28 
29 namespace boost {
30 namespace atomics {
31 namespace detail {
32 
33 //! The function invokes x86 cpuid instruction
cpuid(uint32_t & eax,uint32_t & ebx,uint32_t & ecx,uint32_t & edx)34 inline void cpuid(uint32_t& eax, uint32_t& ebx, uint32_t& ecx, uint32_t& edx)
35 {
36 #if defined(__GNUC__)
37 #if (defined(__i386__) || defined(__VXWORKS__)) && (defined(__PIC__) || defined(__PIE__)) && !(defined(__clang__) || (defined(BOOST_GCC) && BOOST_GCC >= 50100))
38     // 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.
39     // For VxWorks ebx is reserved on 64-bit as well.
40 #if defined(__x86_64__)
41     uint64_t rbx = ebx;
42     __asm__ __volatile__
43     (
44         "xchgq %%rbx, %0\n\t"
45         "cpuid\n\t"
46         "xchgq %%rbx, %0\n\t"
47             : "+DS" (rbx), "+a" (eax), "+c" (ecx), "+d" (edx)
48     );
49     ebx = static_cast< uint32_t >(rbx);
50 #else // defined(__x86_64__)
51     __asm__ __volatile__
52     (
53         "xchgl %%ebx, %0\n\t"
54         "cpuid\n\t"
55         "xchgl %%ebx, %0\n\t"
56             : "+DS" (ebx), "+a" (eax), "+c" (ecx), "+d" (edx)
57     );
58 #endif // defined(__x86_64__)
59 #else
60     __asm__ __volatile__
61     (
62         "cpuid\n\t"
63             : "+a" (eax), "+b" (ebx), "+c" (ecx), "+d" (edx)
64     );
65 #endif
66 #elif defined(_MSC_VER)
67     int regs[4] = {};
68     __cpuid(regs, eax);
69     eax = regs[0];
70     ebx = regs[1];
71     ecx = regs[2];
72     edx = regs[3];
73 #else
74 #error "Boost.Atomic: Unsupported compiler, cpuid instruction cannot be generated"
75 #endif
76 }
77 
78 } // namespace detail
79 } // namespace atomics
80 } // namespace boost
81 
82 #include <boost/atomic/detail/footer.hpp>
83 
84 #endif // BOOST_ARCH_X86
85 
86 #endif // BOOST_ATOMIC_CPUID_HPP_INCLUDED_
87