//===- ConstantInitBuilder.h - Builder for LLVM IR constants ----*- C++ -*-===//
 
//
 
// 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 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));
 
  }
 
 
 
  /// Same as addRelativeOffset(), but instead relative to an element in this
 
  /// aggregate, identified by its index.
 
  void addRelativeOffsetToPosition(llvm::IntegerType *type,
 
                                   llvm::Constant *target, size_t position) {
 
    add(getRelativeOffsetToPosition(type, target, position));
 
  }
 
 
 
  /// 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 type. This
 
  /// type can differ from the type of the actual element.
 
  llvm::Constant *getAddrOfCurrentPosition(llvm::Type *type);
 
 
 
  /// Produce an address which points to a position in the aggregate being
 
  /// constructed. This is computed with an indexed getelementptr rather than by
 
  /// computing offsets.
 
  ///
 
  /// The returned pointer will have type T*, where T is the given type. This
 
  /// type can differ from the type of the actual element.
 
  llvm::Constant *getAddrOfPosition(llvm::Type *type, size_t position);
 
 
 
  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);
 
 
 
  llvm::Constant *getRelativeOffsetToPosition(llvm::IntegerType *offsetType,
 
                                              llvm::Constant *target,
 
                                              size_t position);
 
 
 
  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