diff options
Diffstat (limited to 'clang/lib/CodeGen/ConstantInitBuilder.cpp')
-rw-r--r-- | clang/lib/CodeGen/ConstantInitBuilder.cpp | 131 |
1 files changed, 131 insertions, 0 deletions
diff --git a/clang/lib/CodeGen/ConstantInitBuilder.cpp b/clang/lib/CodeGen/ConstantInitBuilder.cpp new file mode 100644 index 00000000000..772391e77db --- /dev/null +++ b/clang/lib/CodeGen/ConstantInitBuilder.cpp @@ -0,0 +1,131 @@ +//===--- ConstantInitBuilder.cpp - Global initializer builder -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// 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::GlobalVariable * +ConstantInitBuilder::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.getQuantity()); + resolveSelfReferences(GV); + return GV; +} + +void ConstantInitBuilder::setGlobalInitializer(llvm::GlobalVariable *GV, + llvm::Constant *initializer) { + GV->setInitializer(initializer); + + if (!SelfReferences.empty()) + resolveSelfReferences(GV); +} + +void ConstantInitBuilder::resolveSelfReferences(llvm::GlobalVariable *GV) { + for (auto &entry : SelfReferences) { + llvm::Constant *resolvedReference = + llvm::ConstantExpr::getInBoundsGetElementPtr( + GV->getValueType(), GV, entry.Indices); + entry.Dummy->replaceAllUsesWith(resolvedReference); + entry.Dummy->eraseFromParent(); + } +} + +void ConstantInitBuilder::AggregateBuilderBase::addSize(CharUnits size) { + add(Builder.CGM.getSize(size)); +} + +llvm::Constant * +ConstantInitBuilder::AggregateBuilderBase::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 ConstantInitBuilder::AggregateBuilderBase::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)); +} + +llvm::Constant *ConstantArrayBuilder::finishImpl() { + 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); + auto eltTy = 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 *ConstantStructBuilder::finishImpl() { + markFinished(); + + auto &buffer = getBuffer(); + assert(Begin < buffer.size() && "didn't add any struct elements?"); + auto elts = llvm::makeArrayRef(buffer).slice(Begin); + + llvm::Constant *constant; + if (Ty) { + constant = llvm::ConstantStruct::get(Ty, elts); + } else { + constant = llvm::ConstantStruct::getAnon(elts, /*packed*/ false); + } + + buffer.erase(buffer.begin() + Begin, buffer.end()); + return constant; +} |