clang 24.0.0git
ConstantInitBuilder.cpp
Go to the documentation of this file.
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
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 *>(Data)) {
24 return C->getType();
25 } else {
26 return cast<ConstantInitBuilderBase *>(Data)->Buffer[0]->getType();
27 }
28}
29
31 assert(Data && "abandoning null future");
32 if (auto *builder = dyn_cast<ConstantInitBuilderBase *>(Data)) {
33 builder->abandon(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 *>(Data)) {
41 GV->setInitializer(C);
42 } else {
43 auto &builder = *cast<ConstantInitBuilderBase *>(Data);
44 assert(builder.Buffer.size() == 1);
45 builder.setGlobalInitializer(GV, builder.Buffer[0]);
46 builder.Buffer.clear();
47 Data = nullptr;
48 }
49}
50
52ConstantInitBuilderBase::createFuture(llvm::Constant *initializer) {
53 assert(Buffer.empty() && "buffer not current empty");
54 Buffer.push_back(initializer);
55 return ConstantInitFuture(this);
56}
57
58// Only used in this file.
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 GV->getValueType(), GV, entry.Indices);
97 auto dummy = entry.Dummy;
98 dummy->replaceAllUsesWith(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(Buffer.begin() + newEnd, 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(llvm::PoisonValue::get(dummy->getType()));
115 dummy->eraseFromParent();
116 }
117 SelfReferences.clear();
118 }
119}
120
124
125llvm::Constant *
126ConstantAggregateBuilderBase::getRelativeOffset(llvm::IntegerType *offsetType,
127 llvm::Constant *target) {
128 return getRelativeOffsetToPosition(offsetType, target,
129 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(offsetType, position);
136
137 // Subtract.
138 base = llvm::ConstantExpr::getPtrToInt(base, Builder.CGM.IntPtrTy);
139 target = llvm::ConstantExpr::getPtrToInt(target, Builder.CGM.IntPtrTy);
140 llvm::Constant *offset = llvm::ConstantExpr::getSub(target, base);
141
142 // Truncate to the relative-address type if necessary.
143 if (Builder.CGM.IntPtrTy != offsetType) {
144 offset = llvm::ConstantExpr::getTrunc(offset, offsetType);
145 }
146
147 return offset;
148}
149
150llvm::Constant *
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(dummy);
159 auto &entry = Builder.SelfReferences.back();
160 getGEPIndicesTo(entry.Indices, position + Begin);
161 return dummy;
162}
163
164llvm::Constant *
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(dummy);
173 auto &entry = Builder.SelfReferences.back();
174 (void) getGEPIndicesToCurrentPosition(entry.Indices);
175 return dummy;
176}
177
178void ConstantAggregateBuilderBase::getGEPIndicesTo(
180 size_t position) const {
181 // Recurse on the parent builder if present.
182 if (Parent) {
183 Parent->getGEPIndicesTo(indices, 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(llvm::ConstantInt::get(Builder.CGM.Int32Ty, 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(llvm::ConstantInt::get(Builder.CGM.Int32Ty,
195 position - Begin));
196}
197
200 // Bring the offset up to the last field.
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(CharUnits::fromQuantity(layout.getABITypeAlign(type)));
210 offset += CharUnits::fromQuantity(layout.getTypeStoreSize(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) {
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(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 CharUnits::fromQuantity(layout.getABITypeAlign(elementType)));
250 offset += CharUnits::fromQuantity(layout.getTypeStoreSize(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(Begin);
268 if (!eltTy) eltTy = elts[0]->getType();
269 auto type = llvm::ArrayType::get(eltTy, elts.size());
270 auto constant = llvm::ConstantArray::get(type, elts);
271 buffer.erase(buffer.begin() + Begin, buffer.end());
272 return constant;
273}
274
275llvm::Constant *
277 markFinished();
278
279 auto &buffer = getBuffer();
280 auto elts = llvm::ArrayRef(buffer).slice(Begin);
281
282 if (ty == nullptr && elts.empty())
283 ty = llvm::StructType::get(Builder.CGM.getLLVMContext(), {}, Packed);
284
285 llvm::Constant *constant;
286 if (ty) {
287 assert(ty->isPacked() == Packed);
288 constant = llvm::ConstantStruct::get(ty, elts);
289 } else {
290 constant = llvm::ConstantStruct::getAnon(elts, Packed);
291 }
292
293 buffer.erase(buffer.begin() + Begin, buffer.end());
294 return constant;
295}
296
297/// Sign the given pointer and add it to the constant initializer
298/// currently being built.
300 llvm::Constant *Pointer, const PointerAuthSchema &Schema,
301 GlobalDecl CalleeDecl, QualType CalleeType) {
302 if (!Schema || !Builder.CGM.shouldSignPointer(Schema))
303 return add(Pointer);
304
305 llvm::Constant *StorageAddress = nullptr;
306 if (Schema.isAddressDiscriminated()) {
307 StorageAddress = getAddrOfCurrentPosition(Pointer->getType());
308 }
309
310 llvm::Constant *SignedPointer = Builder.CGM.getConstantSignedPointer(
311 Pointer, Schema, StorageAddress, CalleeDecl, CalleeType);
312 add(SignedPointer);
313}
CharUnits - This is an opaque type for sizes expressed in character units.
Definition CharUnits.h:38
llvm::Align getAsAlign() const
getAsAlign - Returns Quantity as a valid llvm::Align, Beware llvm::Align assumes power of two 8-bit b...
Definition CharUnits.h:189
static CharUnits fromQuantity(QuantityType Quantity)
fromQuantity - Construct a CharUnits quantity from a raw integer type.
Definition CharUnits.h:63
CharUnits alignTo(const CharUnits &Align) const
alignTo - Returns the next integer (mod 2**64) that is greater than or equal to this quantity and is ...
Definition CharUnits.h:201
llvm::Module & getModule() const
An opaque class to hold the abstract position of a placeholder.
llvm::Constant * getAddrOfPosition(llvm::Type *type, size_t position)
Produce an address which points to a position in the aggregate being constructed.
PlaceholderPosition addPlaceholder()
Add a placeholder value to the structure.
llvm::SmallVectorImpl< llvm::Constant * > & getBuffer()
void add(llvm::Constant *value)
Add a new value to this initializer.
llvm::Constant * finishArray(llvm::Type *eltTy)
PlaceholderPosition addPlaceholderWithSize(llvm::Type *expectedType)
Add a placeholder, giving the expected type that will be filled in.
void addSize(CharUnits size)
Add an integer value of type size_t.
llvm::Constant * finishStruct(llvm::StructType *structTy)
llvm::Constant * getAddrOfCurrentPosition(llvm::Type *type)
Produce an address which will eventually point to the next position to be filled.
CharUnits getNextOffsetFromGlobal() const
Return the offset from the start of the initializer to the next position, assuming no padding is requ...
llvm::ArrayRef< llvm::Constant * > getGEPIndicesToCurrentPosition(llvm::SmallVectorImpl< llvm::Constant * > &indices)
size_t size() const
Return the number of elements that have been added to this struct or array.
void addSignedPointer(llvm::Constant *Pointer, const PointerAuthSchema &Schema, GlobalDecl CalleeDecl, QualType CalleeType)
Add a signed pointer using the given pointer authentication schema.
A convenience builder class for complex constant initializers, especially for anonymous global struct...
A "future" for a completed constant initializer, which can be passed around independently of any sub-...
llvm::Type * getType() const
Return the type of the initializer.
void abandon()
Abandon this initializer.
void installInGlobal(llvm::GlobalVariable *global)
Install the initializer into a global variable.
GlobalDecl - represents a global declaration.
Definition GlobalDecl.h:60
A (possibly-)qualified type.
Definition TypeBase.h:938
const internal::VariadicAllOfMatcher< Type > type
Matches Types in the clang AST.
Top level wrappers for InstallAPI frontend operations.
U cast(CodeGen::Address addr)
Definition Address.h:327