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