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