|  | //===--- 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) { | 
|  | return getRelativeOffsetToPosition(offsetType, target, | 
|  | Builder.Buffer.size() - Begin); | 
|  | } | 
|  |  | 
|  | llvm::Constant *ConstantAggregateBuilderBase::getRelativeOffsetToPosition( | 
|  | llvm::IntegerType *offsetType, llvm::Constant *target, size_t position) { | 
|  | // Compute the address of the relative-address slot. | 
|  | auto base = getAddrOfPosition(offsetType, position); | 
|  |  | 
|  | // 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::getAddrOfPosition(llvm::Type *type, | 
|  | size_t position) { | 
|  | // 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)getGEPIndicesTo(entry.Indices, position + Begin); | 
|  | return dummy; | 
|  | } | 
|  |  | 
|  | 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; | 
|  | } |