Browse Source

[libc] Add ffs(), ffsl(), and ffsll()

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 9 years ago
parent
commit
79697c75ee

+ 45
- 1
src/arch/i386/include/bits/strings.h View File

3
 
3
 
4
 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
4
 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
5
 
5
 
6
+/**
7
+ * Find first (i.e. least significant) set bit
8
+ *
9
+ * @v value		Value
10
+ * @ret lsb		Least significant bit set in value (LSB=1), or zero
11
+ */
12
+static inline __attribute__ (( always_inline )) int __ffsl ( long value ) {
13
+	long lsb_minus_one;
14
+
15
+	/* If the input value is zero, the BSF instruction returns
16
+	 * ZF=0 and leaves an undefined value in the output register.
17
+	 * Perform this check in C rather than asm so that it can be
18
+	 * omitted in cases where the compiler is able to prove that
19
+	 * the input is non-zero.
20
+	 */
21
+	if ( value ) {
22
+		__asm__ ( "bsfl %1, %0"
23
+			  : "=r" ( lsb_minus_one )
24
+			  : "rm" ( value ) );
25
+		return ( lsb_minus_one + 1 );
26
+	} else {
27
+		return 0;
28
+	}
29
+}
30
+
31
+/**
32
+ * Find first (i.e. least significant) set bit
33
+ *
34
+ * @v value		Value
35
+ * @ret lsb		Least significant bit set in value (LSB=1), or zero
36
+ */
37
+static inline __attribute__ (( always_inline )) int __ffsll ( long long value ){
38
+	unsigned long high = ( value >> 32 );
39
+	unsigned long low = ( value >> 0 );
40
+
41
+	if ( low ) {
42
+		return ( __ffsl ( low ) );
43
+	} else if ( high ) {
44
+		return ( 32 + __ffsl ( high ) );
45
+	} else {
46
+		return 0;
47
+	}
48
+}
49
+
6
 /**
50
 /**
7
  * Find last (i.e. most significant) set bit
51
  * Find last (i.e. most significant) set bit
8
  *
52
  *
13
 	long msb_minus_one;
57
 	long msb_minus_one;
14
 
58
 
15
 	/* If the input value is zero, the BSR instruction returns
59
 	/* If the input value is zero, the BSR instruction returns
16
-	 * ZF=1 and leaves an undefined value in the output register.
60
+	 * ZF=0 and leaves an undefined value in the output register.
17
 	 * Perform this check in C rather than asm so that it can be
61
 	 * Perform this check in C rather than asm so that it can be
18
 	 * omitted in cases where the compiler is able to prove that
62
 	 * omitted in cases where the compiler is able to prove that
19
 	 * the input is non-zero.
63
 	 * the input is non-zero.

+ 37
- 1
src/arch/x86_64/include/bits/strings.h View File

3
 
3
 
4
 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
4
 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
5
 
5
 
6
+/**
7
+ * Find first (i.e. least significant) set bit
8
+ *
9
+ * @v value		Value
10
+ * @ret lsb		Least significant bit set in value (LSB=1), or zero
11
+ */
12
+static inline __attribute__ (( always_inline )) int __ffsll ( long long value ){
13
+	long long lsb_minus_one;
14
+
15
+	/* If the input value is zero, the BSF instruction returns
16
+	 * ZF=0 and leaves an undefined value in the output register.
17
+	 * Perform this check in C rather than asm so that it can be
18
+	 * omitted in cases where the compiler is able to prove that
19
+	 * the input is non-zero.
20
+	 */
21
+	if ( value ) {
22
+		__asm__ ( "bsfq %1, %0"
23
+			  : "=r" ( lsb_minus_one )
24
+			  : "rm" ( value ) );
25
+		return ( lsb_minus_one + 1 );
26
+	} else {
27
+		return 0;
28
+	}
29
+}
30
+
31
+/**
32
+ * Find first (i.e. least significant) set bit
33
+ *
34
+ * @v value		Value
35
+ * @ret lsb		Least significant bit set in value (LSB=1), or zero
36
+ */
37
+static inline __attribute__ (( always_inline )) int __ffsl ( long value ) {
38
+
39
+	return __ffsll ( value );
40
+}
41
+
6
 /**
42
 /**
7
  * Find last (i.e. most significant) set bit
43
  * Find last (i.e. most significant) set bit
8
  *
44
  *
13
 	long long msb_minus_one;
49
 	long long msb_minus_one;
14
 
50
 
15
 	/* If the input value is zero, the BSR instruction returns
51
 	/* If the input value is zero, the BSR instruction returns
16
-	 * ZF=1 and leaves an undefined value in the output register.
52
+	 * ZF=0 and leaves an undefined value in the output register.
17
 	 * Perform this check in C rather than asm so that it can be
53
 	 * Perform this check in C rather than asm so that it can be
18
 	 * omitted in cases where the compiler is able to prove that
54
 	 * omitted in cases where the compiler is able to prove that
19
 	 * the input is non-zero.
55
 	 * the input is non-zero.

+ 77
- 4
src/include/strings.h View File

12
 #include <string.h>
12
 #include <string.h>
13
 #include <bits/strings.h>
13
 #include <bits/strings.h>
14
 
14
 
15
+/**
16
+ * Find first (i.e. least significant) set bit
17
+ *
18
+ * @v x			Value
19
+ * @ret lsb		Least significant bit set in value (LSB=1), or zero
20
+ */
21
+static inline __attribute__ (( always_inline )) int
22
+__constant_ffsll ( unsigned long long x ) {
23
+	int r = 0;
24
+
25
+	if ( ! ( x & 0x00000000ffffffffULL ) ) {
26
+		x >>= 32;
27
+		r += 32;
28
+	}
29
+	if ( ! ( x & 0x0000ffffUL ) ) {
30
+		x >>= 16;
31
+		r += 16;
32
+	}
33
+	if ( ! ( x & 0x00ff ) ) {
34
+		x >>= 8;
35
+		r += 8;
36
+	}
37
+	if ( ! ( x & 0x0f ) ) {
38
+		x >>= 4;
39
+		r += 4;
40
+	}
41
+	if ( ! ( x & 0x3 ) ) {
42
+		x >>= 2;
43
+		r += 2;
44
+	}
45
+	if ( ! ( x & 0x1 ) ) {
46
+		x >>= 1;
47
+		r += 1;
48
+	}
49
+	return ( x ? ( r + 1 ) : 0 );
50
+}
51
+
52
+/**
53
+ * Find first (i.e. least significant) set bit
54
+ *
55
+ * @v x			Value
56
+ * @ret lsb		Least significant bit set in value (LSB=1), or zero
57
+ */
58
+static inline __attribute__ (( always_inline )) int
59
+__constant_ffsl ( unsigned long x ) {
60
+	return __constant_ffsll ( x );
61
+}
62
+
15
 /**
63
 /**
16
  * Find last (i.e. most significant) set bit
64
  * Find last (i.e. most significant) set bit
17
  *
65
  *
46
 		x >>= 1;
94
 		x >>= 1;
47
 		r += 1;
95
 		r += 1;
48
 	}
96
 	}
49
-	if ( x & 0x1 ) {
50
-		r += 1;
51
-	}
52
-	return r;
97
+	return ( x ? ( r + 1 ) : 0 );
53
 }
98
 }
54
 
99
 
55
 /**
100
 /**
63
 	return __constant_flsll ( x );
108
 	return __constant_flsll ( x );
64
 }
109
 }
65
 
110
 
111
+int __ffsll ( long long x );
112
+int __ffsl ( long x );
66
 int __flsll ( long long x );
113
 int __flsll ( long long x );
67
 int __flsl ( long x );
114
 int __flsl ( long x );
68
 
115
 
116
+/**
117
+ * Find first (i.e. least significant) set bit
118
+ *
119
+ * @v x			Value
120
+ * @ret lsb		Least significant bit set in value (LSB=1), or zero
121
+ */
122
+#define ffsll( x ) \
123
+	( __builtin_constant_p ( x ) ? __constant_ffsll ( x ) : __ffsll ( x ) )
124
+
125
+/**
126
+ * Find first (i.e. least significant) set bit
127
+ *
128
+ * @v x			Value
129
+ * @ret lsb		Least significant bit set in value (LSB=1), or zero
130
+ */
131
+#define ffsl( x ) \
132
+	( __builtin_constant_p ( x ) ? __constant_ffsl ( x ) : __ffsl ( x ) )
133
+
134
+/**
135
+ * Find first (i.e. least significant) set bit
136
+ *
137
+ * @v x			Value
138
+ * @ret lsb		Least significant bit set in value (LSB=1), or zero
139
+ */
140
+#define ffs( x ) ffsl ( x )
141
+
69
 /**
142
 /**
70
  * Find last (i.e. most significant) set bit
143
  * Find last (i.e. most significant) set bit
71
  *
144
  *

+ 74
- 0
src/tests/math_test.c View File

38
 #include <ipxe/test.h>
38
 #include <ipxe/test.h>
39
 #include <ipxe/isqrt.h>
39
 #include <ipxe/isqrt.h>
40
 
40
 
41
+/**
42
+ * Force a call to the non-constant implementation of ffsl()
43
+ *
44
+ * @v value		Value
45
+ * @ret lsb		Least significant bit set in value (LSB=1), or zero
46
+ */
47
+__attribute__ (( noinline )) int ffsl_var ( long value ) {
48
+	return ffsl ( value );
49
+}
50
+
51
+/**
52
+ * Force a call to the non-constant implementation of ffsll()
53
+ *
54
+ * @v value		Value
55
+ * @ret lsb		Least significant bit set in value (LSB=1), or zero
56
+ */
57
+__attribute__ (( noinline )) int ffsll_var ( long long value ) {
58
+	return ffsll ( value );
59
+}
60
+
41
 /**
61
 /**
42
  * Force a call to the non-constant implementation of flsl()
62
  * Force a call to the non-constant implementation of flsl()
43
  *
63
  *
176
 	return check_divmod ( dividend, divisor, % );
196
 	return check_divmod ( dividend, divisor, % );
177
 }
197
 }
178
 
198
 
199
+/**
200
+ * Report a ffsl() test result
201
+ *
202
+ * @v value		Value
203
+ * @v lsb		Expected LSB
204
+ * @v file		Test code file
205
+ * @v line		Test code line
206
+ */
207
+static inline __attribute__ (( always_inline )) void
208
+ffsl_okx ( long value, int lsb, const char *file, unsigned int line ) {
209
+
210
+	/* Verify as a constant (requires to be inlined) */
211
+	okx ( ffsl ( value ) == lsb, file, line );
212
+
213
+	/* Verify as a non-constant */
214
+	okx ( ffsl_var ( value ) == lsb, file, line );
215
+}
216
+#define ffsl_ok( value, lsb ) ffsl_okx ( value, lsb, __FILE__, __LINE__ )
217
+
218
+/**
219
+ * Report a ffsll() test result
220
+ *
221
+ * @v value		Value
222
+ * @v lsb		Expected LSB
223
+ * @v file		Test code file
224
+ * @v line		Test code line
225
+ */
226
+static inline __attribute__ (( always_inline )) void
227
+ffsll_okx ( long long value, int lsb, const char *file, unsigned int line ) {
228
+
229
+	/* Verify as a constant (requires to be inlined) */
230
+	okx ( ffsll ( value ) == lsb, file, line );
231
+
232
+	/* Verify as a non-constant */
233
+	okx ( ffsll_var ( value ) == lsb, file, line );
234
+}
235
+#define ffsll_ok( value, lsb ) ffsll_okx ( value, lsb, __FILE__, __LINE__ )
236
+
179
 /**
237
 /**
180
  * Report a flsl() test result
238
  * Report a flsl() test result
181
  *
239
  *
274
  */
332
  */
275
 static void math_test_exec ( void ) {
333
 static void math_test_exec ( void ) {
276
 
334
 
335
+	/* Test ffsl() */
336
+	ffsl_ok ( 0, 0 );
337
+	ffsl_ok ( 1, 1 );
338
+	ffsl_ok ( 255, 1 );
339
+	ffsl_ok ( 256, 9 );
340
+	ffsl_ok ( 257, 1 );
341
+	ffsl_ok ( 0x54850596, 2 );
342
+	ffsl_ok ( 0x80000000, 32 );
343
+
344
+	/* Test ffsll() */
345
+	ffsll_ok ( 0, 0 );
346
+	ffsll_ok ( 1, 1 );
347
+	ffsll_ok ( 0x6d63623330ULL, 5 );
348
+	ffsll_ok ( 0x80000000UL, 32 );
349
+	ffsll_ok ( 0x8000000000000000ULL, 64 );
350
+
277
 	/* Test flsl() */
351
 	/* Test flsl() */
278
 	flsl_ok ( 0, 0 );
352
 	flsl_ok ( 0, 0 );
279
 	flsl_ok ( 1, 1 );
353
 	flsl_ok ( 1, 1 );

Loading…
Cancel
Save