1 | /* |
2 | Copyright Charly Chevalier 2015 |
3 | Copyright Joel Falcou 2015 |
4 | Distributed under the Boost Software License, Version 1.0. |
5 | (See accompanying file LICENSE_1_0.txt or copy at |
6 | http://www.boost.org/LICENSE_1_0.txt) |
7 | */ |
8 | |
9 | #include <boost/predef/hardware/simd/x86.h> |
10 | #include <boost/predef/hardware/simd/x86_amd.h> |
11 | #include <boost/predef/hardware/simd/arm.h> |
12 | #include <boost/predef/hardware/simd/ppc.h> |
13 | |
14 | #ifndef BOOST_PREDEF_HARDWARE_SIMD_H |
15 | #define BOOST_PREDEF_HARDWARE_SIMD_H |
16 | |
17 | #include <boost/predef/version_number.h> |
18 | |
19 | /* tag::reference[] |
20 | = Using the `BOOST_HW_SIMD_*` predefs |
21 | |
22 | SIMD predefs depend on compiler options. For example, you will have to add the |
23 | option `-msse3` to clang or gcc to enable SSE3. SIMD predefs are also inclusive. |
24 | This means that if SSE3 is enabled, then every other extensions with a lower |
25 | version number will implicitly be enabled and detected. However, some extensions |
26 | are CPU specific, they may not be detected nor enabled when an upper version is |
27 | enabled. |
28 | |
29 | NOTE: SSE(1) and SSE2 are automatically enabled by default when using x86-64 |
30 | architecture. |
31 | |
32 | To check if any SIMD extension has been enabled, you can use: |
33 | |
34 | [source] |
35 | ---- |
36 | #include <boost/predef/hardware/simd.h> |
37 | #include <iostream> |
38 | |
39 | int main() |
40 | { |
41 | #if defined(BOOST_HW_SIMD_AVAILABLE) |
42 | std::cout << "SIMD detected!" << std::endl; |
43 | #endif |
44 | return 0; |
45 | } |
46 | ---- |
47 | |
48 | When writing SIMD specific code, you may want to check if a particular extension |
49 | has been detected. To do so you have to use the right architecture predef and |
50 | compare it. Those predef are of the form `BOOST_HW_SIMD_"ARCH"` (where `"ARCH"` |
51 | is either `ARM`, `PPC`, or `X86`). For example, if you compile code for x86 |
52 | architecture, you will have to use `BOOST_HW_SIMD_X86`. Its value will be the |
53 | version number of the most recent SIMD extension detected for the architecture. |
54 | |
55 | To check if an extension has been enabled: |
56 | |
57 | [source] |
58 | ---- |
59 | #include <boost/predef/hardware/simd.h> |
60 | #include <iostream> |
61 | |
62 | int main() |
63 | { |
64 | #if BOOST_HW_SIMD_X86 >= BOOST_HW_SIMD_X86_SSE3_VERSION |
65 | std::cout << "This is SSE3!" << std::endl; |
66 | #endif |
67 | return 0; |
68 | } |
69 | ---- |
70 | |
71 | NOTE: The *_VERSION* defines that map version number to actual real |
72 | identifiers. This way it is easier to write comparisons without messing up with |
73 | version numbers. |
74 | |
75 | To *"strictly"* check the most recent detected extension: |
76 | |
77 | [source] |
78 | ---- |
79 | #include <boost/predef/hardware/simd.h> |
80 | #include <iostream> |
81 | |
82 | int main() |
83 | { |
84 | #if BOOST_HW_SIMD_X86 == BOOST_HW_SIMD_X86_SSE3_VERSION |
85 | std::cout << "This is SSE3 and this is the most recent enabled extension!" |
86 | << std::endl; |
87 | #endif |
88 | return 0; |
89 | } |
90 | ---- |
91 | |
92 | Because of the version systems of predefs and of the inclusive property of SIMD |
93 | extensions macros, you can easily check for ranges of supported extensions: |
94 | |
95 | [source] |
96 | ---- |
97 | #include <boost/predef/hardware/simd.h> |
98 | #include <iostream> |
99 | |
100 | int main() |
101 | { |
102 | #if BOOST_HW_SIMD_X86 >= BOOST_HW_SIMD_X86_SSE2_VERSION &&\ |
103 | BOOST_HW_SIMD_X86 <= BOOST_HW_SIMD_X86_SSSE3_VERSION |
104 | std::cout << "This is SSE2, SSE3 and SSSE3!" << std::endl; |
105 | #endif |
106 | return 0; |
107 | } |
108 | ---- |
109 | |
110 | NOTE: Unlike gcc and clang, Visual Studio does not allow you to specify precisely |
111 | the SSE variants you want to use, the only detections that will take place are |
112 | SSE, SSE2, AVX and AVX2. For more informations, |
113 | see [@https://msdn.microsoft.com/en-us/library/b0084kay.aspx here]. |
114 | |
115 | |
116 | */ // end::reference[] |
117 | |
118 | // We check if SIMD extension of multiples architectures have been detected, |
119 | // if yes, then this is an error! |
120 | // |
121 | // NOTE: _X86_AMD implies _X86, so there is no need to check for it here! |
122 | // |
123 | #if defined(BOOST_HW_SIMD_ARM_AVAILABLE) && defined(BOOST_HW_SIMD_PPC_AVAILABLE) ||\ |
124 | defined(BOOST_HW_SIMD_ARM_AVAILABLE) && defined(BOOST_HW_SIMD_X86_AVAILABLE) ||\ |
125 | defined(BOOST_HW_SIMD_PPC_AVAILABLE) && defined(BOOST_HW_SIMD_X86_AVAILABLE) |
126 | # error "Multiple SIMD architectures detected, this cannot happen!" |
127 | #endif |
128 | |
129 | #if defined(BOOST_HW_SIMD_X86_AVAILABLE) && defined(BOOST_HW_SIMD_X86_AMD_AVAILABLE) |
130 | // If both standard _X86 and _X86_AMD are available, |
131 | // then take the biggest version of the two! |
132 | # if BOOST_HW_SIMD_X86 >= BOOST_HW_SIMD_X86_AMD |
133 | # define BOOST_HW_SIMD BOOST_HW_SIMD_X86 |
134 | # else |
135 | # define BOOST_HW_SIMD BOOST_HW_SIMD_X86_AMD |
136 | # endif |
137 | #endif |
138 | |
139 | #if !defined(BOOST_HW_SIMD) |
140 | // At this point, only one of these two is defined |
141 | # if defined(BOOST_HW_SIMD_X86_AVAILABLE) |
142 | # define BOOST_HW_SIMD BOOST_HW_SIMD_X86 |
143 | # endif |
144 | # if defined(BOOST_HW_SIMD_X86_AMD_AVAILABLE) |
145 | # define BOOST_HW_SIMD BOOST_HW_SIMD_X86_AMD |
146 | # endif |
147 | #endif |
148 | |
149 | #if defined(BOOST_HW_SIMD_ARM_AVAILABLE) |
150 | # define BOOST_HW_SIMD BOOST_HW_SIMD_ARM |
151 | #endif |
152 | |
153 | #if defined(BOOST_HW_SIMD_PPC_AVAILABLE) |
154 | # define BOOST_HW_SIMD BOOST_HW_SIMD_PPC |
155 | #endif |
156 | |
157 | #if defined(BOOST_HW_SIMD) |
158 | # define BOOST_HW_SIMD_AVAILABLE |
159 | #else |
160 | # define BOOST_HW_SIMD BOOST_VERSION_NUMBER_NOT_AVAILABLE |
161 | #endif |
162 | |
163 | #define BOOST_HW_SIMD_NAME "Hardware SIMD" |
164 | |
165 | #endif |
166 | |
167 | #include <boost/predef/detail/test.h> |
168 | BOOST_PREDEF_DECLARE_TEST(BOOST_HW_SIMD, BOOST_HW_SIMD_NAME) |
169 | |