1 | //===--- ConstantInitBuilder.cpp - Global initializer builder -------------===// |
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 file defines out-of-line routines for building initializers for |
10 | // global variables, in particular the kind of globals that are implicitly |
11 | // introduced by various language ABIs. |
12 | // |
13 | //===----------------------------------------------------------------------===// |
14 | |
15 | #include "clang/CodeGen/ConstantInitBuilder.h" |
16 | #include "CodeGenModule.h" |
17 | |
18 | using namespace clang; |
19 | using namespace CodeGen; |
20 | |
21 | llvm::Type *ConstantInitFuture::getType() const { |
22 | assert(Data && "dereferencing null future" ); |
23 | if (Data.is<llvm::Constant*>()) { |
24 | return Data.get<llvm::Constant*>()->getType(); |
25 | } else { |
26 | return Data.get<ConstantInitBuilderBase*>()->Buffer[0]->getType(); |
27 | } |
28 | } |
29 | |
30 | void ConstantInitFuture::abandon() { |
31 | assert(Data && "abandoning null future" ); |
32 | if (auto builder = Data.dyn_cast<ConstantInitBuilderBase*>()) { |
33 | builder->abandon(newEnd: 0); |
34 | } |
35 | Data = nullptr; |
36 | } |
37 | |
38 | void ConstantInitFuture::installInGlobal(llvm::GlobalVariable *GV) { |
39 | assert(Data && "installing null future" ); |
40 | if (Data.is<llvm::Constant*>()) { |
41 | GV->setInitializer(Data.get<llvm::Constant*>()); |
42 | } else { |
43 | auto &builder = *Data.get<ConstantInitBuilderBase*>(); |
44 | assert(builder.Buffer.size() == 1); |
45 | builder.setGlobalInitializer(GV, initializer: builder.Buffer[0]); |
46 | builder.Buffer.clear(); |
47 | Data = nullptr; |
48 | } |
49 | } |
50 | |
51 | ConstantInitFuture |
52 | ConstantInitBuilderBase::createFuture(llvm::Constant *initializer) { |
53 | assert(Buffer.empty() && "buffer not current empty" ); |
54 | Buffer.push_back(Elt: initializer); |
55 | return ConstantInitFuture(this); |
56 | } |
57 | |
58 | // Only used in this file. |
59 | inline ConstantInitFuture::ConstantInitFuture(ConstantInitBuilderBase *builder) |
60 | : Data(builder) { |
61 | assert(!builder->Frozen); |
62 | assert(builder->Buffer.size() == 1); |
63 | assert(builder->Buffer[0] != nullptr); |
64 | } |
65 | |
66 | llvm::GlobalVariable * |
67 | ConstantInitBuilderBase::createGlobal(llvm::Constant *initializer, |
68 | const llvm::Twine &name, |
69 | CharUnits alignment, |
70 | bool constant, |
71 | llvm::GlobalValue::LinkageTypes linkage, |
72 | unsigned addressSpace) { |
73 | auto GV = new llvm::GlobalVariable(CGM.getModule(), |
74 | initializer->getType(), |
75 | constant, |
76 | linkage, |
77 | initializer, |
78 | name, |
79 | /*insert before*/ nullptr, |
80 | llvm::GlobalValue::NotThreadLocal, |
81 | addressSpace); |
82 | GV->setAlignment(alignment.getAsAlign()); |
83 | resolveSelfReferences(GV); |
84 | return GV; |
85 | } |
86 | |
87 | void ConstantInitBuilderBase::setGlobalInitializer(llvm::GlobalVariable *GV, |
88 | llvm::Constant *initializer){ |
89 | GV->setInitializer(initializer); |
90 | |
91 | if (!SelfReferences.empty()) |
92 | resolveSelfReferences(GV); |
93 | } |
94 | |
95 | void ConstantInitBuilderBase::resolveSelfReferences(llvm::GlobalVariable *GV) { |
96 | for (auto &entry : SelfReferences) { |
97 | llvm::Constant *resolvedReference = |
98 | llvm::ConstantExpr::getInBoundsGetElementPtr( |
99 | Ty: GV->getValueType(), C: GV, IdxList: entry.Indices); |
100 | auto dummy = entry.Dummy; |
101 | dummy->replaceAllUsesWith(V: resolvedReference); |
102 | dummy->eraseFromParent(); |
103 | } |
104 | SelfReferences.clear(); |
105 | } |
106 | |
107 | void ConstantInitBuilderBase::abandon(size_t newEnd) { |
108 | // Remove all the entries we've added. |
109 | Buffer.erase(CS: Buffer.begin() + newEnd, CE: Buffer.end()); |
110 | |
111 | // If we're abandoning all the way to the beginning, destroy |
112 | // all the self-references, because we might not get another |
113 | // opportunity. |
114 | if (newEnd == 0) { |
115 | for (auto &entry : SelfReferences) { |
116 | auto dummy = entry.Dummy; |
117 | dummy->replaceAllUsesWith(V: llvm::PoisonValue::get(T: dummy->getType())); |
118 | dummy->eraseFromParent(); |
119 | } |
120 | SelfReferences.clear(); |
121 | } |
122 | } |
123 | |
124 | void ConstantAggregateBuilderBase::addSize(CharUnits size) { |
125 | add(value: Builder.CGM.getSize(numChars: size)); |
126 | } |
127 | |
128 | llvm::Constant * |
129 | ConstantAggregateBuilderBase::getRelativeOffset(llvm::IntegerType *offsetType, |
130 | llvm::Constant *target) { |
131 | return getRelativeOffsetToPosition(offsetType, target, |
132 | position: Builder.Buffer.size() - Begin); |
133 | } |
134 | |
135 | llvm::Constant *ConstantAggregateBuilderBase::getRelativeOffsetToPosition( |
136 | llvm::IntegerType *offsetType, llvm::Constant *target, size_t position) { |
137 | // Compute the address of the relative-address slot. |
138 | auto base = getAddrOfPosition(type: offsetType, position); |
139 | |
140 | // Subtract. |
141 | base = llvm::ConstantExpr::getPtrToInt(C: base, Ty: Builder.CGM.IntPtrTy); |
142 | target = llvm::ConstantExpr::getPtrToInt(C: target, Ty: Builder.CGM.IntPtrTy); |
143 | llvm::Constant *offset = llvm::ConstantExpr::getSub(C1: target, C2: base); |
144 | |
145 | // Truncate to the relative-address type if necessary. |
146 | if (Builder.CGM.IntPtrTy != offsetType) { |
147 | offset = llvm::ConstantExpr::getTrunc(C: offset, Ty: offsetType); |
148 | } |
149 | |
150 | return offset; |
151 | } |
152 | |
153 | llvm::Constant * |
154 | ConstantAggregateBuilderBase::getAddrOfPosition(llvm::Type *type, |
155 | size_t position) { |
156 | // Make a global variable. We will replace this with a GEP to this |
157 | // position after installing the initializer. |
158 | auto dummy = new llvm::GlobalVariable(Builder.CGM.getModule(), type, true, |
159 | llvm::GlobalVariable::PrivateLinkage, |
160 | nullptr, "" ); |
161 | Builder.SelfReferences.emplace_back(args&: dummy); |
162 | auto &entry = Builder.SelfReferences.back(); |
163 | (void)getGEPIndicesTo(indices&: entry.Indices, position: position + Begin); |
164 | return dummy; |
165 | } |
166 | |
167 | llvm::Constant * |
168 | ConstantAggregateBuilderBase::getAddrOfCurrentPosition(llvm::Type *type) { |
169 | // Make a global variable. We will replace this with a GEP to this |
170 | // position after installing the initializer. |
171 | auto dummy = |
172 | new llvm::GlobalVariable(Builder.CGM.getModule(), type, true, |
173 | llvm::GlobalVariable::PrivateLinkage, |
174 | nullptr, "" ); |
175 | Builder.SelfReferences.emplace_back(args&: dummy); |
176 | auto &entry = Builder.SelfReferences.back(); |
177 | (void) getGEPIndicesToCurrentPosition(indices&: entry.Indices); |
178 | return dummy; |
179 | } |
180 | |
181 | void ConstantAggregateBuilderBase::getGEPIndicesTo( |
182 | llvm::SmallVectorImpl<llvm::Constant*> &indices, |
183 | size_t position) const { |
184 | // Recurse on the parent builder if present. |
185 | if (Parent) { |
186 | Parent->getGEPIndicesTo(indices, position: Begin); |
187 | |
188 | // Otherwise, add an index to drill into the first level of pointer. |
189 | } else { |
190 | assert(indices.empty()); |
191 | indices.push_back(Elt: llvm::ConstantInt::get(Ty: Builder.CGM.Int32Ty, V: 0)); |
192 | } |
193 | |
194 | assert(position >= Begin); |
195 | // We have to use i32 here because struct GEPs demand i32 indices. |
196 | // It's rather unlikely to matter in practice. |
197 | indices.push_back(Elt: llvm::ConstantInt::get(Ty: Builder.CGM.Int32Ty, |
198 | V: position - Begin)); |
199 | } |
200 | |
201 | ConstantAggregateBuilderBase::PlaceholderPosition |
202 | ConstantAggregateBuilderBase::addPlaceholderWithSize(llvm::Type *type) { |
203 | // Bring the offset up to the last field. |
204 | CharUnits offset = getNextOffsetFromGlobal(); |
205 | |
206 | // Create the placeholder. |
207 | auto position = addPlaceholder(); |
208 | |
209 | // Advance the offset past that field. |
210 | auto &layout = Builder.CGM.getDataLayout(); |
211 | if (!Packed) |
212 | offset = offset.alignTo(Align: CharUnits::fromQuantity(Quantity: layout.getABITypeAlign(Ty: type))); |
213 | offset += CharUnits::fromQuantity(Quantity: layout.getTypeStoreSize(Ty: type)); |
214 | |
215 | CachedOffsetEnd = Builder.Buffer.size(); |
216 | CachedOffsetFromGlobal = offset; |
217 | |
218 | return position; |
219 | } |
220 | |
221 | CharUnits ConstantAggregateBuilderBase::getOffsetFromGlobalTo(size_t end) const{ |
222 | size_t cacheEnd = CachedOffsetEnd; |
223 | assert(cacheEnd <= end); |
224 | |
225 | // Fast path: if the cache is valid, just use it. |
226 | if (cacheEnd == end) { |
227 | return CachedOffsetFromGlobal; |
228 | } |
229 | |
230 | // If the cached range ends before the index at which the current |
231 | // aggregate starts, recurse for the parent. |
232 | CharUnits offset; |
233 | if (cacheEnd < Begin) { |
234 | assert(cacheEnd == 0); |
235 | assert(Parent && "Begin != 0 for root builder" ); |
236 | cacheEnd = Begin; |
237 | offset = Parent->getOffsetFromGlobalTo(end: Begin); |
238 | } else { |
239 | offset = CachedOffsetFromGlobal; |
240 | } |
241 | |
242 | // Perform simple layout on the elements in cacheEnd..<end. |
243 | if (cacheEnd != end) { |
244 | auto &layout = Builder.CGM.getDataLayout(); |
245 | do { |
246 | llvm::Constant *element = Builder.Buffer[cacheEnd]; |
247 | assert(element != nullptr && |
248 | "cannot compute offset when a placeholder is present" ); |
249 | llvm::Type *elementType = element->getType(); |
250 | if (!Packed) |
251 | offset = offset.alignTo( |
252 | Align: CharUnits::fromQuantity(Quantity: layout.getABITypeAlign(Ty: elementType))); |
253 | offset += CharUnits::fromQuantity(Quantity: layout.getTypeStoreSize(Ty: elementType)); |
254 | } while (++cacheEnd != end); |
255 | } |
256 | |
257 | // Cache and return. |
258 | CachedOffsetEnd = cacheEnd; |
259 | CachedOffsetFromGlobal = offset; |
260 | return offset; |
261 | } |
262 | |
263 | llvm::Constant *ConstantAggregateBuilderBase::finishArray(llvm::Type *eltTy) { |
264 | markFinished(); |
265 | |
266 | auto &buffer = getBuffer(); |
267 | assert((Begin < buffer.size() || |
268 | (Begin == buffer.size() && eltTy)) |
269 | && "didn't add any array elements without element type" ); |
270 | auto elts = llvm::ArrayRef(buffer).slice(N: Begin); |
271 | if (!eltTy) eltTy = elts[0]->getType(); |
272 | auto type = llvm::ArrayType::get(ElementType: eltTy, NumElements: elts.size()); |
273 | auto constant = llvm::ConstantArray::get(T: type, V: elts); |
274 | buffer.erase(CS: buffer.begin() + Begin, CE: buffer.end()); |
275 | return constant; |
276 | } |
277 | |
278 | llvm::Constant * |
279 | ConstantAggregateBuilderBase::finishStruct(llvm::StructType *ty) { |
280 | markFinished(); |
281 | |
282 | auto &buffer = getBuffer(); |
283 | auto elts = llvm::ArrayRef(buffer).slice(N: Begin); |
284 | |
285 | if (ty == nullptr && elts.empty()) |
286 | ty = llvm::StructType::get(Context&: Builder.CGM.getLLVMContext(), Elements: {}, isPacked: Packed); |
287 | |
288 | llvm::Constant *constant; |
289 | if (ty) { |
290 | assert(ty->isPacked() == Packed); |
291 | constant = llvm::ConstantStruct::get(T: ty, V: elts); |
292 | } else { |
293 | constant = llvm::ConstantStruct::getAnon(V: elts, Packed); |
294 | } |
295 | |
296 | buffer.erase(CS: buffer.begin() + Begin, CE: buffer.end()); |
297 | return constant; |
298 | } |
299 | |
300 | /// Sign the given pointer and add it to the constant initializer |
301 | /// currently being built. |
302 | void ConstantAggregateBuilderBase::addSignedPointer( |
303 | llvm::Constant *Pointer, const PointerAuthSchema &Schema, |
304 | GlobalDecl CalleeDecl, QualType CalleeType) { |
305 | if (!Schema || !Builder.CGM.shouldSignPointer(Schema)) |
306 | return add(value: Pointer); |
307 | |
308 | llvm::Constant *StorageAddress = nullptr; |
309 | if (Schema.isAddressDiscriminated()) { |
310 | StorageAddress = getAddrOfCurrentPosition(type: Pointer->getType()); |
311 | } |
312 | |
313 | llvm::Constant *SignedPointer = Builder.CGM.getConstantSignedPointer( |
314 | Pointer, Schema, StorageAddress, SchemaDecl: CalleeDecl, SchemaType: CalleeType); |
315 | add(value: SignedPointer); |
316 | } |
317 | |