1 /* CpuArch.h -- CPU specific code
2 2018-07-04 : Igor Pavlov : Public domain */
3 
4 #ifndef __CPU_ARCH_H
5 #define __CPU_ARCH_H
6 
7 #include "7zTypes.h"
8 
9 EXTERN_C_BEGIN
10 
11 /*
12 MY_CPU_LE means that CPU is LITTLE ENDIAN.
13 MY_CPU_BE means that CPU is BIG ENDIAN.
14 If MY_CPU_LE and MY_CPU_BE are not defined, we don't know about ENDIANNESS of platform.
15 
16 MY_CPU_LE_UNALIGN means that CPU is LITTLE ENDIAN and CPU supports unaligned memory accesses.
17 */
18 
19 #if  defined(_M_X64) \
20   || defined(_M_AMD64) \
21   || defined(__x86_64__) \
22   || defined(__AMD64__) \
23   || defined(__amd64__)
24   #define MY_CPU_AMD64
25   #ifdef __ILP32__
26     #define MY_CPU_NAME "x32"
27   #else
28     #define MY_CPU_NAME "x64"
29   #endif
30   #define MY_CPU_64BIT
31 #endif
32 
33 
34 #if  defined(_M_IX86) \
35   || defined(__i386__)
36   #define MY_CPU_X86
37   #define MY_CPU_NAME "x86"
38   #define MY_CPU_32BIT
39 #endif
40 
41 
42 #if  defined(_M_ARM64) \
43   || defined(__AARCH64EL__) \
44   || defined(__AARCH64EB__) \
45   || defined(__aarch64__)
46   #define MY_CPU_ARM64
47   #define MY_CPU_NAME "arm64"
48   #define MY_CPU_64BIT
49 #endif
50 
51 
52 #if  defined(_M_ARM) \
53   || defined(_M_ARM_NT) \
54   || defined(_M_ARMT) \
55   || defined(__arm__) \
56   || defined(__thumb__) \
57   || defined(__ARMEL__) \
58   || defined(__ARMEB__) \
59   || defined(__THUMBEL__) \
60   || defined(__THUMBEB__)
61   #define MY_CPU_ARM
62   #define MY_CPU_NAME "arm"
63   #define MY_CPU_32BIT
64 #endif
65 
66 
67 #if  defined(_M_IA64) \
68   || defined(__ia64__)
69   #define MY_CPU_IA64
70   #define MY_CPU_NAME "ia64"
71   #define MY_CPU_64BIT
72 #endif
73 
74 
75 #if  defined(__mips64) \
76   || defined(__mips64__) \
77   || (defined(__mips) && (__mips == 64 || __mips == 4 || __mips == 3))
78   #define MY_CPU_NAME "mips64"
79   #define MY_CPU_64BIT
80 #elif defined(__mips__)
81   #define MY_CPU_NAME "mips"
82   /* #define MY_CPU_32BIT */
83 #endif
84 
85 
86 #if  defined(__ppc64__) \
87   || defined(__powerpc64__)
88   #ifdef __ILP32__
89     #define MY_CPU_NAME "ppc64-32"
90   #else
91     #define MY_CPU_NAME "ppc64"
92   #endif
93   #define MY_CPU_64BIT
94 #elif defined(__ppc__) \
95   || defined(__powerpc__)
96   #define MY_CPU_NAME "ppc"
97   #define MY_CPU_32BIT
98 #endif
99 
100 
101 #if  defined(__sparc64__)
102   #define MY_CPU_NAME "sparc64"
103   #define MY_CPU_64BIT
104 #elif defined(__sparc__)
105   #define MY_CPU_NAME "sparc"
106   /* #define MY_CPU_32BIT */
107 #endif
108 
109 
110 #if defined(MY_CPU_X86) || defined(MY_CPU_AMD64)
111 #define MY_CPU_X86_OR_AMD64
112 #endif
113 
114 
115 #ifdef _WIN32
116 
117   #ifdef MY_CPU_ARM
118   #define MY_CPU_ARM_LE
119   #endif
120 
121   #ifdef MY_CPU_ARM64
122   #define MY_CPU_ARM64_LE
123   #endif
124 
125   #ifdef _M_IA64
126   #define MY_CPU_IA64_LE
127   #endif
128 
129 #endif
130 
131 
132 #if defined(MY_CPU_X86_OR_AMD64) \
133     || defined(MY_CPU_ARM_LE) \
134     || defined(MY_CPU_ARM64_LE) \
135     || defined(MY_CPU_IA64_LE) \
136     || defined(__LITTLE_ENDIAN__) \
137     || defined(__ARMEL__) \
138     || defined(__THUMBEL__) \
139     || defined(__AARCH64EL__) \
140     || defined(__MIPSEL__) \
141     || defined(__MIPSEL) \
142     || defined(_MIPSEL) \
143     || defined(__BFIN__) \
144     || (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
145   #define MY_CPU_LE
146 #endif
147 
148 #if defined(__BIG_ENDIAN__) \
149     || defined(__ARMEB__) \
150     || defined(__THUMBEB__) \
151     || defined(__AARCH64EB__) \
152     || defined(__MIPSEB__) \
153     || defined(__MIPSEB) \
154     || defined(_MIPSEB) \
155     || defined(__m68k__) \
156     || defined(__s390__) \
157     || defined(__s390x__) \
158     || defined(__zarch__) \
159     || (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))
160   #define MY_CPU_BE
161 #endif
162 
163 
164 #if defined(MY_CPU_LE) && defined(MY_CPU_BE)
165   #error Stop_Compiling_Bad_Endian
166 #endif
167 
168 
169 #if defined(MY_CPU_32BIT) && defined(MY_CPU_64BIT)
170   #error Stop_Compiling_Bad_32_64_BIT
171 #endif
172 
173 
174 #ifndef MY_CPU_NAME
175   #ifdef MY_CPU_LE
176     #define MY_CPU_NAME "LE"
177   #elif defined(MY_CPU_BE)
178     #define MY_CPU_NAME "BE"
179   #else
180     /*
181     #define MY_CPU_NAME ""
182     */
183   #endif
184 #endif
185 
186 
187 
188 
189 
190 #ifdef MY_CPU_LE
191   #if defined(MY_CPU_X86_OR_AMD64) \
192       || defined(MY_CPU_ARM64) \
193       || defined(__ARM_FEATURE_UNALIGNED)
194     #define MY_CPU_LE_UNALIGN
195   #endif
196 #endif
197 
198 
199 #ifdef MY_CPU_LE_UNALIGN
200 
201 #define GetUi16(p) (*(const UInt16 *)(const void *)(p))
202 #define GetUi32(p) (*(const UInt32 *)(const void *)(p))
203 #define GetUi64(p) (*(const UInt64 *)(const void *)(p))
204 
205 #define SetUi16(p, v) { *(UInt16 *)(p) = (v); }
206 #define SetUi32(p, v) { *(UInt32 *)(p) = (v); }
207 #define SetUi64(p, v) { *(UInt64 *)(p) = (v); }
208 
209 #else
210 
211 #define GetUi16(p) ( (UInt16) ( \
212              ((const Byte *)(p))[0] | \
213     ((UInt16)((const Byte *)(p))[1] << 8) ))
214 
215 #define GetUi32(p) ( \
216              ((const Byte *)(p))[0]        | \
217     ((UInt32)((const Byte *)(p))[1] <<  8) | \
218     ((UInt32)((const Byte *)(p))[2] << 16) | \
219     ((UInt32)((const Byte *)(p))[3] << 24))
220 
221 #define GetUi64(p) (GetUi32(p) | ((UInt64)GetUi32(((const Byte *)(p)) + 4) << 32))
222 
223 #define SetUi16(p, v) { Byte *_ppp_ = (Byte *)(p); UInt32 _vvv_ = (v); \
224     _ppp_[0] = (Byte)_vvv_; \
225     _ppp_[1] = (Byte)(_vvv_ >> 8); }
226 
227 #define SetUi32(p, v) { Byte *_ppp_ = (Byte *)(p); UInt32 _vvv_ = (v); \
228     _ppp_[0] = (Byte)_vvv_; \
229     _ppp_[1] = (Byte)(_vvv_ >> 8); \
230     _ppp_[2] = (Byte)(_vvv_ >> 16); \
231     _ppp_[3] = (Byte)(_vvv_ >> 24); }
232 
233 #define SetUi64(p, v) { Byte *_ppp2_ = (Byte *)(p); UInt64 _vvv2_ = (v); \
234     SetUi32(_ppp2_    , (UInt32)_vvv2_); \
235     SetUi32(_ppp2_ + 4, (UInt32)(_vvv2_ >> 32)); }
236 
237 #endif
238 
239 #ifdef __has_builtin
240   #define MY__has_builtin(x) __has_builtin(x)
241 #else
242   #define MY__has_builtin(x) 0
243 #endif
244 
245 #if defined(MY_CPU_LE_UNALIGN) && /* defined(_WIN64) && */ (_MSC_VER >= 1300)
246 
247 /* Note: we use bswap instruction, that is unsupported in 386 cpu */
248 
249 #include <stdlib.h>
250 
251 #pragma intrinsic(_byteswap_ushort)
252 #pragma intrinsic(_byteswap_ulong)
253 #pragma intrinsic(_byteswap_uint64)
254 
255 /* #define GetBe16(p) _byteswap_ushort(*(const UInt16 *)(const Byte *)(p)) */
256 #define GetBe32(p) _byteswap_ulong(*(const UInt32 *)(const Byte *)(p))
257 #define GetBe64(p) _byteswap_uint64(*(const UInt64 *)(const Byte *)(p))
258 
259 #define SetBe32(p, v) (*(UInt32 *)(void *)(p)) = _byteswap_ulong(v)
260 
261 #elif defined(MY_CPU_LE_UNALIGN) && ( \
262        (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))) \
263     || (defined(__clang__) && MY__has_builtin(__builtin_bswap16)) )
264 
265 /* #define GetBe16(p) __builtin_bswap16(*(const UInt16 *)(const Byte *)(p)) */
266 #define GetBe32(p) __builtin_bswap32(*(const UInt32 *)(const Byte *)(p))
267 #define GetBe64(p) __builtin_bswap64(*(const UInt64 *)(const Byte *)(p))
268 
269 #define SetBe32(p, v) (*(UInt32 *)(void *)(p)) = __builtin_bswap32(v)
270 
271 #else
272 
273 #define GetBe32(p) ( \
274     ((UInt32)((const Byte *)(p))[0] << 24) | \
275     ((UInt32)((const Byte *)(p))[1] << 16) | \
276     ((UInt32)((const Byte *)(p))[2] <<  8) | \
277              ((const Byte *)(p))[3] )
278 
279 #define GetBe64(p) (((UInt64)GetBe32(p) << 32) | GetBe32(((const Byte *)(p)) + 4))
280 
281 #define SetBe32(p, v) { Byte *_ppp_ = (Byte *)(p); UInt32 _vvv_ = (v); \
282     _ppp_[0] = (Byte)(_vvv_ >> 24); \
283     _ppp_[1] = (Byte)(_vvv_ >> 16); \
284     _ppp_[2] = (Byte)(_vvv_ >> 8); \
285     _ppp_[3] = (Byte)_vvv_; }
286 
287 #endif
288 
289 
290 #ifndef GetBe16
291 
292 #define GetBe16(p) ( (UInt16) ( \
293     ((UInt16)((const Byte *)(p))[0] << 8) | \
294              ((const Byte *)(p))[1] ))
295 
296 #endif
297 
298 
299 
300 #ifdef MY_CPU_X86_OR_AMD64
301 
302 typedef struct
303 {
304   UInt32 maxFunc;
305   UInt32 vendor[3];
306   UInt32 ver;
307   UInt32 b;
308   UInt32 c;
309   UInt32 d;
310 } Cx86cpuid;
311 
312 enum
313 {
314   CPU_FIRM_INTEL,
315   CPU_FIRM_AMD,
316   CPU_FIRM_VIA
317 };
318 
319 void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d);
320 
321 BoolInt x86cpuid_CheckAndRead(Cx86cpuid *p);
322 int x86cpuid_GetFirm(const Cx86cpuid *p);
323 
324 #define x86cpuid_GetFamily(ver) (((ver >> 16) & 0xFF0) | ((ver >> 8) & 0xF))
325 #define x86cpuid_GetModel(ver)  (((ver >> 12) &  0xF0) | ((ver >> 4) & 0xF))
326 #define x86cpuid_GetStepping(ver) (ver & 0xF)
327 
328 BoolInt CPU_Is_InOrder();
329 BoolInt CPU_Is_Aes_Supported();
330 
331 #endif
332 
333 EXTERN_C_END
334 
335 #endif
336