qemu/tests/test-int128.c
<<
>>
Prefs
   1/*
   2 * Test Int128 arithmetic
   3 *
   4 * This work is licensed under the terms of the GNU LGPL, version 2 or later.
   5 * See the COPYING.LIB file in the top-level directory.
   6 *
   7 */
   8
   9#include "qemu/osdep.h"
  10#include <glib.h>
  11#include "qemu/int128.h"
  12
  13/* clang doesn't support __noclone__ but it does have a mechanism for
  14 * telling us this. We assume that if we don't have __has_attribute()
  15 * then this is GCC and that GCC always supports __noclone__.
  16 */
  17#if defined(__has_attribute)
  18#if !__has_attribute(__noclone__)
  19#define ATTRIBUTE_NOCLONE
  20#endif
  21#endif
  22#ifndef ATTRIBUTE_NOCLONE
  23#define ATTRIBUTE_NOCLONE __attribute__((__noclone__))
  24#endif
  25
  26static uint32_t tests[8] = {
  27    0x00000000, 0x00000001, 0x7FFFFFFE, 0x7FFFFFFF,
  28    0x80000000, 0x80000001, 0xFFFFFFFE, 0xFFFFFFFF,
  29};
  30
  31#define LOW    3ULL
  32#define HIGH   (1ULL << 63)
  33#define MIDDLE (-1ULL & ~LOW & ~HIGH)
  34
  35static uint64_t expand16(unsigned x)
  36{
  37    return (x & LOW) | ((x & 4) ? MIDDLE : 0) | (x & 0x8000 ? HIGH : 0);
  38}
  39
  40static Int128 expand(uint32_t x)
  41{
  42    uint64_t l, h;
  43    l = expand16(x & 65535);
  44    h = expand16(x >> 16);
  45    return (Int128) {l, h};
  46};
  47
  48static void test_and(void)
  49{
  50    int i, j;
  51
  52    for (i = 0; i < ARRAY_SIZE(tests); ++i) {
  53        for (j = 0; j < ARRAY_SIZE(tests); ++j) {
  54            Int128 a = expand(tests[i]);
  55            Int128 b = expand(tests[j]);
  56            Int128 r = expand(tests[i] & tests[j]);
  57            Int128 s = int128_and(a, b);
  58            g_assert_cmpuint(r.lo, ==, s.lo);
  59            g_assert_cmpuint(r.hi, ==, s.hi);
  60        }
  61    }
  62}
  63
  64static void test_add(void)
  65{
  66    int i, j;
  67
  68    for (i = 0; i < ARRAY_SIZE(tests); ++i) {
  69        for (j = 0; j < ARRAY_SIZE(tests); ++j) {
  70            Int128 a = expand(tests[i]);
  71            Int128 b = expand(tests[j]);
  72            Int128 r = expand(tests[i] + tests[j]);
  73            Int128 s = int128_add(a, b);
  74            g_assert_cmpuint(r.lo, ==, s.lo);
  75            g_assert_cmpuint(r.hi, ==, s.hi);
  76        }
  77    }
  78}
  79
  80static void test_sub(void)
  81{
  82    int i, j;
  83
  84    for (i = 0; i < ARRAY_SIZE(tests); ++i) {
  85        for (j = 0; j < ARRAY_SIZE(tests); ++j) {
  86            Int128 a = expand(tests[i]);
  87            Int128 b = expand(tests[j]);
  88            Int128 r = expand(tests[i] - tests[j]);
  89            Int128 s = int128_sub(a, b);
  90            g_assert_cmpuint(r.lo, ==, s.lo);
  91            g_assert_cmpuint(r.hi, ==, s.hi);
  92        }
  93    }
  94}
  95
  96static void test_neg(void)
  97{
  98    int i;
  99
 100    for (i = 0; i < ARRAY_SIZE(tests); ++i) {
 101        Int128 a = expand(tests[i]);
 102        Int128 r = expand(-tests[i]);
 103        Int128 s = int128_neg(a);
 104        g_assert_cmpuint(r.lo, ==, s.lo);
 105        g_assert_cmpuint(r.hi, ==, s.hi);
 106    }
 107}
 108
 109static void test_nz(void)
 110{
 111    int i, j;
 112
 113    for (i = 0; i < ARRAY_SIZE(tests); ++i) {
 114        for (j = 0; j < ARRAY_SIZE(tests); ++j) {
 115            Int128 a = expand(tests[i]);
 116            g_assert_cmpuint(int128_nz(a), ==, tests[i] != 0);
 117        }
 118    }
 119}
 120
 121static void test_le(void)
 122{
 123    int i, j;
 124
 125    for (i = 0; i < ARRAY_SIZE(tests); ++i) {
 126        for (j = 0; j < ARRAY_SIZE(tests); ++j) {
 127            /* Signed comparison */
 128            int32_t a = (int32_t) tests[i];
 129            int32_t b = (int32_t) tests[j];
 130            g_assert_cmpuint(int128_le(expand(a), expand(b)), ==, a <= b);
 131        }
 132    }
 133}
 134
 135static void test_lt(void)
 136{
 137    int i, j;
 138
 139    for (i = 0; i < ARRAY_SIZE(tests); ++i) {
 140        for (j = 0; j < ARRAY_SIZE(tests); ++j) {
 141            /* Signed comparison */
 142            int32_t a = (int32_t) tests[i];
 143            int32_t b = (int32_t) tests[j];
 144            g_assert_cmpuint(int128_lt(expand(a), expand(b)), ==, a < b);
 145        }
 146    }
 147}
 148
 149static void test_ge(void)
 150{
 151    int i, j;
 152
 153    for (i = 0; i < ARRAY_SIZE(tests); ++i) {
 154        for (j = 0; j < ARRAY_SIZE(tests); ++j) {
 155            /* Signed comparison */
 156            int32_t a = (int32_t) tests[i];
 157            int32_t b = (int32_t) tests[j];
 158            g_assert_cmpuint(int128_ge(expand(a), expand(b)), ==, a >= b);
 159        }
 160    }
 161}
 162
 163static void test_gt(void)
 164{
 165    int i, j;
 166
 167    for (i = 0; i < ARRAY_SIZE(tests); ++i) {
 168        for (j = 0; j < ARRAY_SIZE(tests); ++j) {
 169            /* Signed comparison */
 170            int32_t a = (int32_t) tests[i];
 171            int32_t b = (int32_t) tests[j];
 172            g_assert_cmpuint(int128_gt(expand(a), expand(b)), ==, a > b);
 173        }
 174    }
 175}
 176
 177/* Make sure to test undefined behavior at runtime! */
 178
 179static void __attribute__((__noinline__)) ATTRIBUTE_NOCLONE
 180test_rshift_one(uint32_t x, int n, uint64_t h, uint64_t l)
 181{
 182    Int128 a = expand(x);
 183    Int128 r = int128_rshift(a, n);
 184    g_assert_cmpuint(r.lo, ==, l);
 185    g_assert_cmpuint(r.hi, ==, h);
 186}
 187
 188static void test_rshift(void)
 189{
 190    test_rshift_one(0x00010000U, 64, 0x0000000000000000ULL, 0x0000000000000001ULL);
 191    test_rshift_one(0x80010000U, 64, 0xFFFFFFFFFFFFFFFFULL, 0x8000000000000001ULL);
 192    test_rshift_one(0x7FFE0000U, 64, 0x0000000000000000ULL, 0x7FFFFFFFFFFFFFFEULL);
 193    test_rshift_one(0xFFFE0000U, 64, 0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFEULL);
 194    test_rshift_one(0x00010000U, 60, 0x0000000000000000ULL, 0x0000000000000010ULL);
 195    test_rshift_one(0x80010000U, 60, 0xFFFFFFFFFFFFFFF8ULL, 0x0000000000000010ULL);
 196    test_rshift_one(0x00018000U, 60, 0x0000000000000000ULL, 0x0000000000000018ULL);
 197    test_rshift_one(0x80018000U, 60, 0xFFFFFFFFFFFFFFF8ULL, 0x0000000000000018ULL);
 198    test_rshift_one(0x7FFE0000U, 60, 0x0000000000000007ULL, 0xFFFFFFFFFFFFFFE0ULL);
 199    test_rshift_one(0xFFFE0000U, 60, 0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFE0ULL);
 200    test_rshift_one(0x7FFE8000U, 60, 0x0000000000000007ULL, 0xFFFFFFFFFFFFFFE8ULL);
 201    test_rshift_one(0xFFFE8000U, 60, 0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFE8ULL);
 202    test_rshift_one(0x00018000U,  0, 0x0000000000000001ULL, 0x8000000000000000ULL);
 203    test_rshift_one(0x80018000U,  0, 0x8000000000000001ULL, 0x8000000000000000ULL);
 204    test_rshift_one(0x7FFE0000U,  0, 0x7FFFFFFFFFFFFFFEULL, 0x0000000000000000ULL);
 205    test_rshift_one(0xFFFE0000U,  0, 0xFFFFFFFFFFFFFFFEULL, 0x0000000000000000ULL);
 206    test_rshift_one(0x7FFE8000U,  0, 0x7FFFFFFFFFFFFFFEULL, 0x8000000000000000ULL);
 207    test_rshift_one(0xFFFE8000U,  0, 0xFFFFFFFFFFFFFFFEULL, 0x8000000000000000ULL);
 208}
 209
 210int main(int argc, char **argv)
 211{
 212    g_test_init(&argc, &argv, NULL);
 213    g_test_add_func("/int128/int128_and", test_and);
 214    g_test_add_func("/int128/int128_add", test_add);
 215    g_test_add_func("/int128/int128_sub", test_sub);
 216    g_test_add_func("/int128/int128_neg", test_neg);
 217    g_test_add_func("/int128/int128_nz", test_nz);
 218    g_test_add_func("/int128/int128_le", test_le);
 219    g_test_add_func("/int128/int128_lt", test_lt);
 220    g_test_add_func("/int128/int128_ge", test_ge);
 221    g_test_add_func("/int128/int128_gt", test_gt);
 222    g_test_add_func("/int128/int128_rshift", test_rshift);
 223    return g_test_run();
 224}
 225