| //===- ConstantInitBuilder.h - Builder for LLVM IR constants ----*- C++ -*-===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This class provides a convenient interface for building complex |
| // global initializers of the sort that are frequently required for |
| // language ABIs. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLVM_CLANG_CODEGEN_CONSTANTINITBUILDER_H |
| #define LLVM_CLANG_CODEGEN_CONSTANTINITBUILDER_H |
| |
| #include "llvm/ADT/ArrayRef.h" |
| #include "llvm/ADT/SmallVector.h" |
| #include "llvm/IR/Constants.h" |
| #include "llvm/IR/GlobalValue.h" |
| #include "clang/AST/CharUnits.h" |
| #include "clang/CodeGen/ConstantInitFuture.h" |
| |
| #include <vector> |
| |
| namespace clang { |
| namespace CodeGen { |
| |
| class CodeGenModule; |
| |
| /// A convenience builder class for complex constant initializers, |
| /// especially for anonymous global structures used by various language |
| /// runtimes. |
| /// |
| /// The basic usage pattern is expected to be something like: |
| /// ConstantInitBuilder builder(CGM); |
| /// auto toplevel = builder.beginStruct(); |
| /// toplevel.addInt(CGM.SizeTy, widgets.size()); |
| /// auto widgetArray = builder.beginArray(); |
| /// for (auto &widget : widgets) { |
| /// auto widgetDesc = widgetArray.beginStruct(); |
| /// widgetDesc.addInt(CGM.SizeTy, widget.getPower()); |
| /// widgetDesc.add(CGM.GetAddrOfConstantString(widget.getName())); |
| /// widgetDesc.add(CGM.GetAddrOfGlobal(widget.getInitializerDecl())); |
| /// widgetDesc.finishAndAddTo(widgetArray); |
| /// } |
| /// widgetArray.finishAndAddTo(toplevel); |
| /// auto global = toplevel.finishAndCreateGlobal("WIDGET_LIST", Align, |
| /// /*constant*/ true); |
| class ConstantInitBuilderBase { |
| struct SelfReference { |
| llvm::GlobalVariable *Dummy; |
| llvm::SmallVector<llvm::Constant*, 4> Indices; |
| |
| SelfReference(llvm::GlobalVariable *dummy) : Dummy(dummy) {} |
| }; |
| CodeGenModule &CGM; |
| llvm::SmallVector<llvm::Constant*, 16> Buffer; |
| std::vector<SelfReference> SelfReferences; |
| bool Frozen = false; |
| |
| friend class ConstantInitFuture; |
| friend class ConstantAggregateBuilderBase; |
| template <class, class> |
| friend class ConstantAggregateBuilderTemplateBase; |
| |
| protected: |
| explicit ConstantInitBuilderBase(CodeGenModule &CGM) : CGM(CGM) {} |
| |
| ~ConstantInitBuilderBase() { |
| assert(Buffer.empty() && "didn't claim all values out of buffer"); |
| assert(SelfReferences.empty() && "didn't apply all self-references"); |
| } |
| |
| private: |
| llvm::GlobalVariable *createGlobal(llvm::Constant *initializer, |
| const llvm::Twine &name, |
| CharUnits alignment, |
| bool constant = false, |
| llvm::GlobalValue::LinkageTypes linkage |
| = llvm::GlobalValue::InternalLinkage, |
| unsigned addressSpace = 0); |
| |
| ConstantInitFuture createFuture(llvm::Constant *initializer); |
| |
| void setGlobalInitializer(llvm::GlobalVariable *GV, |
| llvm::Constant *initializer); |
| |
| void resolveSelfReferences(llvm::GlobalVariable *GV); |
| |
| void abandon(size_t newEnd); |
| }; |
| |
| /// A concrete base class for struct and array aggregate |
| /// initializer builders. |
| class ConstantAggregateBuilderBase { |
| protected: |
| ConstantInitBuilderBase &Builder; |
| ConstantAggregateBuilderBase *Parent; |
| size_t Begin; |
| mutable size_t CachedOffsetEnd = 0; |
| bool Finished = false; |
| bool Frozen = false; |
| bool Packed = false; |
| mutable CharUnits CachedOffsetFromGlobal; |
| |
| llvm::SmallVectorImpl<llvm::Constant*> &getBuffer() { |
| return Builder.Buffer; |
| } |
| |
| const llvm::SmallVectorImpl<llvm::Constant*> &getBuffer() const { |
| return Builder.Buffer; |
| } |
| |
| ConstantAggregateBuilderBase(ConstantInitBuilderBase &builder, |
| ConstantAggregateBuilderBase *parent) |
| : Builder(builder), Parent(parent), Begin(builder.Buffer.size()) { |
| if (parent) { |
| assert(!parent->Frozen && "parent already has child builder active"); |
| parent->Frozen = true; |
| } else { |
| assert(!builder.Frozen && "builder already has child builder active"); |
| builder.Frozen = true; |
| } |
| } |
| |
| ~ConstantAggregateBuilderBase() { |
| assert(Finished && "didn't finish aggregate builder"); |
| } |
| |
| void markFinished() { |
| assert(!Frozen && "child builder still active"); |
| assert(!Finished && "builder already finished"); |
| Finished = true; |
| if (Parent) { |
| assert(Parent->Frozen && |
| "parent not frozen while child builder active"); |
| Parent->Frozen = false; |
| } else { |
| assert(Builder.Frozen && |
| "builder not frozen while child builder active"); |
| Builder.Frozen = false; |
| } |
| } |
| |
| public: |
| // Not copyable. |
| ConstantAggregateBuilderBase(const ConstantAggregateBuilderBase &) = delete; |
| ConstantAggregateBuilderBase &operator=(const ConstantAggregateBuilderBase &) |
| = delete; |
| |
| // Movable, mostly to allow returning. But we have to write this out |
| // properly to satisfy the assert in the destructor. |
| ConstantAggregateBuilderBase(ConstantAggregateBuilderBase &&other) |
| : Builder(other.Builder), Parent(other.Parent), Begin(other.Begin), |
| CachedOffsetEnd(other.CachedOffsetEnd), |
| Finished(other.Finished), Frozen(other.Frozen), Packed(other.Packed), |
| CachedOffsetFromGlobal(other.CachedOffsetFromGlobal) { |
| other.Finished = true; |
| } |
| ConstantAggregateBuilderBase &operator=(ConstantAggregateBuilderBase &&other) |
| = delete; |
| |
| /// Return the number of elements that have been added to |
| /// this struct or array. |
| size_t size() const { |
| assert(!this->Finished && "cannot query after finishing builder"); |
| assert(!this->Frozen && "cannot query while sub-builder is active"); |
| assert(this->Begin <= this->getBuffer().size()); |
| return this->getBuffer().size() - this->Begin; |
| } |
| |
| /// Return true if no elements have yet been added to this struct or array. |
| bool empty() const { |
| return size() == 0; |
| } |
| |
| /// Abandon this builder completely. |
| void abandon() { |
| markFinished(); |
| Builder.abandon(Begin); |
| } |
| |
| /// Add a new value to this initializer. |
| void add(llvm::Constant *value) { |
| assert(value && "adding null value to constant initializer"); |
| assert(!Finished && "cannot add more values after finishing builder"); |
| assert(!Frozen && "cannot add values while subbuilder is active"); |
| Builder.Buffer.push_back(value); |
| } |
| |
| /// Add an integer value of type size_t. |
| void addSize(CharUnits size); |
| |
| /// Add an integer value of a specific type. |
| void addInt(llvm::IntegerType *intTy, uint64_t value, |
| bool isSigned = false) { |
| add(llvm::ConstantInt::get(intTy, value, isSigned)); |
| } |
| |
| /// Add a null pointer of a specific type. |
| void addNullPointer(llvm::PointerType *ptrTy) { |
| add(llvm::ConstantPointerNull::get(ptrTy)); |
| } |
| |
| /// Add a bitcast of a value to a specific type. |
| void addBitCast(llvm::Constant *value, llvm::Type *type) { |
| add(llvm::ConstantExpr::getBitCast(value, type)); |
| } |
| |
| /// Add a bunch of new values to this initializer. |
| void addAll(llvm::ArrayRef<llvm::Constant *> values) { |
| assert(!Finished && "cannot add more values after finishing builder"); |
| assert(!Frozen && "cannot add values while subbuilder is active"); |
| Builder.Buffer.append(values.begin(), values.end()); |
| } |
| |
| /// Add a relative offset to the given target address, i.e. the |
| /// static difference between the target address and the address |
| /// of the relative offset. The target must be known to be defined |
| /// in the current linkage unit. The offset will have the given |
| /// integer type, which must be no wider than intptr_t. Some |
| /// targets may not fully support this operation. |
| void addRelativeOffset(llvm::IntegerType *type, llvm::Constant *target) { |
| add(getRelativeOffset(type, target)); |
| } |
| |
| /// Add a relative offset to the target address, plus a small |
| /// constant offset. This is primarily useful when the relative |
| /// offset is known to be a multiple of (say) four and therefore |
| /// the tag can be used to express an extra two bits of information. |
| void addTaggedRelativeOffset(llvm::IntegerType *type, |
| llvm::Constant *address, |
| unsigned tag) { |
| llvm::Constant *offset = getRelativeOffset(type, address); |
| if (tag) { |
| offset = llvm::ConstantExpr::getAdd(offset, |
| llvm::ConstantInt::get(type, tag)); |
| } |
| add(offset); |
| } |
| |
| /// Return the offset from the start of the initializer to the |
| /// next position, assuming no padding is required prior to it. |
| /// |
| /// This operation will not succeed if any unsized placeholders are |
| /// currently in place in the initializer. |
| CharUnits getNextOffsetFromGlobal() const { |
| assert(!Finished && "cannot add more values after finishing builder"); |
| assert(!Frozen && "cannot add values while subbuilder is active"); |
| return getOffsetFromGlobalTo(Builder.Buffer.size()); |
| } |
| |
| /// An opaque class to hold the abstract position of a placeholder. |
| class PlaceholderPosition { |
| size_t Index; |
| friend class ConstantAggregateBuilderBase; |
| PlaceholderPosition(size_t index) : Index(index) {} |
| }; |
| |
| /// Add a placeholder value to the structure. The returned position |
| /// can be used to set the value later; it will not be invalidated by |
| /// any intermediate operations except (1) filling the same position or |
| /// (2) finishing the entire builder. |
| /// |
| /// This is useful for emitting certain kinds of structure which |
| /// contain some sort of summary field, generally a count, before any |
| /// of the data. By emitting a placeholder first, the structure can |
| /// be emitted eagerly. |
| PlaceholderPosition addPlaceholder() { |
| assert(!Finished && "cannot add more values after finishing builder"); |
| assert(!Frozen && "cannot add values while subbuilder is active"); |
| Builder.Buffer.push_back(nullptr); |
| return Builder.Buffer.size() - 1; |
| } |
| |
| /// Add a placeholder, giving the expected type that will be filled in. |
| PlaceholderPosition addPlaceholderWithSize(llvm::Type *expectedType); |
| |
| /// Fill a previously-added placeholder. |
| void fillPlaceholderWithInt(PlaceholderPosition position, |
| llvm::IntegerType *type, uint64_t value, |
| bool isSigned = false) { |
| fillPlaceholder(position, llvm::ConstantInt::get(type, value, isSigned)); |
| } |
| |
| /// Fill a previously-added placeholder. |
| void fillPlaceholder(PlaceholderPosition position, llvm::Constant *value) { |
| assert(!Finished && "cannot change values after finishing builder"); |
| assert(!Frozen && "cannot add values while subbuilder is active"); |
| llvm::Constant *&slot = Builder.Buffer[position.Index]; |
| assert(slot == nullptr && "placeholder already filled"); |
| slot = value; |
| } |
| |
| /// Produce an address which will eventually point to the next |
| /// position to be filled. This is computed with an indexed |
| /// getelementptr rather than by computing offsets. |
| /// |
| /// The returned pointer will have type T*, where T is the given |
| /// position. |
| llvm::Constant *getAddrOfCurrentPosition(llvm::Type *type); |
| |
| llvm::ArrayRef<llvm::Constant*> getGEPIndicesToCurrentPosition( |
| llvm::SmallVectorImpl<llvm::Constant*> &indices) { |
| getGEPIndicesTo(indices, Builder.Buffer.size()); |
| return indices; |
| } |
| |
| protected: |
| llvm::Constant *finishArray(llvm::Type *eltTy); |
| llvm::Constant *finishStruct(llvm::StructType *structTy); |
| |
| private: |
| void getGEPIndicesTo(llvm::SmallVectorImpl<llvm::Constant*> &indices, |
| size_t position) const; |
| |
| llvm::Constant *getRelativeOffset(llvm::IntegerType *offsetType, |
| llvm::Constant *target); |
| |
| CharUnits getOffsetFromGlobalTo(size_t index) const; |
| }; |
| |
| template <class Impl, class Traits> |
| class ConstantAggregateBuilderTemplateBase |
| : public Traits::AggregateBuilderBase { |
| using super = typename Traits::AggregateBuilderBase; |
| public: |
| using InitBuilder = typename Traits::InitBuilder; |
| using ArrayBuilder = typename Traits::ArrayBuilder; |
| using StructBuilder = typename Traits::StructBuilder; |
| using AggregateBuilderBase = typename Traits::AggregateBuilderBase; |
| |
| protected: |
| ConstantAggregateBuilderTemplateBase(InitBuilder &builder, |
| AggregateBuilderBase *parent) |
| : super(builder, parent) {} |
| |
| Impl &asImpl() { return *static_cast<Impl*>(this); } |
| |
| public: |
| ArrayBuilder beginArray(llvm::Type *eltTy = nullptr) { |
| return ArrayBuilder(static_cast<InitBuilder&>(this->Builder), this, eltTy); |
| } |
| |
| StructBuilder beginStruct(llvm::StructType *ty = nullptr) { |
| return StructBuilder(static_cast<InitBuilder&>(this->Builder), this, ty); |
| } |
| |
| /// Given that this builder was created by beginning an array or struct |
| /// component on the given parent builder, finish the array/struct |
| /// component and add it to the parent. |
| /// |
| /// It is an intentional choice that the parent is passed in explicitly |
| /// despite it being redundant with information already kept in the |
| /// builder. This aids in readability by making it easier to find the |
| /// places that add components to a builder, as well as "bookending" |
| /// the sub-builder more explicitly. |
| void finishAndAddTo(AggregateBuilderBase &parent) { |
| assert(this->Parent == &parent && "adding to non-parent builder"); |
| parent.add(asImpl().finishImpl()); |
| } |
| |
| /// Given that this builder was created by beginning an array or struct |
| /// directly on a ConstantInitBuilder, finish the array/struct and |
| /// create a global variable with it as the initializer. |
| template <class... As> |
| llvm::GlobalVariable *finishAndCreateGlobal(As &&...args) { |
| assert(!this->Parent && "finishing non-root builder"); |
| return this->Builder.createGlobal(asImpl().finishImpl(), |
| std::forward<As>(args)...); |
| } |
| |
| /// Given that this builder was created by beginning an array or struct |
| /// directly on a ConstantInitBuilder, finish the array/struct and |
| /// set it as the initializer of the given global variable. |
| void finishAndSetAsInitializer(llvm::GlobalVariable *global) { |
| assert(!this->Parent && "finishing non-root builder"); |
| return this->Builder.setGlobalInitializer(global, asImpl().finishImpl()); |
| } |
| |
| /// Given that this builder was created by beginning an array or struct |
| /// directly on a ConstantInitBuilder, finish the array/struct and |
| /// return a future which can be used to install the initializer in |
| /// a global later. |
| /// |
| /// This is useful for allowing a finished initializer to passed to |
| /// an API which will build the global. However, the "future" preserves |
| /// a dependency on the original builder; it is an error to pass it aside. |
| ConstantInitFuture finishAndCreateFuture() { |
| assert(!this->Parent && "finishing non-root builder"); |
| return this->Builder.createFuture(asImpl().finishImpl()); |
| } |
| }; |
| |
| template <class Traits> |
| class ConstantArrayBuilderTemplateBase |
| : public ConstantAggregateBuilderTemplateBase<typename Traits::ArrayBuilder, |
| Traits> { |
| using super = |
| ConstantAggregateBuilderTemplateBase<typename Traits::ArrayBuilder, Traits>; |
| |
| public: |
| using InitBuilder = typename Traits::InitBuilder; |
| using AggregateBuilderBase = typename Traits::AggregateBuilderBase; |
| |
| private: |
| llvm::Type *EltTy; |
| |
| template <class, class> |
| friend class ConstantAggregateBuilderTemplateBase; |
| |
| protected: |
| ConstantArrayBuilderTemplateBase(InitBuilder &builder, |
| AggregateBuilderBase *parent, |
| llvm::Type *eltTy) |
| : super(builder, parent), EltTy(eltTy) {} |
| |
| private: |
| /// Form an array constant from the values that have been added to this |
| /// builder. |
| llvm::Constant *finishImpl() { |
| return AggregateBuilderBase::finishArray(EltTy); |
| } |
| }; |
| |
| /// A template class designed to allow other frontends to |
| /// easily customize the builder classes used by ConstantInitBuilder, |
| /// and thus to extend the API to work with the abstractions they |
| /// prefer. This would probably not be necessary if C++ just |
| /// supported extension methods. |
| template <class Traits> |
| class ConstantStructBuilderTemplateBase |
| : public ConstantAggregateBuilderTemplateBase<typename Traits::StructBuilder, |
| Traits> { |
| using super = |
| ConstantAggregateBuilderTemplateBase<typename Traits::StructBuilder,Traits>; |
| |
| public: |
| using InitBuilder = typename Traits::InitBuilder; |
| using AggregateBuilderBase = typename Traits::AggregateBuilderBase; |
| |
| private: |
| llvm::StructType *StructTy; |
| |
| template <class, class> |
| friend class ConstantAggregateBuilderTemplateBase; |
| |
| protected: |
| ConstantStructBuilderTemplateBase(InitBuilder &builder, |
| AggregateBuilderBase *parent, |
| llvm::StructType *structTy) |
| : super(builder, parent), StructTy(structTy) { |
| if (structTy) this->Packed = structTy->isPacked(); |
| } |
| |
| public: |
| void setPacked(bool packed) { |
| this->Packed = packed; |
| } |
| |
| /// Use the given type for the struct if its element count is correct. |
| /// Don't add more elements after calling this. |
| void suggestType(llvm::StructType *structTy) { |
| if (this->size() == structTy->getNumElements()) { |
| StructTy = structTy; |
| } |
| } |
| |
| private: |
| /// Form an array constant from the values that have been added to this |
| /// builder. |
| llvm::Constant *finishImpl() { |
| return AggregateBuilderBase::finishStruct(StructTy); |
| } |
| }; |
| |
| /// A template class designed to allow other frontends to |
| /// easily customize the builder classes used by ConstantInitBuilder, |
| /// and thus to extend the API to work with the abstractions they |
| /// prefer. This would probably not be necessary if C++ just |
| /// supported extension methods. |
| template <class Traits> |
| class ConstantInitBuilderTemplateBase : public ConstantInitBuilderBase { |
| protected: |
| ConstantInitBuilderTemplateBase(CodeGenModule &CGM) |
| : ConstantInitBuilderBase(CGM) {} |
| |
| public: |
| using InitBuilder = typename Traits::InitBuilder; |
| using ArrayBuilder = typename Traits::ArrayBuilder; |
| using StructBuilder = typename Traits::StructBuilder; |
| |
| ArrayBuilder beginArray(llvm::Type *eltTy = nullptr) { |
| return ArrayBuilder(static_cast<InitBuilder&>(*this), nullptr, eltTy); |
| } |
| |
| StructBuilder beginStruct(llvm::StructType *structTy = nullptr) { |
| return StructBuilder(static_cast<InitBuilder&>(*this), nullptr, structTy); |
| } |
| }; |
| |
| class ConstantInitBuilder; |
| class ConstantStructBuilder; |
| class ConstantArrayBuilder; |
| |
| struct ConstantInitBuilderTraits { |
| using InitBuilder = ConstantInitBuilder; |
| using AggregateBuilderBase = ConstantAggregateBuilderBase; |
| using ArrayBuilder = ConstantArrayBuilder; |
| using StructBuilder = ConstantStructBuilder; |
| }; |
| |
| /// The standard implementation of ConstantInitBuilder used in Clang. |
| class ConstantInitBuilder |
| : public ConstantInitBuilderTemplateBase<ConstantInitBuilderTraits> { |
| public: |
| explicit ConstantInitBuilder(CodeGenModule &CGM) : |
| ConstantInitBuilderTemplateBase(CGM) {} |
| }; |
| |
| /// A helper class of ConstantInitBuilder, used for building constant |
| /// array initializers. |
| class ConstantArrayBuilder |
| : public ConstantArrayBuilderTemplateBase<ConstantInitBuilderTraits> { |
| template <class Traits> |
| friend class ConstantInitBuilderTemplateBase; |
| |
| // The use of explicit qualification is a GCC workaround. |
| template <class Impl, class Traits> |
| friend class CodeGen::ConstantAggregateBuilderTemplateBase; |
| |
| ConstantArrayBuilder(ConstantInitBuilder &builder, |
| ConstantAggregateBuilderBase *parent, |
| llvm::Type *eltTy) |
| : ConstantArrayBuilderTemplateBase(builder, parent, eltTy) {} |
| }; |
| |
| /// A helper class of ConstantInitBuilder, used for building constant |
| /// struct initializers. |
| class ConstantStructBuilder |
| : public ConstantStructBuilderTemplateBase<ConstantInitBuilderTraits> { |
| template <class Traits> |
| friend class ConstantInitBuilderTemplateBase; |
| |
| // The use of explicit qualification is a GCC workaround. |
| template <class Impl, class Traits> |
| friend class CodeGen::ConstantAggregateBuilderTemplateBase; |
| |
| ConstantStructBuilder(ConstantInitBuilder &builder, |
| ConstantAggregateBuilderBase *parent, |
| llvm::StructType *structTy) |
| : ConstantStructBuilderTemplateBase(builder, parent, structTy) {} |
| }; |
| |
| } // end namespace CodeGen |
| } // end namespace clang |
| |
| #endif |