forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			280 lines
		
	
	
		
			9.4 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			280 lines
		
	
	
		
			9.4 KiB
		
	
	
	
		
			C++
		
	
	
	
//===--- ConstantInitBuilder.cpp - Global initializer builder -------------===//
 | 
						|
//
 | 
						|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 | 
						|
// See https://llvm.org/LICENSE.txt for license information.
 | 
						|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 | 
						|
//
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
//
 | 
						|
// This file defines out-of-line routines for building initializers for
 | 
						|
// global variables, in particular the kind of globals that are implicitly
 | 
						|
// introduced by various language ABIs.
 | 
						|
//
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
 | 
						|
#include "clang/CodeGen/ConstantInitBuilder.h"
 | 
						|
#include "CodeGenModule.h"
 | 
						|
 | 
						|
using namespace clang;
 | 
						|
using namespace CodeGen;
 | 
						|
 | 
						|
llvm::Type *ConstantInitFuture::getType() const {
 | 
						|
  assert(Data && "dereferencing null future");
 | 
						|
  if (Data.is<llvm::Constant*>()) {
 | 
						|
    return Data.get<llvm::Constant*>()->getType();
 | 
						|
  } else {
 | 
						|
    return Data.get<ConstantInitBuilderBase*>()->Buffer[0]->getType();
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void ConstantInitFuture::abandon() {
 | 
						|
  assert(Data && "abandoning null future");
 | 
						|
  if (auto builder = Data.dyn_cast<ConstantInitBuilderBase*>()) {
 | 
						|
    builder->abandon(0);
 | 
						|
  }
 | 
						|
  Data = nullptr;
 | 
						|
}
 | 
						|
 | 
						|
void ConstantInitFuture::installInGlobal(llvm::GlobalVariable *GV) {
 | 
						|
  assert(Data && "installing null future");
 | 
						|
  if (Data.is<llvm::Constant*>()) {
 | 
						|
    GV->setInitializer(Data.get<llvm::Constant*>());
 | 
						|
  } else {
 | 
						|
    auto &builder = *Data.get<ConstantInitBuilderBase*>();
 | 
						|
    assert(builder.Buffer.size() == 1);
 | 
						|
    builder.setGlobalInitializer(GV, builder.Buffer[0]);
 | 
						|
    builder.Buffer.clear();
 | 
						|
    Data = nullptr;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
ConstantInitFuture
 | 
						|
ConstantInitBuilderBase::createFuture(llvm::Constant *initializer) {
 | 
						|
  assert(Buffer.empty() && "buffer not current empty");
 | 
						|
  Buffer.push_back(initializer);
 | 
						|
  return ConstantInitFuture(this);
 | 
						|
}
 | 
						|
 | 
						|
// Only used in this file.
 | 
						|
inline ConstantInitFuture::ConstantInitFuture(ConstantInitBuilderBase *builder)
 | 
						|
    : Data(builder) {
 | 
						|
  assert(!builder->Frozen);
 | 
						|
  assert(builder->Buffer.size() == 1);
 | 
						|
  assert(builder->Buffer[0] != nullptr);
 | 
						|
}
 | 
						|
 | 
						|
llvm::GlobalVariable *
 | 
						|
ConstantInitBuilderBase::createGlobal(llvm::Constant *initializer,
 | 
						|
                                      const llvm::Twine &name,
 | 
						|
                                      CharUnits alignment,
 | 
						|
                                      bool constant,
 | 
						|
                                      llvm::GlobalValue::LinkageTypes linkage,
 | 
						|
                                      unsigned addressSpace) {
 | 
						|
  auto GV = new llvm::GlobalVariable(CGM.getModule(),
 | 
						|
                                     initializer->getType(),
 | 
						|
                                     constant,
 | 
						|
                                     linkage,
 | 
						|
                                     initializer,
 | 
						|
                                     name,
 | 
						|
                                     /*insert before*/ nullptr,
 | 
						|
                                     llvm::GlobalValue::NotThreadLocal,
 | 
						|
                                     addressSpace);
 | 
						|
  GV->setAlignment(alignment.getAsAlign());
 | 
						|
  resolveSelfReferences(GV);
 | 
						|
  return GV;
 | 
						|
}
 | 
						|
 | 
						|
void ConstantInitBuilderBase::setGlobalInitializer(llvm::GlobalVariable *GV,
 | 
						|
                                                   llvm::Constant *initializer){
 | 
						|
  GV->setInitializer(initializer);
 | 
						|
 | 
						|
  if (!SelfReferences.empty())
 | 
						|
    resolveSelfReferences(GV);
 | 
						|
}
 | 
						|
 | 
						|
void ConstantInitBuilderBase::resolveSelfReferences(llvm::GlobalVariable *GV) {
 | 
						|
  for (auto &entry : SelfReferences) {
 | 
						|
    llvm::Constant *resolvedReference =
 | 
						|
      llvm::ConstantExpr::getInBoundsGetElementPtr(
 | 
						|
        GV->getValueType(), GV, entry.Indices);
 | 
						|
    auto dummy = entry.Dummy;
 | 
						|
    dummy->replaceAllUsesWith(resolvedReference);
 | 
						|
    dummy->eraseFromParent();
 | 
						|
  }
 | 
						|
  SelfReferences.clear();
 | 
						|
}
 | 
						|
 | 
						|
void ConstantInitBuilderBase::abandon(size_t newEnd) {
 | 
						|
  // Remove all the entries we've added.
 | 
						|
  Buffer.erase(Buffer.begin() + newEnd, Buffer.end());
 | 
						|
 | 
						|
  // If we're abandoning all the way to the beginning, destroy
 | 
						|
  // all the self-references, because we might not get another
 | 
						|
  // opportunity.
 | 
						|
  if (newEnd == 0) {
 | 
						|
    for (auto &entry : SelfReferences) {
 | 
						|
      auto dummy = entry.Dummy;
 | 
						|
      dummy->replaceAllUsesWith(llvm::UndefValue::get(dummy->getType()));
 | 
						|
      dummy->eraseFromParent();
 | 
						|
    }
 | 
						|
    SelfReferences.clear();
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void ConstantAggregateBuilderBase::addSize(CharUnits size) {
 | 
						|
  add(Builder.CGM.getSize(size));
 | 
						|
}
 | 
						|
 | 
						|
llvm::Constant *
 | 
						|
ConstantAggregateBuilderBase::getRelativeOffset(llvm::IntegerType *offsetType,
 | 
						|
                                                llvm::Constant *target) {
 | 
						|
  // Compute the address of the relative-address slot.
 | 
						|
  auto base = getAddrOfCurrentPosition(offsetType);
 | 
						|
 | 
						|
  // Subtract.
 | 
						|
  base = llvm::ConstantExpr::getPtrToInt(base, Builder.CGM.IntPtrTy);
 | 
						|
  target = llvm::ConstantExpr::getPtrToInt(target, Builder.CGM.IntPtrTy);
 | 
						|
  llvm::Constant *offset = llvm::ConstantExpr::getSub(target, base);
 | 
						|
 | 
						|
  // Truncate to the relative-address type if necessary.
 | 
						|
  if (Builder.CGM.IntPtrTy != offsetType) {
 | 
						|
    offset = llvm::ConstantExpr::getTrunc(offset, offsetType);
 | 
						|
  }
 | 
						|
 | 
						|
  return offset;
 | 
						|
}
 | 
						|
 | 
						|
llvm::Constant *
 | 
						|
ConstantAggregateBuilderBase::getAddrOfCurrentPosition(llvm::Type *type) {
 | 
						|
  // Make a global variable.  We will replace this with a GEP to this
 | 
						|
  // position after installing the initializer.
 | 
						|
  auto dummy =
 | 
						|
    new llvm::GlobalVariable(Builder.CGM.getModule(), type, true,
 | 
						|
                             llvm::GlobalVariable::PrivateLinkage,
 | 
						|
                             nullptr, "");
 | 
						|
  Builder.SelfReferences.emplace_back(dummy);
 | 
						|
  auto &entry = Builder.SelfReferences.back();
 | 
						|
  (void) getGEPIndicesToCurrentPosition(entry.Indices);
 | 
						|
  return dummy;
 | 
						|
}
 | 
						|
 | 
						|
void ConstantAggregateBuilderBase::getGEPIndicesTo(
 | 
						|
                               llvm::SmallVectorImpl<llvm::Constant*> &indices,
 | 
						|
                               size_t position) const {
 | 
						|
  // Recurse on the parent builder if present.
 | 
						|
  if (Parent) {
 | 
						|
    Parent->getGEPIndicesTo(indices, Begin);
 | 
						|
 | 
						|
  // Otherwise, add an index to drill into the first level of pointer.
 | 
						|
  } else {
 | 
						|
    assert(indices.empty());
 | 
						|
    indices.push_back(llvm::ConstantInt::get(Builder.CGM.Int32Ty, 0));
 | 
						|
  }
 | 
						|
 | 
						|
  assert(position >= Begin);
 | 
						|
  // We have to use i32 here because struct GEPs demand i32 indices.
 | 
						|
  // It's rather unlikely to matter in practice.
 | 
						|
  indices.push_back(llvm::ConstantInt::get(Builder.CGM.Int32Ty,
 | 
						|
                                           position - Begin));
 | 
						|
}
 | 
						|
 | 
						|
ConstantAggregateBuilderBase::PlaceholderPosition
 | 
						|
ConstantAggregateBuilderBase::addPlaceholderWithSize(llvm::Type *type) {
 | 
						|
  // Bring the offset up to the last field.
 | 
						|
  CharUnits offset = getNextOffsetFromGlobal();
 | 
						|
 | 
						|
  // Create the placeholder.
 | 
						|
  auto position = addPlaceholder();
 | 
						|
 | 
						|
  // Advance the offset past that field.
 | 
						|
  auto &layout = Builder.CGM.getDataLayout();
 | 
						|
  if (!Packed)
 | 
						|
    offset = offset.alignTo(CharUnits::fromQuantity(
 | 
						|
                                layout.getABITypeAlignment(type)));
 | 
						|
  offset += CharUnits::fromQuantity(layout.getTypeStoreSize(type));
 | 
						|
 | 
						|
  CachedOffsetEnd = Builder.Buffer.size();
 | 
						|
  CachedOffsetFromGlobal = offset;
 | 
						|
 | 
						|
  return position;
 | 
						|
}
 | 
						|
 | 
						|
CharUnits ConstantAggregateBuilderBase::getOffsetFromGlobalTo(size_t end) const{
 | 
						|
  size_t cacheEnd = CachedOffsetEnd;
 | 
						|
  assert(cacheEnd <= end);
 | 
						|
 | 
						|
  // Fast path: if the cache is valid, just use it.
 | 
						|
  if (cacheEnd == end) {
 | 
						|
    return CachedOffsetFromGlobal;
 | 
						|
  }
 | 
						|
 | 
						|
  // If the cached range ends before the index at which the current
 | 
						|
  // aggregate starts, recurse for the parent.
 | 
						|
  CharUnits offset;
 | 
						|
  if (cacheEnd < Begin) {
 | 
						|
    assert(cacheEnd == 0);
 | 
						|
    assert(Parent && "Begin != 0 for root builder");
 | 
						|
    cacheEnd = Begin;
 | 
						|
    offset = Parent->getOffsetFromGlobalTo(Begin);
 | 
						|
  } else {
 | 
						|
    offset = CachedOffsetFromGlobal;
 | 
						|
  }
 | 
						|
 | 
						|
  // Perform simple layout on the elements in cacheEnd..<end.
 | 
						|
  if (cacheEnd != end) {
 | 
						|
    auto &layout = Builder.CGM.getDataLayout();
 | 
						|
    do {
 | 
						|
      llvm::Constant *element = Builder.Buffer[cacheEnd];
 | 
						|
      assert(element != nullptr &&
 | 
						|
             "cannot compute offset when a placeholder is present");
 | 
						|
      llvm::Type *elementType = element->getType();
 | 
						|
      if (!Packed)
 | 
						|
        offset = offset.alignTo(CharUnits::fromQuantity(
 | 
						|
                                  layout.getABITypeAlignment(elementType)));
 | 
						|
      offset += CharUnits::fromQuantity(layout.getTypeStoreSize(elementType));
 | 
						|
    } while (++cacheEnd != end);
 | 
						|
  }
 | 
						|
 | 
						|
  // Cache and return.
 | 
						|
  CachedOffsetEnd = cacheEnd;
 | 
						|
  CachedOffsetFromGlobal = offset;
 | 
						|
  return offset;
 | 
						|
}
 | 
						|
 | 
						|
llvm::Constant *ConstantAggregateBuilderBase::finishArray(llvm::Type *eltTy) {
 | 
						|
  markFinished();
 | 
						|
 | 
						|
  auto &buffer = getBuffer();
 | 
						|
  assert((Begin < buffer.size() ||
 | 
						|
          (Begin == buffer.size() && eltTy))
 | 
						|
         && "didn't add any array elements without element type");
 | 
						|
  auto elts = llvm::makeArrayRef(buffer).slice(Begin);
 | 
						|
  if (!eltTy) eltTy = elts[0]->getType();
 | 
						|
  auto type = llvm::ArrayType::get(eltTy, elts.size());
 | 
						|
  auto constant = llvm::ConstantArray::get(type, elts);
 | 
						|
  buffer.erase(buffer.begin() + Begin, buffer.end());
 | 
						|
  return constant;
 | 
						|
}
 | 
						|
 | 
						|
llvm::Constant *
 | 
						|
ConstantAggregateBuilderBase::finishStruct(llvm::StructType *ty) {
 | 
						|
  markFinished();
 | 
						|
 | 
						|
  auto &buffer = getBuffer();
 | 
						|
  auto elts = llvm::makeArrayRef(buffer).slice(Begin);
 | 
						|
 | 
						|
  if (ty == nullptr && elts.empty())
 | 
						|
    ty = llvm::StructType::get(Builder.CGM.getLLVMContext(), {}, Packed);
 | 
						|
 | 
						|
  llvm::Constant *constant;
 | 
						|
  if (ty) {
 | 
						|
    assert(ty->isPacked() == Packed);
 | 
						|
    constant = llvm::ConstantStruct::get(ty, elts);
 | 
						|
  } else {
 | 
						|
    constant = llvm::ConstantStruct::getAnon(elts, Packed);
 | 
						|
  }
 | 
						|
 | 
						|
  buffer.erase(buffer.begin() + Begin, buffer.end());
 | 
						|
  return constant;
 | 
						|
}
 |