brintos

brintos / llvm-project-archived public Read only

0
0
Text · 10.9 KiB · 7b3e7ae Raw
317 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9// This file defines out-of-line routines for building initializers for10// global variables, in particular the kind of globals that are implicitly11// introduced by various language ABIs.12//13//===----------------------------------------------------------------------===//14 15#include "clang/CodeGen/ConstantInitBuilder.h"16#include "CodeGenModule.h"17 18using namespace clang;19using namespace CodeGen;20 21llvm::Type *ConstantInitFuture::getType() const {22  assert(Data && "dereferencing null future");23  if (const auto *C = dyn_cast<llvm::Constant *>(Data)) {24    return C->getType();25  } else {26    return cast<ConstantInitBuilderBase *>(Data)->Buffer[0]->getType();27  }28}29 30void ConstantInitFuture::abandon() {31  assert(Data && "abandoning null future");32  if (auto *builder = dyn_cast<ConstantInitBuilderBase *>(Data)) {33    builder->abandon(0);34  }35  Data = nullptr;36}37 38void ConstantInitFuture::installInGlobal(llvm::GlobalVariable *GV) {39  assert(Data && "installing null future");40  if (auto *C = dyn_cast<llvm::Constant *>(Data)) {41    GV->setInitializer(C);42  } else {43    auto &builder = *cast<ConstantInitBuilderBase *>(Data);44    assert(builder.Buffer.size() == 1);45    builder.setGlobalInitializer(GV, builder.Buffer[0]);46    builder.Buffer.clear();47    Data = nullptr;48  }49}50 51ConstantInitFuture52ConstantInitBuilderBase::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.59inline 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 66llvm::GlobalVariable *67ConstantInitBuilderBase::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 87void ConstantInitBuilderBase::setGlobalInitializer(llvm::GlobalVariable *GV,88                                                   llvm::Constant *initializer){89  GV->setInitializer(initializer);90 91  if (!SelfReferences.empty())92    resolveSelfReferences(GV);93}94 95void 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 107void 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, destroy112  // all the self-references, because we might not get another113  // opportunity.114  if (newEnd == 0) {115    for (auto &entry : SelfReferences) {116      auto dummy = entry.Dummy;117      dummy->replaceAllUsesWith(llvm::PoisonValue::get(dummy->getType()));118      dummy->eraseFromParent();119    }120    SelfReferences.clear();121  }122}123 124void ConstantAggregateBuilderBase::addSize(CharUnits size) {125  add(Builder.CGM.getSize(size));126}127 128llvm::Constant *129ConstantAggregateBuilderBase::getRelativeOffset(llvm::IntegerType *offsetType,130                                                llvm::Constant *target) {131  return getRelativeOffsetToPosition(offsetType, target,132                                     Builder.Buffer.size() - Begin);133}134 135llvm::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 153llvm::Constant *154ConstantAggregateBuilderBase::getAddrOfPosition(llvm::Type *type,155                                                size_t position) {156  // Make a global variable.  We will replace this with a GEP to this157  // 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  getGEPIndicesTo(entry.Indices, position + Begin);164  return dummy;165}166 167llvm::Constant *168ConstantAggregateBuilderBase::getAddrOfCurrentPosition(llvm::Type *type) {169  // Make a global variable.  We will replace this with a GEP to this170  // 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 181void 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 201ConstantAggregateBuilderBase::PlaceholderPosition202ConstantAggregateBuilderBase::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(layout.getABITypeAlign(type)));213  offset += CharUnits::fromQuantity(layout.getTypeStoreSize(type));214 215  CachedOffsetEnd = Builder.Buffer.size();216  CachedOffsetFromGlobal = offset;217 218  return position;219}220 221CharUnits ConstantAggregateBuilderBase::getOffsetFromGlobalTo(size_t end) const{222  size_t cacheEnd = CachedOffsetEnd;223  assert(cacheEnd <= end);224 225  // Fast path: if the cache is valid, just use it.226  if (cacheEnd == end) {227    return CachedOffsetFromGlobal;228  }229 230  // If the cached range ends before the index at which the current231  // aggregate starts, recurse for the parent.232  CharUnits offset;233  if (cacheEnd < Begin) {234    assert(cacheEnd == 0);235    assert(Parent && "Begin != 0 for root builder");236    cacheEnd = Begin;237    offset = Parent->getOffsetFromGlobalTo(Begin);238  } else {239    offset = CachedOffsetFromGlobal;240  }241 242  // Perform simple layout on the elements in cacheEnd..<end.243  if (cacheEnd != end) {244    auto &layout = Builder.CGM.getDataLayout();245    do {246      llvm::Constant *element = Builder.Buffer[cacheEnd];247      assert(element != nullptr &&248             "cannot compute offset when a placeholder is present");249      llvm::Type *elementType = element->getType();250      if (!Packed)251        offset = offset.alignTo(252            CharUnits::fromQuantity(layout.getABITypeAlign(elementType)));253      offset += CharUnits::fromQuantity(layout.getTypeStoreSize(elementType));254    } while (++cacheEnd != end);255  }256 257  // Cache and return.258  CachedOffsetEnd = cacheEnd;259  CachedOffsetFromGlobal = offset;260  return offset;261}262 263llvm::Constant *ConstantAggregateBuilderBase::finishArray(llvm::Type *eltTy) {264  markFinished();265 266  auto &buffer = getBuffer();267  assert((Begin < buffer.size() ||268          (Begin == buffer.size() && eltTy))269         && "didn't add any array elements without element type");270  auto elts = llvm::ArrayRef(buffer).slice(Begin);271  if (!eltTy) eltTy = elts[0]->getType();272  auto type = llvm::ArrayType::get(eltTy, elts.size());273  auto constant = llvm::ConstantArray::get(type, elts);274  buffer.erase(buffer.begin() + Begin, buffer.end());275  return constant;276}277 278llvm::Constant *279ConstantAggregateBuilderBase::finishStruct(llvm::StructType *ty) {280  markFinished();281 282  auto &buffer = getBuffer();283  auto elts = llvm::ArrayRef(buffer).slice(Begin);284 285  if (ty == nullptr && elts.empty())286    ty = llvm::StructType::get(Builder.CGM.getLLVMContext(), {}, Packed);287 288  llvm::Constant *constant;289  if (ty) {290    assert(ty->isPacked() == Packed);291    constant = llvm::ConstantStruct::get(ty, elts);292  } else {293    constant = llvm::ConstantStruct::getAnon(elts, Packed);294  }295 296  buffer.erase(buffer.begin() + Begin, buffer.end());297  return constant;298}299 300/// Sign the given pointer and add it to the constant initializer301/// currently being built.302void ConstantAggregateBuilderBase::addSignedPointer(303    llvm::Constant *Pointer, const PointerAuthSchema &Schema,304    GlobalDecl CalleeDecl, QualType CalleeType) {305  if (!Schema || !Builder.CGM.shouldSignPointer(Schema))306    return add(Pointer);307 308  llvm::Constant *StorageAddress = nullptr;309  if (Schema.isAddressDiscriminated()) {310    StorageAddress = getAddrOfCurrentPosition(Pointer->getType());311  }312 313  llvm::Constant *SignedPointer = Builder.CGM.getConstantSignedPointer(314      Pointer, Schema, StorageAddress, CalleeDecl, CalleeType);315  add(SignedPointer);316}317