1 | //===--- TypeLocBuilder.cpp - Type Source Info collector ------------------===// |
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 | // This files defines TypeLocBuilder, a class for building TypeLocs |
10 | // bottom-up. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #include "TypeLocBuilder.h" |
15 | |
16 | using namespace clang; |
17 | |
18 | void TypeLocBuilder::pushFullCopy(TypeLoc L) { |
19 | size_t Size = L.getFullDataSize(); |
20 | reserve(Requested: Size); |
21 | |
22 | SmallVector<TypeLoc, 4> TypeLocs; |
23 | TypeLoc CurTL = L; |
24 | while (CurTL) { |
25 | TypeLocs.push_back(Elt: CurTL); |
26 | CurTL = CurTL.getNextTypeLoc(); |
27 | } |
28 | |
29 | for (unsigned i = 0, e = TypeLocs.size(); i < e; ++i) { |
30 | TypeLoc CurTL = TypeLocs[e-i-1]; |
31 | switch (CurTL.getTypeLocClass()) { |
32 | #define ABSTRACT_TYPELOC(CLASS, PARENT) |
33 | #define TYPELOC(CLASS, PARENT) \ |
34 | case TypeLoc::CLASS: { \ |
35 | CLASS##TypeLoc NewTL = push<class CLASS##TypeLoc>(CurTL.getType()); \ |
36 | memcpy(NewTL.getOpaqueData(), CurTL.getOpaqueData(), NewTL.getLocalDataSize()); \ |
37 | break; \ |
38 | } |
39 | #include "clang/AST/TypeLocNodes.def" |
40 | } |
41 | } |
42 | } |
43 | |
44 | void TypeLocBuilder::pushTrivial(ASTContext &Context, QualType T, |
45 | SourceLocation Loc) { |
46 | auto L = TypeLoc(T, nullptr); |
47 | reserve(Requested: L.getFullDataSize()); |
48 | |
49 | SmallVector<TypeLoc, 4> TypeLocs; |
50 | for (auto CurTL = L; CurTL; CurTL = CurTL.getNextTypeLoc()) |
51 | TypeLocs.push_back(Elt: CurTL); |
52 | |
53 | for (const auto &CurTL : llvm::reverse(C&: TypeLocs)) { |
54 | switch (CurTL.getTypeLocClass()) { |
55 | #define ABSTRACT_TYPELOC(CLASS, PARENT) |
56 | #define TYPELOC(CLASS, PARENT) \ |
57 | case TypeLoc::CLASS: { \ |
58 | auto NewTL = push<class CLASS##TypeLoc>(CurTL.getType()); \ |
59 | NewTL.initializeLocal(Context, Loc); \ |
60 | break; \ |
61 | } |
62 | #include "clang/AST/TypeLocNodes.def" |
63 | } |
64 | } |
65 | } |
66 | |
67 | void TypeLocBuilder::grow(size_t NewCapacity) { |
68 | assert(NewCapacity > Capacity); |
69 | |
70 | // Allocate the new buffer and copy the old data into it. |
71 | char *NewBuffer = new char[NewCapacity]; |
72 | unsigned NewIndex = Index + NewCapacity - Capacity; |
73 | memcpy(dest: &NewBuffer[NewIndex], |
74 | src: &Buffer[Index], |
75 | n: Capacity - Index); |
76 | |
77 | if (Buffer != InlineBuffer) |
78 | delete[] Buffer; |
79 | |
80 | Buffer = NewBuffer; |
81 | Capacity = NewCapacity; |
82 | Index = NewIndex; |
83 | } |
84 | |
85 | TypeLoc TypeLocBuilder::pushImpl(QualType T, size_t LocalSize, unsigned LocalAlignment) { |
86 | #ifndef NDEBUG |
87 | QualType TLast = TypeLoc(T, nullptr).getNextTypeLoc().getType(); |
88 | assert(TLast == LastTy && |
89 | "mismatch between last type and new type's inner type" ); |
90 | LastTy = T; |
91 | #endif |
92 | |
93 | assert(LocalAlignment <= BufferMaxAlignment && "Unexpected alignment" ); |
94 | |
95 | // If we need to grow, grow by a factor of 2. |
96 | if (LocalSize > Index) { |
97 | size_t RequiredCapacity = Capacity + (LocalSize - Index); |
98 | size_t NewCapacity = Capacity * 2; |
99 | while (RequiredCapacity > NewCapacity) |
100 | NewCapacity *= 2; |
101 | grow(NewCapacity); |
102 | } |
103 | |
104 | // Because we're adding elements to the TypeLoc backwards, we have to |
105 | // do some extra work to keep everything aligned appropriately. |
106 | // FIXME: This algorithm is a absolute mess because every TypeLoc returned |
107 | // needs to be valid. Partial TypeLocs are a terrible idea. |
108 | // FIXME: 4 and 8 are sufficient at the moment, but it's pretty ugly to |
109 | // hardcode them. |
110 | if (LocalAlignment == 4) { |
111 | if (!AtAlign8) { |
112 | NumBytesAtAlign4 += LocalSize; |
113 | } else { |
114 | unsigned Padding = NumBytesAtAlign4 % 8; |
115 | if (Padding == 0) { |
116 | if (LocalSize % 8 == 0) { |
117 | // Everything is set: there's no padding and we don't need to add |
118 | // any. |
119 | } else { |
120 | assert(LocalSize % 8 == 4); |
121 | // No existing padding; add in 4 bytes padding |
122 | memmove(dest: &Buffer[Index - 4], src: &Buffer[Index], n: NumBytesAtAlign4); |
123 | Index -= 4; |
124 | } |
125 | } else { |
126 | assert(Padding == 4); |
127 | if (LocalSize % 8 == 0) { |
128 | // Everything is set: there's 4 bytes padding and we don't need |
129 | // to add any. |
130 | } else { |
131 | assert(LocalSize % 8 == 4); |
132 | // There are 4 bytes padding, but we don't need any; remove it. |
133 | memmove(dest: &Buffer[Index + 4], src: &Buffer[Index], n: NumBytesAtAlign4); |
134 | Index += 4; |
135 | } |
136 | } |
137 | NumBytesAtAlign4 += LocalSize; |
138 | } |
139 | } else if (LocalAlignment == 8) { |
140 | if (!AtAlign8) { |
141 | // We have not seen any 8-byte aligned element yet. We insert a padding |
142 | // only if the new Index is not 8-byte-aligned. |
143 | if ((Index - LocalSize) % 8 != 0) { |
144 | memmove(dest: &Buffer[Index - 4], src: &Buffer[Index], n: NumBytesAtAlign4); |
145 | Index -= 4; |
146 | } |
147 | } else { |
148 | unsigned Padding = NumBytesAtAlign4 % 8; |
149 | if (Padding == 0) { |
150 | if (LocalSize % 8 == 0) { |
151 | // Everything is set: there's no padding and we don't need to add |
152 | // any. |
153 | } else { |
154 | assert(LocalSize % 8 == 4); |
155 | // No existing padding; add in 4 bytes padding |
156 | memmove(dest: &Buffer[Index - 4], src: &Buffer[Index], n: NumBytesAtAlign4); |
157 | Index -= 4; |
158 | } |
159 | } else { |
160 | assert(Padding == 4); |
161 | if (LocalSize % 8 == 0) { |
162 | // Everything is set: there's 4 bytes padding and we don't need |
163 | // to add any. |
164 | } else { |
165 | assert(LocalSize % 8 == 4); |
166 | // There are 4 bytes padding, but we don't need any; remove it. |
167 | memmove(dest: &Buffer[Index + 4], src: &Buffer[Index], n: NumBytesAtAlign4); |
168 | Index += 4; |
169 | } |
170 | } |
171 | } |
172 | |
173 | // Forget about any padding. |
174 | NumBytesAtAlign4 = 0; |
175 | AtAlign8 = true; |
176 | } else { |
177 | assert(LocalSize == 0); |
178 | } |
179 | |
180 | Index -= LocalSize; |
181 | |
182 | assert(Capacity - Index == TypeLoc::getFullDataSizeForType(T) && |
183 | "incorrect data size provided to CreateTypeSourceInfo!" ); |
184 | |
185 | return getTemporaryTypeLoc(T); |
186 | } |
187 | |