2 * Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 * You can also choose to distribute this program under the terms of
20 * the Unmodified Binary Distribution Licence (as given in the file
21 * COPYING.UBDL), provided that you have satisfied its requirements.
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
28 * Mathematical self-tests
32 /* Forcibly enable assertions */
38 #include <ipxe/test.h>
39 #include <ipxe/isqrt.h>
42 * Force a call to the non-constant implementation of ffsl()
45 * @ret lsb Least significant bit set in value (LSB=1), or zero
47 __attribute__ (( noinline )) int ffsl_var ( long value ) {
48 return ffsl ( value );
52 * Force a call to the non-constant implementation of ffsll()
55 * @ret lsb Least significant bit set in value (LSB=1), or zero
57 __attribute__ (( noinline )) int ffsll_var ( long long value ) {
58 return ffsll ( value );
62 * Force a call to the non-constant implementation of flsl()
65 * @ret msb Most significant bit set in value (LSB=1), or zero
67 __attribute__ (( noinline )) int flsl_var ( long value ) {
68 return flsl ( value );
72 * Force a call to the non-constant implementation of flsll()
75 * @ret msb Most significant bit set in value (LSB=1), or zero
77 __attribute__ (( noinline )) int flsll_var ( long long value ) {
78 return flsll ( value );
82 * Check current stack pointer
84 * @ret stack A value at a fixed offset from the current stack pointer
86 * Used by check_divmod()
88 static __attribute__ (( noinline )) void * stack_check ( void ) {
92 /* Hide the fact that we are returning the address of a local
93 * variable, to prevent a compiler warning.
95 __asm__ ( "\n" : "=g" ( ret ) : "0" ( &a ) );
101 * Check division/modulus operation
103 * One aspect of the calling convention for the implicit arithmetic
104 * functions (__udivmoddi4() etc) is whether the caller or the callee
105 * is expected to pop any stack-based arguments. This distinction can
106 * be masked if the compiler chooses to uses a frame pointer in the
107 * caller, since the caller will then reload the stack pointer from
108 * the frame pointer and so can mask an error in the value of the
111 * We run the division operation in a loop, and check that the stack
112 * pointer does not change value on the second iteration. To prevent
113 * the compiler from performing various optimisations which might
114 * invalidate our intended test (such as unrolling the loop, or moving
115 * the division operation outside the loop), we include some dummy
116 * inline assembly code.
118 #define check_divmod( dividend, divisor, OP ) ( { \
121 void *check = NULL; \
123 /* Prevent compiler from unrolling the loop */ \
124 __asm__ ( "\n" : "=g" ( count ) : "0" ( count ) ); \
127 /* Check that stack pointer does not change between \
131 assert ( check == stack_check() ); \
133 check = stack_check(); \
136 /* Perform division, preventing the compiler from \
137 * moving the division out of the loop. \
139 __asm__ ( "\n" : "=g" ( dividend ), "=g" ( divisor ) \
140 : "0" ( dividend ), "1" ( divisor ) ); \
141 result = ( dividend OP divisor ); \
142 __asm__ ( "\n" : "=g" ( result ) : "0" ( result ) ); \
144 } while ( --count ); \
148 * Force a use of runtime 64-bit unsigned integer division
150 * @v dividend Dividend
152 * @ret quotient Quotient
154 __attribute__ (( noinline )) uint64_t u64div_var ( uint64_t dividend,
157 return check_divmod ( dividend, divisor, / );
161 * Force a use of runtime 64-bit unsigned integer modulus
163 * @v dividend Dividend
165 * @ret remainder Remainder
167 __attribute__ (( noinline )) uint64_t u64mod_var ( uint64_t dividend,
170 return check_divmod ( dividend, divisor, % );
174 * Force a use of runtime 64-bit signed integer division
176 * @v dividend Dividend
178 * @ret quotient Quotient
180 __attribute__ (( noinline )) int64_t s64div_var ( int64_t dividend,
183 return check_divmod ( dividend, divisor, / );
187 * Force a use of runtime 64-bit unsigned integer modulus
189 * @v dividend Dividend
191 * @ret remainder Remainder
193 __attribute__ (( noinline )) int64_t s64mod_var ( int64_t dividend,
196 return check_divmod ( dividend, divisor, % );
200 * Report a ffsl() test result
203 * @v lsb Expected LSB
204 * @v file Test code file
205 * @v line Test code line
207 static inline __attribute__ (( always_inline )) void
208 ffsl_okx ( long value, int lsb, const char *file, unsigned int line ) {
210 /* Verify as a constant (requires to be inlined) */
211 okx ( ffsl ( value ) == lsb, file, line );
213 /* Verify as a non-constant */
214 okx ( ffsl_var ( value ) == lsb, file, line );
216 #define ffsl_ok( value, lsb ) ffsl_okx ( value, lsb, __FILE__, __LINE__ )
219 * Report a ffsll() test result
222 * @v lsb Expected LSB
223 * @v file Test code file
224 * @v line Test code line
226 static inline __attribute__ (( always_inline )) void
227 ffsll_okx ( long long value, int lsb, const char *file, unsigned int line ) {
229 /* Verify as a constant (requires to be inlined) */
230 okx ( ffsll ( value ) == lsb, file, line );
232 /* Verify as a non-constant */
233 okx ( ffsll_var ( value ) == lsb, file, line );
235 #define ffsll_ok( value, lsb ) ffsll_okx ( value, lsb, __FILE__, __LINE__ )
238 * Report a flsl() test result
241 * @v msb Expected MSB
242 * @v file Test code file
243 * @v line Test code line
245 static inline __attribute__ (( always_inline )) void
246 flsl_okx ( long value, int msb, const char *file, unsigned int line ) {
248 /* Verify as a constant (requires to be inlined) */
249 okx ( flsl ( value ) == msb, file, line );
251 /* Verify as a non-constant */
252 okx ( flsl_var ( value ) == msb, file, line );
254 #define flsl_ok( value, msb ) flsl_okx ( value, msb, __FILE__, __LINE__ )
257 * Report a flsll() test result
260 * @v msb Expected MSB
261 * @v file Test code file
262 * @v line Test code line
264 static inline __attribute__ (( always_inline )) void
265 flsll_okx ( long long value, int msb, const char *file, unsigned int line ) {
267 /* Verify as a constant (requires to be inlined) */
268 okx ( flsll ( value ) == msb, file, line );
270 /* Verify as a non-constant */
271 okx ( flsll_var ( value ) == msb, file, line );
273 #define flsll_ok( value, msb ) flsll_okx ( value, msb, __FILE__, __LINE__ )
276 * Report a 64-bit unsigned integer division test result
278 * @v dividend Dividend
280 * @v quotient Quotient
281 * @v remainder Remainder
282 * @v file Test code file
283 * @v line Test code line
285 static void u64divmod_okx ( uint64_t dividend, uint64_t divisor,
286 uint64_t quotient, uint64_t remainder,
287 const char *file, unsigned int line ) {
290 okx ( ( ( divisor * quotient ) + remainder ) == dividend, file, line );
293 okx ( u64div_var ( dividend, divisor ) == quotient, file, line );
296 okx ( u64mod_var ( dividend, divisor ) == remainder, file, line );
298 #define u64divmod_ok( dividend, divisor, quotient, remainder ) \
299 u64divmod_okx ( dividend, divisor, quotient, remainder, \
303 * Report a 64-bit signed integer division test result
305 * @v dividend Dividend
307 * @v quotient Quotient
308 * @v remainder Remainder
309 * @v file Test code file
310 * @v line Test code line
312 static void s64divmod_okx ( int64_t dividend, int64_t divisor,
313 int64_t quotient, int64_t remainder,
314 const char *file, unsigned int line ) {
317 okx ( ( ( divisor * quotient ) + remainder ) == dividend, file, line );
320 okx ( s64div_var ( dividend, divisor ) == quotient, file, line );
323 okx ( s64mod_var ( dividend, divisor ) == remainder, file, line );
325 #define s64divmod_ok( dividend, divisor, quotient, remainder ) \
326 s64divmod_okx ( dividend, divisor, quotient, remainder, \
330 * Perform mathematical self-tests
333 static void math_test_exec ( void ) {
341 ffsl_ok ( 0x54850596, 2 );
342 ffsl_ok ( 0x80000000, 32 );
347 ffsll_ok ( 0x6d63623330ULL, 5 );
348 ffsll_ok ( 0x80000000UL, 32 );
349 ffsll_ok ( 0x8000000000000000ULL, 64 );
357 flsl_ok ( 0x69505845, 31 );
358 flsl_ok ( -1U, ( 8 * sizeof ( int ) ) );
359 flsl_ok ( -1UL, ( 8 * sizeof ( long ) ) );
364 flsll_ok ( 0x6d63623330ULL, 39 );
365 flsll_ok ( -1U, ( 8 * sizeof ( int ) ) );
366 flsll_ok ( -1UL, ( 8 * sizeof ( long ) ) );
367 flsll_ok ( -1ULL, ( 8 * sizeof ( long long ) ) );
369 /* Test 64-bit arithmetic
371 * On a 64-bit machine, these tests are fairly meaningless.
373 * On a 32-bit machine, these tests verify the correct
374 * operation of our libgcc functions __udivmoddi4()
375 * etc. (including checking that the implicit calling
376 * convention assumed by gcc matches our expectations).
378 u64divmod_ok ( 0x2b90ddccf699f765ULL, 0xed9f5e73ULL,
379 0x2eef6ab4ULL, 0x0e12f089ULL );
380 s64divmod_ok ( 0x2b90ddccf699f765ULL, 0xed9f5e73ULL,
381 0x2eef6ab4ULL, 0x0e12f089ULL );
382 u64divmod_ok ( 0xc09e00dcb9e34b54ULL, 0x35968185cdc744f3ULL,
383 3, 0x1fda7c4b508d7c7bULL );
384 s64divmod_ok ( -0x3f61ff23461cb4acLL, 0x35968185cdc744f3ULL,
385 -1LL, -0x9cb7d9d78556fb9LL );
386 u64divmod_ok ( 0, 0x5b2f2737f4ffULL, 0, 0 );
387 s64divmod_ok ( 0, 0xbb00ded72766207fULL, 0, 0 );
389 /* Test integer square root */
390 ok ( isqrt ( 0 ) == 0 );
391 ok ( isqrt ( 1 ) == 1 );
392 ok ( isqrt ( 255 ) == 15 );
393 ok ( isqrt ( 256 ) == 16 );
394 ok ( isqrt ( 257 ) == 16 );
395 ok ( isqrt ( 0xa53df2adUL ) == 52652 );
396 ok ( isqrt ( 0x123793c6UL ) == 17482 );
397 ok ( isqrt ( -1UL ) == ( -1UL >> ( 8 * sizeof ( unsigned long ) / 2 )));
400 /** Mathematical self-tests */
401 struct self_test math_test __self_test = {
403 .exec = math_test_exec,