| // Copyright lowRISC contributors. |
| // Licensed under the Apache License, Version 2.0, see LICENSE for details. |
| // SPDX-License-Identifier: Apache-2.0 |
| |
| #include <bitset> |
| #include <ostream> |
| #include <stdint.h> |
| |
| #include "gmock/gmock.h" |
| #include "gtest/gtest.h" |
| |
| // Reach into math_builtins.c and grab the internal testing symbols. |
| extern "C" { |
| int64_t _ot_builtin_lshift_i64(int64_t val, int32_t shift); |
| int64_t _ot_builtin_rshift_i64(int64_t val, int32_t shift); |
| int64_t _ot_builtin_ashift_i64(int64_t val, int32_t shift); |
| |
| int32_t _ot_builtin_bswap_i32(int32_t val); |
| int _ot_builtin_popcount_i32(int32_t val); |
| int _ot_builtin_parity_i32(int32_t val); |
| |
| int _ot_builtin_clz_i32(int32_t val); |
| int _ot_builtin_ctz_i32(int32_t val); |
| int _ot_builtin_find_first_i32(int32_t val); |
| } |
| |
| namespace math_unittest { |
| namespace { |
| |
| class ShiftTest : public testing::TestWithParam<std::tuple<uint64_t, int>> {}; |
| |
| TEST_P(ShiftTest, LShift) { |
| auto val = std::get<0>(GetParam()); |
| auto sh = std::get<1>(GetParam()); |
| EXPECT_EQ(_ot_builtin_lshift_i64(val, sh), val << sh); |
| } |
| |
| TEST_P(ShiftTest, RShift) { |
| auto val = std::get<0>(GetParam()); |
| auto sh = std::get<1>(GetParam()); |
| EXPECT_EQ(_ot_builtin_rshift_i64(val, sh), val >> sh); |
| } |
| |
| TEST_P(ShiftTest, AShift) { |
| int64_t val = std::get<0>(GetParam()); |
| auto sh = std::get<1>(GetParam()); |
| EXPECT_EQ(_ot_builtin_ashift_i64(val, sh), val >> sh); |
| } |
| |
| // clang-format off |
| constexpr uint64_t kShiftVectors[] = { |
| 0x72e31374b288d54b, 0xe3803f2635f6ee6f, 0xba25acc04b1c109f, 0xc47399918b992246, |
| 0xfcd337f4a9657652, 0xad1d516938ba9e58, 0xcaf2ea72ecab24ce, 0xe575c95799b3fd25, |
| 0x7179d63f5318a042, 0x66cb3b7bafa9ab91, 0x01e3a61671afb124, 0x883dec25388a7d17, |
| 0x2409a453b22f2afb, 0xa3a22aaf52b455a6, 0xe6aafa4b21df3fde, 0x1ab66cae8bf7f70a, |
| 0xa2c5ce0f7a8c39ae, 0xb4dfee68dc55a333, 0x424a9080c3eb7f28, 0x33e20b7ad01ed2d3, |
| 0x012986549ba5c18e, 0x71470e3eab601397, 0x7c641906111c4a97, 0x4947714cc88fa328, |
| 0x95ef5317cba3383a, 0x8cc65207c9a01c75, 0xbacd69c7b9f07da5, 0x7ea168d4980e39b1, |
| 0xfd434457e60eea3b, 0xfb06cbaefee8dac0, 0x59c6cbe506da5009, 0x17384e6055a26fda, |
| 0x5f7a2b0fb58b3d5b, 0x04581fca7eca14c5, 0xb0e85631e03a2f5f, 0x072ef34c9ffe2af0, |
| 0xb7a8416d262ab414, 0xaaeda113b5c0f99b, 0x5ec1edc1bb424e4c, 0xd7a6efda2c1adfd9, |
| 0x58c00ce60adee54e, 0x2738634afbe4fa68, 0xfbd84af315127e70, 0xd7b1c602bbc5f287, |
| 0xa87ed34fade4ca9e, 0x274c0d4536a73a4f, 0x6bd60d1fbd5dd8bf, 0x3e3480053ffa2b32, |
| 0xe4509fb8d04198c7, 0x1ca94e3528b69802, 0xc1db8afa638209dd, 0xf3b127563b4e67e6, |
| 0x55945fc85fce5a15, 0x2f46dfdd59dc99bb, 0xd305bd01c6fc90cb, 0xb6f3e737ae6852e2, |
| 0x23a1a2588da1b8bc, 0xa9e4f54d6aa91ab0, 0x754b06a594c37253, 0x530d325ad21250ad, |
| 0x9ba1df480099e563, 0xaeddb8f02430fa05, 0x95420781c1434885, 0x7ef252bb0353cc94, |
| 0x360b0516971db663, 0xd984feb6fb7f383d, 0xe76cb6124460dce4, 0x00b449c6afad532c, |
| 0x9549d9a4db6698bd, 0x472176983d94969d, 0x44203ca1c11f6698, 0x316b015904b9a585, |
| 0xef529bbe99f8789d, 0x6797c2899a4a6338, 0x5856d8199b694d0d, 0x40d8a06d9ea5d550, |
| 0x063371e154698005, 0xd0b4a74656dfacc3, 0x904d67ecddc9bdc1, 0xf3da1b4f14a8ee38, |
| 0xa7f2008e10ff5104, 0xc971d6076bb18705, 0x542052cbcf18e642, 0x8bc461ce47296918, |
| 0x050cd8d5a1d205f5, 0x96b852ad44647978, 0xf06eb96bb06c5014, 0x7f34e0824755f34d, |
| 0xef2bad1655aa4af3, 0xfa2a29654ec5cde7, 0x25c5b8b6be8210f9, 0xdb2abc045c3debf2, |
| 0xc87cd628ca86ee17, 0x754dcf0f9ef1f43f, 0x5b41d1713ec1d622, 0xf04e0ccadb55f484, |
| 0x91cc30dba5cb088a, 0x8fadd12094d86765, 0x4b32b8bf703b2bcb, 0x2b388b7267361d11, |
| 0x796c96e61c5cee34, 0xa422df223c6f4386, 0x2c73a57443bd8e55, 0x5055ba2568f0840e, |
| 0x2c12963cc6252411, 0x2866daa721519adf, 0x9cf9fc214a9bf499, 0xd2a1b710d03a83c8, |
| 0x4aaefeec333d2bc6, 0x74f426e6c662351d, 0xca9137650e7ff7ff, 0x81a59590069af3df, |
| 0x90413762d48e5fe4, 0x9acdf15570b4d51a, 0x7a18f080c38fbe68, 0x4819af998c5480b5, |
| 0x0b1ab546043e8c39, 0x5c41cd7dcd416951, 0x123138f887109c2d, 0xa75ed843bf10be7e, |
| 0xfd1361e852c595f0, 0xa9346bdc942d64db, 0xb090a120f73defb7, 0xff73e1a0c52dbc5e, |
| 0x3f32be41f8ba8b90, 0x72f3825c514d8bb8, 0xe4f28307980edcd7, 0x373036b9647f0a8b, |
| }; |
| // clang-format on |
| |
| INSTANTIATE_TEST_SUITE_P(ShiftTest, ShiftTest, |
| testing::Combine(testing::ValuesIn(kShiftVectors), |
| testing::Range(0, 63))); |
| |
| struct Bswap32Vector { |
| uint32_t a, b; |
| friend void operator<<(std::ostream &out, const Bswap32Vector &v) { |
| out << "{" << v.a << ", " << v.b << "}"; |
| } |
| }; |
| |
| class Bswap32Test : public testing::TestWithParam<Bswap32Vector> {}; |
| |
| TEST_P(Bswap32Test, Bswap32) { |
| EXPECT_EQ(_ot_builtin_bswap_i32(GetParam().a), GetParam().b); |
| } |
| |
| // Simple python snippet for generating vectors: |
| // |
| // import random |
| // def bswap(x): |
| // enc = x.to_bytes(4, byteorder='little') |
| // return int.from_bytes(enc, byteorder='big', signed=False) |
| // for _ in range(0, 16): |
| // line = [] |
| // for _ in range (0, 4): |
| // a = random.getrandbits(32) |
| // line.append(f"{{0x{a:08x}, 0x{bswap(a):08x}}},") |
| // print(" ".join(line)) |
| // clang-format off |
| constexpr Bswap32Vector kBswap32Vectors[] = { |
| {0xf695f7f1, 0xf1f795f6}, {0x0c607801, 0x0178600c}, {0x59ffdc85, 0x85dcff59}, {0xaa655be2, 0xe25b65aa}, |
| {0xaa7330bd, 0xbd3073aa}, {0xb6d355da, 0xda55d3b6}, {0xdb93201c, 0x1c2093db}, {0x24f94ecc, 0xcc4ef924}, |
| {0x1ac3b892, 0x92b8c31a}, {0xb82dd98f, 0x8fd92db8}, {0x22d45753, 0x5357d422}, {0x87d7b7c0, 0xc0b7d787}, |
| {0x51c134c8, 0xc834c151}, {0xb75bd393, 0x93d35bb7}, {0x4d728dd5, 0xd58d724d}, {0x82219f2c, 0x2c9f2182}, |
| {0xe5d4039f, 0x9f03d4e5}, {0xdad1b011, 0x11b0d1da}, {0x842cda8a, 0x8ada2c84}, {0xd0c139a3, 0xa339c1d0}, |
| {0x9457a5bd, 0xbda55794}, {0x3c9c4149, 0x49419c3c}, {0xfc885a02, 0x025a88fc}, {0xfcd849e1, 0xe149d8fc}, |
| {0xe74ea521, 0x21a54ee7}, {0xbd5cb79e, 0x9eb75cbd}, {0x64b922b6, 0xb622b964}, {0x83e4a528, 0x28a5e483}, |
| {0x37e301e2, 0xe201e337}, {0x30af4e73, 0x734eaf30}, {0x57844ed8, 0xd84e8457}, {0xf69e4821, 0x21489ef6}, |
| {0xedc4c65a, 0x5ac6c4ed}, {0x64864ea9, 0xa94e8664}, {0x62dc20bc, 0xbc20dc62}, {0x00512130, 0x30215100}, |
| {0x0e18fd9e, 0x9efd180e}, {0x53f3a1cc, 0xcca1f353}, {0xc667d326, 0x26d367c6}, {0x5158bd5c, 0x5cbd5851}, |
| {0xddbe895f, 0x5f89bedd}, {0xa2ff822a, 0x2a82ffa2}, {0xefa5f882, 0x82f8a5ef}, {0x7bf9d61a, 0x1ad6f97b}, |
| {0xfe5a30cf, 0xcf305afe}, {0x197df65f, 0x5ff67d19}, {0xab90efaf, 0xafef90ab}, {0x92d0ba32, 0x32bad092}, |
| {0x7649bf9f, 0x9fbf4976}, {0x3e98ff6a, 0x6aff983e}, {0x1069fd34, 0x34fd6910}, {0x1e9ed02c, 0x2cd09e1e}, |
| {0x1d0a8e62, 0x628e0a1d}, {0xc3aa9fb8, 0xb89faac3}, {0xf249d680, 0x80d649f2}, {0x50d8dea1, 0xa1ded850}, |
| {0xa15582fb, 0xfb8255a1}, {0xc85ebafd, 0xfdba5ec8}, {0x59f83e7e, 0x7e3ef859}, {0x74642a4e, 0x4e2a6474}, |
| {0xfb5833aa, 0xaa3358fb}, {0x0d6051bc, 0xbc51600d}, {0x81ab8c1d, 0x1d8cab81}, {0x8aa14e9d, 0x9d4ea18a}, |
| }; |
| // clang-format on |
| |
| INSTANTIATE_TEST_SUITE_P(Bswap32Test, Bswap32Test, |
| testing::ValuesIn(kBswap32Vectors)); |
| |
| struct CountBitsVector { |
| uint32_t bits, count; |
| friend void operator<<(std::ostream &out, const CountBitsVector &v) { |
| out << "{0b" << std::bitset<32>(v.bits) << ", " << v.count << "}"; |
| } |
| }; |
| |
| class Popcount32Test : public testing::TestWithParam<CountBitsVector> {}; |
| |
| TEST_P(Popcount32Test, Popcount32) { |
| EXPECT_EQ(_ot_builtin_popcount_i32(GetParam().bits), GetParam().count); |
| } |
| |
| TEST_P(Popcount32Test, Parity32) { |
| EXPECT_EQ(_ot_builtin_parity_i32(GetParam().bits), GetParam().count % 2); |
| } |
| |
| // Simple python snippet for generating vectors: |
| // |
| // import random |
| // def popcnt(x): |
| // return bin(x).count('1') |
| // for _ in range(0, 32): |
| // line = [] |
| // for _ in range (0, 2): |
| // a = random.getrandbits(32) |
| // line.append(f"{{0b{a:032b}, {popcnt(a)}}},") |
| // print(" ".join(line)) |
| // clang-format off |
| constexpr CountBitsVector kPopcount32Vectors[] = { |
| {0, 0}, {UINT32_MAX, 32}, // Trivial cases. |
| |
| {0b10010100010001010000001100111111, 14}, {0b11011001111100101001100001010100, 16}, |
| {0b00000000110111100011110111011111, 18}, {0b10101111100101100010000001111001, 16}, |
| {0b11000100010100101111011011100000, 15}, {0b11111101100111111010010000101000, 18}, |
| {0b00010001101111001100011000101011, 15}, {0b11101111000001000000110000101011, 14}, |
| {0b00110010011010111010011001111001, 17}, {0b10000110011010110000010000110000, 11}, |
| {0b00111111010000001010000010111101, 15}, {0b00100111011111011001111101101111, 22}, |
| {0b11100011100110000011111110000110, 17}, {0b00111100101000100010101000110011, 14}, |
| {0b01000011010000001010100111011101, 14}, {0b00010101000011001011100000011110, 13}, |
| {0b00011110111001101111000110000100, 16}, {0b10000110000010000100000100101001, 9}, |
| {0b00001111010011010100000000010101, 12}, {0b00110111100111000001011111111111, 21}, |
| {0b01001000000110100011011001010011, 13}, {0b11111100110111110110100111011010, 22}, |
| {0b00000001110111011000111100010101, 15}, {0b00010010101100101001100010001000, 11}, |
| {0b10110110000010001011111110010001, 16}, {0b11011101000111101010001011001001, 17}, |
| {0b00011000110101001100000001001100, 11}, {0b10101011011001011001100110011010, 17}, |
| {0b01001000000011111001111100001010, 14}, {0b00111110101010101011001010101011, 18}, |
| {0b10110000110100110111010110110011, 18}, {0b00110101110110101011101101010110, 19}, |
| {0b00000111110111010110010101000001, 15}, {0b10101000010001011010001010010111, 14}, |
| {0b00001100011011111010100010011001, 15}, {0b11000000100000010000000110100101, 9}, |
| {0b01101100010001100101110010011001, 15}, {0b01101011001111111010010111000110, 19}, |
| {0b00101101010100010010010110010100, 13}, {0b00100001100010001001100100100000, 9}, |
| {0b10101011100100110011011000000011, 15}, {0b10000000110010011111011010111011, 17}, |
| {0b01011100100101100000111001000011, 14}, {0b11101000110001110100101111101001, 18}, |
| {0b10010010010000001101001111110011, 15}, {0b10100100100011110100001010010110, 14}, |
| {0b11011000000001111100000010111001, 14}, {0b00010110000010010011000100101100, 11}, |
| {0b00010100110010010010001110110110, 14}, {0b01001001001100011010011010000000, 11}, |
| {0b10101010000001110110111111011101, 19}, {0b11011110100111001010010000000111, 16}, |
| {0b01000110001011110010111111100000, 16}, {0b01100111001111011001101100111010, 19}, |
| {0b00011000010001100100000001110110, 11}, {0b01100000100101001011000010010101, 12}, |
| {0b01000110110101110100101010111110, 18}, {0b11010110111010111001110100111110, 21}, |
| {0b01100001100011100011101000010110, 14}, {0b01001101010010001111100110101010, 16}, |
| {0b00110010100011111111101001111010, 19}, {0b11010010110101110010100100100101, 16}, |
| {0b00111100100001101010011101101100, 16}, {0b01010101111000010100001001011101, 15}, |
| }; |
| // clang-format on |
| |
| INSTANTIATE_TEST_SUITE_P(Popcount32Test, Popcount32Test, |
| testing::ValuesIn(kPopcount32Vectors)); |
| |
| class Ctz32Test : public testing::TestWithParam<CountBitsVector> {}; |
| |
| TEST_P(Ctz32Test, Ctz32) { |
| EXPECT_EQ(_ot_builtin_ctz_i32(GetParam().bits), GetParam().count); |
| } |
| |
| TEST_P(Ctz32Test, Ffs32) { |
| EXPECT_EQ(_ot_builtin_find_first_i32(GetParam().bits), GetParam().count + 1); |
| } |
| |
| // Simple python snippet for generating vectors: |
| // |
| // import random |
| // for i in range(0, 32): |
| // line = [] |
| // for _ in range (0, 2): |
| // a = random.getrandbits(32) |
| // a &= ((1 << (32 - i)) - 1) << i |
| // a |= (1 << i) |
| // line.append(f"{{0b{a:032b}, {i}}},") |
| // print(" ".join(line)) |
| // clang-format off |
| constexpr CountBitsVector kCtz32Vectors[] = { |
| {0b00011101000010010001101001101011, 0}, {0b10101100110101111100001001101011, 0}, |
| {0b00101000001011000000001110010110, 1}, {0b10101111000001011001011010001110, 1}, |
| {0b00111111010100111101010010001100, 2}, {0b00010110010100010110110011000100, 2}, |
| {0b01000101111100100000101010101000, 3}, {0b10111010011000111010100100001000, 3}, |
| {0b00001011001110000100011110110000, 4}, {0b00010100010100110011011101010000, 4}, |
| {0b00001101110001110001011010100000, 5}, {0b00010100001011100110110101100000, 5}, |
| {0b11010011000011111101100101000000, 6}, {0b01100110101111101011101011000000, 6}, |
| {0b11001101011101101111011010000000, 7}, {0b00011010101100101000010110000000, 7}, |
| {0b10100001011010010100100100000000, 8}, {0b11001001011000010111100100000000, 8}, |
| {0b10010010001110001100101000000000, 9}, {0b10000111000010111110101000000000, 9}, |
| {0b10000111111100010001010000000000, 10}, {0b01111101101111001010110000000000, 10}, |
| {0b01010011000001101101100000000000, 11}, {0b00110110001011110011100000000000, 11}, |
| {0b00101001111000101101000000000000, 12}, {0b10110010010101010011000000000000, 12}, |
| {0b00010100011001001010000000000000, 13}, {0b00111110000111001010000000000000, 13}, |
| {0b11100100011011110100000000000000, 14}, {0b11101001111011010100000000000000, 14}, |
| {0b00100111001001011000000000000000, 15}, {0b11011010111000111000000000000000, 15}, |
| {0b00100001111111110000000000000000, 16}, {0b10100100100010110000000000000000, 16}, |
| {0b10100100011110100000000000000000, 17}, {0b11111001100101100000000000000000, 17}, |
| {0b01111001101011000000000000000000, 18}, {0b10110010001001000000000000000000, 18}, |
| {0b00110100110110000000000000000000, 19}, {0b00001010100110000000000000000000, 19}, |
| {0b00011010100100000000000000000000, 20}, {0b00110101110100000000000000000000, 20}, |
| {0b11100100111000000000000000000000, 21}, {0b01100010101000000000000000000000, 21}, |
| {0b10100001110000000000000000000000, 22}, {0b11000110010000000000000000000000, 22}, |
| {0b10101011100000000000000000000000, 23}, {0b01000001100000000000000000000000, 23}, |
| {0b00110001000000000000000000000000, 24}, {0b01000011000000000000000000000000, 24}, |
| {0b11001110000000000000000000000000, 25}, {0b11011110000000000000000000000000, 25}, |
| {0b01010100000000000000000000000000, 26}, {0b10010100000000000000000000000000, 26}, |
| {0b00011000000000000000000000000000, 27}, {0b01101000000000000000000000000000, 27}, |
| {0b11010000000000000000000000000000, 28}, {0b11010000000000000000000000000000, 28}, |
| {0b10100000000000000000000000000000, 29}, {0b10100000000000000000000000000000, 29}, |
| {0b01000000000000000000000000000000, 30}, {0b01000000000000000000000000000000, 30}, |
| {0b10000000000000000000000000000000, 31}, {0b10000000000000000000000000000000, 31}, |
| }; |
| // clang-format on |
| |
| INSTANTIATE_TEST_SUITE_P(Ctz32Test, Ctz32Test, |
| testing::ValuesIn(kCtz32Vectors)); |
| |
| class Clz32Test : public testing::TestWithParam<CountBitsVector> {}; |
| |
| TEST_P(Clz32Test, Clz32) { |
| EXPECT_EQ(_ot_builtin_clz_i32(GetParam().bits), GetParam().count); |
| } |
| |
| // Simple python snippet for generating vectors: |
| // |
| // import random |
| // for i in range(0, 32): |
| // line = [] |
| // for _ in range (0, 2): |
| // a = random.getrandbits(32) |
| // a &= ((1 << (32 - i)) - 1); |
| // a |= (1 << (32 - i - 1)) |
| // line.append(f"{{0b{a:032b}, {i}}},") |
| // print(" ".join(line)) |
| // clang-format off |
| constexpr CountBitsVector kClz32Vectors[] = { |
| {0b10000011010010000110000111110001, 0}, {0b11110101110110101110000011011000, 0}, |
| {0b01000001101011100111011110110011, 1}, {0b01001010110100011100010100011110, 1}, |
| {0b00100010111110110100101110101100, 2}, {0b00111010100110000100101010001100, 2}, |
| {0b00010001101100110110001100011101, 3}, {0b00010010011100011011001101100101, 3}, |
| {0b00001001001001110110000001110110, 4}, {0b00001010001110000111111000010010, 4}, |
| {0b00000111000101010000110010111111, 5}, {0b00000100101001000010000000000011, 5}, |
| {0b00000010010110111110111000001101, 6}, {0b00000011101110000111010000011110, 6}, |
| {0b00000001011100000010000000101110, 7}, {0b00000001111100100011100101110111, 7}, |
| {0b00000000110011110101101011110000, 8}, {0b00000000111010001111010000111010, 8}, |
| {0b00000000010100001111111010100011, 9}, {0b00000000010101011000101101010100, 9}, |
| {0b00000000001110010111001101001111, 10}, {0b00000000001111011011001101000000, 10}, |
| {0b00000000000111001110101010111111, 11}, {0b00000000000111101011000001011011, 11}, |
| {0b00000000000011001101111110000011, 12}, {0b00000000000010010000010101101011, 12}, |
| {0b00000000000001110111101010111001, 13}, {0b00000000000001011100010000110110, 13}, |
| {0b00000000000000101111011011011000, 14}, {0b00000000000000111101110111000001, 14}, |
| {0b00000000000000011100111010000011, 15}, {0b00000000000000010001100111101010, 15}, |
| {0b00000000000000001000001010011110, 16}, {0b00000000000000001001100110101111, 16}, |
| {0b00000000000000000110100100101111, 17}, {0b00000000000000000111101111000110, 17}, |
| {0b00000000000000000010001101101010, 18}, {0b00000000000000000010000101011100, 18}, |
| {0b00000000000000000001100110011000, 19}, {0b00000000000000000001000000001010, 19}, |
| {0b00000000000000000000100111011101, 20}, {0b00000000000000000000110100101001, 20}, |
| {0b00000000000000000000011000100100, 21}, {0b00000000000000000000011001001000, 21}, |
| {0b00000000000000000000001000010111, 22}, {0b00000000000000000000001010010010, 22}, |
| {0b00000000000000000000000101110010, 23}, {0b00000000000000000000000101111010, 23}, |
| {0b00000000000000000000000010100100, 24}, {0b00000000000000000000000011100110, 24}, |
| {0b00000000000000000000000001011100, 25}, {0b00000000000000000000000001111100, 25}, |
| {0b00000000000000000000000000111000, 26}, {0b00000000000000000000000000111000, 26}, |
| {0b00000000000000000000000000010100, 27}, {0b00000000000000000000000000010100, 27}, |
| {0b00000000000000000000000000001000, 28}, {0b00000000000000000000000000001101, 28}, |
| {0b00000000000000000000000000000100, 29}, {0b00000000000000000000000000000111, 29}, |
| {0b00000000000000000000000000000011, 30}, {0b00000000000000000000000000000010, 30}, |
| {0b00000000000000000000000000000001, 31}, {0b00000000000000000000000000000001, 31}, |
| }; |
| // clang-format on |
| |
| INSTANTIATE_TEST_SUITE_P(Clz32Test, Clz32Test, |
| testing::ValuesIn(kClz32Vectors)); |
| |
| } // namespace |
| } // namespace math_unittest |