xref: /freebsd-src/contrib/llvm-project/clang/lib/CodeGen/ConstantInitBuilder.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===--- ConstantInitBuilder.cpp - Global initializer builder -------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file defines out-of-line routines for building initializers for
100b57cec5SDimitry Andric // global variables, in particular the kind of globals that are implicitly
110b57cec5SDimitry Andric // introduced by various language ABIs.
120b57cec5SDimitry Andric //
130b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
140b57cec5SDimitry Andric 
150b57cec5SDimitry Andric #include "clang/CodeGen/ConstantInitBuilder.h"
160b57cec5SDimitry Andric #include "CodeGenModule.h"
170b57cec5SDimitry Andric 
180b57cec5SDimitry Andric using namespace clang;
190b57cec5SDimitry Andric using namespace CodeGen;
200b57cec5SDimitry Andric 
210b57cec5SDimitry Andric llvm::Type *ConstantInitFuture::getType() const {
220b57cec5SDimitry Andric   assert(Data && "dereferencing null future");
230b57cec5SDimitry Andric   if (Data.is<llvm::Constant*>()) {
240b57cec5SDimitry Andric     return Data.get<llvm::Constant*>()->getType();
250b57cec5SDimitry Andric   } else {
260b57cec5SDimitry Andric     return Data.get<ConstantInitBuilderBase*>()->Buffer[0]->getType();
270b57cec5SDimitry Andric   }
280b57cec5SDimitry Andric }
290b57cec5SDimitry Andric 
300b57cec5SDimitry Andric void ConstantInitFuture::abandon() {
310b57cec5SDimitry Andric   assert(Data && "abandoning null future");
320b57cec5SDimitry Andric   if (auto builder = Data.dyn_cast<ConstantInitBuilderBase*>()) {
330b57cec5SDimitry Andric     builder->abandon(0);
340b57cec5SDimitry Andric   }
350b57cec5SDimitry Andric   Data = nullptr;
360b57cec5SDimitry Andric }
370b57cec5SDimitry Andric 
380b57cec5SDimitry Andric void ConstantInitFuture::installInGlobal(llvm::GlobalVariable *GV) {
390b57cec5SDimitry Andric   assert(Data && "installing null future");
400b57cec5SDimitry Andric   if (Data.is<llvm::Constant*>()) {
410b57cec5SDimitry Andric     GV->setInitializer(Data.get<llvm::Constant*>());
420b57cec5SDimitry Andric   } else {
430b57cec5SDimitry Andric     auto &builder = *Data.get<ConstantInitBuilderBase*>();
440b57cec5SDimitry Andric     assert(builder.Buffer.size() == 1);
450b57cec5SDimitry Andric     builder.setGlobalInitializer(GV, builder.Buffer[0]);
460b57cec5SDimitry Andric     builder.Buffer.clear();
470b57cec5SDimitry Andric     Data = nullptr;
480b57cec5SDimitry Andric   }
490b57cec5SDimitry Andric }
500b57cec5SDimitry Andric 
510b57cec5SDimitry Andric ConstantInitFuture
520b57cec5SDimitry Andric ConstantInitBuilderBase::createFuture(llvm::Constant *initializer) {
530b57cec5SDimitry Andric   assert(Buffer.empty() && "buffer not current empty");
540b57cec5SDimitry Andric   Buffer.push_back(initializer);
550b57cec5SDimitry Andric   return ConstantInitFuture(this);
560b57cec5SDimitry Andric }
570b57cec5SDimitry Andric 
580b57cec5SDimitry Andric // Only used in this file.
590b57cec5SDimitry Andric inline ConstantInitFuture::ConstantInitFuture(ConstantInitBuilderBase *builder)
600b57cec5SDimitry Andric     : Data(builder) {
610b57cec5SDimitry Andric   assert(!builder->Frozen);
620b57cec5SDimitry Andric   assert(builder->Buffer.size() == 1);
630b57cec5SDimitry Andric   assert(builder->Buffer[0] != nullptr);
640b57cec5SDimitry Andric }
650b57cec5SDimitry Andric 
660b57cec5SDimitry Andric llvm::GlobalVariable *
670b57cec5SDimitry Andric ConstantInitBuilderBase::createGlobal(llvm::Constant *initializer,
680b57cec5SDimitry Andric                                       const llvm::Twine &name,
690b57cec5SDimitry Andric                                       CharUnits alignment,
700b57cec5SDimitry Andric                                       bool constant,
710b57cec5SDimitry Andric                                       llvm::GlobalValue::LinkageTypes linkage,
720b57cec5SDimitry Andric                                       unsigned addressSpace) {
730b57cec5SDimitry Andric   auto GV = new llvm::GlobalVariable(CGM.getModule(),
740b57cec5SDimitry Andric                                      initializer->getType(),
750b57cec5SDimitry Andric                                      constant,
760b57cec5SDimitry Andric                                      linkage,
770b57cec5SDimitry Andric                                      initializer,
780b57cec5SDimitry Andric                                      name,
790b57cec5SDimitry Andric                                      /*insert before*/ nullptr,
800b57cec5SDimitry Andric                                      llvm::GlobalValue::NotThreadLocal,
810b57cec5SDimitry Andric                                      addressSpace);
82a7dea167SDimitry Andric   GV->setAlignment(alignment.getAsAlign());
830b57cec5SDimitry Andric   resolveSelfReferences(GV);
840b57cec5SDimitry Andric   return GV;
850b57cec5SDimitry Andric }
860b57cec5SDimitry Andric 
870b57cec5SDimitry Andric void ConstantInitBuilderBase::setGlobalInitializer(llvm::GlobalVariable *GV,
880b57cec5SDimitry Andric                                                    llvm::Constant *initializer){
890b57cec5SDimitry Andric   GV->setInitializer(initializer);
900b57cec5SDimitry Andric 
910b57cec5SDimitry Andric   if (!SelfReferences.empty())
920b57cec5SDimitry Andric     resolveSelfReferences(GV);
930b57cec5SDimitry Andric }
940b57cec5SDimitry Andric 
950b57cec5SDimitry Andric void ConstantInitBuilderBase::resolveSelfReferences(llvm::GlobalVariable *GV) {
960b57cec5SDimitry Andric   for (auto &entry : SelfReferences) {
970b57cec5SDimitry Andric     llvm::Constant *resolvedReference =
980b57cec5SDimitry Andric       llvm::ConstantExpr::getInBoundsGetElementPtr(
990b57cec5SDimitry Andric         GV->getValueType(), GV, entry.Indices);
1000b57cec5SDimitry Andric     auto dummy = entry.Dummy;
1010b57cec5SDimitry Andric     dummy->replaceAllUsesWith(resolvedReference);
1020b57cec5SDimitry Andric     dummy->eraseFromParent();
1030b57cec5SDimitry Andric   }
1040b57cec5SDimitry Andric   SelfReferences.clear();
1050b57cec5SDimitry Andric }
1060b57cec5SDimitry Andric 
1070b57cec5SDimitry Andric void ConstantInitBuilderBase::abandon(size_t newEnd) {
1080b57cec5SDimitry Andric   // Remove all the entries we've added.
1090b57cec5SDimitry Andric   Buffer.erase(Buffer.begin() + newEnd, Buffer.end());
1100b57cec5SDimitry Andric 
1110b57cec5SDimitry Andric   // If we're abandoning all the way to the beginning, destroy
1120b57cec5SDimitry Andric   // all the self-references, because we might not get another
1130b57cec5SDimitry Andric   // opportunity.
1140b57cec5SDimitry Andric   if (newEnd == 0) {
1150b57cec5SDimitry Andric     for (auto &entry : SelfReferences) {
1160b57cec5SDimitry Andric       auto dummy = entry.Dummy;
11781ad6265SDimitry Andric       dummy->replaceAllUsesWith(llvm::PoisonValue::get(dummy->getType()));
1180b57cec5SDimitry Andric       dummy->eraseFromParent();
1190b57cec5SDimitry Andric     }
1200b57cec5SDimitry Andric     SelfReferences.clear();
1210b57cec5SDimitry Andric   }
1220b57cec5SDimitry Andric }
1230b57cec5SDimitry Andric 
1240b57cec5SDimitry Andric void ConstantAggregateBuilderBase::addSize(CharUnits size) {
1250b57cec5SDimitry Andric   add(Builder.CGM.getSize(size));
1260b57cec5SDimitry Andric }
1270b57cec5SDimitry Andric 
1280b57cec5SDimitry Andric llvm::Constant *
1290b57cec5SDimitry Andric ConstantAggregateBuilderBase::getRelativeOffset(llvm::IntegerType *offsetType,
1300b57cec5SDimitry Andric                                                 llvm::Constant *target) {
1315ffd83dbSDimitry Andric   return getRelativeOffsetToPosition(offsetType, target,
1325ffd83dbSDimitry Andric                                      Builder.Buffer.size() - Begin);
1335ffd83dbSDimitry Andric }
1345ffd83dbSDimitry Andric 
1355ffd83dbSDimitry Andric llvm::Constant *ConstantAggregateBuilderBase::getRelativeOffsetToPosition(
1365ffd83dbSDimitry Andric     llvm::IntegerType *offsetType, llvm::Constant *target, size_t position) {
1370b57cec5SDimitry Andric   // Compute the address of the relative-address slot.
1385ffd83dbSDimitry Andric   auto base = getAddrOfPosition(offsetType, position);
1390b57cec5SDimitry Andric 
1400b57cec5SDimitry Andric   // Subtract.
1410b57cec5SDimitry Andric   base = llvm::ConstantExpr::getPtrToInt(base, Builder.CGM.IntPtrTy);
1420b57cec5SDimitry Andric   target = llvm::ConstantExpr::getPtrToInt(target, Builder.CGM.IntPtrTy);
1430b57cec5SDimitry Andric   llvm::Constant *offset = llvm::ConstantExpr::getSub(target, base);
1440b57cec5SDimitry Andric 
1450b57cec5SDimitry Andric   // Truncate to the relative-address type if necessary.
1460b57cec5SDimitry Andric   if (Builder.CGM.IntPtrTy != offsetType) {
1470b57cec5SDimitry Andric     offset = llvm::ConstantExpr::getTrunc(offset, offsetType);
1480b57cec5SDimitry Andric   }
1490b57cec5SDimitry Andric 
1500b57cec5SDimitry Andric   return offset;
1510b57cec5SDimitry Andric }
1520b57cec5SDimitry Andric 
1530b57cec5SDimitry Andric llvm::Constant *
1545ffd83dbSDimitry Andric ConstantAggregateBuilderBase::getAddrOfPosition(llvm::Type *type,
1555ffd83dbSDimitry Andric                                                 size_t position) {
1565ffd83dbSDimitry Andric   // Make a global variable.  We will replace this with a GEP to this
1575ffd83dbSDimitry Andric   // position after installing the initializer.
1585ffd83dbSDimitry Andric   auto dummy = new llvm::GlobalVariable(Builder.CGM.getModule(), type, true,
1595ffd83dbSDimitry Andric                                         llvm::GlobalVariable::PrivateLinkage,
1605ffd83dbSDimitry Andric                                         nullptr, "");
1615ffd83dbSDimitry Andric   Builder.SelfReferences.emplace_back(dummy);
1625ffd83dbSDimitry Andric   auto &entry = Builder.SelfReferences.back();
1635ffd83dbSDimitry Andric   (void)getGEPIndicesTo(entry.Indices, position + Begin);
1645ffd83dbSDimitry Andric   return dummy;
1655ffd83dbSDimitry Andric }
1665ffd83dbSDimitry Andric 
1675ffd83dbSDimitry Andric llvm::Constant *
1680b57cec5SDimitry Andric ConstantAggregateBuilderBase::getAddrOfCurrentPosition(llvm::Type *type) {
1690b57cec5SDimitry Andric   // Make a global variable.  We will replace this with a GEP to this
1700b57cec5SDimitry Andric   // position after installing the initializer.
1710b57cec5SDimitry Andric   auto dummy =
1720b57cec5SDimitry Andric     new llvm::GlobalVariable(Builder.CGM.getModule(), type, true,
1730b57cec5SDimitry Andric                              llvm::GlobalVariable::PrivateLinkage,
1740b57cec5SDimitry Andric                              nullptr, "");
1750b57cec5SDimitry Andric   Builder.SelfReferences.emplace_back(dummy);
1760b57cec5SDimitry Andric   auto &entry = Builder.SelfReferences.back();
1770b57cec5SDimitry Andric   (void) getGEPIndicesToCurrentPosition(entry.Indices);
1780b57cec5SDimitry Andric   return dummy;
1790b57cec5SDimitry Andric }
1800b57cec5SDimitry Andric 
1810b57cec5SDimitry Andric void ConstantAggregateBuilderBase::getGEPIndicesTo(
1820b57cec5SDimitry Andric                                llvm::SmallVectorImpl<llvm::Constant*> &indices,
1830b57cec5SDimitry Andric                                size_t position) const {
1840b57cec5SDimitry Andric   // Recurse on the parent builder if present.
1850b57cec5SDimitry Andric   if (Parent) {
1860b57cec5SDimitry Andric     Parent->getGEPIndicesTo(indices, Begin);
1870b57cec5SDimitry Andric 
1880b57cec5SDimitry Andric   // Otherwise, add an index to drill into the first level of pointer.
1890b57cec5SDimitry Andric   } else {
1900b57cec5SDimitry Andric     assert(indices.empty());
1910b57cec5SDimitry Andric     indices.push_back(llvm::ConstantInt::get(Builder.CGM.Int32Ty, 0));
1920b57cec5SDimitry Andric   }
1930b57cec5SDimitry Andric 
1940b57cec5SDimitry Andric   assert(position >= Begin);
1950b57cec5SDimitry Andric   // We have to use i32 here because struct GEPs demand i32 indices.
1960b57cec5SDimitry Andric   // It's rather unlikely to matter in practice.
1970b57cec5SDimitry Andric   indices.push_back(llvm::ConstantInt::get(Builder.CGM.Int32Ty,
1980b57cec5SDimitry Andric                                            position - Begin));
1990b57cec5SDimitry Andric }
2000b57cec5SDimitry Andric 
2010b57cec5SDimitry Andric ConstantAggregateBuilderBase::PlaceholderPosition
2020b57cec5SDimitry Andric ConstantAggregateBuilderBase::addPlaceholderWithSize(llvm::Type *type) {
2030b57cec5SDimitry Andric   // Bring the offset up to the last field.
2040b57cec5SDimitry Andric   CharUnits offset = getNextOffsetFromGlobal();
2050b57cec5SDimitry Andric 
2060b57cec5SDimitry Andric   // Create the placeholder.
2070b57cec5SDimitry Andric   auto position = addPlaceholder();
2080b57cec5SDimitry Andric 
2090b57cec5SDimitry Andric   // Advance the offset past that field.
2100b57cec5SDimitry Andric   auto &layout = Builder.CGM.getDataLayout();
2110b57cec5SDimitry Andric   if (!Packed)
212bdd1243dSDimitry Andric     offset = offset.alignTo(CharUnits::fromQuantity(layout.getABITypeAlign(type)));
2130b57cec5SDimitry Andric   offset += CharUnits::fromQuantity(layout.getTypeStoreSize(type));
2140b57cec5SDimitry Andric 
2150b57cec5SDimitry Andric   CachedOffsetEnd = Builder.Buffer.size();
2160b57cec5SDimitry Andric   CachedOffsetFromGlobal = offset;
2170b57cec5SDimitry Andric 
2180b57cec5SDimitry Andric   return position;
2190b57cec5SDimitry Andric }
2200b57cec5SDimitry Andric 
2210b57cec5SDimitry Andric CharUnits ConstantAggregateBuilderBase::getOffsetFromGlobalTo(size_t end) const{
2220b57cec5SDimitry Andric   size_t cacheEnd = CachedOffsetEnd;
2230b57cec5SDimitry Andric   assert(cacheEnd <= end);
2240b57cec5SDimitry Andric 
2250b57cec5SDimitry Andric   // Fast path: if the cache is valid, just use it.
2260b57cec5SDimitry Andric   if (cacheEnd == end) {
2270b57cec5SDimitry Andric     return CachedOffsetFromGlobal;
2280b57cec5SDimitry Andric   }
2290b57cec5SDimitry Andric 
2300b57cec5SDimitry Andric   // If the cached range ends before the index at which the current
2310b57cec5SDimitry Andric   // aggregate starts, recurse for the parent.
2320b57cec5SDimitry Andric   CharUnits offset;
2330b57cec5SDimitry Andric   if (cacheEnd < Begin) {
2340b57cec5SDimitry Andric     assert(cacheEnd == 0);
2350b57cec5SDimitry Andric     assert(Parent && "Begin != 0 for root builder");
2360b57cec5SDimitry Andric     cacheEnd = Begin;
2370b57cec5SDimitry Andric     offset = Parent->getOffsetFromGlobalTo(Begin);
2380b57cec5SDimitry Andric   } else {
2390b57cec5SDimitry Andric     offset = CachedOffsetFromGlobal;
2400b57cec5SDimitry Andric   }
2410b57cec5SDimitry Andric 
2420b57cec5SDimitry Andric   // Perform simple layout on the elements in cacheEnd..<end.
2430b57cec5SDimitry Andric   if (cacheEnd != end) {
2440b57cec5SDimitry Andric     auto &layout = Builder.CGM.getDataLayout();
2450b57cec5SDimitry Andric     do {
2460b57cec5SDimitry Andric       llvm::Constant *element = Builder.Buffer[cacheEnd];
2470b57cec5SDimitry Andric       assert(element != nullptr &&
2480b57cec5SDimitry Andric              "cannot compute offset when a placeholder is present");
2490b57cec5SDimitry Andric       llvm::Type *elementType = element->getType();
2500b57cec5SDimitry Andric       if (!Packed)
251bdd1243dSDimitry Andric         offset = offset.alignTo(
252bdd1243dSDimitry Andric             CharUnits::fromQuantity(layout.getABITypeAlign(elementType)));
2530b57cec5SDimitry Andric       offset += CharUnits::fromQuantity(layout.getTypeStoreSize(elementType));
2540b57cec5SDimitry Andric     } while (++cacheEnd != end);
2550b57cec5SDimitry Andric   }
2560b57cec5SDimitry Andric 
2570b57cec5SDimitry Andric   // Cache and return.
2580b57cec5SDimitry Andric   CachedOffsetEnd = cacheEnd;
2590b57cec5SDimitry Andric   CachedOffsetFromGlobal = offset;
2600b57cec5SDimitry Andric   return offset;
2610b57cec5SDimitry Andric }
2620b57cec5SDimitry Andric 
2630b57cec5SDimitry Andric llvm::Constant *ConstantAggregateBuilderBase::finishArray(llvm::Type *eltTy) {
2640b57cec5SDimitry Andric   markFinished();
2650b57cec5SDimitry Andric 
2660b57cec5SDimitry Andric   auto &buffer = getBuffer();
2670b57cec5SDimitry Andric   assert((Begin < buffer.size() ||
2680b57cec5SDimitry Andric           (Begin == buffer.size() && eltTy))
2690b57cec5SDimitry Andric          && "didn't add any array elements without element type");
270bdd1243dSDimitry Andric   auto elts = llvm::ArrayRef(buffer).slice(Begin);
2710b57cec5SDimitry Andric   if (!eltTy) eltTy = elts[0]->getType();
2720b57cec5SDimitry Andric   auto type = llvm::ArrayType::get(eltTy, elts.size());
2730b57cec5SDimitry Andric   auto constant = llvm::ConstantArray::get(type, elts);
2740b57cec5SDimitry Andric   buffer.erase(buffer.begin() + Begin, buffer.end());
2750b57cec5SDimitry Andric   return constant;
2760b57cec5SDimitry Andric }
2770b57cec5SDimitry Andric 
2780b57cec5SDimitry Andric llvm::Constant *
2790b57cec5SDimitry Andric ConstantAggregateBuilderBase::finishStruct(llvm::StructType *ty) {
2800b57cec5SDimitry Andric   markFinished();
2810b57cec5SDimitry Andric 
2820b57cec5SDimitry Andric   auto &buffer = getBuffer();
283bdd1243dSDimitry Andric   auto elts = llvm::ArrayRef(buffer).slice(Begin);
2840b57cec5SDimitry Andric 
2850b57cec5SDimitry Andric   if (ty == nullptr && elts.empty())
2860b57cec5SDimitry Andric     ty = llvm::StructType::get(Builder.CGM.getLLVMContext(), {}, Packed);
2870b57cec5SDimitry Andric 
2880b57cec5SDimitry Andric   llvm::Constant *constant;
2890b57cec5SDimitry Andric   if (ty) {
2900b57cec5SDimitry Andric     assert(ty->isPacked() == Packed);
2910b57cec5SDimitry Andric     constant = llvm::ConstantStruct::get(ty, elts);
2920b57cec5SDimitry Andric   } else {
2930b57cec5SDimitry Andric     constant = llvm::ConstantStruct::getAnon(elts, Packed);
2940b57cec5SDimitry Andric   }
2950b57cec5SDimitry Andric 
2960b57cec5SDimitry Andric   buffer.erase(buffer.begin() + Begin, buffer.end());
2970b57cec5SDimitry Andric   return constant;
2980b57cec5SDimitry Andric }
299*0fca6ea1SDimitry Andric 
300*0fca6ea1SDimitry Andric /// Sign the given pointer and add it to the constant initializer
301*0fca6ea1SDimitry Andric /// currently being built.
302*0fca6ea1SDimitry Andric void ConstantAggregateBuilderBase::addSignedPointer(
303*0fca6ea1SDimitry Andric     llvm::Constant *Pointer, const PointerAuthSchema &Schema,
304*0fca6ea1SDimitry Andric     GlobalDecl CalleeDecl, QualType CalleeType) {
305*0fca6ea1SDimitry Andric   if (!Schema || !Builder.CGM.shouldSignPointer(Schema))
306*0fca6ea1SDimitry Andric     return add(Pointer);
307*0fca6ea1SDimitry Andric 
308*0fca6ea1SDimitry Andric   llvm::Constant *StorageAddress = nullptr;
309*0fca6ea1SDimitry Andric   if (Schema.isAddressDiscriminated()) {
310*0fca6ea1SDimitry Andric     StorageAddress = getAddrOfCurrentPosition(Pointer->getType());
311*0fca6ea1SDimitry Andric   }
312*0fca6ea1SDimitry Andric 
313*0fca6ea1SDimitry Andric   llvm::Constant *SignedPointer = Builder.CGM.getConstantSignedPointer(
314*0fca6ea1SDimitry Andric       Pointer, Schema, StorageAddress, CalleeDecl, CalleeType);
315*0fca6ea1SDimitry Andric   add(SignedPointer);
316*0fca6ea1SDimitry Andric }
317