1 | //===- llvm/unittest/ADT/PointerIntPairTest.cpp - Unit tests --------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "llvm/ADT/PointerIntPair.h" |
10 | #include "gtest/gtest.h" |
11 | #include <limits> |
12 | using namespace llvm; |
13 | |
14 | namespace { |
15 | |
16 | TEST(PointerIntPairTest, GetSet) { |
17 | struct S { |
18 | int i; |
19 | }; |
20 | S s; |
21 | |
22 | PointerIntPair<S *, 2> Pair(&s, 1U); |
23 | EXPECT_EQ(&s, Pair.getPointer()); |
24 | EXPECT_EQ(1U, Pair.getInt()); |
25 | |
26 | Pair.setInt(2); |
27 | EXPECT_EQ(&s, Pair.getPointer()); |
28 | EXPECT_EQ(2U, Pair.getInt()); |
29 | |
30 | Pair.setPointer(nullptr); |
31 | EXPECT_EQ(nullptr, Pair.getPointer()); |
32 | EXPECT_EQ(2U, Pair.getInt()); |
33 | |
34 | Pair.setPointerAndInt(PtrVal: &s, IntVal: 3U); |
35 | EXPECT_EQ(&s, Pair.getPointer()); |
36 | EXPECT_EQ(3U, Pair.getInt()); |
37 | |
38 | // Make sure that we can perform all of our operations on enum classes. |
39 | // |
40 | // The concern is that enum classes are only explicitly convertible to |
41 | // integers. This means that if we assume in PointerIntPair this, a |
42 | // compilation error will result. This group of tests exercises the enum class |
43 | // code to make sure that we do not run into such issues in the future. |
44 | enum class E : unsigned { |
45 | Case1, |
46 | Case2, |
47 | Case3, |
48 | }; |
49 | PointerIntPair<S *, 2, E> Pair2(&s, E::Case1); |
50 | EXPECT_EQ(&s, Pair2.getPointer()); |
51 | EXPECT_EQ(E::Case1, Pair2.getInt()); |
52 | |
53 | Pair2.setInt(E::Case2); |
54 | EXPECT_EQ(&s, Pair2.getPointer()); |
55 | EXPECT_EQ(E::Case2, Pair2.getInt()); |
56 | |
57 | Pair2.setPointer(nullptr); |
58 | EXPECT_EQ(nullptr, Pair2.getPointer()); |
59 | EXPECT_EQ(E::Case2, Pair2.getInt()); |
60 | |
61 | Pair2.setPointerAndInt(PtrVal: &s, IntVal: E::Case3); |
62 | EXPECT_EQ(&s, Pair2.getPointer()); |
63 | EXPECT_EQ(E::Case3, Pair2.getInt()); |
64 | |
65 | auto [Pointer2, Int2] = Pair2; |
66 | EXPECT_EQ(Pair2.getPointer(), Pointer2); |
67 | EXPECT_EQ(Pair2.getInt(), Int2); |
68 | |
69 | static_assert(std::is_trivially_copyable_v<PointerIntPair<S *, 2, E>>, |
70 | "trivially copyable" ); |
71 | } |
72 | |
73 | TEST(PointerIntPairTest, DefaultInitialize) { |
74 | PointerIntPair<float *, 2> Pair; |
75 | EXPECT_EQ(nullptr, Pair.getPointer()); |
76 | EXPECT_EQ(0U, Pair.getInt()); |
77 | } |
78 | |
79 | // In real code this would be a word-sized integer limited to 31 bits. |
80 | struct Fixnum31 { |
81 | uintptr_t Value; |
82 | }; |
83 | struct FixnumPointerTraits { |
84 | static inline void *getAsVoidPointer(Fixnum31 Num) { |
85 | return reinterpret_cast<void *>(Num.Value << NumLowBitsAvailable); |
86 | } |
87 | static inline Fixnum31 getFromVoidPointer(void *P) { |
88 | // In real code this would assert that the value is in range. |
89 | return {.Value: reinterpret_cast<uintptr_t>(P) >> NumLowBitsAvailable}; |
90 | } |
91 | static constexpr int NumLowBitsAvailable = |
92 | std::numeric_limits<uintptr_t>::digits - 31; |
93 | }; |
94 | TEST(PointerIntPairTest, ManyUnusedBits) { |
95 | |
96 | PointerIntPair<Fixnum31, 1, bool, FixnumPointerTraits> pair; |
97 | EXPECT_EQ((uintptr_t)0, pair.getPointer().Value); |
98 | EXPECT_FALSE(pair.getInt()); |
99 | |
100 | pair.setPointerAndInt(PtrVal: { .Value: 0x7FFFFFFF }, IntVal: true ); |
101 | EXPECT_EQ((uintptr_t)0x7FFFFFFF, pair.getPointer().Value); |
102 | EXPECT_TRUE(pair.getInt()); |
103 | |
104 | EXPECT_EQ(FixnumPointerTraits::NumLowBitsAvailable - 1, |
105 | (int)PointerLikeTypeTraits<decltype(pair)>::NumLowBitsAvailable); |
106 | |
107 | static_assert(std::is_trivially_copyable_v< |
108 | PointerIntPair<Fixnum31, 1, bool, FixnumPointerTraits>>, |
109 | "trivially copyable" ); |
110 | } |
111 | |
112 | TEST(PointerIntPairTest, TypePunning) { |
113 | int I = 0; |
114 | int *IntPtr = &I; |
115 | |
116 | int **IntPtrBegin = &IntPtr; |
117 | int **IntPtrEnd = IntPtrBegin + 1; |
118 | |
119 | PointerIntPair<int *, 1> Pair; |
120 | int **PairAddr = Pair.getAddrOfPointer(); |
121 | |
122 | while (IntPtrBegin != IntPtrEnd) { |
123 | *PairAddr = *IntPtrBegin; |
124 | ++PairAddr; |
125 | ++IntPtrBegin; |
126 | } |
127 | EXPECT_EQ(Pair.getPointer(), IntPtr); |
128 | } |
129 | |
130 | } // end anonymous namespace |
131 | |