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