| /* | |
| * Copyright (c) 2021 ARM Limited | |
| * | |
| * The license below extends only to copyright in the software and shall | |
| * not be construed as granting a license to any other intellectual | |
| * property including but not limited to intellectual property relating | |
| * to a hardware implementation of the functionality of the software | |
| * licensed hereunder. You may use the software subject to the license | |
| * terms below provided that you ensure that this notice is replicated | |
| * unmodified and in its entirety in all distributions of the software, | |
| * modified or unmodified, in source code or in binary form. | |
| * | |
| * Copyright (c) 2019 The Regents of the University of California | |
| * All rights reserved | |
| * | |
| * Redistribution and use in source and binary forms, with or without | |
| * modification, are permitted provided that the following conditions are | |
| * met: redistributions of source code must retain the above copyright | |
| * notice, this list of conditions and the following disclaimer; | |
| * redistributions in binary form must reproduce the above copyright | |
| * notice, this list of conditions and the following disclaimer in the | |
| * documentation and/or other materials provided with the distribution; | |
| * neither the name of the copyright holders nor the names of its | |
| * contributors may be used to endorse or promote products derived from | |
| * this software without specific prior written permission. | |
| * | |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
| * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| */ | |
| #include <gtest/gtest.h> | |
| #include <tuple> | |
| #include "base/intmath.hh" | |
| using namespace gem5; | |
| TEST(IntmathTest, isPowerOf2) | |
| { | |
| EXPECT_TRUE(isPowerOf2(1)); | |
| EXPECT_TRUE(isPowerOf2(32)); | |
| EXPECT_TRUE(isPowerOf2(65536)); | |
| EXPECT_TRUE(isPowerOf2(131072)); | |
| EXPECT_TRUE(isPowerOf2(262144)); | |
| EXPECT_FALSE(isPowerOf2(0)); | |
| EXPECT_FALSE(isPowerOf2(36)); | |
| EXPECT_FALSE(isPowerOf2(2521)); | |
| EXPECT_FALSE(isPowerOf2(1679616)); | |
| } | |
| TEST(IntmathTest, floorLog2) | |
| { | |
| EXPECT_EQ(0, floorLog2(1)); | |
| EXPECT_EQ(4, floorLog2(16)); | |
| EXPECT_EQ(4, floorLog2(31)); | |
| EXPECT_EQ(5, floorLog2(36)); | |
| EXPECT_EQ(8, floorLog2(436)); | |
| EXPECT_EQ(16, floorLog2(65537)); | |
| EXPECT_EQ(20, floorLog2(1783592)); | |
| EXPECT_EQ(41, floorLog2(2821109907456)); | |
| // Test unsigned integers of various sizes. | |
| EXPECT_EQ(0, floorLog2((uint8_t)1)); | |
| EXPECT_EQ(0, floorLog2((uint16_t)1)); | |
| EXPECT_EQ(0, floorLog2((uint32_t)1)); | |
| EXPECT_EQ(0, floorLog2((uint64_t)1)); | |
| // Test signed integers of various sizes. | |
| EXPECT_EQ(0, floorLog2((int8_t)1)); | |
| EXPECT_EQ(0, floorLog2((int16_t)1)); | |
| EXPECT_EQ(0, floorLog2((int32_t)1)); | |
| EXPECT_EQ(0, floorLog2((int64_t)1)); | |
| } | |
| /* The IntmathDeathTest floorLog2 test is dependent on an assert being | |
| * triggered. We therefore only run this test for .debug and .opt (where | |
| * `TRACING_ON == 1`). | |
| */ | |
| #if TRACING_ON | |
| TEST(IntmathDeathTest, floorLog2) | |
| { | |
| // Verify a non-positive input triggers an assert. | |
| EXPECT_DEATH_IF_SUPPORTED(floorLog2(0), "x > 0"); | |
| } | |
| #endif | |
| TEST(IntmathTest, ceilLog2) | |
| { | |
| EXPECT_EQ(0, ceilLog2(1)); | |
| EXPECT_EQ(4, ceilLog2(16)); | |
| EXPECT_EQ(5, ceilLog2(31)); | |
| EXPECT_EQ(6, ceilLog2(36)); | |
| EXPECT_EQ(9, ceilLog2(436)); | |
| EXPECT_EQ(17, ceilLog2(65537)); | |
| EXPECT_EQ(21, ceilLog2(1783592)); | |
| EXPECT_EQ(42, ceilLog2(2821109907456)); | |
| } | |
| TEST(IntmathTest, divCeil) | |
| { | |
| EXPECT_EQ(5, divCeil(55, 13)); | |
| EXPECT_EQ(90, divCeil(7922, 89)); | |
| EXPECT_EQ(4, divCeil(4800, 1442)); | |
| EXPECT_EQ(4, divCeil(75, 24)); | |
| EXPECT_EQ(46, divCeil(451, 10)); | |
| } | |
| TEST(IntmathTest, mulUnsignedNarrow) | |
| { | |
| uint8_t a = 0xff; | |
| uint8_t b = 0x02; | |
| uint8_t hi; | |
| uint8_t low; | |
| mulUnsigned<uint8_t>(hi, low, a, b); | |
| EXPECT_EQ(hi, 0x1); | |
| EXPECT_EQ(low, 0xfe); | |
| a = 14; | |
| b = 9; | |
| mulUnsigned<uint8_t>(hi, low, a, b); | |
| EXPECT_EQ(hi, 0); | |
| EXPECT_EQ(low, 0x7e); | |
| a = 0; | |
| b = 0x55; | |
| mulUnsigned<uint8_t>(hi, low, a, b); | |
| EXPECT_EQ(hi, 0); | |
| EXPECT_EQ(low, 0); | |
| } | |
| TEST(IntmathTest, mulSignedNarrow) | |
| { | |
| int8_t a = -0x80; | |
| int8_t b = -0x7f; | |
| int8_t hi; | |
| int8_t low; | |
| mulSigned<int8_t>(hi, low, a, b); | |
| EXPECT_EQ(hi, 0x3f); | |
| EXPECT_EQ(low, -0x80); | |
| a = 14; | |
| b = -9; | |
| mulSigned<int8_t>(hi, low, a, b); | |
| EXPECT_EQ(hi, -0x01); | |
| EXPECT_EQ(low, -0x7e); | |
| a = 0; | |
| b = -0x55; | |
| mulSigned<int8_t>(hi, low, a, b); | |
| EXPECT_EQ(hi, 0); | |
| EXPECT_EQ(low, 0); | |
| } | |
| TEST(IntmathTest, mulUnsignedMid) | |
| { | |
| uint32_t a = 0xffffffffULL; | |
| uint32_t b = 0x00000002ULL; | |
| uint32_t hi; | |
| uint32_t low; | |
| mulUnsigned<uint32_t>(hi, low, a, b); | |
| EXPECT_EQ(hi, 0x1); | |
| EXPECT_EQ(low, 0xfffffffe); | |
| a = 68026386; | |
| b = 5152; | |
| mulUnsigned<uint32_t>(hi, low, a, b); | |
| EXPECT_EQ(hi, 0x51); | |
| EXPECT_EQ(low, 0x99c16a40); | |
| a = 0; | |
| b = 0x55555555; | |
| mulUnsigned<uint32_t>(hi, low, a, b); | |
| EXPECT_EQ(hi, 0); | |
| EXPECT_EQ(low, 0); | |
| } | |
| TEST(IntmathTest, mulSignedMid) | |
| { | |
| int32_t a = -0x80000000; | |
| int32_t b = -0x7fffffff; | |
| int32_t hi; | |
| int32_t low; | |
| mulSigned<int32_t>(hi, low, a, b); | |
| EXPECT_EQ(hi, 0x3fffffff); | |
| EXPECT_EQ(low, -0x80000000); | |
| a = -68026386; | |
| b = 5152; | |
| mulSigned<int32_t>(hi, low, a, b); | |
| EXPECT_EQ(hi, -0x52); | |
| EXPECT_EQ(low, -0x99c16a40); | |
| a = 0; | |
| b = -0x55555555; | |
| mulSigned<int32_t>(hi, low, a, b); | |
| EXPECT_EQ(hi, 0); | |
| EXPECT_EQ(low, 0); | |
| } | |
| TEST(IntmathTest, mulUnsignedWide) | |
| { | |
| uint64_t a = 0xffffffffffffffffULL; | |
| uint64_t b = 0x0000000000000002ULL; | |
| uint64_t hi; | |
| uint64_t low; | |
| mulUnsigned<uint64_t>(hi, low, a, b); | |
| EXPECT_EQ(hi, 0x1); | |
| EXPECT_EQ(low, 0xfffffffffffffffe); | |
| hi = 0; | |
| low = 0; | |
| mulUnsignedManual<uint64_t>(hi, low, a, b); | |
| EXPECT_EQ(hi, 0x1); | |
| EXPECT_EQ(low, 0xfffffffffffffffe); | |
| hi = 0; | |
| low = 0; | |
| std::tie(hi, low) = mulUnsigned<uint64_t>(a, b); | |
| EXPECT_EQ(hi, 0x1); | |
| EXPECT_EQ(low, 0xfffffffffffffffe); | |
| a = 0; | |
| b = 0x5555555555555555; | |
| mulUnsigned<uint64_t>(hi, low, a, b); | |
| EXPECT_EQ(hi, 0); | |
| EXPECT_EQ(low, 0); | |
| } | |
| TEST(IntmathTest, mulSignedWide) | |
| { | |
| int64_t a = -0x8000000000000000; | |
| int64_t b = -0x7fffffffffffffff; | |
| int64_t hi; | |
| int64_t low; | |
| mulSigned<int64_t>(hi, low, a, b); | |
| EXPECT_EQ(hi, 0x3fffffffffffffff); | |
| EXPECT_EQ(low, -0x8000000000000000); | |
| hi = 0; | |
| low = 0; | |
| mulSignedManual<int64_t>(hi, low, a, b); | |
| EXPECT_EQ(hi, 0x3fffffffffffffff); | |
| EXPECT_EQ(low, -0x8000000000000000); | |
| hi = 0; | |
| low = 0; | |
| std::tie(hi, low) = mulSigned<int64_t>(a, b); | |
| EXPECT_EQ(hi, 0x3fffffffffffffff); | |
| EXPECT_EQ(low, -0x8000000000000000); | |
| a = 0; | |
| b = -0x5555555555555555; | |
| mulSigned<int64_t>(hi, low, a, b); | |
| EXPECT_EQ(hi, 0); | |
| EXPECT_EQ(low, 0); | |
| } | |
| TEST(IntmathTest, roundUp) | |
| { | |
| EXPECT_EQ(4104, roundUp(4101, 4)); | |
| EXPECT_EQ(4112, roundUp(4105, 8)); | |
| EXPECT_EQ(4112, roundUp(4101, 16)); | |
| EXPECT_EQ(8192, roundUp(7991, 256)); | |
| } | |
| TEST(IntmathTest, roundDown) | |
| { | |
| EXPECT_EQ(4100, roundDown(4101, 4)); | |
| EXPECT_EQ(4104, roundDown(4105, 8)); | |
| EXPECT_EQ(4096, roundDown(4101, 16)); | |
| EXPECT_EQ(7936, roundDown(7991, 256)); | |
| } | |
| /** This is testing if log2i actually works. | |
| * at every iteration value is multiplied by 2 (left shift) and expected | |
| * is incremented by one. This until value reaches becomes negative (by | |
| * left shifting) which is when expected points to the MSB | |
| */ | |
| TEST(IntmathTest, Log2i) | |
| { | |
| int expected = 0; | |
| for (int value = 1; value > 0; expected++, value <<= 1) { | |
| EXPECT_EQ(expected, log2i(value)); | |
| } | |
| // Just as a sanity check for expected to point to the MSB | |
| EXPECT_EQ(expected, sizeof(int) * 8 - 1); | |
| } | |
| /** This is testing the assertions: what if invalid arguments are | |
| * provided to log2i: | |
| * | |
| * 1) value = 0 | |
| * 2) value < 0 | |
| * 3) value is not a power of 2 | |
| */ | |
| TEST(IntmathDeathTest, Log2iDeath) | |
| { | |
| #ifdef NDEBUG | |
| GTEST_SKIP() << "Skipping as assertions are " | |
| "stripped out of fast builds"; | |
| #endif | |
| // 1) value = 0 | |
| EXPECT_DEATH({ | |
| const int value = 0; | |
| log2i(value); | |
| }, "value > 0.*failed"); | |
| // 2) value < 0 | |
| EXPECT_DEATH({ | |
| const int value = -1; | |
| log2i(value); | |
| }, "value > 0.*failed"); | |
| // 3) value is not a power of 2 | |
| EXPECT_DEATH({ | |
| const int value = 5; | |
| log2i(value); | |
| }, "isPowerOf2"); | |
| } |