xref: /netbsd-src/external/apache2/llvm/dist/clang/lib/CodeGen/ConstantInitBuilder.cpp (revision e038c9c4676b0f19b1b7dd08a940c6ed64a6d5ae)
17330f729Sjoerg //===--- ConstantInitBuilder.cpp - Global initializer builder -------------===//
27330f729Sjoerg //
37330f729Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47330f729Sjoerg // See https://llvm.org/LICENSE.txt for license information.
57330f729Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67330f729Sjoerg //
77330f729Sjoerg //===----------------------------------------------------------------------===//
87330f729Sjoerg //
97330f729Sjoerg // This file defines out-of-line routines for building initializers for
107330f729Sjoerg // global variables, in particular the kind of globals that are implicitly
117330f729Sjoerg // introduced by various language ABIs.
127330f729Sjoerg //
137330f729Sjoerg //===----------------------------------------------------------------------===//
147330f729Sjoerg 
157330f729Sjoerg #include "clang/CodeGen/ConstantInitBuilder.h"
167330f729Sjoerg #include "CodeGenModule.h"
177330f729Sjoerg 
187330f729Sjoerg using namespace clang;
197330f729Sjoerg using namespace CodeGen;
207330f729Sjoerg 
getType() const217330f729Sjoerg llvm::Type *ConstantInitFuture::getType() const {
227330f729Sjoerg   assert(Data && "dereferencing null future");
237330f729Sjoerg   if (Data.is<llvm::Constant*>()) {
247330f729Sjoerg     return Data.get<llvm::Constant*>()->getType();
257330f729Sjoerg   } else {
267330f729Sjoerg     return Data.get<ConstantInitBuilderBase*>()->Buffer[0]->getType();
277330f729Sjoerg   }
287330f729Sjoerg }
297330f729Sjoerg 
abandon()307330f729Sjoerg void ConstantInitFuture::abandon() {
317330f729Sjoerg   assert(Data && "abandoning null future");
327330f729Sjoerg   if (auto builder = Data.dyn_cast<ConstantInitBuilderBase*>()) {
337330f729Sjoerg     builder->abandon(0);
347330f729Sjoerg   }
357330f729Sjoerg   Data = nullptr;
367330f729Sjoerg }
377330f729Sjoerg 
installInGlobal(llvm::GlobalVariable * GV)387330f729Sjoerg void ConstantInitFuture::installInGlobal(llvm::GlobalVariable *GV) {
397330f729Sjoerg   assert(Data && "installing null future");
407330f729Sjoerg   if (Data.is<llvm::Constant*>()) {
417330f729Sjoerg     GV->setInitializer(Data.get<llvm::Constant*>());
427330f729Sjoerg   } else {
437330f729Sjoerg     auto &builder = *Data.get<ConstantInitBuilderBase*>();
447330f729Sjoerg     assert(builder.Buffer.size() == 1);
457330f729Sjoerg     builder.setGlobalInitializer(GV, builder.Buffer[0]);
467330f729Sjoerg     builder.Buffer.clear();
477330f729Sjoerg     Data = nullptr;
487330f729Sjoerg   }
497330f729Sjoerg }
507330f729Sjoerg 
517330f729Sjoerg ConstantInitFuture
createFuture(llvm::Constant * initializer)527330f729Sjoerg ConstantInitBuilderBase::createFuture(llvm::Constant *initializer) {
537330f729Sjoerg   assert(Buffer.empty() && "buffer not current empty");
547330f729Sjoerg   Buffer.push_back(initializer);
557330f729Sjoerg   return ConstantInitFuture(this);
567330f729Sjoerg }
577330f729Sjoerg 
587330f729Sjoerg // Only used in this file.
ConstantInitFuture(ConstantInitBuilderBase * builder)597330f729Sjoerg inline ConstantInitFuture::ConstantInitFuture(ConstantInitBuilderBase *builder)
607330f729Sjoerg     : Data(builder) {
617330f729Sjoerg   assert(!builder->Frozen);
627330f729Sjoerg   assert(builder->Buffer.size() == 1);
637330f729Sjoerg   assert(builder->Buffer[0] != nullptr);
647330f729Sjoerg }
657330f729Sjoerg 
667330f729Sjoerg llvm::GlobalVariable *
createGlobal(llvm::Constant * initializer,const llvm::Twine & name,CharUnits alignment,bool constant,llvm::GlobalValue::LinkageTypes linkage,unsigned addressSpace)677330f729Sjoerg ConstantInitBuilderBase::createGlobal(llvm::Constant *initializer,
687330f729Sjoerg                                       const llvm::Twine &name,
697330f729Sjoerg                                       CharUnits alignment,
707330f729Sjoerg                                       bool constant,
717330f729Sjoerg                                       llvm::GlobalValue::LinkageTypes linkage,
727330f729Sjoerg                                       unsigned addressSpace) {
737330f729Sjoerg   auto GV = new llvm::GlobalVariable(CGM.getModule(),
747330f729Sjoerg                                      initializer->getType(),
757330f729Sjoerg                                      constant,
767330f729Sjoerg                                      linkage,
777330f729Sjoerg                                      initializer,
787330f729Sjoerg                                      name,
797330f729Sjoerg                                      /*insert before*/ nullptr,
807330f729Sjoerg                                      llvm::GlobalValue::NotThreadLocal,
817330f729Sjoerg                                      addressSpace);
827330f729Sjoerg   GV->setAlignment(alignment.getAsAlign());
837330f729Sjoerg   resolveSelfReferences(GV);
847330f729Sjoerg   return GV;
857330f729Sjoerg }
867330f729Sjoerg 
setGlobalInitializer(llvm::GlobalVariable * GV,llvm::Constant * initializer)877330f729Sjoerg void ConstantInitBuilderBase::setGlobalInitializer(llvm::GlobalVariable *GV,
887330f729Sjoerg                                                    llvm::Constant *initializer){
897330f729Sjoerg   GV->setInitializer(initializer);
907330f729Sjoerg 
917330f729Sjoerg   if (!SelfReferences.empty())
927330f729Sjoerg     resolveSelfReferences(GV);
937330f729Sjoerg }
947330f729Sjoerg 
resolveSelfReferences(llvm::GlobalVariable * GV)957330f729Sjoerg void ConstantInitBuilderBase::resolveSelfReferences(llvm::GlobalVariable *GV) {
967330f729Sjoerg   for (auto &entry : SelfReferences) {
977330f729Sjoerg     llvm::Constant *resolvedReference =
987330f729Sjoerg       llvm::ConstantExpr::getInBoundsGetElementPtr(
997330f729Sjoerg         GV->getValueType(), GV, entry.Indices);
1007330f729Sjoerg     auto dummy = entry.Dummy;
1017330f729Sjoerg     dummy->replaceAllUsesWith(resolvedReference);
1027330f729Sjoerg     dummy->eraseFromParent();
1037330f729Sjoerg   }
1047330f729Sjoerg   SelfReferences.clear();
1057330f729Sjoerg }
1067330f729Sjoerg 
abandon(size_t newEnd)1077330f729Sjoerg void ConstantInitBuilderBase::abandon(size_t newEnd) {
1087330f729Sjoerg   // Remove all the entries we've added.
1097330f729Sjoerg   Buffer.erase(Buffer.begin() + newEnd, Buffer.end());
1107330f729Sjoerg 
1117330f729Sjoerg   // If we're abandoning all the way to the beginning, destroy
1127330f729Sjoerg   // all the self-references, because we might not get another
1137330f729Sjoerg   // opportunity.
1147330f729Sjoerg   if (newEnd == 0) {
1157330f729Sjoerg     for (auto &entry : SelfReferences) {
1167330f729Sjoerg       auto dummy = entry.Dummy;
1177330f729Sjoerg       dummy->replaceAllUsesWith(llvm::UndefValue::get(dummy->getType()));
1187330f729Sjoerg       dummy->eraseFromParent();
1197330f729Sjoerg     }
1207330f729Sjoerg     SelfReferences.clear();
1217330f729Sjoerg   }
1227330f729Sjoerg }
1237330f729Sjoerg 
addSize(CharUnits size)1247330f729Sjoerg void ConstantAggregateBuilderBase::addSize(CharUnits size) {
1257330f729Sjoerg   add(Builder.CGM.getSize(size));
1267330f729Sjoerg }
1277330f729Sjoerg 
1287330f729Sjoerg llvm::Constant *
getRelativeOffset(llvm::IntegerType * offsetType,llvm::Constant * target)1297330f729Sjoerg ConstantAggregateBuilderBase::getRelativeOffset(llvm::IntegerType *offsetType,
1307330f729Sjoerg                                                 llvm::Constant *target) {
131*e038c9c4Sjoerg   return getRelativeOffsetToPosition(offsetType, target,
132*e038c9c4Sjoerg                                      Builder.Buffer.size() - Begin);
133*e038c9c4Sjoerg }
134*e038c9c4Sjoerg 
getRelativeOffsetToPosition(llvm::IntegerType * offsetType,llvm::Constant * target,size_t position)135*e038c9c4Sjoerg llvm::Constant *ConstantAggregateBuilderBase::getRelativeOffsetToPosition(
136*e038c9c4Sjoerg     llvm::IntegerType *offsetType, llvm::Constant *target, size_t position) {
1377330f729Sjoerg   // Compute the address of the relative-address slot.
138*e038c9c4Sjoerg   auto base = getAddrOfPosition(offsetType, position);
1397330f729Sjoerg 
1407330f729Sjoerg   // Subtract.
1417330f729Sjoerg   base = llvm::ConstantExpr::getPtrToInt(base, Builder.CGM.IntPtrTy);
1427330f729Sjoerg   target = llvm::ConstantExpr::getPtrToInt(target, Builder.CGM.IntPtrTy);
1437330f729Sjoerg   llvm::Constant *offset = llvm::ConstantExpr::getSub(target, base);
1447330f729Sjoerg 
1457330f729Sjoerg   // Truncate to the relative-address type if necessary.
1467330f729Sjoerg   if (Builder.CGM.IntPtrTy != offsetType) {
1477330f729Sjoerg     offset = llvm::ConstantExpr::getTrunc(offset, offsetType);
1487330f729Sjoerg   }
1497330f729Sjoerg 
1507330f729Sjoerg   return offset;
1517330f729Sjoerg }
1527330f729Sjoerg 
1537330f729Sjoerg llvm::Constant *
getAddrOfPosition(llvm::Type * type,size_t position)154*e038c9c4Sjoerg ConstantAggregateBuilderBase::getAddrOfPosition(llvm::Type *type,
155*e038c9c4Sjoerg                                                 size_t position) {
156*e038c9c4Sjoerg   // Make a global variable.  We will replace this with a GEP to this
157*e038c9c4Sjoerg   // position after installing the initializer.
158*e038c9c4Sjoerg   auto dummy = new llvm::GlobalVariable(Builder.CGM.getModule(), type, true,
159*e038c9c4Sjoerg                                         llvm::GlobalVariable::PrivateLinkage,
160*e038c9c4Sjoerg                                         nullptr, "");
161*e038c9c4Sjoerg   Builder.SelfReferences.emplace_back(dummy);
162*e038c9c4Sjoerg   auto &entry = Builder.SelfReferences.back();
163*e038c9c4Sjoerg   (void)getGEPIndicesTo(entry.Indices, position + Begin);
164*e038c9c4Sjoerg   return dummy;
165*e038c9c4Sjoerg }
166*e038c9c4Sjoerg 
167*e038c9c4Sjoerg llvm::Constant *
getAddrOfCurrentPosition(llvm::Type * type)1687330f729Sjoerg ConstantAggregateBuilderBase::getAddrOfCurrentPosition(llvm::Type *type) {
1697330f729Sjoerg   // Make a global variable.  We will replace this with a GEP to this
1707330f729Sjoerg   // position after installing the initializer.
1717330f729Sjoerg   auto dummy =
1727330f729Sjoerg     new llvm::GlobalVariable(Builder.CGM.getModule(), type, true,
1737330f729Sjoerg                              llvm::GlobalVariable::PrivateLinkage,
1747330f729Sjoerg                              nullptr, "");
1757330f729Sjoerg   Builder.SelfReferences.emplace_back(dummy);
1767330f729Sjoerg   auto &entry = Builder.SelfReferences.back();
1777330f729Sjoerg   (void) getGEPIndicesToCurrentPosition(entry.Indices);
1787330f729Sjoerg   return dummy;
1797330f729Sjoerg }
1807330f729Sjoerg 
getGEPIndicesTo(llvm::SmallVectorImpl<llvm::Constant * > & indices,size_t position) const1817330f729Sjoerg void ConstantAggregateBuilderBase::getGEPIndicesTo(
1827330f729Sjoerg                                llvm::SmallVectorImpl<llvm::Constant*> &indices,
1837330f729Sjoerg                                size_t position) const {
1847330f729Sjoerg   // Recurse on the parent builder if present.
1857330f729Sjoerg   if (Parent) {
1867330f729Sjoerg     Parent->getGEPIndicesTo(indices, Begin);
1877330f729Sjoerg 
1887330f729Sjoerg   // Otherwise, add an index to drill into the first level of pointer.
1897330f729Sjoerg   } else {
1907330f729Sjoerg     assert(indices.empty());
1917330f729Sjoerg     indices.push_back(llvm::ConstantInt::get(Builder.CGM.Int32Ty, 0));
1927330f729Sjoerg   }
1937330f729Sjoerg 
1947330f729Sjoerg   assert(position >= Begin);
1957330f729Sjoerg   // We have to use i32 here because struct GEPs demand i32 indices.
1967330f729Sjoerg   // It's rather unlikely to matter in practice.
1977330f729Sjoerg   indices.push_back(llvm::ConstantInt::get(Builder.CGM.Int32Ty,
1987330f729Sjoerg                                            position - Begin));
1997330f729Sjoerg }
2007330f729Sjoerg 
2017330f729Sjoerg ConstantAggregateBuilderBase::PlaceholderPosition
addPlaceholderWithSize(llvm::Type * type)2027330f729Sjoerg ConstantAggregateBuilderBase::addPlaceholderWithSize(llvm::Type *type) {
2037330f729Sjoerg   // Bring the offset up to the last field.
2047330f729Sjoerg   CharUnits offset = getNextOffsetFromGlobal();
2057330f729Sjoerg 
2067330f729Sjoerg   // Create the placeholder.
2077330f729Sjoerg   auto position = addPlaceholder();
2087330f729Sjoerg 
2097330f729Sjoerg   // Advance the offset past that field.
2107330f729Sjoerg   auto &layout = Builder.CGM.getDataLayout();
2117330f729Sjoerg   if (!Packed)
2127330f729Sjoerg     offset = offset.alignTo(CharUnits::fromQuantity(
2137330f729Sjoerg                                 layout.getABITypeAlignment(type)));
2147330f729Sjoerg   offset += CharUnits::fromQuantity(layout.getTypeStoreSize(type));
2157330f729Sjoerg 
2167330f729Sjoerg   CachedOffsetEnd = Builder.Buffer.size();
2177330f729Sjoerg   CachedOffsetFromGlobal = offset;
2187330f729Sjoerg 
2197330f729Sjoerg   return position;
2207330f729Sjoerg }
2217330f729Sjoerg 
getOffsetFromGlobalTo(size_t end) const2227330f729Sjoerg CharUnits ConstantAggregateBuilderBase::getOffsetFromGlobalTo(size_t end) const{
2237330f729Sjoerg   size_t cacheEnd = CachedOffsetEnd;
2247330f729Sjoerg   assert(cacheEnd <= end);
2257330f729Sjoerg 
2267330f729Sjoerg   // Fast path: if the cache is valid, just use it.
2277330f729Sjoerg   if (cacheEnd == end) {
2287330f729Sjoerg     return CachedOffsetFromGlobal;
2297330f729Sjoerg   }
2307330f729Sjoerg 
2317330f729Sjoerg   // If the cached range ends before the index at which the current
2327330f729Sjoerg   // aggregate starts, recurse for the parent.
2337330f729Sjoerg   CharUnits offset;
2347330f729Sjoerg   if (cacheEnd < Begin) {
2357330f729Sjoerg     assert(cacheEnd == 0);
2367330f729Sjoerg     assert(Parent && "Begin != 0 for root builder");
2377330f729Sjoerg     cacheEnd = Begin;
2387330f729Sjoerg     offset = Parent->getOffsetFromGlobalTo(Begin);
2397330f729Sjoerg   } else {
2407330f729Sjoerg     offset = CachedOffsetFromGlobal;
2417330f729Sjoerg   }
2427330f729Sjoerg 
2437330f729Sjoerg   // Perform simple layout on the elements in cacheEnd..<end.
2447330f729Sjoerg   if (cacheEnd != end) {
2457330f729Sjoerg     auto &layout = Builder.CGM.getDataLayout();
2467330f729Sjoerg     do {
2477330f729Sjoerg       llvm::Constant *element = Builder.Buffer[cacheEnd];
2487330f729Sjoerg       assert(element != nullptr &&
2497330f729Sjoerg              "cannot compute offset when a placeholder is present");
2507330f729Sjoerg       llvm::Type *elementType = element->getType();
2517330f729Sjoerg       if (!Packed)
2527330f729Sjoerg         offset = offset.alignTo(CharUnits::fromQuantity(
2537330f729Sjoerg                                   layout.getABITypeAlignment(elementType)));
2547330f729Sjoerg       offset += CharUnits::fromQuantity(layout.getTypeStoreSize(elementType));
2557330f729Sjoerg     } while (++cacheEnd != end);
2567330f729Sjoerg   }
2577330f729Sjoerg 
2587330f729Sjoerg   // Cache and return.
2597330f729Sjoerg   CachedOffsetEnd = cacheEnd;
2607330f729Sjoerg   CachedOffsetFromGlobal = offset;
2617330f729Sjoerg   return offset;
2627330f729Sjoerg }
2637330f729Sjoerg 
finishArray(llvm::Type * eltTy)2647330f729Sjoerg llvm::Constant *ConstantAggregateBuilderBase::finishArray(llvm::Type *eltTy) {
2657330f729Sjoerg   markFinished();
2667330f729Sjoerg 
2677330f729Sjoerg   auto &buffer = getBuffer();
2687330f729Sjoerg   assert((Begin < buffer.size() ||
2697330f729Sjoerg           (Begin == buffer.size() && eltTy))
2707330f729Sjoerg          && "didn't add any array elements without element type");
2717330f729Sjoerg   auto elts = llvm::makeArrayRef(buffer).slice(Begin);
2727330f729Sjoerg   if (!eltTy) eltTy = elts[0]->getType();
2737330f729Sjoerg   auto type = llvm::ArrayType::get(eltTy, elts.size());
2747330f729Sjoerg   auto constant = llvm::ConstantArray::get(type, elts);
2757330f729Sjoerg   buffer.erase(buffer.begin() + Begin, buffer.end());
2767330f729Sjoerg   return constant;
2777330f729Sjoerg }
2787330f729Sjoerg 
2797330f729Sjoerg llvm::Constant *
finishStruct(llvm::StructType * ty)2807330f729Sjoerg ConstantAggregateBuilderBase::finishStruct(llvm::StructType *ty) {
2817330f729Sjoerg   markFinished();
2827330f729Sjoerg 
2837330f729Sjoerg   auto &buffer = getBuffer();
2847330f729Sjoerg   auto elts = llvm::makeArrayRef(buffer).slice(Begin);
2857330f729Sjoerg 
2867330f729Sjoerg   if (ty == nullptr && elts.empty())
2877330f729Sjoerg     ty = llvm::StructType::get(Builder.CGM.getLLVMContext(), {}, Packed);
2887330f729Sjoerg 
2897330f729Sjoerg   llvm::Constant *constant;
2907330f729Sjoerg   if (ty) {
2917330f729Sjoerg     assert(ty->isPacked() == Packed);
2927330f729Sjoerg     constant = llvm::ConstantStruct::get(ty, elts);
2937330f729Sjoerg   } else {
2947330f729Sjoerg     constant = llvm::ConstantStruct::getAnon(elts, Packed);
2957330f729Sjoerg   }
2967330f729Sjoerg 
2977330f729Sjoerg   buffer.erase(buffer.begin() + Begin, buffer.end());
2987330f729Sjoerg   return constant;
2997330f729Sjoerg }
300