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 
24 FILE_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  */
124 static __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  */
243 static inline __attribute__ (( always_inline )) void
244 ffsl_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 );
248 
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  */
262 static inline __attribute__ (( always_inline )) void
263 ffsll_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 );
267 
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  */
281 static inline __attribute__ (( always_inline )) void
282 flsl_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 );
286 
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  */
300 static inline __attribute__ (( always_inline )) void
301 flsll_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 );
305 
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  */
320 static inline __attribute__ (( always_inline )) void
321 lsl64_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 );
326 
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  */
342 static inline __attribute__ (( always_inline )) void
343 lsr64_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 );
348 
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  */
364 static inline __attribute__ (( always_inline )) void
365 asr64_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 );
370 
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  */
387 static 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 );
396 
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  */
414 static 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 );
423 
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  */
435 static 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 */
518 struct self_test math_test __self_test = {
519  .name = "math",
520  .exec = math_test_exec,
521 };
#define __attribute__(x)
Definition: compiler.h:10
#define s64divmod_ok(dividend, divisor, quotient, remainder)
Definition: math_test.c:427
#define ffsl(x)
Find first (i.e.
Definition: strings.h:131
#define ffsl_ok(value, lsb)
Definition: math_test.c:252
#define lsl64_ok(value, shift, expected)
Definition: math_test.c:330
unsigned long isqrt(unsigned long value)
Find integer square root.
Definition: isqrt.c:40
unsigned long long uint64_t
Definition: stdint.h:13
Self-test infrastructure.
const char * name
Test set name.
Definition: test.h:17
static void ffsl_okx(long value, int lsb, const char *file, unsigned int line)
Report a ffsl() test result.
Definition: math_test.c:244
#define flsll(x)
Find last (i.e.
Definition: strings.h:148
A self-test set.
Definition: test.h:15
int ffsll_var(long long value)
Force a call to the non-constant implementation of ffsll()
Definition: math_test.c:57
int64_t s64div_var(int64_t dividend, int64_t divisor)
Force a use of runtime 64-bit signed integer division.
Definition: math_test.c:216
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:343
#define u64divmod_ok(dividend, divisor, quotient, remainder)
Definition: math_test.c:400
uint64_t u64div_var(uint64_t dividend, uint64_t divisor)
Force a use of runtime 64-bit unsigned integer division.
Definition: math_test.c:190
struct self_test math_test __self_test
Mathematical self-tests.
Definition: math_test.c:518
#define okx(success, file, line)
Report test result.
Definition: test.h:44
Assertions.
#define ffsll(x)
Find first (i.e.
Definition: strings.h:122
signed long long int64_t
Definition: stdint.h:18
#define ffsll_ok(value, lsb)
Definition: math_test.c:271
static void math_test_exec(void)
Perform mathematical self-tests.
Definition: math_test.c:435
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:365
pseudo_bit_t value[0x00020]
Definition: arbel.h:13
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:387
static void ffsll_okx(long long value, int lsb, const char *file, unsigned int line)
Report a ffsll() test result.
Definition: math_test.c:263
Integer square root.
static void * stack_check(void)
Check current stack pointer.
Definition: math_test.c:124
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:414
int64_t s64mod_var(int64_t dividend, int64_t divisor)
Force a use of runtime 64-bit unsigned integer modulus.
Definition: math_test.c:229
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
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
__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")
uint64_t u64mod_var(uint64_t dividend, uint64_t divisor)
Force a use of runtime 64-bit unsigned integer modulus.
Definition: math_test.c:203
#define flsll_ok(value, msb)
Definition: math_test.c:309
uint64_t lsl64_var(uint64_t value, unsigned int shift)
Force a use of runtime 64-bit shift left.
Definition: math_test.c:88
#define asr64_ok(value, shift, expected)
Definition: math_test.c:374
static void flsl_okx(long value, int msb, const char *file, unsigned int line)
Report a flsl() test result.
Definition: math_test.c:282
int flsll_var(long long value)
Force a call to the non-constant implementation of flsll()
Definition: math_test.c:77
static void flsll_okx(long long value, int msb, const char *file, unsigned int line)
Report a flsll() test result.
Definition: math_test.c:301
#define check_divmod(dividend, divisor, OP)
Check division/modulus operation.
Definition: math_test.c:154
int ffsl_var(long value)
Force a call to the non-constant implementation of ffsl()
Definition: math_test.c:47
#define flsl(x)
Find last (i.e.
Definition: strings.h:157
#define lsr64_ok(value, shift, expected)
Definition: math_test.c:352
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:321
int flsl_var(long value)
Force a call to the non-constant implementation of flsl()
Definition: math_test.c:67
#define ok(success)
Definition: test.h:46
String functions.
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
String functions.
#define flsl_ok(value, msb)
Definition: math_test.c:290