1 /** @file host.c
2  ** @brief Host - Definition
3  ** @author Andrea Vedaldi
4  ** @see @ref portability
5  **/
6 
7 /*
8 Copyright (C) 2007-12 Andrea Vedaldi and Brian Fulkerson.
9 All rights reserved.
10 
11 This file is part of the VLFeat library and is made available under
12 the terms of the BSD license (see the COPYING file).
13 */
14 
15 /**
16 <!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  -->
17 @page portability Portability features
18 @author Andrea Vedaldi
19 @tableofcontents
20 <!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  -->
21 
22 Platform dependent details are isolated in the @ref host.h.  This
23 module provides functionalities to identify the host operating system,
24 C compiler, and CPU architecture. It also provides a few features to
25 abstract from such details.
26 
27 @see http://predef.sourceforge.net/index.php
28 @see http://en.wikipedia.org/wiki/64-bit_computing
29 
30 @section host-os Host operating system
31 
32 The module defines a symbol to identify the host operating system:
33 ::VL_OS_WIN for Windows, ::VL_OS_LINUX for Linux, ::VL_OS_MACOSX for
34 Mac OS X, and so on.
35 
36 @section host-compiler Host compiler
37 
38 The module defines a symbol to identify the host compiler:
39 ::VL_COMPILER_MSC for Microsoft Visual C++, ::VL_COMPILER_GNUC for
40 GNU C, and so on. The (integer) value of such symbols corresponds the
41 version of the compiler.
42 
43 The module defines a symbol to identify the data model of the
44 compiler: ::VL_COMPILER_ILP32, ::VL_COMPILER_LP64, or
45 ::VL_COMPILER_LLP64 (see Sect. @ref host-compiler-data-model).  For
46 convenience, it also defines a number of atomic types of prescribed
47 width (::vl_int8, ::vl_int16, ::vl_int32, etc.).
48 
49 @remark While some of such functionalities are provided by the
50 standard header @c stdint.h, the latter is not supported by all
51 platforms.
52 
53 @subsection host-compiler-data-model Data models
54 
55 The C language defines a number of atomic data types (such as @c char,
56 @c short, @c int and so on). The number of bits (width) used to
57 represent each data type depends on the compiler data model. The
58 different models are *ILP32* (@c int, @c long, and pointer 32 bit),
59 *LP64* (@c int 32 bit, @c long and pointer 64 bit), *ILP64* (@c int,
60 @c long, and pointer 64 bit), and *LLP64* (@c int, @c long 32 bit and
61 pointer 64 -- and `long long` -- 64 bit). Note in particular that
62 `long long` is 64 bit in all models of interest. The following table
63 summarizes them:
64 
65 <table><caption><b>Compiler data models.</b> </caption>
66 <tr style="font-weight:bold;">
67 <td>Data model</td>
68 <td><code>short</code></td>
69 <td><code>int</code></td>
70 <td><code>long</code></td>
71 <td><code>long long</code></td>
72 <td><code>void*</code></td>
73 <td>Compiler</td>
74 </tr>
75 <tr>
76 <td>ILP32</td>
77 <td style="background-color:#ffa;">16</td>
78 <td style="background-color:#afa;">32</td>
79 <td style="background-color:#afa;">32</td>
80 <td>64</td>
81 <td style="background-color:#afa;">32</td>
82 <td>Most 32 bit architectures.</td>
83 </tr>
84 <tr>
85 <td>LP64</td>
86 <td style="background-color:#ffa;">16</td>
87 <td style="background-color:#afa;">32</td>
88 <td>64</td>
89 <td>64</td>
90 <td>64</td>
91 <td>UNIX-64 (Linux, Mac OS X)</td>
92 </tr>
93 <tr>
94 <td>ILP64</td>
95 <td style="background-color:#ffa;">16</td>
96 <td>64</td>
97 <td>64</td>
98 <td>64</td>
99 <td>64</td>
100 <td>Alpha, Cray</td>
101 </tr>
102 <tr>
103 <td>SLIP64</td>
104 <td>64</td>
105 <td>64</td>
106 <td>64</td>
107 <td>64</td>
108 <td>64</td>
109 <td></td>
110 </tr>
111 <tr>
112 <td>LLP64</td>
113 <td style="background-color:#ffa;">16</td>
114 <td style="background-color:#afa;">32</td>
115 <td style="background-color:#afa;">32</td>
116 <td>64</td>
117 <td>64</td>
118 <td>Windows-64</td>
119 </tr>
120 </table>
121 
122 Macros such as ::VL_UINT32_C can be used to generate integer literal
123 with the correct suffix for a type of a given width.
124 
125 @subsection host-compiler-other Other compiler-specific features
126 
127 The module provides the macro ::VL_EXPORT to declare symbols exported
128 from the library and the macro ::VL_INLINE to declare inline
129 functions.  Such features are not part of the C89 standard, and
130 change depending on the compiler.
131 
132 @par "Example:"
133 The following header file declares a function @c f that
134 should be visible from outside the library.
135 @code
136 #include <vl/generic.h>
137 VL_EXPORT void f () ;
138 VL_EXPORT int i ;
139 @endcode
140 Notice that the macro ::VL_EXPORT needs not to be included again
141 when the function is defined.
142 
143 @par "Example:"
144 The following header file declares an inline function @c f:
145 @code
146 #include <vl/generic.h>
147 VL_INLINE int f() ;
148 
149 VL_INLINE int f() { return 1 ; }
150 @endcode
151 
152 Here the first instruction defines the function @c f, where the
153 second declares it. Notice that since this is an inline function, its
154 definition must be found in the header file rather than in an
155 implementation file.  Notice also that definition and declaration can
156 be merged.
157 
158 These macros translate according to the following tables:
159 
160 <table class="doxtable" style="font-size:70%;">
161 <caption>Macros for exporting library symbols</caption>
162 <tr>
163 <td>Platform</td>
164 <td>Macro name</td>
165 <td>Value when building the library</td>
166 <td>Value when importing the library</td>
167 </tr>
168 <tr>
169 <td>Unix/GCC</td>
170 <td>::VL_EXPORT</td>
171 <td>empty (assumes <c>-visibility=hidden</c> GCC option)</td>
172 <td><c>__attribute__((visibility ("default")))</c></td>
173 </tr>
174 <tr>
175 <td>Win/Visual C++</td>
176 <td>::VL_EXPORT</td>
177 <td>@c __declspec(dllexport)</td>
178 <td>@c __declspec(dllimport)</td>
179 </tr>
180 </table>
181 
182 <table class="doxtable" style="font-size:70%;">
183 <caption>Macros for declaring inline functions</caption>
184 <tr>
185 <td>Platform</td>
186 <td>Macro name</td>
187 <td>Value</td>
188 </tr>
189 <tr>
190 <td>Unix/GCC</td>
191 <td>::VL_INLINE</td>
192 <td>static inline</td>
193 </tr>
194 <tr>
195 <td>Win/Visual C++</td>
196 <td>::VL_INLINE</td>
197 <td>static __inline</td>
198 </tr>
199 </table>
200 
201 @section host-arch Host CPU architecture
202 
203 The module defines a symbol to identify the host CPU architecture:
204 ::VL_ARCH_IX86 for Intel x86, ::VL_ARCH_IA64 for Intel 64, and so on.
205 
206 @subsection host-arch-endianness Endianness
207 
208 The module defines a symbol to identify the host CPU endianness:
209 ::VL_ARCH_BIG_ENDIAN for big endian and ::VL_ARCH_LITTLE_ENDIAN for
210 little endian. The functions ::vl_swap_host_big_endianness_8(),
211 ::vl_swap_host_big_endianness_4(), ::vl_swap_host_big_endianness_2()
212 to change the endianness of data (from/to host and network order).
213 
214 Recall that <em>endianness</em> concerns the way multi-byte data
215 types (such as 16, 32 and 64 bits integers) are stored into the
216 addressable memory.  All CPUs uses a contiguous address range to
217 store atomic data types (e.g. a 16-bit integer could be assigned to
218 the addresses <c>0x10001</c> and <c>0x10002</c>), but the order may
219 differ.
220 
221 - The convention is <em>big endian</em>, or in <em>network
222   order</em>, if the most significant byte of the multi-byte data
223   types is assigned to the smaller memory address. This is the
224   convention used for instance by the PPC architecture.
225 
226 - The convention is <em>little endian</em> if the least significant
227   byte is assigned to the smaller memory address. This is the
228   convention used for instance by the x86 architecture.
229 
230 @remark The names &ldquo;big endian&rdquo; and &ldquo;little
231 endian&rdquo; are a little confusing. &ldquo;Big endian&rdquo; means
232 &ldquo;big endian first&rdquo;, i.e.  the address of the most
233 significant byte comes first. Similarly, &ldquo;little endian&rdquo;
234 means &ldquo;little endian first&rdquo;, in the sense that the
235 address of the least significant byte comes first.
236 
237 Endianness is a concern when data is either exchanged with processors
238 that use different conventions, transmitted over a network, or stored
239 to a file. For the latter two cases, one usually saves data in big
240 endian (network) order regardless of the host CPU.
241 
242 @section host-threads Multi-threading
243 
244 The file defines #VL_THREADS_WIN if multi-threading support is
245 enabled and the host supports Windows threads and #VL_THREADS_POSIX if
246 it supports POSIX threads.
247 **/
248 
249 /** @def VL_OS_LINUX
250  ** @brief Defined if the host operating system is Linux.
251  **/
252 
253 /** @def VL_OS_MACOSX
254  ** @brief Defined if the host operating system is Mac OS X.
255  **/
256 
257 /** @def VL_OS_WIN
258  ** @brief Defined if the host operating system is Windows (32 or 64)
259  **/
260 
261 /** @def VL_OS_WIN64
262  ** @brief Defined if the host operating system is Windows-64.
263  **/
264 
265 /** @def VL_COMPILER_GNUC
266  ** @brief Defined if the host compiler is GNU C.
267  **
268  ** This macro is defined if the compiler is GNUC.
269  ** Its value is calculated as
270  ** @code
271  ** 10000 * MAJOR + 100 * MINOR + PATCHLEVEL
272  ** @endcode
273  ** @see @ref host-compiler
274  **/
275 
276 /** @def VL_COMPILER_MSC
277  ** @brief Defined if the host compiler is Microsoft Visual C++.
278  ** @see @ref host-compiler
279  **/
280 
281 /** @def VL_COMPILER_LCC
282  ** @brief Defined if the host compiler is LCC.
283  ** @deprecated The LCC is not supported anymore.
284  ** @see @ref host-compiler
285  **/
286 
287 /** @def VL_COMPILER_LLP64
288  ** @brief Defined if the host compiler data model is LLP64.
289  ** @see @ref host-compiler-data-model
290  **/
291 
292 /** @def VL_COMPILER_LP64
293  ** @brief Defined if the host compiler data model is LP64.
294  ** @see @ref host-compiler-data-model
295  **/
296 
297 /** @def VL_COMPILER_ILP32
298  ** @brief Defined if the host compiler data model is ILP32.
299  ** @see @ref host-compiler-data-model
300  **/
301 
302 /** @def VL_INT8_C(x)
303  ** @brief Create an integer constant of the specified width and sign
304  ** @param x integer constant.
305  ** @return @a x with the correct suffix for the given sign and size.
306  ** The suffix used depends on the @ref host-compiler-data-model.
307  ** @par "Example:"
308  ** The macro <code>VL_INT64_C(1234)</code> is expanded as @c 123L in
309  ** a LP64 system and as @c 123LL in a LLP64 system.
310  **/
311 
312 /** @def VL_INT16_C(x)
313  ** @copydoc VL_INT8_C */
314 
315 /** @def VL_INT32_C(x)
316  ** @copydoc VL_INT8_C */
317 
318 /** @def VL_INT64_C(x)
319  ** @copydoc VL_INT8_C */
320 
321 /** @def VL_UINT8_C(x)
322  ** @copydoc VL_INT8_C */
323 
324 /** @def VL_UINT16_C(x)
325  ** @copydoc VL_INT8_C */
326 
327 /** @def VL_UINT32_C(x)
328  ** @copydoc VL_INT8_C */
329 
330 /** @def VL_UINT64_C(x)
331  ** @copydoc VL_INT8_C */
332 
333 /** @def VL_ARCH_IX86
334  ** @brief Defined if the host CPU is of the Intel x86 family.
335  ** @see @ref host-arch
336  **/
337 
338 /** @def VL_ARCH_IA64
339  ** @brief Defined if the host CPU is of the Intel Architecture-64 family.
340  ** @see @ref host-arch
341  **/
342 
343 /** @def VL_ARCH_LITTLE_ENDIAN
344  ** @brief Defined if the host CPU is little endian
345  ** @see @ref host-arch-endianness
346  **/
347 
348 /** @def VL_ARCH_BIG_ENDIAN
349  ** @brief Defined if the host CPU is big endian
350  ** @see @ref host-arch-endianness
351  **/
352 
353 /** @def VL_INLINE
354  ** @brief Adds appropriate inline function qualifier
355  ** @see @ref host-compiler-other
356  **/
357 
358 /** @def VL_EXPORT
359  ** @brief Declares a DLL exported symbol
360  ** @see @ref host-compiler-other
361  **/
362 
363 /** @def VL_DISABLE_SSE2
364  ** @brief Defined if SSE2 support if disabled
365  **
366  ** Define this symbol during compliation of the library and linking
367  ** to another project to disable VLFeat SSE2 support.
368  **/
369 
370 /** @def VL_DISABLE_THREADS
371  ** @brief Defined if multi-threading support is disabled
372  **
373  ** Define this symbol during compilation of the library and linking
374  ** to another project to disable VLFeat multi-threading support.
375  **/
376 
377 /** @def VL_DISABLE_OPENMP
378  ** @brief Defined if OpenMP support is disabled
379  **
380  ** Define this symbol during compilation of the library and linking
381  ** to another project to disable VLFeat OpenMP support.
382  **/
383 
384 /** @def VL_THREADS_WIN
385  ** @brief Defined if the host uses Windows threads.
386  ** @see @ref host-threads
387  **/
388 
389 /** @def VL_THREADS_POSIX
390  ** @brief Defiend if the host uses POISX threads.
391  ** @see @ref host-threads
392  **/
393 
394 /** --------------------------------------------------------------- */
395 
396 #include "host.h"
397 #include "generic.h"
398 #include <stdio.h>
399 
400 #if defined(VL_ARCH_IX86) || defined(VL_ARCH_IA64) || defined(VL_ARCH_X64)
401 #define HAS_CPUID
402 #else
403 #undef HAS_CPUID
404 #endif
405 
406 #if defined(HAS_CPUID) & defined(VL_COMPILER_MSC)
407 #include <intrin.h>
408 VL_INLINE void
_vl_cpuid(vl_int32 * info,int function)409 _vl_cpuid (vl_int32* info, int function)
410 {
411   __cpuid(info, function) ;
412 }
413 #endif
414 
415 #if defined(HAS_CPUID) & defined(VL_COMPILER_GNUC)
416 VL_INLINE void
_vl_cpuid(vl_int32 * info,int function)417 _vl_cpuid (vl_int32* info, int function)
418 {
419 #if defined(VL_ARCH_IX86) && (defined(__PIC__) || defined(__pic__))
420   /* This version is compatible with -fPIC on x386 targets. This special
421    * case is required becaus
422    * on such platform -fPIC alocates ebx as global offset table pointer.
423    * Note that =r below will be mapped to a register different from ebx,
424    * so the code is sound. */
425   __asm__ __volatile__
426   ("pushl %%ebx      \n" /* save %ebx */
427    "cpuid            \n"
428    "movl %%ebx, %1   \n" /* save what cpuid just put in %ebx */
429    "popl %%ebx       \n" /* restore the old %ebx */
430    : "=a"(info[0]), "=r"(info[1]), "=c"(info[2]), "=d"(info[3])
431    : "a"(function)
432    : "cc") ; /* clobbered (cc=condition codes) */
433 #else /* no -fPIC or -fPIC with a 64-bit target */
434   __asm__ __volatile__
435   ("cpuid"
436    : "=a"(info[0]), "=b"(info[1]), "=c"(info[2]), "=d"(info[3])
437    : "a"(function)
438    : "cc") ;
439 #endif
440 }
441 
442 #endif
443 
444 #if defined(HAS_CPUID)
445 
446 void
_vl_x86cpu_info_init(VlX86CpuInfo * self)447 _vl_x86cpu_info_init (VlX86CpuInfo *self)
448 {
449   vl_int32 info [4] ;
450   int max_func = 0 ;
451   _vl_cpuid(info, 0) ;
452   max_func = info[0] ;
453   self->vendor.words[0] = info[1] ;
454   self->vendor.words[1] = info[3] ;
455   self->vendor.words[2] = info[2] ;
456 
457   if (max_func >= 1) {
458     _vl_cpuid(info, 1) ;
459     self->hasMMX   = info[3] & (1 << 23) ;
460     self->hasSSE   = info[3] & (1 << 25) ;
461     self->hasSSE2  = info[3] & (1 << 26) ;
462     self->hasSSE3  = info[2] & (1 <<  0) ;
463     self->hasSSE41 = info[2] & (1 << 19) ;
464     self->hasSSE42 = info[2] & (1 << 20) ;
465     self->hasAVX   = info[2] & (1 << 28) ;
466   }
467 }
468 
469 #endif
470 
471 char *
_vl_x86cpu_info_to_string_copy(VlX86CpuInfo const * self)472 _vl_x86cpu_info_to_string_copy (VlX86CpuInfo const *self)
473 {
474   char * string = 0 ;
475   int length = 0 ;
476   while (string == 0) {
477     if (length > 0) {
478       string = vl_malloc(sizeof(char) * length) ;
479       if (string == NULL) break ;
480     }
481     length = snprintf(string, length, "%s%s%s%s%s%s%s%s",
482                       self->vendor.string,
483                       self->hasMMX   ? " MMX" : "",
484                       self->hasSSE   ? " SSE" : "",
485                       self->hasSSE2  ? " SSE2" : "",
486                       self->hasSSE3  ? " SSE3" : "",
487                       self->hasSSE41 ? " SSE41" : "",
488                       self->hasSSE42 ? " SSE42" : "",
489                       self->hasAVX   ? " AVX" : "") ;
490     length += 1 ;
491   }
492   return string ;
493 }
494 
495 /** ------------------------------------------------------------------
496  ** @brief Human readable static library configuration
497  ** @return a new string with the static configuration.
498  **
499  ** The string includes information about the compiler, the host, and
500  ** other static configuration parameters. The string must be released
501  ** by ::vl_free.
502  **/
503 
504 VL_EXPORT char *
vl_static_configuration_to_string_copy()505 vl_static_configuration_to_string_copy ()
506 {
507   char const * hostString =
508 #ifdef VL_ARCH_X64
509   "X64"
510 #endif
511 #ifdef VL_ARCH_IA64
512   "IA64"
513 #endif
514 #ifdef VL_ARCH_IX86
515   "IX86"
516 #endif
517 #ifdef VL_ARCH_PPC
518   "PPC"
519 #endif
520   ", "
521 #ifdef VL_ARCH_BIG_ENDIAN
522   "big_endian"
523 #endif
524 #ifdef VL_ARCH_LITTLE_ENDIAN
525   "little_endian"
526 #endif
527   ;
528 
529   char compilerString [1024] ;
530 
531   char const * libraryString =
532 #ifndef VL_DISABLE_THREADS
533 #ifdef VL_THREADS_WIN
534   "Windows_threads"
535 #elif VL_THREADS_POSIX
536   "POSIX_threads"
537 #endif
538 #else
539   "No_threads"
540 #endif
541 #ifndef VL_DISABLE_SSE2
542   ", SSE2"
543 #endif
544 #if defined(_OPENMP)
545   ", OpenMP"
546 #endif
547   ;
548 
549 snprintf(compilerString, 1024,
550 #ifdef VL_COMPILER_MSC
551   "Microsoft Visual C++ %d"
552 #define v VL_COMPILER_MSC
553 #endif
554 #ifdef VL_COMPILER_GNUC
555   "GNU C %d"
556 #define v VL_COMPILER_GNUC
557 #endif
558   " "
559 #ifdef VL_COMPILER_LP64
560   "LP64"
561 #endif
562 #ifdef VL_COMPILER_LLP64
563   "LP64"
564 #endif
565 #ifdef VL_COMPILER_ILP32
566   "ILP32"
567 #endif
568            , v) ;
569 
570   {
571     char * string = 0 ;
572     int length = 0 ;
573     while (string == 0) {
574       if (length > 0) {
575         string = vl_malloc(sizeof(char) * length) ;
576         if (string == NULL) break ;
577       }
578       length = snprintf(string, length, "%s, %s, %s",
579                         hostString,
580                         compilerString,
581                         libraryString) ;
582       length += 1 ;
583     }
584     return string ;
585   }
586 }
587