| //===- 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 <vector> |
| |
| namespace clang { |
| namespace CodeGen { |
| |
| class CodeGenModule; |
| class ConstantStructBuilder; |
| class ConstantArrayBuilder; |
| |
| /// 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())); |
| /// widgetArray.add(widgetDesc.finish()); |
| /// } |
| /// toplevel.add(widgetArray.finish()); |
| /// auto global = toplevel.finishAndCreateGlobal("WIDGET_LIST", Align, |
| /// /*constant*/ true); |
| class ConstantInitBuilder { |
| 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; |
| |
| public: |
| explicit ConstantInitBuilder(CodeGenModule &CGM) : CGM(CGM) {} |
| |
| ~ConstantInitBuilder() { |
| assert(Buffer.empty() && "didn't claim all values out of buffer"); |
| } |
| |
| class AggregateBuilderBase { |
| protected: |
| ConstantInitBuilder &Builder; |
| AggregateBuilderBase *Parent; |
| size_t Begin; |
| bool Finished = false; |
| bool Frozen = false; |
| |
| llvm::SmallVectorImpl<llvm::Constant*> &getBuffer() { |
| return Builder.Buffer; |
| } |
| |
| const llvm::SmallVectorImpl<llvm::Constant*> &getBuffer() const { |
| return Builder.Buffer; |
| } |
| |
| AggregateBuilderBase(ConstantInitBuilder &builder, |
| AggregateBuilderBase *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; |
| } |
| } |
| |
| ~AggregateBuilderBase() { |
| 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. |
| AggregateBuilderBase(const AggregateBuilderBase &) = delete; |
| AggregateBuilderBase &operator=(const AggregateBuilderBase &) = delete; |
| |
| // Movable, mostly to allow returning. But we have to write this out |
| // properly to satisfy the assert in the destructor. |
| AggregateBuilderBase(AggregateBuilderBase &&other) |
| : Builder(other.Builder), Parent(other.Parent), Begin(other.Begin), |
| Finished(other.Finished), Frozen(other.Frozen) { |
| other.Finished = false; |
| } |
| AggregateBuilderBase &operator=(AggregateBuilderBase &&other) = delete; |
| |
| /// Abandon this builder completely. |
| void abandon() { |
| markFinished(); |
| auto &buffer = Builder.Buffer; |
| buffer.erase(buffer.begin() + Begin, buffer.end()); |
| } |
| |
| /// 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()); |
| } |
| |
| /// An opaque class to hold the abstract position of a placeholder. |
| class PlaceholderPosition { |
| size_t Index; |
| friend class AggregateBuilderBase; |
| 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, generaly 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; |
| } |
| |
| /// 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 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; |
| } |
| |
| ConstantArrayBuilder beginArray(llvm::Type *eltTy = nullptr); |
| ConstantStructBuilder beginStruct(llvm::StructType *structTy = nullptr); |
| |
| private: |
| void getGEPIndicesTo(llvm::SmallVectorImpl<llvm::Constant*> &indices, |
| size_t position) const; |
| }; |
| |
| template <class Impl> |
| class AggregateBuilder : public AggregateBuilderBase { |
| protected: |
| AggregateBuilder(ConstantInitBuilder &builder, |
| AggregateBuilderBase *parent) |
| : AggregateBuilderBase(builder, parent) {} |
| |
| Impl &asImpl() { return *static_cast<Impl*>(this); } |
| |
| public: |
| /// 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(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(!Parent && "finishing non-root builder"); |
| return 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(!Parent && "finishing non-root builder"); |
| return Builder.setGlobalInitializer(global, asImpl().finishImpl()); |
| } |
| }; |
| |
| ConstantArrayBuilder beginArray(llvm::Type *eltTy = nullptr); |
| |
| ConstantStructBuilder beginStruct(llvm::StructType *structTy = nullptr); |
| |
| 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); |
| |
| void setGlobalInitializer(llvm::GlobalVariable *GV, |
| llvm::Constant *initializer); |
| |
| void resolveSelfReferences(llvm::GlobalVariable *GV); |
| }; |
| |
| /// A helper class of ConstantInitBuilder, used for building constant |
| /// array initializers. |
| class ConstantArrayBuilder |
| : public ConstantInitBuilder::AggregateBuilder<ConstantArrayBuilder> { |
| llvm::Type *EltTy; |
| friend class ConstantInitBuilder; |
| template <class Impl> friend class ConstantInitBuilder::AggregateBuilder; |
| ConstantArrayBuilder(ConstantInitBuilder &builder, |
| AggregateBuilderBase *parent, llvm::Type *eltTy) |
| : AggregateBuilder(builder, parent), EltTy(eltTy) {} |
| public: |
| size_t size() const { |
| assert(!Finished); |
| assert(!Frozen); |
| assert(Begin <= getBuffer().size()); |
| return getBuffer().size() - Begin; |
| } |
| |
| bool empty() const { |
| return size() == 0; |
| } |
| |
| private: |
| /// Form an array constant from the values that have been added to this |
| /// builder. |
| llvm::Constant *finishImpl(); |
| }; |
| |
| inline ConstantArrayBuilder |
| ConstantInitBuilder::beginArray(llvm::Type *eltTy) { |
| return ConstantArrayBuilder(*this, nullptr, eltTy); |
| } |
| |
| inline ConstantArrayBuilder |
| ConstantInitBuilder::AggregateBuilderBase::beginArray(llvm::Type *eltTy) { |
| return ConstantArrayBuilder(Builder, this, eltTy); |
| } |
| |
| /// A helper class of ConstantInitBuilder, used for building constant |
| /// struct initializers. |
| class ConstantStructBuilder |
| : public ConstantInitBuilder::AggregateBuilder<ConstantStructBuilder> { |
| llvm::StructType *Ty; |
| friend class ConstantInitBuilder; |
| template <class Impl> friend class ConstantInitBuilder::AggregateBuilder; |
| ConstantStructBuilder(ConstantInitBuilder &builder, |
| AggregateBuilderBase *parent, llvm::StructType *ty) |
| : AggregateBuilder(builder, parent), Ty(ty) {} |
| |
| /// Finish the struct. |
| llvm::Constant *finishImpl(); |
| }; |
| |
| inline ConstantStructBuilder |
| ConstantInitBuilder::beginStruct(llvm::StructType *structTy) { |
| return ConstantStructBuilder(*this, nullptr, structTy); |
| } |
| |
| inline ConstantStructBuilder |
| ConstantInitBuilder::AggregateBuilderBase::beginStruct( |
| llvm::StructType *structTy) { |
| return ConstantStructBuilder(Builder, this, structTy); |
| } |
| |
| } // end namespace CodeGen |
| } // end namespace clang |
| |
| #endif |