1 /*
2  * Copyright © 2009 CNRS
3  * Copyright © 2009-2018 Inria.  All rights reserved.
4  * Copyright © 2009-2012 Université Bordeaux
5  * Copyright © 2011 Cisco Systems, Inc.  All rights reserved.
6  * See COPYING in top-level directory.
7  */
8 
9 /* Misc macros and inlines.  */
10 
11 #ifndef HWLOC_PRIVATE_MISC_H
12 #define HWLOC_PRIVATE_MISC_H
13 
14 #include <hwloc/autogen/config.h>
15 #include <private/autogen/config.h>
16 
17 #ifdef HWLOC_HAVE_DECL_STRNCASECMP
18 #ifdef HAVE_STRINGS_H
19 #include <strings.h>
20 #endif
21 #else
22 #ifdef HAVE_CTYPE_H
23 #include <ctype.h>
24 #endif
25 #endif
26 
27 /* Compile-time assertion */
28 #define HWLOC_BUILD_ASSERT(condition) ((void)sizeof(char[1 - 2*!(condition)]))
29 
30 #define HWLOC_BITS_PER_LONG (HWLOC_SIZEOF_UNSIGNED_LONG * 8)
31 #define HWLOC_BITS_PER_INT (HWLOC_SIZEOF_UNSIGNED_INT * 8)
32 
33 #if (HWLOC_BITS_PER_LONG != 32) && (HWLOC_BITS_PER_LONG != 64)
34 #error "unknown size for unsigned long."
35 #endif
36 
37 #if (HWLOC_BITS_PER_INT != 16) && (HWLOC_BITS_PER_INT != 32) && (HWLOC_BITS_PER_INT != 64)
38 #error "unknown size for unsigned int."
39 #endif
40 
41 
42 /**
43  * ffsl helpers.
44  */
45 
46 #if defined(HWLOC_HAVE_BROKEN_FFS)
47 
48 /* System has a broken ffs().
49  * We must check the before __GNUC__ or HWLOC_HAVE_FFSL
50  */
51 #    define HWLOC_NO_FFS
52 
53 #elif defined(__GNUC__)
54 
55 #  if (__GNUC__ >= 4) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 4))
56      /* Starting from 3.4, gcc has a long variant.  */
57 #    define hwloc_ffsl(x) __builtin_ffsl(x)
58 #  else
59 #    define hwloc_ffs(x) __builtin_ffs(x)
60 #    define HWLOC_NEED_FFSL
61 #  endif
62 
63 #elif defined(HWLOC_HAVE_FFSL)
64 
65 #  ifndef HWLOC_HAVE_DECL_FFSL
66 extern int ffsl(long) __hwloc_attribute_const;
67 #  endif
68 
69 #  define hwloc_ffsl(x) ffsl(x)
70 
71 #elif defined(HWLOC_HAVE_FFS)
72 
73 #  ifndef HWLOC_HAVE_DECL_FFS
74 extern int ffs(int) __hwloc_attribute_const;
75 #  endif
76 
77 #  define hwloc_ffs(x) ffs(x)
78 #  define HWLOC_NEED_FFSL
79 
80 #else /* no ffs implementation */
81 
82 #    define HWLOC_NO_FFS
83 
84 #endif
85 
86 #ifdef HWLOC_NO_FFS
87 
88 /* no ffs or it is known to be broken */
89 static __hwloc_inline int
90 hwloc_ffsl_manual(unsigned long x) __hwloc_attribute_const;
91 static __hwloc_inline int
hwloc_ffsl_manual(unsigned long x)92 hwloc_ffsl_manual(unsigned long x)
93 {
94 	int i;
95 
96 	if (!x)
97 		return 0;
98 
99 	i = 1;
100 #if HWLOC_BITS_PER_LONG >= 64
101 	if (!(x & 0xfffffffful)) {
102 		x >>= 32;
103 		i += 32;
104 	}
105 #endif
106 	if (!(x & 0xffffu)) {
107 		x >>= 16;
108 		i += 16;
109 	}
110 	if (!(x & 0xff)) {
111 		x >>= 8;
112 		i += 8;
113 	}
114 	if (!(x & 0xf)) {
115 		x >>= 4;
116 		i += 4;
117 	}
118 	if (!(x & 0x3)) {
119 		x >>= 2;
120 		i += 2;
121 	}
122 	if (!(x & 0x1)) {
123 		x >>= 1;
124 		i += 1;
125 	}
126 
127 	return i;
128 }
129 /* always define hwloc_ffsl as a macro, to avoid renaming breakage */
130 #define hwloc_ffsl hwloc_ffsl_manual
131 
132 #elif defined(HWLOC_NEED_FFSL)
133 
134 /* We only have an int ffs(int) implementation, build a long one.  */
135 
136 /* First make it 32 bits if it was only 16.  */
137 static __hwloc_inline int
138 hwloc_ffs32(unsigned long x) __hwloc_attribute_const;
139 static __hwloc_inline int
hwloc_ffs32(unsigned long x)140 hwloc_ffs32(unsigned long x)
141 {
142 #if HWLOC_BITS_PER_INT == 16
143 	int low_ffs, hi_ffs;
144 
145 	low_ffs = hwloc_ffs(x & 0xfffful);
146 	if (low_ffs)
147 		return low_ffs;
148 
149 	hi_ffs = hwloc_ffs(x >> 16);
150 	if (hi_ffs)
151 		return hi_ffs + 16;
152 
153 	return 0;
154 #else
155 	return hwloc_ffs(x);
156 #endif
157 }
158 
159 /* Then make it 64 bit if longs are.  */
160 static __hwloc_inline int
161 hwloc_ffsl_from_ffs32(unsigned long x) __hwloc_attribute_const;
162 static __hwloc_inline int
hwloc_ffsl_from_ffs32(unsigned long x)163 hwloc_ffsl_from_ffs32(unsigned long x)
164 {
165 #if HWLOC_BITS_PER_LONG == 64
166 	int low_ffs, hi_ffs;
167 
168 	low_ffs = hwloc_ffs32(x & 0xfffffffful);
169 	if (low_ffs)
170 		return low_ffs;
171 
172 	hi_ffs = hwloc_ffs32(x >> 32);
173 	if (hi_ffs)
174 		return hi_ffs + 32;
175 
176 	return 0;
177 #else
178 	return hwloc_ffs32(x);
179 #endif
180 }
181 /* always define hwloc_ffsl as a macro, to avoid renaming breakage */
182 #define hwloc_ffsl hwloc_ffsl_from_ffs32
183 
184 #endif
185 
186 /**
187  * flsl helpers.
188  */
189 #ifdef __GNUC_____
190 
191 #  if (__GNUC__ >= 4) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 4))
192 #    define hwloc_flsl(x) ((x) ? (8*sizeof(long) - __builtin_clzl(x)) : 0)
193 #  else
194 #    define hwloc_fls(x) ((x) ? (8*sizeof(int) - __builtin_clz(x)) : 0)
195 #    define HWLOC_NEED_FLSL
196 #  endif
197 
198 #elif defined(HWLOC_HAVE_FLSL)
199 
200 #  ifndef HWLOC_HAVE_DECL_FLSL
201 extern int flsl(long) __hwloc_attribute_const;
202 #  endif
203 
204 #  define hwloc_flsl(x) flsl(x)
205 
206 #elif defined(HWLOC_HAVE_CLZL)
207 
208 #  ifndef HWLOC_HAVE_DECL_CLZL
209 extern int clzl(long) __hwloc_attribute_const;
210 #  endif
211 
212 #  define hwloc_flsl(x) ((x) ? (8*sizeof(long) - clzl(x)) : 0)
213 
214 #elif defined(HWLOC_HAVE_FLS)
215 
216 #  ifndef HWLOC_HAVE_DECL_FLS
217 extern int fls(int) __hwloc_attribute_const;
218 #  endif
219 
220 #  define hwloc_fls(x) fls(x)
221 #  define HWLOC_NEED_FLSL
222 
223 #elif defined(HWLOC_HAVE_CLZ)
224 
225 #  ifndef HWLOC_HAVE_DECL_CLZ
226 extern int clz(int) __hwloc_attribute_const;
227 #  endif
228 
229 #  define hwloc_fls(x) ((x) ? (8*sizeof(int) - clz(x)) : 0)
230 #  define HWLOC_NEED_FLSL
231 
232 #else /* no fls implementation */
233 
234 static __hwloc_inline int
235 hwloc_flsl_manual(unsigned long x) __hwloc_attribute_const;
236 static __hwloc_inline int
hwloc_flsl_manual(unsigned long x)237 hwloc_flsl_manual(unsigned long x)
238 {
239 	int i = 0;
240 
241 	if (!x)
242 		return 0;
243 
244 	i = 1;
245 #if HWLOC_BITS_PER_LONG >= 64
246 	if ((x & 0xffffffff00000000ul)) {
247 		x >>= 32;
248 		i += 32;
249 	}
250 #endif
251 	if ((x & 0xffff0000u)) {
252 		x >>= 16;
253 		i += 16;
254 	}
255 	if ((x & 0xff00)) {
256 		x >>= 8;
257 		i += 8;
258 	}
259 	if ((x & 0xf0)) {
260 		x >>= 4;
261 		i += 4;
262 	}
263 	if ((x & 0xc)) {
264 		x >>= 2;
265 		i += 2;
266 	}
267 	if ((x & 0x2)) {
268 		x >>= 1;
269 		i += 1;
270 	}
271 
272 	return i;
273 }
274 /* always define hwloc_flsl as a macro, to avoid renaming breakage */
275 #define hwloc_flsl hwloc_flsl_manual
276 
277 #endif
278 
279 #ifdef HWLOC_NEED_FLSL
280 
281 /* We only have an int fls(int) implementation, build a long one.  */
282 
283 /* First make it 32 bits if it was only 16.  */
284 static __hwloc_inline int
285 hwloc_fls32(unsigned long x) __hwloc_attribute_const;
286 static __hwloc_inline int
hwloc_fls32(unsigned long x)287 hwloc_fls32(unsigned long x)
288 {
289 #if HWLOC_BITS_PER_INT == 16
290 	int low_fls, hi_fls;
291 
292 	hi_fls = hwloc_fls(x >> 16);
293 	if (hi_fls)
294 		return hi_fls + 16;
295 
296 	low_fls = hwloc_fls(x & 0xfffful);
297 	if (low_fls)
298 		return low_fls;
299 
300 	return 0;
301 #else
302 	return hwloc_fls(x);
303 #endif
304 }
305 
306 /* Then make it 64 bit if longs are.  */
307 static __hwloc_inline int
308 hwloc_flsl_from_fls32(unsigned long x) __hwloc_attribute_const;
309 static __hwloc_inline int
hwloc_flsl_from_fls32(unsigned long x)310 hwloc_flsl_from_fls32(unsigned long x)
311 {
312 #if HWLOC_BITS_PER_LONG == 64
313 	int low_fls, hi_fls;
314 
315 	hi_fls = hwloc_fls32(x >> 32);
316 	if (hi_fls)
317 		return hi_fls + 32;
318 
319 	low_fls = hwloc_fls32(x & 0xfffffffful);
320 	if (low_fls)
321 		return low_fls;
322 
323 	return 0;
324 #else
325 	return hwloc_fls32(x);
326 #endif
327 }
328 /* always define hwloc_flsl as a macro, to avoid renaming breakage */
329 #define hwloc_flsl hwloc_flsl_from_fls32
330 
331 #endif
332 
333 static __hwloc_inline int
334 hwloc_weight_long(unsigned long w) __hwloc_attribute_const;
335 static __hwloc_inline int
hwloc_weight_long(unsigned long w)336 hwloc_weight_long(unsigned long w)
337 {
338 #if HWLOC_BITS_PER_LONG == 32
339 #if (__GNUC__ >= 4) || ((__GNUC__ == 3) && (__GNUC_MINOR__) >= 4)
340 	return __builtin_popcount(w);
341 #else
342 	unsigned int res = (w & 0x55555555) + ((w >> 1) & 0x55555555);
343 	res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
344 	res = (res & 0x0F0F0F0F) + ((res >> 4) & 0x0F0F0F0F);
345 	res = (res & 0x00FF00FF) + ((res >> 8) & 0x00FF00FF);
346 	return (res & 0x0000FFFF) + ((res >> 16) & 0x0000FFFF);
347 #endif
348 #else /* HWLOC_BITS_PER_LONG == 32 */
349 #if (__GNUC__ >= 4) || ((__GNUC__ == 3) && (__GNUC_MINOR__) >= 4)
350 	return __builtin_popcountll(w);
351 #else
352 	unsigned long res;
353 	res = (w & 0x5555555555555555ul) + ((w >> 1) & 0x5555555555555555ul);
354 	res = (res & 0x3333333333333333ul) + ((res >> 2) & 0x3333333333333333ul);
355 	res = (res & 0x0F0F0F0F0F0F0F0Ful) + ((res >> 4) & 0x0F0F0F0F0F0F0F0Ful);
356 	res = (res & 0x00FF00FF00FF00FFul) + ((res >> 8) & 0x00FF00FF00FF00FFul);
357 	res = (res & 0x0000FFFF0000FFFFul) + ((res >> 16) & 0x0000FFFF0000FFFFul);
358 	return (res & 0x00000000FFFFFFFFul) + ((res >> 32) & 0x00000000FFFFFFFFul);
359 #endif
360 #endif /* HWLOC_BITS_PER_LONG == 64 */
361 }
362 
363 #if !HAVE_DECL_STRTOULL && defined(HAVE_STRTOULL)
364 unsigned long long int strtoull(const char *nptr, char **endptr, int base);
365 #endif
366 
hwloc_strncasecmp(const char * s1,const char * s2,size_t n)367 static __hwloc_inline int hwloc_strncasecmp(const char *s1, const char *s2, size_t n)
368 {
369 #ifdef HWLOC_HAVE_DECL_STRNCASECMP
370   return strncasecmp(s1, s2, n);
371 #else
372   while (n) {
373     char c1 = tolower(*s1), c2 = tolower(*s2);
374     if (!c1 || !c2 || c1 != c2)
375       return c1-c2;
376     n--; s1++; s2++;
377   }
378   return 0;
379 #endif
380 }
381 
382 /* Parse a PCI link speed (GT/s) string from Linux sysfs */
383 #ifdef HWLOC_LINUX_SYS
384 #include <stdlib.h> /* for atof() */
385 static __hwloc_inline float
hwloc_linux_pci_link_speed_from_string(const char * string)386 hwloc_linux_pci_link_speed_from_string(const char *string)
387 {
388   /* don't parse Gen1 with atof() since it expects a localized string
389    * while the kernel sysfs files aren't.
390    */
391   if (!strncmp(string, "2.5 ", 4))
392     /* "2.5 GT/s" is Gen1 with 8/10 encoding */
393     return 2.5 * .8;
394 
395   /* also hardwire Gen2 since it also has a specific encoding */
396   if (!strncmp(string, "5 ", 2))
397     /* "5 GT/s" is Gen2 with 8/10 encoding */
398     return 5 * .8;
399 
400   /* handle Gen3+ in a generic way */
401   return atof(string) * 128./130; /* Gen3+ encoding is 128/130 */
402 }
403 #endif
404 
405 #if !HAVE_DECL_MODFF
406 #define modff(x,iptr) (float)modf((double)x,(double *)iptr)
407 #endif
408 
409 #ifdef HWLOC_WIN_SYS
410 #  ifndef HAVE_SSIZE_T
411 typedef SSIZE_T ssize_t;
412 #  endif
413 #  if !HAVE_DECL_STRTOULL && !defined(HAVE_STRTOULL)
414 #    define strtoull _strtoui64
415 #  endif
416 #  ifndef S_ISREG
417 #    define S_ISREG(m) ((m) & S_IFREG)
418 #  endif
419 #  ifndef S_ISDIR
420 #    define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
421 #  endif
422 #  ifndef S_IRWXU
423 #    define S_IRWXU 00700
424 #  endif
425 #  ifndef HWLOC_HAVE_DECL_STRCASECMP
426 #    define strcasecmp _stricmp
427 #  endif
428 #  if !HAVE_DECL_SNPRINTF
429 #    define snprintf _snprintf
430 #  endif
431 #  if HAVE_DECL__STRDUP
432 #    define strdup _strdup
433 #  endif
434 #  if HAVE_DECL__PUTENV
435 #    define putenv _putenv
436 #  endif
437 #endif
438 
439 #endif /* HWLOC_PRIVATE_MISC_H */
440