15ad74075SJohn McCall //===--- ConstantInitBuilder.cpp - Global initializer builder -------------===//
25ad74075SJohn McCall //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65ad74075SJohn McCall //
75ad74075SJohn McCall //===----------------------------------------------------------------------===//
85ad74075SJohn McCall //
95ad74075SJohn McCall // This file defines out-of-line routines for building initializers for
105ad74075SJohn McCall // global variables, in particular the kind of globals that are implicitly
115ad74075SJohn McCall // introduced by various language ABIs.
125ad74075SJohn McCall //
135ad74075SJohn McCall //===----------------------------------------------------------------------===//
145ad74075SJohn McCall
155ad74075SJohn McCall #include "clang/CodeGen/ConstantInitBuilder.h"
165ad74075SJohn McCall #include "CodeGenModule.h"
175ad74075SJohn McCall
185ad74075SJohn McCall using namespace clang;
195ad74075SJohn McCall using namespace CodeGen;
205ad74075SJohn McCall
getType() const21262f9622SJohn McCall llvm::Type *ConstantInitFuture::getType() const {
22262f9622SJohn McCall assert(Data && "dereferencing null future");
23262f9622SJohn McCall if (Data.is<llvm::Constant*>()) {
24262f9622SJohn McCall return Data.get<llvm::Constant*>()->getType();
25262f9622SJohn McCall } else {
26262f9622SJohn McCall return Data.get<ConstantInitBuilderBase*>()->Buffer[0]->getType();
27262f9622SJohn McCall }
28262f9622SJohn McCall }
29262f9622SJohn McCall
abandon()30262f9622SJohn McCall void ConstantInitFuture::abandon() {
31262f9622SJohn McCall assert(Data && "abandoning null future");
32262f9622SJohn McCall if (auto builder = Data.dyn_cast<ConstantInitBuilderBase*>()) {
33262f9622SJohn McCall builder->abandon(0);
34262f9622SJohn McCall }
35262f9622SJohn McCall Data = nullptr;
36262f9622SJohn McCall }
37262f9622SJohn McCall
installInGlobal(llvm::GlobalVariable * GV)38262f9622SJohn McCall void ConstantInitFuture::installInGlobal(llvm::GlobalVariable *GV) {
39262f9622SJohn McCall assert(Data && "installing null future");
40262f9622SJohn McCall if (Data.is<llvm::Constant*>()) {
41262f9622SJohn McCall GV->setInitializer(Data.get<llvm::Constant*>());
42262f9622SJohn McCall } else {
43262f9622SJohn McCall auto &builder = *Data.get<ConstantInitBuilderBase*>();
44262f9622SJohn McCall assert(builder.Buffer.size() == 1);
45262f9622SJohn McCall builder.setGlobalInitializer(GV, builder.Buffer[0]);
46262f9622SJohn McCall builder.Buffer.clear();
47262f9622SJohn McCall Data = nullptr;
48262f9622SJohn McCall }
49262f9622SJohn McCall }
50262f9622SJohn McCall
51262f9622SJohn McCall ConstantInitFuture
createFuture(llvm::Constant * initializer)52262f9622SJohn McCall ConstantInitBuilderBase::createFuture(llvm::Constant *initializer) {
53262f9622SJohn McCall assert(Buffer.empty() && "buffer not current empty");
54262f9622SJohn McCall Buffer.push_back(initializer);
55262f9622SJohn McCall return ConstantInitFuture(this);
56262f9622SJohn McCall }
57262f9622SJohn McCall
58262f9622SJohn McCall // Only used in this file.
ConstantInitFuture(ConstantInitBuilderBase * builder)59262f9622SJohn McCall inline ConstantInitFuture::ConstantInitFuture(ConstantInitBuilderBase *builder)
60262f9622SJohn McCall : Data(builder) {
61262f9622SJohn McCall assert(!builder->Frozen);
62262f9622SJohn McCall assert(builder->Buffer.size() == 1);
63262f9622SJohn McCall assert(builder->Buffer[0] != nullptr);
64262f9622SJohn McCall }
65262f9622SJohn McCall
665ad74075SJohn McCall llvm::GlobalVariable *
createGlobal(llvm::Constant * initializer,const llvm::Twine & name,CharUnits alignment,bool constant,llvm::GlobalValue::LinkageTypes linkage,unsigned addressSpace)6732e0d186SJohn McCall ConstantInitBuilderBase::createGlobal(llvm::Constant *initializer,
685ad74075SJohn McCall const llvm::Twine &name,
695ad74075SJohn McCall CharUnits alignment,
705ad74075SJohn McCall bool constant,
715ad74075SJohn McCall llvm::GlobalValue::LinkageTypes linkage,
725ad74075SJohn McCall unsigned addressSpace) {
735ad74075SJohn McCall auto GV = new llvm::GlobalVariable(CGM.getModule(),
745ad74075SJohn McCall initializer->getType(),
755ad74075SJohn McCall constant,
765ad74075SJohn McCall linkage,
775ad74075SJohn McCall initializer,
785ad74075SJohn McCall name,
795ad74075SJohn McCall /*insert before*/ nullptr,
805ad74075SJohn McCall llvm::GlobalValue::NotThreadLocal,
815ad74075SJohn McCall addressSpace);
82c79099e0SGuillaume Chatelet GV->setAlignment(alignment.getAsAlign());
835ad74075SJohn McCall resolveSelfReferences(GV);
845ad74075SJohn McCall return GV;
855ad74075SJohn McCall }
865ad74075SJohn McCall
setGlobalInitializer(llvm::GlobalVariable * GV,llvm::Constant * initializer)8732e0d186SJohn McCall void ConstantInitBuilderBase::setGlobalInitializer(llvm::GlobalVariable *GV,
885ad74075SJohn McCall llvm::Constant *initializer){
895ad74075SJohn McCall GV->setInitializer(initializer);
905ad74075SJohn McCall
915ad74075SJohn McCall if (!SelfReferences.empty())
925ad74075SJohn McCall resolveSelfReferences(GV);
935ad74075SJohn McCall }
945ad74075SJohn McCall
resolveSelfReferences(llvm::GlobalVariable * GV)9532e0d186SJohn McCall void ConstantInitBuilderBase::resolveSelfReferences(llvm::GlobalVariable *GV) {
965ad74075SJohn McCall for (auto &entry : SelfReferences) {
975ad74075SJohn McCall llvm::Constant *resolvedReference =
985ad74075SJohn McCall llvm::ConstantExpr::getInBoundsGetElementPtr(
995ad74075SJohn McCall GV->getValueType(), GV, entry.Indices);
100262f9622SJohn McCall auto dummy = entry.Dummy;
101262f9622SJohn McCall dummy->replaceAllUsesWith(resolvedReference);
102262f9622SJohn McCall dummy->eraseFromParent();
103262f9622SJohn McCall }
104262f9622SJohn McCall SelfReferences.clear();
105262f9622SJohn McCall }
106262f9622SJohn McCall
abandon(size_t newEnd)107262f9622SJohn McCall void ConstantInitBuilderBase::abandon(size_t newEnd) {
108262f9622SJohn McCall // Remove all the entries we've added.
109262f9622SJohn McCall Buffer.erase(Buffer.begin() + newEnd, Buffer.end());
110262f9622SJohn McCall
111262f9622SJohn McCall // If we're abandoning all the way to the beginning, destroy
112262f9622SJohn McCall // all the self-references, because we might not get another
113262f9622SJohn McCall // opportunity.
114262f9622SJohn McCall if (newEnd == 0) {
115262f9622SJohn McCall for (auto &entry : SelfReferences) {
116262f9622SJohn McCall auto dummy = entry.Dummy;
117*4dd1bffcSNuno Lopes dummy->replaceAllUsesWith(llvm::PoisonValue::get(dummy->getType()));
118262f9622SJohn McCall dummy->eraseFromParent();
119262f9622SJohn McCall }
120262f9622SJohn McCall SelfReferences.clear();
1215ad74075SJohn McCall }
1225ad74075SJohn McCall }
1235ad74075SJohn McCall
addSize(CharUnits size)12432e0d186SJohn McCall void ConstantAggregateBuilderBase::addSize(CharUnits size) {
1255ad74075SJohn McCall add(Builder.CGM.getSize(size));
1265ad74075SJohn McCall }
1275ad74075SJohn McCall
1285ad74075SJohn McCall llvm::Constant *
getRelativeOffset(llvm::IntegerType * offsetType,llvm::Constant * target)12932e0d186SJohn McCall ConstantAggregateBuilderBase::getRelativeOffset(llvm::IntegerType *offsetType,
13032e0d186SJohn McCall llvm::Constant *target) {
13171568a9eSLeonard Chan return getRelativeOffsetToPosition(offsetType, target,
1324a8120caSArnold Schwaighofer Builder.Buffer.size() - Begin);
13371568a9eSLeonard Chan }
13471568a9eSLeonard Chan
getRelativeOffsetToPosition(llvm::IntegerType * offsetType,llvm::Constant * target,size_t position)13571568a9eSLeonard Chan llvm::Constant *ConstantAggregateBuilderBase::getRelativeOffsetToPosition(
13671568a9eSLeonard Chan llvm::IntegerType *offsetType, llvm::Constant *target, size_t position) {
13732e0d186SJohn McCall // Compute the address of the relative-address slot.
13871568a9eSLeonard Chan auto base = getAddrOfPosition(offsetType, position);
13932e0d186SJohn McCall
14032e0d186SJohn McCall // Subtract.
14132e0d186SJohn McCall base = llvm::ConstantExpr::getPtrToInt(base, Builder.CGM.IntPtrTy);
14232e0d186SJohn McCall target = llvm::ConstantExpr::getPtrToInt(target, Builder.CGM.IntPtrTy);
14332e0d186SJohn McCall llvm::Constant *offset = llvm::ConstantExpr::getSub(target, base);
14432e0d186SJohn McCall
14532e0d186SJohn McCall // Truncate to the relative-address type if necessary.
14632e0d186SJohn McCall if (Builder.CGM.IntPtrTy != offsetType) {
14732e0d186SJohn McCall offset = llvm::ConstantExpr::getTrunc(offset, offsetType);
14832e0d186SJohn McCall }
14932e0d186SJohn McCall
15032e0d186SJohn McCall return offset;
15132e0d186SJohn McCall }
15232e0d186SJohn McCall
15332e0d186SJohn McCall llvm::Constant *
getAddrOfPosition(llvm::Type * type,size_t position)15471568a9eSLeonard Chan ConstantAggregateBuilderBase::getAddrOfPosition(llvm::Type *type,
15571568a9eSLeonard Chan size_t position) {
15671568a9eSLeonard Chan // Make a global variable. We will replace this with a GEP to this
15771568a9eSLeonard Chan // position after installing the initializer.
15871568a9eSLeonard Chan auto dummy = new llvm::GlobalVariable(Builder.CGM.getModule(), type, true,
15971568a9eSLeonard Chan llvm::GlobalVariable::PrivateLinkage,
16071568a9eSLeonard Chan nullptr, "");
16171568a9eSLeonard Chan Builder.SelfReferences.emplace_back(dummy);
16271568a9eSLeonard Chan auto &entry = Builder.SelfReferences.back();
16371568a9eSLeonard Chan (void)getGEPIndicesTo(entry.Indices, position + Begin);
16471568a9eSLeonard Chan return dummy;
16571568a9eSLeonard Chan }
16671568a9eSLeonard Chan
16771568a9eSLeonard Chan llvm::Constant *
getAddrOfCurrentPosition(llvm::Type * type)16832e0d186SJohn McCall ConstantAggregateBuilderBase::getAddrOfCurrentPosition(llvm::Type *type) {
1695ad74075SJohn McCall // Make a global variable. We will replace this with a GEP to this
1705ad74075SJohn McCall // position after installing the initializer.
1715ad74075SJohn McCall auto dummy =
1725ad74075SJohn McCall new llvm::GlobalVariable(Builder.CGM.getModule(), type, true,
1735ad74075SJohn McCall llvm::GlobalVariable::PrivateLinkage,
1745ad74075SJohn McCall nullptr, "");
1755ad74075SJohn McCall Builder.SelfReferences.emplace_back(dummy);
1765ad74075SJohn McCall auto &entry = Builder.SelfReferences.back();
1775ad74075SJohn McCall (void) getGEPIndicesToCurrentPosition(entry.Indices);
1785ad74075SJohn McCall return dummy;
1795ad74075SJohn McCall }
1805ad74075SJohn McCall
getGEPIndicesTo(llvm::SmallVectorImpl<llvm::Constant * > & indices,size_t position) const18132e0d186SJohn McCall void ConstantAggregateBuilderBase::getGEPIndicesTo(
1825ad74075SJohn McCall llvm::SmallVectorImpl<llvm::Constant*> &indices,
1835ad74075SJohn McCall size_t position) const {
1845ad74075SJohn McCall // Recurse on the parent builder if present.
1855ad74075SJohn McCall if (Parent) {
1865ad74075SJohn McCall Parent->getGEPIndicesTo(indices, Begin);
1875ad74075SJohn McCall
1885ad74075SJohn McCall // Otherwise, add an index to drill into the first level of pointer.
1895ad74075SJohn McCall } else {
1905ad74075SJohn McCall assert(indices.empty());
1915ad74075SJohn McCall indices.push_back(llvm::ConstantInt::get(Builder.CGM.Int32Ty, 0));
1925ad74075SJohn McCall }
1935ad74075SJohn McCall
1945ad74075SJohn McCall assert(position >= Begin);
1955ad74075SJohn McCall // We have to use i32 here because struct GEPs demand i32 indices.
1965ad74075SJohn McCall // It's rather unlikely to matter in practice.
1975ad74075SJohn McCall indices.push_back(llvm::ConstantInt::get(Builder.CGM.Int32Ty,
1985ad74075SJohn McCall position - Begin));
1995ad74075SJohn McCall }
2005ad74075SJohn McCall
201262f9622SJohn McCall ConstantAggregateBuilderBase::PlaceholderPosition
addPlaceholderWithSize(llvm::Type * type)202262f9622SJohn McCall ConstantAggregateBuilderBase::addPlaceholderWithSize(llvm::Type *type) {
203262f9622SJohn McCall // Bring the offset up to the last field.
204262f9622SJohn McCall CharUnits offset = getNextOffsetFromGlobal();
205262f9622SJohn McCall
206262f9622SJohn McCall // Create the placeholder.
207262f9622SJohn McCall auto position = addPlaceholder();
208262f9622SJohn McCall
209262f9622SJohn McCall // Advance the offset past that field.
210262f9622SJohn McCall auto &layout = Builder.CGM.getDataLayout();
211262f9622SJohn McCall if (!Packed)
212262f9622SJohn McCall offset = offset.alignTo(CharUnits::fromQuantity(
213262f9622SJohn McCall layout.getABITypeAlignment(type)));
214262f9622SJohn McCall offset += CharUnits::fromQuantity(layout.getTypeStoreSize(type));
215262f9622SJohn McCall
216262f9622SJohn McCall CachedOffsetEnd = Builder.Buffer.size();
217262f9622SJohn McCall CachedOffsetFromGlobal = offset;
218262f9622SJohn McCall
219262f9622SJohn McCall return position;
220262f9622SJohn McCall }
221262f9622SJohn McCall
getOffsetFromGlobalTo(size_t end) const22232e0d186SJohn McCall CharUnits ConstantAggregateBuilderBase::getOffsetFromGlobalTo(size_t end) const{
22332e0d186SJohn McCall size_t cacheEnd = CachedOffsetEnd;
22432e0d186SJohn McCall assert(cacheEnd <= end);
22532e0d186SJohn McCall
22632e0d186SJohn McCall // Fast path: if the cache is valid, just use it.
22732e0d186SJohn McCall if (cacheEnd == end) {
22832e0d186SJohn McCall return CachedOffsetFromGlobal;
22932e0d186SJohn McCall }
23032e0d186SJohn McCall
23132e0d186SJohn McCall // If the cached range ends before the index at which the current
23232e0d186SJohn McCall // aggregate starts, recurse for the parent.
23332e0d186SJohn McCall CharUnits offset;
23432e0d186SJohn McCall if (cacheEnd < Begin) {
23532e0d186SJohn McCall assert(cacheEnd == 0);
23632e0d186SJohn McCall assert(Parent && "Begin != 0 for root builder");
23732e0d186SJohn McCall cacheEnd = Begin;
23832e0d186SJohn McCall offset = Parent->getOffsetFromGlobalTo(Begin);
23932e0d186SJohn McCall } else {
24032e0d186SJohn McCall offset = CachedOffsetFromGlobal;
24132e0d186SJohn McCall }
24232e0d186SJohn McCall
24332e0d186SJohn McCall // Perform simple layout on the elements in cacheEnd..<end.
24432e0d186SJohn McCall if (cacheEnd != end) {
24532e0d186SJohn McCall auto &layout = Builder.CGM.getDataLayout();
24632e0d186SJohn McCall do {
24732e0d186SJohn McCall llvm::Constant *element = Builder.Buffer[cacheEnd];
24832e0d186SJohn McCall assert(element != nullptr &&
24932e0d186SJohn McCall "cannot compute offset when a placeholder is present");
25032e0d186SJohn McCall llvm::Type *elementType = element->getType();
251262f9622SJohn McCall if (!Packed)
25232e0d186SJohn McCall offset = offset.alignTo(CharUnits::fromQuantity(
25332e0d186SJohn McCall layout.getABITypeAlignment(elementType)));
25432e0d186SJohn McCall offset += CharUnits::fromQuantity(layout.getTypeStoreSize(elementType));
25532e0d186SJohn McCall } while (++cacheEnd != end);
25632e0d186SJohn McCall }
25732e0d186SJohn McCall
25832e0d186SJohn McCall // Cache and return.
25932e0d186SJohn McCall CachedOffsetEnd = cacheEnd;
26032e0d186SJohn McCall CachedOffsetFromGlobal = offset;
26132e0d186SJohn McCall return offset;
26232e0d186SJohn McCall }
26332e0d186SJohn McCall
finishArray(llvm::Type * eltTy)26432e0d186SJohn McCall llvm::Constant *ConstantAggregateBuilderBase::finishArray(llvm::Type *eltTy) {
2655ad74075SJohn McCall markFinished();
2665ad74075SJohn McCall
2675ad74075SJohn McCall auto &buffer = getBuffer();
2685ad74075SJohn McCall assert((Begin < buffer.size() ||
26932e0d186SJohn McCall (Begin == buffer.size() && eltTy))
2705ad74075SJohn McCall && "didn't add any array elements without element type");
2715ad74075SJohn McCall auto elts = llvm::makeArrayRef(buffer).slice(Begin);
27232e0d186SJohn McCall if (!eltTy) eltTy = elts[0]->getType();
2735ad74075SJohn McCall auto type = llvm::ArrayType::get(eltTy, elts.size());
2745ad74075SJohn McCall auto constant = llvm::ConstantArray::get(type, elts);
2755ad74075SJohn McCall buffer.erase(buffer.begin() + Begin, buffer.end());
2765ad74075SJohn McCall return constant;
2775ad74075SJohn McCall }
2785ad74075SJohn McCall
27932e0d186SJohn McCall llvm::Constant *
finishStruct(llvm::StructType * ty)28032e0d186SJohn McCall ConstantAggregateBuilderBase::finishStruct(llvm::StructType *ty) {
2815ad74075SJohn McCall markFinished();
2825ad74075SJohn McCall
2835ad74075SJohn McCall auto &buffer = getBuffer();
2845ad74075SJohn McCall auto elts = llvm::makeArrayRef(buffer).slice(Begin);
2855ad74075SJohn McCall
286262f9622SJohn McCall if (ty == nullptr && elts.empty())
287262f9622SJohn McCall ty = llvm::StructType::get(Builder.CGM.getLLVMContext(), {}, Packed);
288262f9622SJohn McCall
2895ad74075SJohn McCall llvm::Constant *constant;
29032e0d186SJohn McCall if (ty) {
291262f9622SJohn McCall assert(ty->isPacked() == Packed);
29232e0d186SJohn McCall constant = llvm::ConstantStruct::get(ty, elts);
2935ad74075SJohn McCall } else {
294262f9622SJohn McCall constant = llvm::ConstantStruct::getAnon(elts, Packed);
2955ad74075SJohn McCall }
2965ad74075SJohn McCall
2975ad74075SJohn McCall buffer.erase(buffer.begin() + Begin, buffer.end());
2985ad74075SJohn McCall return constant;
2995ad74075SJohn McCall }
300