LCOV - code coverage report
Current view: top level - src/test/modules/test_int128 - test_int128.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 62.4 % 125 78
Test Date: 2026-02-28 12:14:50 Functions: 100.0 % 2 2
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*-------------------------------------------------------------------------
       2              :  *
       3              :  * test_int128.c
       4              :  *    Testbed for roll-our-own 128-bit integer arithmetic.
       5              :  *
       6              :  * This is a standalone test program that compares the behavior of an
       7              :  * implementation in int128.h to an (assumed correct) int128 native type.
       8              :  *
       9              :  * Copyright (c) 2017-2026, PostgreSQL Global Development Group
      10              :  *
      11              :  *
      12              :  * IDENTIFICATION
      13              :  *    src/test/modules/test_int128/test_int128.c
      14              :  *
      15              :  *-------------------------------------------------------------------------
      16              :  */
      17              : 
      18              : #include "postgres_fe.h"
      19              : 
      20              : #include <time.h>
      21              : 
      22              : /* Require a native int128 type */
      23              : #ifdef HAVE_INT128
      24              : 
      25              : /*
      26              :  * By default, we test the non-native implementation in int128.h; but
      27              :  * by predefining USE_NATIVE_INT128 to 1, you can test the native
      28              :  * implementation, just to be sure.
      29              :  */
      30              : #ifndef USE_NATIVE_INT128
      31              : #define USE_NATIVE_INT128 0
      32              : #endif
      33              : 
      34              : #include "common/int128.h"
      35              : #include "common/pg_prng.h"
      36              : 
      37              : /*
      38              :  * We assume the parts of this union are laid out compatibly.
      39              :  */
      40              : typedef union
      41              : {
      42              :     int128      i128;
      43              :     INT128      I128;
      44              :     struct
      45              :     {
      46              : #ifdef WORDS_BIGENDIAN
      47              :         int64       hi;
      48              :         uint64      lo;
      49              : #else
      50              :         uint64      lo;
      51              :         int64       hi;
      52              : #endif
      53              :     }           hl;
      54              : } test128;
      55              : 
      56              : #define INT128_HEX_FORMAT   "%016" PRIx64 "%016" PRIx64
      57              : 
      58              : /*
      59              :  * Control version of comparator.
      60              :  */
      61              : static inline int
      62      2000000 : my_int128_compare(int128 x, int128 y)
      63              : {
      64      2000000 :     if (x < y)
      65      1000738 :         return -1;
      66       999262 :     if (x > y)
      67       999262 :         return 1;
      68            0 :     return 0;
      69              : }
      70              : 
      71              : /*
      72              :  * Main program.
      73              :  *
      74              :  * Generates a lot of random numbers and tests the implementation for each.
      75              :  * The results should be reproducible, since we use a fixed PRNG seed.
      76              :  *
      77              :  * You can give a loop count if you don't like the default 1B iterations.
      78              :  */
      79              : int
      80            1 : main(int argc, char **argv)
      81              : {
      82              :     long        count;
      83              : 
      84            1 :     pg_prng_seed(&pg_global_prng_state, (uint64) time(NULL));
      85              : 
      86            1 :     if (argc >= 2)
      87            1 :         count = strtol(argv[1], NULL, 0);
      88              :     else
      89            0 :         count = 1000000000;
      90              : 
      91      1000001 :     while (count-- > 0)
      92              :     {
      93      1000000 :         int64       x = pg_prng_int64(&pg_global_prng_state);
      94      1000000 :         int64       y = pg_prng_int64(&pg_global_prng_state);
      95      1000000 :         int64       z = pg_prng_int64(&pg_global_prng_state);
      96      1000000 :         int64       w = pg_prng_int64(&pg_global_prng_state);
      97      1000000 :         int32       z32 = pg_prng_int32(&pg_global_prng_state);
      98              :         test128     t1;
      99              :         test128     t2;
     100              :         test128     t3;
     101              :         int32       r1;
     102              :         int32       r2;
     103              : 
     104              :         /* prevent division by zero in the 128/32-bit division test */
     105      1000000 :         while (z32 == 0)
     106            0 :             z32 = pg_prng_int32(&pg_global_prng_state);
     107              : 
     108              :         /* check unsigned addition */
     109      1000000 :         t1.hl.hi = x;
     110      1000000 :         t1.hl.lo = y;
     111      1000000 :         t2 = t1;
     112      1000000 :         t1.i128 += (int128) (uint64) z;
     113      1000000 :         int128_add_uint64(&t2.I128, (uint64) z);
     114              : 
     115      1000000 :         if (t1.hl.hi != t2.hl.hi || t1.hl.lo != t2.hl.lo)
     116              :         {
     117            0 :             printf(INT128_HEX_FORMAT " + unsigned %016" PRIx64 "\n", x, y, z);
     118            0 :             printf("native = " INT128_HEX_FORMAT "\n", t1.hl.hi, t1.hl.lo);
     119            0 :             printf("result = " INT128_HEX_FORMAT "\n", t2.hl.hi, t2.hl.lo);
     120            0 :             return 1;
     121              :         }
     122              : 
     123              :         /* check signed addition */
     124      1000000 :         t1.hl.hi = x;
     125      1000000 :         t1.hl.lo = y;
     126      1000000 :         t2 = t1;
     127      1000000 :         t1.i128 += (int128) z;
     128      1000000 :         int128_add_int64(&t2.I128, z);
     129              : 
     130      1000000 :         if (t1.hl.hi != t2.hl.hi || t1.hl.lo != t2.hl.lo)
     131              :         {
     132            0 :             printf(INT128_HEX_FORMAT " + signed %016" PRIx64 "\n", x, y, z);
     133            0 :             printf("native = " INT128_HEX_FORMAT "\n", t1.hl.hi, t1.hl.lo);
     134            0 :             printf("result = " INT128_HEX_FORMAT "\n", t2.hl.hi, t2.hl.lo);
     135            0 :             return 1;
     136              :         }
     137              : 
     138              :         /* check 128-bit signed addition */
     139      1000000 :         t1.hl.hi = x;
     140      1000000 :         t1.hl.lo = y;
     141      1000000 :         t2 = t1;
     142      1000000 :         t3.hl.hi = z;
     143      1000000 :         t3.hl.lo = w;
     144      1000000 :         t1.i128 += t3.i128;
     145      1000000 :         int128_add_int128(&t2.I128, t3.I128);
     146              : 
     147      1000000 :         if (t1.hl.hi != t2.hl.hi || t1.hl.lo != t2.hl.lo)
     148              :         {
     149            0 :             printf(INT128_HEX_FORMAT " + " INT128_HEX_FORMAT "\n", x, y, z, w);
     150            0 :             printf("native = " INT128_HEX_FORMAT "\n", t1.hl.hi, t1.hl.lo);
     151            0 :             printf("result = " INT128_HEX_FORMAT "\n", t2.hl.hi, t2.hl.lo);
     152            0 :             return 1;
     153              :         }
     154              : 
     155              :         /* check unsigned subtraction */
     156      1000000 :         t1.hl.hi = x;
     157      1000000 :         t1.hl.lo = y;
     158      1000000 :         t2 = t1;
     159      1000000 :         t1.i128 -= (int128) (uint64) z;
     160      1000000 :         int128_sub_uint64(&t2.I128, (uint64) z);
     161              : 
     162      1000000 :         if (t1.hl.hi != t2.hl.hi || t1.hl.lo != t2.hl.lo)
     163              :         {
     164            0 :             printf(INT128_HEX_FORMAT " - unsigned %016" PRIx64 "\n", x, y, z);
     165            0 :             printf("native = " INT128_HEX_FORMAT "\n", t1.hl.hi, t1.hl.lo);
     166            0 :             printf("result = " INT128_HEX_FORMAT "\n", t2.hl.hi, t2.hl.lo);
     167            0 :             return 1;
     168              :         }
     169              : 
     170              :         /* check signed subtraction */
     171      1000000 :         t1.hl.hi = x;
     172      1000000 :         t1.hl.lo = y;
     173      1000000 :         t2 = t1;
     174      1000000 :         t1.i128 -= (int128) z;
     175      1000000 :         int128_sub_int64(&t2.I128, z);
     176              : 
     177      1000000 :         if (t1.hl.hi != t2.hl.hi || t1.hl.lo != t2.hl.lo)
     178              :         {
     179            0 :             printf(INT128_HEX_FORMAT " - signed %016" PRIx64 "\n", x, y, z);
     180            0 :             printf("native = " INT128_HEX_FORMAT "\n", t1.hl.hi, t1.hl.lo);
     181            0 :             printf("result = " INT128_HEX_FORMAT "\n", t2.hl.hi, t2.hl.lo);
     182            0 :             return 1;
     183              :         }
     184              : 
     185              :         /* check 64x64-bit multiply-add */
     186      1000000 :         t1.hl.hi = x;
     187      1000000 :         t1.hl.lo = y;
     188      1000000 :         t2 = t1;
     189      1000000 :         t1.i128 += (int128) z * (int128) w;
     190      1000000 :         int128_add_int64_mul_int64(&t2.I128, z, w);
     191              : 
     192      1000000 :         if (t1.hl.hi != t2.hl.hi || t1.hl.lo != t2.hl.lo)
     193              :         {
     194            0 :             printf(INT128_HEX_FORMAT " + %016" PRIx64 " * %016" PRIx64 "\n", x, y, z, w);
     195            0 :             printf("native = " INT128_HEX_FORMAT "\n", t1.hl.hi, t1.hl.lo);
     196            0 :             printf("result = " INT128_HEX_FORMAT "\n", t2.hl.hi, t2.hl.lo);
     197            0 :             return 1;
     198              :         }
     199              : 
     200              :         /* check 64x64-bit multiply-subtract */
     201      1000000 :         t1.hl.hi = x;
     202      1000000 :         t1.hl.lo = y;
     203      1000000 :         t2 = t1;
     204      1000000 :         t1.i128 -= (int128) z * (int128) w;
     205      1000000 :         int128_sub_int64_mul_int64(&t2.I128, z, w);
     206              : 
     207      1000000 :         if (t1.hl.hi != t2.hl.hi || t1.hl.lo != t2.hl.lo)
     208              :         {
     209            0 :             printf(INT128_HEX_FORMAT " - %016" PRIx64 " * %016" PRIx64 "\n", x, y, z, w);
     210            0 :             printf("native = " INT128_HEX_FORMAT "\n", t1.hl.hi, t1.hl.lo);
     211            0 :             printf("result = " INT128_HEX_FORMAT "\n", t2.hl.hi, t2.hl.lo);
     212            0 :             return 1;
     213              :         }
     214              : 
     215              :         /* check 128/32-bit division */
     216      1000000 :         t3.hl.hi = x;
     217      1000000 :         t3.hl.lo = y;
     218      1000000 :         t1.i128 = t3.i128 / z32;
     219      1000000 :         r1 = (int32) (t3.i128 % z32);
     220      1000000 :         t2 = t3;
     221      1000000 :         int128_div_mod_int32(&t2.I128, z32, &r2);
     222              : 
     223      1000000 :         if (t1.hl.hi != t2.hl.hi || t1.hl.lo != t2.hl.lo)
     224              :         {
     225            0 :             printf(INT128_HEX_FORMAT " / signed %08X\n", t3.hl.hi, t3.hl.lo, z32);
     226            0 :             printf("native = " INT128_HEX_FORMAT "\n", t1.hl.hi, t1.hl.lo);
     227            0 :             printf("result = " INT128_HEX_FORMAT "\n", t2.hl.hi, t2.hl.lo);
     228            0 :             return 1;
     229              :         }
     230      1000000 :         if (r1 != r2)
     231              :         {
     232            0 :             printf(INT128_HEX_FORMAT " %% signed %08X\n", t3.hl.hi, t3.hl.lo, z32);
     233            0 :             printf("native = %08X\n", r1);
     234            0 :             printf("result = %08X\n", r2);
     235            0 :             return 1;
     236              :         }
     237              : 
     238              :         /* check comparison */
     239      1000000 :         t1.hl.hi = x;
     240      1000000 :         t1.hl.lo = y;
     241      1000000 :         t2.hl.hi = z;
     242      1000000 :         t2.hl.lo = w;
     243              : 
     244      2000000 :         if (my_int128_compare(t1.i128, t2.i128) !=
     245      1000000 :             int128_compare(t1.I128, t2.I128))
     246              :         {
     247            0 :             printf("comparison failure: %d vs %d\n",
     248              :                    my_int128_compare(t1.i128, t2.i128),
     249              :                    int128_compare(t1.I128, t2.I128));
     250            0 :             printf("arg1 = " INT128_HEX_FORMAT "\n", t1.hl.hi, t1.hl.lo);
     251            0 :             printf("arg2 = " INT128_HEX_FORMAT "\n", t2.hl.hi, t2.hl.lo);
     252            0 :             return 1;
     253              :         }
     254              : 
     255              :         /* check case with identical hi parts; above will hardly ever hit it */
     256      1000000 :         t2.hl.hi = x;
     257              : 
     258      2000000 :         if (my_int128_compare(t1.i128, t2.i128) !=
     259      1000000 :             int128_compare(t1.I128, t2.I128))
     260              :         {
     261            0 :             printf("comparison failure: %d vs %d\n",
     262              :                    my_int128_compare(t1.i128, t2.i128),
     263              :                    int128_compare(t1.I128, t2.I128));
     264            0 :             printf("arg1 = " INT128_HEX_FORMAT "\n", t1.hl.hi, t1.hl.lo);
     265            0 :             printf("arg2 = " INT128_HEX_FORMAT "\n", t2.hl.hi, t2.hl.lo);
     266            0 :             return 1;
     267              :         }
     268              :     }
     269              : 
     270            1 :     return 0;
     271              : }
     272              : 
     273              : #else                           /* ! HAVE_INT128 */
     274              : 
     275              : /*
     276              :  * For now, do nothing if we don't have a native int128 type.
     277              :  */
     278              : int
     279              : main(int argc, char **argv)
     280              : {
     281              :     printf("skipping tests: no native int128 type\n");
     282              :     return 0;
     283              : }
     284              : 
     285              : #endif
        

Generated by: LCOV version 2.0-1