iPXE
Defines | Functions | Variables
math_test.c File Reference

Mathematical self-tests. More...

#include <string.h>
#include <strings.h>
#include <assert.h>
#include <ipxe/test.h>
#include <ipxe/isqrt.h>

Go to the source code of this file.

Defines

#define check_divmod(dividend, divisor, OP)
 Check division/modulus operation.
#define ffsl_ok(value, lsb)   ffsl_okx ( value, lsb, __FILE__, __LINE__ )
#define ffsll_ok(value, lsb)   ffsll_okx ( value, lsb, __FILE__, __LINE__ )
#define flsl_ok(value, msb)   flsl_okx ( value, msb, __FILE__, __LINE__ )
#define flsll_ok(value, msb)   flsll_okx ( value, msb, __FILE__, __LINE__ )
#define u64divmod_ok(dividend, divisor, quotient, remainder)
#define s64divmod_ok(dividend, divisor, quotient, remainder)

Functions

 FILE_LICENCE (GPL2_OR_LATER_OR_UBDL)
int ffsl_var (long value)
 Force a call to the non-constant implementation of ffsl()
int ffsll_var (long long value)
 Force a call to the non-constant implementation of ffsll()
int flsl_var (long value)
 Force a call to the non-constant implementation of flsl()
int flsll_var (long long value)
 Force a call to the non-constant implementation of flsll()
static void * stack_check (void)
 Check current stack pointer.
uint64_t u64div_var (uint64_t dividend, uint64_t divisor)
 Force a use of runtime 64-bit unsigned integer division.
uint64_t u64mod_var (uint64_t dividend, uint64_t divisor)
 Force a use of runtime 64-bit unsigned integer modulus.
int64_t s64div_var (int64_t dividend, int64_t divisor)
 Force a use of runtime 64-bit signed integer division.
int64_t s64mod_var (int64_t dividend, int64_t divisor)
 Force a use of runtime 64-bit unsigned integer modulus.
static void ffsl_okx (long value, int lsb, const char *file, unsigned int line)
 Report a ffsl() test result.
static void ffsll_okx (long long value, int lsb, const char *file, unsigned int line)
 Report a ffsll() test result.
static void flsl_okx (long value, int msb, const char *file, unsigned int line)
 Report a flsl() test result.
static void flsll_okx (long long value, int msb, const char *file, unsigned int line)
 Report a flsll() test result.
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.
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.
static void math_test_exec (void)
 Perform mathematical self-tests.

Variables

struct self_test math_test __self_test
 Mathematical self-tests.

Detailed Description

Mathematical self-tests.

Definition in file math_test.c.


Define Documentation

#define check_divmod (   dividend,
  divisor,
  OP 
)
Value:
( {                     \
        uint64_t result;                                                \
        int count = 2;                                                  \
        void *check = NULL;                                             \
                                                                        \
        /* Prevent compiler from unrolling the loop */                  \
        __asm__ ( "\n" : "=g" ( count ) : "0" ( count ) );              \
                                                                        \
        do {                                                            \
                /* Check that stack pointer does not change between     \
                 * loop iterations.                                     \
                 */                                                     \
                if ( check ) {                                          \
                        assert ( check == stack_check() );              \
                } else {                                                \
                        check = stack_check();                          \
                }                                                       \
                                                                        \
                /* Perform division, preventing the compiler from       \
                 * moving the division out of the loop.                 \
                 */                                                     \
                __asm__ ( "\n" : "=g" ( dividend ), "=g" ( divisor )    \
                          : "0" ( dividend ), "1" ( divisor ) );        \
                result = ( dividend OP divisor );                       \
                __asm__ ( "\n" : "=g" ( result ) : "0" ( result ) );    \
                                                                        \
        } while ( --count );                                            \
        result; } )

Check division/modulus operation.

One aspect of the calling convention for the implicit arithmetic functions (__udivmoddi4() etc) is whether the caller or the callee is expected to pop any stack-based arguments. This distinction can be masked if the compiler chooses to uses a frame pointer in the caller, since the caller will then reload the stack pointer from the frame pointer and so can mask an error in the value of the stack pointer.

We run the division operation in a loop, and check that the stack pointer does not change value on the second iteration. To prevent the compiler from performing various optimisations which might invalidate our intended test (such as unrolling the loop, or moving the division operation outside the loop), we include some dummy inline assembly code.

Definition at line 118 of file math_test.c.

Referenced by s64div_var(), s64mod_var(), u64div_var(), and u64mod_var().

#define ffsl_ok (   value,
  lsb 
)    ffsl_okx ( value, lsb, __FILE__, __LINE__ )

Definition at line 212 of file math_test.c.

Referenced by math_test_exec().

#define ffsll_ok (   value,
  lsb 
)    ffsll_okx ( value, lsb, __FILE__, __LINE__ )

Definition at line 231 of file math_test.c.

Referenced by math_test_exec().

#define flsl_ok (   value,
  msb 
)    flsl_okx ( value, msb, __FILE__, __LINE__ )

Definition at line 250 of file math_test.c.

Referenced by math_test_exec().

#define flsll_ok (   value,
  msb 
)    flsll_okx ( value, msb, __FILE__, __LINE__ )

Definition at line 269 of file math_test.c.

Referenced by math_test_exec().

#define u64divmod_ok (   dividend,
  divisor,
  quotient,
  remainder 
)
Value:
u64divmod_okx ( dividend, divisor, quotient, remainder, \
                        __FILE__, __LINE__ )

Definition at line 294 of file math_test.c.

Referenced by math_test_exec().

#define s64divmod_ok (   dividend,
  divisor,
  quotient,
  remainder 
)
Value:
s64divmod_okx ( dividend, divisor, quotient, remainder, \
                        __FILE__, __LINE__ )

Definition at line 321 of file math_test.c.

Referenced by math_test_exec().


Function Documentation

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL  )
int ffsl_var ( long  value)

Force a call to the non-constant implementation of ffsl()

Parameters:
valueValue
Return values:
lsbLeast significant bit set in value (LSB=1), or zero

Definition at line 47 of file math_test.c.

References ffsl.

                                                         {
        return ffsl ( value );
}
int ffsll_var ( long long  value)

Force a call to the non-constant implementation of ffsll()

Parameters:
valueValue
Return values:
lsbLeast significant bit set in value (LSB=1), or zero

Definition at line 57 of file math_test.c.

References ffsll.

                                                               {
        return ffsll ( value );
}
int flsl_var ( long  value)

Force a call to the non-constant implementation of flsl()

Parameters:
valueValue
Return values:
msbMost significant bit set in value (LSB=1), or zero

Definition at line 67 of file math_test.c.

References flsl.

                                                         {
        return flsl ( value );
}
int flsll_var ( long long  value)

Force a call to the non-constant implementation of flsll()

Parameters:
valueValue
Return values:
msbMost significant bit set in value (LSB=1), or zero

Definition at line 77 of file math_test.c.

References flsll.

                                                               {
        return flsll ( value );
}
static void* stack_check ( void  ) [static]

Check current stack pointer.

Return values:
stackA value at a fixed offset from the current stack pointer

Used by check_divmod()

Definition at line 88 of file math_test.c.

References __asm__(), and ret.

                                                                {
        int a;
        void *ret;

        /* Hide the fact that we are returning the address of a local
         * variable, to prevent a compiler warning.
         */
        __asm__ ( "\n" : "=g" ( ret ) : "0" ( &a ) );

        return ret;
}
uint64_t u64div_var ( uint64_t  dividend,
uint64_t  divisor 
)

Force a use of runtime 64-bit unsigned integer division.

Parameters:
dividendDividend
divisorDivisor
Return values:
quotientQuotient

Definition at line 150 of file math_test.c.

References check_divmod.

Referenced by u64divmod_okx().

                                                                      {
uint64_t u64mod_var ( uint64_t  dividend,
uint64_t  divisor 
)

Force a use of runtime 64-bit unsigned integer modulus.

Parameters:
dividendDividend
divisorDivisor
Return values:
remainderRemainder

Definition at line 163 of file math_test.c.

References check_divmod.

                                                                      {
int64_t s64div_var ( int64_t  dividend,
int64_t  divisor 
)

Force a use of runtime 64-bit signed integer division.

Parameters:
dividendDividend
divisorDivisor
Return values:
quotientQuotient

Definition at line 176 of file math_test.c.

References check_divmod.

Referenced by s64divmod_okx().

                                                                    {
int64_t s64mod_var ( int64_t  dividend,
int64_t  divisor 
)

Force a use of runtime 64-bit unsigned integer modulus.

Parameters:
dividendDividend
divisorDivisor
Return values:
remainderRemainder

Definition at line 189 of file math_test.c.

References check_divmod.

                                                                    {
static void ffsl_okx ( long  value,
int  lsb,
const char *  file,
unsigned int  line 
) [inline, static]

Report a ffsl() test result.

Parameters:
valueValue
lsbExpected LSB
fileTest code file
lineTest code line

Definition at line 204 of file math_test.c.

References ffsl, and okx.

                                                                      {

        /* Verify as a constant (requires to be inlined) */
        okx ( ffsl ( value ) == lsb, file, line );
static void ffsll_okx ( long long  value,
int  lsb,
const char *  file,
unsigned int  line 
) [inline, static]

Report a ffsll() test result.

Parameters:
valueValue
lsbExpected LSB
fileTest code file
lineTest code line

Definition at line 223 of file math_test.c.

References ffsll, and okx.

                                                                            {

        /* Verify as a constant (requires to be inlined) */
        okx ( ffsll ( value ) == lsb, file, line );
static void flsl_okx ( long  value,
int  msb,
const char *  file,
unsigned int  line 
) [inline, static]

Report a flsl() test result.

Parameters:
valueValue
msbExpected MSB
fileTest code file
lineTest code line

Definition at line 242 of file math_test.c.

References flsl, and okx.

                                                                      {

        /* Verify as a constant (requires to be inlined) */
        okx ( flsl ( value ) == msb, file, line );
static void flsll_okx ( long long  value,
int  msb,
const char *  file,
unsigned int  line 
) [inline, static]

Report a flsll() test result.

Parameters:
valueValue
msbExpected MSB
fileTest code file
lineTest code line

Definition at line 261 of file math_test.c.

References flsll, and okx.

                                                                            {

        /* Verify as a constant (requires to be inlined) */
        okx ( flsll ( value ) == msb, file, line );
static void u64divmod_okx ( uint64_t  dividend,
uint64_t  divisor,
uint64_t  quotient,
uint64_t  remainder,
const char *  file,
unsigned int  line 
) [static]

Report a 64-bit unsigned integer division test result.

Parameters:
dividendDividend
divisorDivisor
quotientQuotient
remainderRemainder
fileTest code file
lineTest code line

Definition at line 281 of file math_test.c.

References okx, and u64div_var().

                                                                  {

        /* Sanity check */
        okx ( ( ( divisor * quotient ) + remainder ) == dividend, file, line );

        /* Check division */
        okx ( u64div_var ( dividend, divisor ) == quotient, file, line );
static void s64divmod_okx ( int64_t  dividend,
int64_t  divisor,
int64_t  quotient,
int64_t  remainder,
const char *  file,
unsigned int  line 
) [static]

Report a 64-bit signed integer division test result.

Parameters:
dividendDividend
divisorDivisor
quotientQuotient
remainderRemainder
fileTest code file
lineTest code line

Definition at line 308 of file math_test.c.

References okx, and s64div_var().

                                                                  {

        /* Sanity check */
        okx ( ( ( divisor * quotient ) + remainder ) == dividend, file, line );

        /* Check division */
        okx ( s64div_var ( dividend, divisor ) == quotient, file, line );
static void math_test_exec ( void  ) [static]

Perform mathematical self-tests.

Definition at line 329 of file math_test.c.

References ffsl_ok, ffsll_ok, flsl_ok, flsll_ok, isqrt(), ok, s64divmod_ok, and u64divmod_ok.

                                    {

        /* Test ffsl() */
        ffsl_ok ( 0, 0 );
        ffsl_ok ( 1, 1 );
        ffsl_ok ( 255, 1 );
        ffsl_ok ( 256, 9 );
        ffsl_ok ( 257, 1 );
        ffsl_ok ( 0x54850596, 2 );
        ffsl_ok ( 0x80000000, 32 );

        /* Test ffsll() */
        ffsll_ok ( 0, 0 );
        ffsll_ok ( 1, 1 );
        ffsll_ok ( 0x6d63623330ULL, 5 );
        ffsll_ok ( 0x80000000UL, 32 );
        ffsll_ok ( 0x8000000000000000ULL, 64 );

        /* Test flsl() */
        flsl_ok ( 0, 0 );
        flsl_ok ( 1, 1 );
        flsl_ok ( 255, 8 );
        flsl_ok ( 256, 9 );
        flsl_ok ( 257, 9 );
        flsl_ok ( 0x69505845, 31 );
        flsl_ok ( -1U, ( 8 * sizeof ( int ) ) );
        flsl_ok ( -1UL, ( 8 * sizeof ( long ) ) );

        /* Test flsll() */
        flsll_ok ( 0, 0 );
        flsll_ok ( 1, 1 );
        flsll_ok ( 0x6d63623330ULL, 39 );
        flsll_ok ( -1U, ( 8 * sizeof ( int ) ) );
        flsll_ok ( -1UL, ( 8 * sizeof ( long ) ) );
        flsll_ok ( -1ULL, ( 8 * sizeof ( long long ) ) );

        /* Test 64-bit arithmetic
         *
         * On a 64-bit machine, these tests are fairly meaningless.
         *
         * On a 32-bit machine, these tests verify the correct
         * operation of our libgcc functions __udivmoddi4()
         * etc. (including checking that the implicit calling
         * convention assumed by gcc matches our expectations).
         */
        u64divmod_ok ( 0x2b90ddccf699f765ULL, 0xed9f5e73ULL,
                       0x2eef6ab4ULL, 0x0e12f089ULL );
        s64divmod_ok ( 0x2b90ddccf699f765ULL, 0xed9f5e73ULL,
                       0x2eef6ab4ULL, 0x0e12f089ULL );
        u64divmod_ok ( 0xc09e00dcb9e34b54ULL, 0x35968185cdc744f3ULL,
                       3, 0x1fda7c4b508d7c7bULL );
        s64divmod_ok ( -0x3f61ff23461cb4acLL, 0x35968185cdc744f3ULL,
                       -1LL, -0x9cb7d9d78556fb9LL );
        u64divmod_ok ( 0, 0x5b2f2737f4ffULL, 0, 0 );
        s64divmod_ok ( 0, 0xbb00ded72766207fULL, 0, 0 );

        /* Test integer square root */
        ok ( isqrt ( 0 ) == 0 );
        ok ( isqrt ( 1 ) == 1 );
        ok ( isqrt ( 255 ) == 15 );
        ok ( isqrt ( 256 ) == 16 );
        ok ( isqrt ( 257 ) == 16 );

Variable Documentation

struct self_test math_test __self_test
Initial value:
 {
        .name = "math",
        .exec = math_test_exec,
}

Mathematical self-tests.

Definition at line 397 of file math_test.c.