clang 17.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 (Data.is<llvm::Constant*>()) {
24 return Data.get<llvm::Constant*>()->getType();
25 } else {
26 return Data.get<ConstantInitBuilderBase*>()->Buffer[0]->getType();
27 }
28}
29
31 assert(Data && "abandoning null future");
32 if (auto builder = Data.dyn_cast<ConstantInitBuilderBase*>()) {
33 builder->abandon(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, 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 *
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 GV->getValueType(), GV, entry.Indices);
100 auto dummy = entry.Dummy;
101 dummy->replaceAllUsesWith(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(Buffer.begin() + newEnd, 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(llvm::PoisonValue::get(dummy->getType()));
118 dummy->eraseFromParent();
119 }
120 SelfReferences.clear();
121 }
122}
123
125 add(Builder.CGM.getSize(size));
126}
127
128llvm::Constant *
129ConstantAggregateBuilderBase::getRelativeOffset(llvm::IntegerType *offsetType,
130 llvm::Constant *target) {
131 return getRelativeOffsetToPosition(offsetType, target,
132 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(offsetType, position);
139
140 // Subtract.
141 base = llvm::ConstantExpr::getPtrToInt(base, Builder.CGM.IntPtrTy);
142 target = llvm::ConstantExpr::getPtrToInt(target, Builder.CGM.IntPtrTy);
143 llvm::Constant *offset = llvm::ConstantExpr::getSub(target, base);
144
145 // Truncate to the relative-address type if necessary.
146 if (Builder.CGM.IntPtrTy != offsetType) {
147 offset = llvm::ConstantExpr::getTrunc(offset, offsetType);
148 }
149
150 return offset;
151}
152
153llvm::Constant *
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(dummy);
162 auto &entry = Builder.SelfReferences.back();
163 (void)getGEPIndicesTo(entry.Indices, position + Begin);
164 return dummy;
165}
166
167llvm::Constant *
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(dummy);
176 auto &entry = Builder.SelfReferences.back();
177 (void) getGEPIndicesToCurrentPosition(entry.Indices);
178 return dummy;
179}
180
181void ConstantAggregateBuilderBase::getGEPIndicesTo(
183 size_t position) const {
184 // Recurse on the parent builder if present.
185 if (Parent) {
186 Parent->getGEPIndicesTo(indices, 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(llvm::ConstantInt::get(Builder.CGM.Int32Ty, 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(llvm::ConstantInt::get(Builder.CGM.Int32Ty,
198 position - Begin));
199}
200
203 // Bring the offset up to the last field.
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(CharUnits::fromQuantity(layout.getABITypeAlign(type)));
213 offset += CharUnits::fromQuantity(layout.getTypeStoreSize(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) {
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(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 CharUnits::fromQuantity(layout.getABITypeAlign(elementType)));
253 offset += CharUnits::fromQuantity(layout.getTypeStoreSize(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(Begin);
271 if (!eltTy) eltTy = elts[0]->getType();
272 auto type = llvm::ArrayType::get(eltTy, elts.size());
273 auto constant = llvm::ConstantArray::get(type, elts);
274 buffer.erase(buffer.begin() + Begin, buffer.end());
275 return constant;
276}
277
278llvm::Constant *
280 markFinished();
281
282 auto &buffer = getBuffer();
283 auto elts = llvm::ArrayRef(buffer).slice(Begin);
284
285 if (ty == nullptr && elts.empty())
286 ty = llvm::StructType::get(Builder.CGM.getLLVMContext(), {}, Packed);
287
288 llvm::Constant *constant;
289 if (ty) {
290 assert(ty->isPacked() == Packed);
291 constant = llvm::ConstantStruct::get(ty, elts);
292 } else {
293 constant = llvm::ConstantStruct::getAnon(elts, Packed);
294 }
295
296 buffer.erase(buffer.begin() + Begin, buffer.end());
297 return constant;
298}
const char * Data
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
const llvm::DataLayout & getDataLayout() const
llvm::LLVMContext & getLLVMContext()
llvm::ConstantInt * getSize(CharUnits numChars)
Emit the given number of characters as a value of type size_t.
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.
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.
const internal::VariadicAllOfMatcher< Type > type
Matches Types in the clang AST.