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