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
18using namespace clang;
19using namespace CodeGen;
20
21llvm::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
30void 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
38void 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
51ConstantInitFuture
52ConstantInitBuilderBase::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.
59inline 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
66llvm::GlobalVariable *
67ConstantInitBuilderBase::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
87void ConstantInitBuilderBase::setGlobalInitializer(llvm::GlobalVariable *GV,
88 llvm::Constant *initializer){
89 GV->setInitializer(initializer);
90
91 if (!SelfReferences.empty())
92 resolveSelfReferences(GV);
93}
94
95void 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
107void 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
124void ConstantAggregateBuilderBase::addSize(CharUnits size) {
125 add(value: Builder.CGM.getSize(numChars: size));
126}
127
128llvm::Constant *
129ConstantAggregateBuilderBase::getRelativeOffset(llvm::IntegerType *offsetType,
130 llvm::Constant *target) {
131 return getRelativeOffsetToPosition(offsetType, target,
132 position: Builder.Buffer.size() - Begin);
133}
134
135llvm::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
153llvm::Constant *
154ConstantAggregateBuilderBase::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
167llvm::Constant *
168ConstantAggregateBuilderBase::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
181void 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
201ConstantAggregateBuilderBase::PlaceholderPosition
202ConstantAggregateBuilderBase::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
221CharUnits 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
263llvm::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
278llvm::Constant *
279ConstantAggregateBuilderBase::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.
302void 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