iPXE
math_test.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>.
3 *
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.
8 *
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.
13 *
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
17 * 02110-1301, USA.
18 *
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.
22 */
23
24FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25
26/** @file
27 *
28 * Mathematical self-tests
29 *
30 */
31
32/* Forcibly enable assertions */
33#undef NDEBUG
34
35#include <string.h>
36#include <strings.h>
37#include <assert.h>
38#include <ipxe/test.h>
39#include <ipxe/isqrt.h>
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
61/**
62 * Force a call to the non-constant implementation of flsl()
63 *
64 * @v value Value
65 * @ret msb Most significant bit set in value (LSB=1), or zero
66 */
67__attribute__ (( noinline )) int flsl_var ( long value ) {
68 return flsl ( value );
69}
70
71/**
72 * Force a call to the non-constant implementation of flsll()
73 *
74 * @v value Value
75 * @ret msb Most significant bit set in value (LSB=1), or zero
76 */
77__attribute__ (( noinline )) int flsll_var ( long long value ) {
78 return flsll ( value );
79}
80
81/**
82 * Force a use of runtime 64-bit shift left
83 *
84 * @v value Value
85 * @v shift Shift amount
86 * @ret value Shifted value
87 */
89 unsigned int shift ) {
90 return ( value << shift );
91}
92
93/**
94 * Force a use of runtime 64-bit logical shift right
95 *
96 * @v value Value
97 * @v shift Shift amount
98 * @ret value Shifted value
99 */
101 unsigned int shift ) {
102 return ( value >> shift );
103}
104
105/**
106 * Force a use of runtime 64-bit arithmetic shift right
107 *
108 * @v value Value
109 * @v shift Shift amount
110 * @ret value Shifted value
111 */
113 unsigned int shift ) {
114 return ( value >> shift );
115}
116
117/**
118 * Check current stack pointer
119 *
120 * @ret stack A value at a fixed offset from the current stack pointer
121 *
122 * Used by check_divmod()
123 */
124static __attribute__ (( noinline )) void * stack_check ( void ) {
125 int a;
126 void *ret;
127
128 /* Hide the fact that we are returning the address of a local
129 * variable, to prevent a compiler warning.
130 */
131 __asm__ ( "\n" : "=g" ( ret ) : "0" ( &a ) );
132
133 return ret;
134}
135
136/**
137 * Check division/modulus operation
138 *
139 * One aspect of the calling convention for the implicit arithmetic
140 * functions (__udivmoddi4() etc) is whether the caller or the callee
141 * is expected to pop any stack-based arguments. This distinction can
142 * be masked if the compiler chooses to uses a frame pointer in the
143 * caller, since the caller will then reload the stack pointer from
144 * the frame pointer and so can mask an error in the value of the
145 * stack pointer.
146 *
147 * We run the division operation in a loop, and check that the stack
148 * pointer does not change value on the second iteration. To prevent
149 * the compiler from performing various optimisations which might
150 * invalidate our intended test (such as unrolling the loop, or moving
151 * the division operation outside the loop), we include some dummy
152 * inline assembly code.
153 */
154#define check_divmod( dividend, divisor, OP ) ( { \
155 uint64_t result; \
156 int count = 2; \
157 void *check = NULL; \
158 \
159 /* Prevent compiler from unrolling the loop */ \
160 __asm__ ( "\n" : "=g" ( count ) : "0" ( count ) ); \
161 \
162 do { \
163 /* Check that stack pointer does not change between \
164 * loop iterations. \
165 */ \
166 if ( check ) { \
167 assert ( check == stack_check() ); \
168 } else { \
169 check = stack_check(); \
170 } \
171 \
172 /* Perform division, preventing the compiler from \
173 * moving the division out of the loop. \
174 */ \
175 __asm__ ( "\n" : "=g" ( dividend ), "=g" ( divisor ) \
176 : "0" ( dividend ), "1" ( divisor ) ); \
177 result = ( dividend OP divisor ); \
178 __asm__ ( "\n" : "=g" ( result ) : "0" ( result ) ); \
179 \
180 } while ( --count ); \
181 result; } )
182
183/**
184 * Force a use of runtime 64-bit unsigned integer division
185 *
186 * @v dividend Dividend
187 * @v divisor Divisor
188 * @ret quotient Quotient
189 */
190__attribute__ (( noinline )) uint64_t u64div_var ( uint64_t dividend,
191 uint64_t divisor ) {
192
193 return check_divmod ( dividend, divisor, / );
194}
195
196/**
197 * Force a use of runtime 64-bit unsigned integer modulus
198 *
199 * @v dividend Dividend
200 * @v divisor Divisor
201 * @ret remainder Remainder
202 */
203__attribute__ (( noinline )) uint64_t u64mod_var ( uint64_t dividend,
204 uint64_t divisor ) {
205
206 return check_divmod ( dividend, divisor, % );
207}
208
209/**
210 * Force a use of runtime 64-bit signed integer division
211 *
212 * @v dividend Dividend
213 * @v divisor Divisor
214 * @ret quotient Quotient
215 */
216__attribute__ (( noinline )) int64_t s64div_var ( int64_t dividend,
217 int64_t divisor ) {
218
219 return check_divmod ( dividend, divisor, / );
220}
221
222/**
223 * Force a use of runtime 64-bit unsigned integer modulus
224 *
225 * @v dividend Dividend
226 * @v divisor Divisor
227 * @ret remainder Remainder
228 */
229__attribute__ (( noinline )) int64_t s64mod_var ( int64_t dividend,
230 int64_t divisor ) {
231
232 return check_divmod ( dividend, divisor, % );
233}
234
235/**
236 * Report a ffsl() test result
237 *
238 * @v value Value
239 * @v lsb Expected LSB
240 * @v file Test code file
241 * @v line Test code line
242 */
243static inline __attribute__ (( always_inline )) void
244ffsl_okx ( long value, int lsb, const char *file, unsigned int line ) {
245
246 /* Verify as a constant (requires to be inlined) */
247 okx ( ffsl ( value ) == lsb, file, line );
249 /* Verify as a non-constant */
250 okx ( ffsl_var ( value ) == lsb, file, line );
251}
252#define ffsl_ok( value, lsb ) ffsl_okx ( value, lsb, __FILE__, __LINE__ )
253
254/**
255 * Report a ffsll() test result
256 *
257 * @v value Value
258 * @v lsb Expected LSB
259 * @v file Test code file
260 * @v line Test code line
261 */
262static inline __attribute__ (( always_inline )) void
263ffsll_okx ( long long value, int lsb, const char *file, unsigned int line ) {
264
265 /* Verify as a constant (requires to be inlined) */
266 okx ( ffsll ( value ) == lsb, file, line );
268 /* Verify as a non-constant */
269 okx ( ffsll_var ( value ) == lsb, file, line );
270}
271#define ffsll_ok( value, lsb ) ffsll_okx ( value, lsb, __FILE__, __LINE__ )
272
273/**
274 * Report a flsl() test result
275 *
276 * @v value Value
277 * @v msb Expected MSB
278 * @v file Test code file
279 * @v line Test code line
280 */
281static inline __attribute__ (( always_inline )) void
282flsl_okx ( long value, int msb, const char *file, unsigned int line ) {
283
284 /* Verify as a constant (requires to be inlined) */
285 okx ( flsl ( value ) == msb, file, line );
287 /* Verify as a non-constant */
288 okx ( flsl_var ( value ) == msb, file, line );
289}
290#define flsl_ok( value, msb ) flsl_okx ( value, msb, __FILE__, __LINE__ )
291
292/**
293 * Report a flsll() test result
294 *
295 * @v value Value
296 * @v msb Expected MSB
297 * @v file Test code file
298 * @v line Test code line
299 */
300static inline __attribute__ (( always_inline )) void
301flsll_okx ( long long value, int msb, const char *file, unsigned int line ) {
302
303 /* Verify as a constant (requires to be inlined) */
304 okx ( flsll ( value ) == msb, file, line );
306 /* Verify as a non-constant */
307 okx ( flsll_var ( value ) == msb, file, line );
308}
309#define flsll_ok( value, msb ) flsll_okx ( value, msb, __FILE__, __LINE__ )
310
311/**
312 * Report a 64-bit shift left test result
313 *
314 * @v value Value
315 * @v shift Shift amount
316 * @v expected Expected value
317 * @v file Test code file
318 * @v line Test code line
319 */
320static inline __attribute__ (( always_inline )) void
321lsl64_okx ( uint64_t value, unsigned int shift, uint64_t expected,
322 const char *file, unsigned int line ) {
323
324 /* Verify as a compile-time calculation */
325 okx ( ( value << shift ) == expected, file, line );
327 /* Verify as a runtime calculation */
328 okx ( lsl64_var ( value, shift ) == expected, file, line );
329}
330#define lsl64_ok( value, shift, expected ) \
331 lsl64_okx ( value, shift, expected, __FILE__, __LINE__ )
332
333/**
334 * Report a 64-bit logical shift right test result
335 *
336 * @v value Value
337 * @v shift Shift amount
338 * @v expected Expected value
339 * @v file Test code file
340 * @v line Test code line
341 */
342static inline __attribute__ (( always_inline )) void
343lsr64_okx ( uint64_t value, unsigned int shift, uint64_t expected,
344 const char *file, unsigned int line ) {
345
346 /* Verify as a compile-time calculation */
347 okx ( ( value >> shift ) == expected, file, line );
349 /* Verify as a runtime calculation */
350 okx ( lsr64_var ( value, shift ) == expected, file, line );
351}
352#define lsr64_ok( value, shift, expected ) \
353 lsr64_okx ( value, shift, expected, __FILE__, __LINE__ )
354
355/**
356 * Report a 64-bit arithmetic shift right test result
357 *
358 * @v value Value
359 * @v shift Shift amount
360 * @v expected Expected value
361 * @v file Test code file
362 * @v line Test code line
363 */
364static inline __attribute__ (( always_inline )) void
365asr64_okx ( int64_t value, unsigned int shift, int64_t expected,
366 const char *file, unsigned int line ) {
367
368 /* Verify as a compile-time calculation */
369 okx ( ( value >> shift ) == expected, file, line );
371 /* Verify as a runtime calculation */
372 okx ( asr64_var ( value, shift ) == expected, file, line );
373}
374#define asr64_ok( value, shift, expected ) \
375 asr64_okx ( value, shift, expected, __FILE__, __LINE__ )
376
377/**
378 * Report a 64-bit unsigned integer division test result
379 *
380 * @v dividend Dividend
381 * @v divisor Divisor
382 * @v quotient Quotient
383 * @v remainder Remainder
384 * @v file Test code file
385 * @v line Test code line
386 */
387static void u64divmod_okx ( uint64_t dividend, uint64_t divisor,
388 uint64_t quotient, uint64_t remainder,
389 const char *file, unsigned int line ) {
390
391 /* Sanity check */
392 okx ( ( ( divisor * quotient ) + remainder ) == dividend, file, line );
393
394 /* Check division */
395 okx ( u64div_var ( dividend, divisor ) == quotient, file, line );
397 /* Check modulus */
398 okx ( u64mod_var ( dividend, divisor ) == remainder, file, line );
399}
400#define u64divmod_ok( dividend, divisor, quotient, remainder ) \
401 u64divmod_okx ( dividend, divisor, quotient, remainder, \
402 __FILE__, __LINE__ )
403
404/**
405 * Report a 64-bit signed integer division test result
406 *
407 * @v dividend Dividend
408 * @v divisor Divisor
409 * @v quotient Quotient
410 * @v remainder Remainder
411 * @v file Test code file
412 * @v line Test code line
413 */
414static void s64divmod_okx ( int64_t dividend, int64_t divisor,
415 int64_t quotient, int64_t remainder,
416 const char *file, unsigned int line ) {
417
418 /* Sanity check */
419 okx ( ( ( divisor * quotient ) + remainder ) == dividend, file, line );
420
421 /* Check division */
422 okx ( s64div_var ( dividend, divisor ) == quotient, file, line );
424 /* Check modulus */
425 okx ( s64mod_var ( dividend, divisor ) == remainder, file, line );
426}
427#define s64divmod_ok( dividend, divisor, quotient, remainder ) \
428 s64divmod_okx ( dividend, divisor, quotient, remainder, \
429 __FILE__, __LINE__ )
430
431/**
432 * Perform mathematical self-tests
433 *
434 */
435static void math_test_exec ( void ) {
436
437 /* Test ffsl() */
438 ffsl_ok ( 0, 0 );
439 ffsl_ok ( 1, 1 );
440 ffsl_ok ( 255, 1 );
441 ffsl_ok ( 256, 9 );
442 ffsl_ok ( 257, 1 );
443 ffsl_ok ( 0x54850596, 2 );
444 ffsl_ok ( 0x80000000, 32 );
445
446 /* Test ffsll() */
447 ffsll_ok ( 0, 0 );
448 ffsll_ok ( 1, 1 );
449 ffsll_ok ( 0x6d63623330ULL, 5 );
450 ffsll_ok ( 0x80000000UL, 32 );
451 ffsll_ok ( 0x8000000000000000ULL, 64 );
452
453 /* Test flsl() */
454 flsl_ok ( 0, 0 );
455 flsl_ok ( 1, 1 );
456 flsl_ok ( 255, 8 );
457 flsl_ok ( 256, 9 );
458 flsl_ok ( 257, 9 );
459 flsl_ok ( 0x69505845, 31 );
460 flsl_ok ( -1U, ( 8 * sizeof ( int ) ) );
461 flsl_ok ( -1UL, ( 8 * sizeof ( long ) ) );
462
463 /* Test flsll() */
464 flsll_ok ( 0, 0 );
465 flsll_ok ( 1, 1 );
466 flsll_ok ( 0x6d63623330ULL, 39 );
467 flsll_ok ( -1U, ( 8 * sizeof ( int ) ) );
468 flsll_ok ( -1UL, ( 8 * sizeof ( long ) ) );
469 flsll_ok ( -1ULL, ( 8 * sizeof ( long long ) ) );
470
471 /* Test 64-bit arithmetic
472 *
473 * On a 64-bit machine, these tests are fairly meaningless.
474 *
475 * On a 32-bit machine, these tests verify the correct
476 * operation of our libgcc functions __udivmoddi4()
477 * etc. (including checking that the implicit calling
478 * convention assumed by gcc matches our expectations).
479 */
480 lsl64_ok ( 0x06760c14710540c2ULL, 0, 0x06760c14710540c2ULL );
481 lsr64_ok ( 0x06760c14710540c2ULL, 0, 0x06760c14710540c2ULL );
482 asr64_ok ( 0x06760c14710540c2ULL, 0, 0x06760c14710540c2ULL );
483 lsl64_ok ( 0xccafd1a8cb724c13ULL, 20, 0x1a8cb724c1300000ULL );
484 lsr64_ok ( 0xccafd1a8cb724c13ULL, 20, 0x00000ccafd1a8cb7ULL );
485 asr64_ok ( 0xccafd1a8cb724c13ULL, 20, 0xfffffccafd1a8cb7ULL );
486 lsl64_ok ( 0x83567264b1234518ULL, 32, 0xb123451800000000ULL );
487 lsr64_ok ( 0x83567264b1234518ULL, 32, 0x0000000083567264ULL );
488 asr64_ok ( 0x83567264b1234518ULL, 32, 0xffffffff83567264ULL );
489 lsl64_ok ( 0x69ee42fcbf1a4ea4ULL, 47, 0x2752000000000000ULL );
490 lsr64_ok ( 0x69ee42fcbf1a4ea4ULL, 47, 0x000000000000d3dcULL );
491 asr64_ok ( 0x69ee42fcbf1a4ea4ULL, 47, 0x000000000000d3dcULL );
492 lsl64_ok ( 0xaa20b8caddee4269ULL, 63, 0x8000000000000000ULL );
493 lsr64_ok ( 0xaa20b8caddee4269ULL, 63, 0x0000000000000001ULL );
494 asr64_ok ( 0xaa20b8caddee4269ULL, 63, 0xffffffffffffffffULL );
495 u64divmod_ok ( 0x2b90ddccf699f765ULL, 0xed9f5e73ULL,
496 0x2eef6ab4ULL, 0x0e12f089ULL );
497 s64divmod_ok ( 0x2b90ddccf699f765ULL, 0xed9f5e73ULL,
498 0x2eef6ab4ULL, 0x0e12f089ULL );
499 u64divmod_ok ( 0xc09e00dcb9e34b54ULL, 0x35968185cdc744f3ULL,
500 3, 0x1fda7c4b508d7c7bULL );
501 s64divmod_ok ( -0x3f61ff23461cb4acLL, 0x35968185cdc744f3ULL,
502 -1LL, -0x9cb7d9d78556fb9LL );
503 u64divmod_ok ( 0, 0x5b2f2737f4ffULL, 0, 0 );
504 s64divmod_ok ( 0, 0xbb00ded72766207fULL, 0, 0 );
505
506 /* Test integer square root */
507 ok ( isqrt ( 0 ) == 0 );
508 ok ( isqrt ( 1 ) == 1 );
509 ok ( isqrt ( 255 ) == 15 );
510 ok ( isqrt ( 256 ) == 16 );
511 ok ( isqrt ( 257 ) == 16 );
512 ok ( isqrt ( 0xa53df2adUL ) == 52652 );
513 ok ( isqrt ( 0x123793c6UL ) == 17482 );
514 ok ( isqrt ( -1UL ) == ( -1UL >> ( 8 * sizeof ( unsigned long ) / 2 )));
515}
516
517/** Mathematical self-tests */
518struct self_test math_test __self_test = {
519 .name = "math",
520 .exec = math_test_exec,
521};
pseudo_bit_t value[0x00020]
Definition arbel.h:2
unsigned long long uint64_t
Definition stdint.h:13
signed long long int64_t
Definition stdint.h:18
Assertions.
#define FILE_LICENCE(_licence)
Declare a particular licence as applying to a file.
Definition compiler.h:896
#define __attribute__(x)
Definition compiler.h:10
String functions.
String functions.
#define flsll(x)
Find last (i.e.
Definition strings.h:149
#define ffsl(x)
Find first (i.e.
Definition strings.h:132
#define ffsll(x)
Find first (i.e.
Definition strings.h:123
#define flsl(x)
Find last (i.e.
Definition strings.h:158
unsigned long isqrt(unsigned long value)
Find integer square root.
Definition isqrt.c:41
Integer square root.
uint64_t u64div_var(uint64_t dividend, uint64_t divisor)
Force a use of runtime 64-bit unsigned integer division.
Definition math_test.c:186
static void lsl64_okx(uint64_t value, unsigned int shift, uint64_t expected, const char *file, unsigned int line)
Report a 64-bit shift left test result.
Definition math_test.c:317
static void flsll_okx(long long value, int msb, const char *file, unsigned int line)
Report a flsll() test result.
Definition math_test.c:297
static void asr64_okx(int64_t value, unsigned int shift, int64_t expected, const char *file, unsigned int line)
Report a 64-bit arithmetic shift right test result.
Definition math_test.c:361
static void math_test_exec(void)
Perform mathematical self-tests.
Definition math_test.c:431
#define lsl64_ok(value, shift, expected)
Definition math_test.c:326
int64_t s64mod_var(int64_t dividend, int64_t divisor)
Force a use of runtime 64-bit unsigned integer modulus.
Definition math_test.c:225
static void ffsll_okx(long long value, int lsb, const char *file, unsigned int line)
Report a ffsll() test result.
Definition math_test.c:259
#define flsll_ok(value, msb)
Definition math_test.c:305
static void s64divmod_okx(int64_t dividend, int64_t divisor, int64_t quotient, int64_t remainder, const char *file, unsigned int line)
Report a 64-bit signed integer division test result.
Definition math_test.c:410
static void * stack_check(void)
Check current stack pointer.
Definition math_test.c:124
static void flsl_okx(long value, int msb, const char *file, unsigned int line)
Report a flsl() test result.
Definition math_test.c:278
uint64_t lsl64_var(uint64_t value, unsigned int shift)
Force a use of runtime 64-bit shift left.
Definition math_test.c:88
static void ffsl_okx(long value, int lsb, const char *file, unsigned int line)
Report a ffsl() test result.
Definition math_test.c:240
int64_t s64div_var(int64_t dividend, int64_t divisor)
Force a use of runtime 64-bit signed integer division.
Definition math_test.c:212
int flsll_var(long long value)
Force a call to the non-constant implementation of flsll()
Definition math_test.c:77
uint64_t lsr64_var(uint64_t value, unsigned int shift)
Force a use of runtime 64-bit logical shift right.
Definition math_test.c:100
int ffsl_var(long value)
Force a call to the non-constant implementation of ffsl()
Definition math_test.c:47
#define asr64_ok(value, shift, expected)
Definition math_test.c:370
uint64_t u64mod_var(uint64_t dividend, uint64_t divisor)
Force a use of runtime 64-bit unsigned integer modulus.
Definition math_test.c:199
#define u64divmod_ok(dividend, divisor, quotient, remainder)
Definition math_test.c:396
int64_t asr64_var(int64_t value, unsigned int shift)
Force a use of runtime 64-bit arithmetic shift right.
Definition math_test.c:112
int flsl_var(long value)
Force a call to the non-constant implementation of flsl()
Definition math_test.c:67
#define check_divmod(dividend, divisor, OP)
Check division/modulus operation.
Definition math_test.c:154
int ffsll_var(long long value)
Force a call to the non-constant implementation of ffsll()
Definition math_test.c:57
static void u64divmod_okx(uint64_t dividend, uint64_t divisor, uint64_t quotient, uint64_t remainder, const char *file, unsigned int line)
Report a 64-bit unsigned integer division test result.
Definition math_test.c:383
#define s64divmod_ok(dividend, divisor, quotient, remainder)
Definition math_test.c:423
#define lsr64_ok(value, shift, expected)
Definition math_test.c:348
#define flsl_ok(value, msb)
Definition math_test.c:286
#define ffsl_ok(value, lsb)
Definition math_test.c:248
static void lsr64_okx(uint64_t value, unsigned int shift, uint64_t expected, const char *file, unsigned int line)
Report a 64-bit logical shift right test result.
Definition math_test.c:339
#define ffsll_ok(value, lsb)
Definition math_test.c:267
__asm__(".section \".rodata\", \"a\", " PROGBITS "\n\t" "\nprivate_key_data:\n\t" ".size private_key_data, ( . - private_key_data )\n\t" ".equ private_key_len, ( . - private_key_data )\n\t" ".previous\n\t")
A self-test set.
Definition test.h:15
Self-test infrastructure.
#define okx(success, file, line)
Report test result.
Definition test.h:44
#define ok(success)
Definition test.h:46
#define __self_test
Declare a self-test.
Definition test.h:32