| //===-- Unittests for memory_utils ----------------------------------------===// | |
| // | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "src/__support/CPP/array.h" | |
| #include "src/__support/macros/config.h" | |
| #include "src/string/memory_utils/utils.h" | |
| #include "test/UnitTest/Test.h" | |
| namespace LIBC_NAMESPACE_DECL { | |
| using UINT = uintptr_t; | |
| // Converts an offset into a pointer. | |
| const void *forge(size_t offset) { | |
| return reinterpret_cast<const void *>(offset); | |
| } | |
| TEST(LlvmLibcUtilsTest, DistanceToNextAligned) { | |
| EXPECT_EQ(distance_to_next_aligned<16>(forge(0)), UINT(16)); | |
| EXPECT_EQ(distance_to_next_aligned<16>(forge(1)), UINT(15)); | |
| EXPECT_EQ(distance_to_next_aligned<16>(forge(16)), UINT(16)); | |
| EXPECT_EQ(distance_to_next_aligned<16>(forge(15)), UINT(1)); | |
| EXPECT_EQ(distance_to_next_aligned<32>(forge(16)), UINT(16)); | |
| } | |
| TEST(LlvmLibcUtilsTest, DistanceToAlignUp) { | |
| EXPECT_EQ(distance_to_align_up<16>(forge(0)), UINT(0)); | |
| EXPECT_EQ(distance_to_align_up<16>(forge(1)), UINT(15)); | |
| EXPECT_EQ(distance_to_align_up<16>(forge(16)), UINT(0)); | |
| EXPECT_EQ(distance_to_align_up<16>(forge(15)), UINT(1)); | |
| EXPECT_EQ(distance_to_align_up<32>(forge(16)), UINT(16)); | |
| } | |
| TEST(LlvmLibcUtilsTest, DistanceToAlignDown) { | |
| EXPECT_EQ(distance_to_align_down<16>(forge(0)), UINT(0)); | |
| EXPECT_EQ(distance_to_align_down<16>(forge(1)), UINT(1)); | |
| EXPECT_EQ(distance_to_align_down<16>(forge(16)), UINT(0)); | |
| EXPECT_EQ(distance_to_align_down<16>(forge(15)), UINT(15)); | |
| EXPECT_EQ(distance_to_align_down<32>(forge(16)), UINT(16)); | |
| } | |
| TEST(LlvmLibcUtilsTest, Adjust2) { | |
| char a, b; | |
| const size_t base_size = 10; | |
| for (uintptr_t i = 0; i < 4; ++i) { | |
| auto *p1 = &a; | |
| auto *p2 = &b; | |
| size_t size = base_size; | |
| adjust(static_cast<ptrdiff_t>(i), p1, p2, size); | |
| EXPECT_EQ(intptr_t(p1), intptr_t(&a + i)); | |
| EXPECT_EQ(intptr_t(p2), intptr_t(&b + i)); | |
| EXPECT_EQ(size, base_size - i); | |
| } | |
| } | |
| TEST(LlvmLibcUtilsTest, Align2) { | |
| char a, b; | |
| const size_t base_size = 10; | |
| { | |
| auto *p1 = &a; | |
| auto *p2 = &b; | |
| size_t size = base_size; | |
| align_to_next_boundary<128, Arg::P1>(p1, p2, size); | |
| EXPECT_TRUE(uintptr_t(p1) % 128 == 0); | |
| EXPECT_GT(p1, &a); | |
| EXPECT_GT(p2, &b); | |
| EXPECT_EQ(size_t(p1 - &a), base_size - size); | |
| EXPECT_EQ(size_t(p2 - &b), base_size - size); | |
| } | |
| { | |
| auto *p1 = &a; | |
| auto *p2 = &b; | |
| size_t size = base_size; | |
| align_to_next_boundary<128, Arg::P2>(p1, p2, size); | |
| EXPECT_TRUE(uintptr_t(p2) % 128 == 0); | |
| EXPECT_GT(p1, &a); | |
| EXPECT_GT(p2, &b); | |
| EXPECT_EQ(size_t(p1 - &a), base_size - size); | |
| EXPECT_EQ(size_t(p2 - &b), base_size - size); | |
| } | |
| } | |
| TEST(LlvmLibcUtilsTest, DisjointBuffers) { | |
| char buf[3]; | |
| const char *const a = buf + 0; | |
| const char *const b = buf + 1; | |
| EXPECT_TRUE(is_disjoint(a, b, 0)); | |
| EXPECT_TRUE(is_disjoint(a, b, 1)); | |
| EXPECT_FALSE(is_disjoint(a, b, 2)); | |
| EXPECT_TRUE(is_disjoint(b, a, 0)); | |
| EXPECT_TRUE(is_disjoint(b, a, 1)); | |
| EXPECT_FALSE(is_disjoint(b, a, 2)); | |
| } | |
| TEST(LlvmLibcUtilsTest, LoadStoreAligned) { | |
| const uint64_t init = 0xDEAD'C0DE'BEEF'F00D; | |
| CPtr const src = reinterpret_cast<CPtr>(&init); | |
| uint64_t store; | |
| Ptr const dst = reinterpret_cast<Ptr>(&store); | |
| using LoadFun = uint64_t (*)(CPtr); | |
| using StoreFun = void (*)(uint64_t, Ptr); | |
| { | |
| LoadFun ld = load_aligned<uint64_t, uint64_t>; | |
| StoreFun st = store_aligned<uint64_t, uint64_t>; | |
| const uint64_t loaded = ld(src); | |
| EXPECT_EQ(init, loaded); | |
| store = 0; | |
| st(init, dst); | |
| EXPECT_EQ(init, store); | |
| } | |
| { | |
| LoadFun ld = load_aligned<uint64_t, uint32_t, uint32_t>; | |
| StoreFun st = store_aligned<uint64_t, uint32_t, uint32_t>; | |
| const uint64_t loaded = ld(src); | |
| EXPECT_EQ(init, loaded); | |
| store = 0; | |
| st(init, dst); | |
| EXPECT_EQ(init, store); | |
| } | |
| { | |
| LoadFun ld = load_aligned<uint64_t, uint32_t, uint16_t, uint8_t, uint8_t>; | |
| StoreFun st = store_aligned<uint64_t, uint32_t, uint16_t, uint8_t, uint8_t>; | |
| const uint64_t loaded = ld(src); | |
| EXPECT_EQ(init, loaded); | |
| store = 0; | |
| st(init, dst); | |
| EXPECT_EQ(init, store); | |
| } | |
| } | |
| TEST(LlvmLibcUtilsTest, LoadStoreAlignedOddAddress) { | |
| const uint8_t inbuf[8] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; | |
| uint8_t outbuf[8]; | |
| const uint32_t loaded = load_aligned<uint32_t, uint8_t, uint16_t, uint8_t>( | |
| reinterpret_cast<CPtr>(inbuf + 1)); | |
| if constexpr (Endian::IS_LITTLE) { | |
| EXPECT_EQ(loaded, uint32_t(0x89674523)); | |
| } else if constexpr (Endian::IS_BIG) { | |
| EXPECT_EQ(loaded, uint32_t(0x23456789)); | |
| } | |
| store_aligned<uint32_t, uint8_t, uint16_t, uint8_t>( | |
| loaded, reinterpret_cast<Ptr>(outbuf + 1)); | |
| for (size_t i = 1; i < 5; ++i) | |
| EXPECT_EQ(outbuf[i], inbuf[i]); | |
| } | |
| } // namespace LIBC_NAMESPACE_DECL |