r296979 - Refactor ConstantInitBuilder to allow other frontends to more

John McCall via cfe-commits cfe-commits at lists.llvm.org
Sat Mar 4 13:26:29 PST 2017


Author: rjmccall
Date: Sat Mar  4 15:26:29 2017
New Revision: 296979

URL: http://llvm.org/viewvc/llvm-project?rev=296979&view=rev
Log:
Refactor ConstantInitBuilder to allow other frontends to more
easily extend the aggregate-builder API.  Stupid missing language
features.

Also add APIs for constructing a relative reference and computing
the offset of a position from the start of the initializer.

Modified:
    cfe/trunk/include/clang/CodeGen/ConstantInitBuilder.h
    cfe/trunk/lib/CodeGen/ConstantInitBuilder.cpp

Modified: cfe/trunk/include/clang/CodeGen/ConstantInitBuilder.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/CodeGen/ConstantInitBuilder.h?rev=296979&r1=296978&r2=296979&view=diff
==============================================================================
--- cfe/trunk/include/clang/CodeGen/ConstantInitBuilder.h (original)
+++ cfe/trunk/include/clang/CodeGen/ConstantInitBuilder.h Sat Mar  4 15:26:29 2017
@@ -28,8 +28,6 @@ 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
@@ -45,12 +43,12 @@ class ConstantArrayBuilder;
 ///      widgetDesc.addInt(CGM.SizeTy, widget.getPower());
 ///      widgetDesc.add(CGM.GetAddrOfConstantString(widget.getName()));
 ///      widgetDesc.add(CGM.GetAddrOfGlobal(widget.getInitializerDecl()));
-///      widgetArray.add(widgetDesc.finish());
+///      widgetDesc.finishAndAddTo(widgetArray);
 ///    }
-///    toplevel.add(widgetArray.finish());
+///    widgetArray.finishAndAddTo(toplevel);
 ///    auto global = toplevel.finishAndCreateGlobal("WIDGET_LIST", Align,
 ///                                                 /*constant*/ true);
-class ConstantInitBuilder {
+class ConstantInitBuilderBase {
   struct SelfReference {
     llvm::GlobalVariable *Dummy;
     llvm::SmallVector<llvm::Constant*, 4> Indices;
@@ -62,254 +60,331 @@ class ConstantInitBuilder {
   std::vector<SelfReference> SelfReferences;
   bool Frozen = false;
 
-public:
-  explicit ConstantInitBuilder(CodeGenModule &CGM) : CGM(CGM) {}
+  friend class ConstantAggregateBuilderBase;
+  template <class, class>
+  friend class ConstantAggregateBuilderTemplateBase;
+
+  // The rule for CachedOffset is that anything which removes elements
+  // from the Buffer
+
+protected:
+  explicit ConstantInitBuilderBase(CodeGenModule &CGM) : CGM(CGM) {}
 
-  ~ConstantInitBuilder() {
+  ~ConstantInitBuilderBase() {
     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;
+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);
 
-    llvm::SmallVectorImpl<llvm::Constant*> &getBuffer() {
-      return Builder.Buffer;
-    }
+  void setGlobalInitializer(llvm::GlobalVariable *GV,
+                            llvm::Constant *initializer);
 
-    const llvm::SmallVectorImpl<llvm::Constant*> &getBuffer() const {
-      return Builder.Buffer;
-    }
+  void resolveSelfReferences(llvm::GlobalVariable *GV);
+};
 
-    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;
-      }
-    }
+/// 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;
+  mutable CharUnits CachedOffsetFromGlobal;
 
-    ~AggregateBuilderBase() {
-      assert(Finished && "didn't finish aggregate builder");
-    }
+  llvm::SmallVectorImpl<llvm::Constant*> &getBuffer() {
+    return Builder.Buffer;
+  }
 
-    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;
-      }
-    }
+  const llvm::SmallVectorImpl<llvm::Constant*> &getBuffer() const {
+    return Builder.Buffer;
+  }
 
-  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;
+  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;
     }
-    AggregateBuilderBase &operator=(AggregateBuilderBase &&other) = delete;
+  }
 
-    /// Abandon this builder completely.
-    void abandon() {
-      markFinished();
-      auto &buffer = Builder.Buffer;
-      buffer.erase(buffer.begin() + Begin, buffer.end());
-    }
+  ~ConstantAggregateBuilderBase() {
+    assert(Finished && "didn't finish aggregate builder");
+  }
 
-    /// 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);
+  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;
     }
+  }
 
-    /// Add an integer value of type size_t.
-    void addSize(CharUnits size);
+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),
+      Finished(other.Finished), Frozen(other.Frozen) {
+    other.Finished = true;
+  }
+  ConstantAggregateBuilderBase &operator=(ConstantAggregateBuilderBase &&other)
+    = delete;
 
-    /// 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));
-    }
+  /// Abandon this builder completely.
+  void abandon() {
+    markFinished();
+    auto &buffer = Builder.Buffer;
+    buffer.erase(buffer.begin() + Begin, buffer.end());
+  }
 
-    /// Add a null pointer of a specific type.
-    void addNullPointer(llvm::PointerType *ptrTy) {
-      add(llvm::ConstantPointerNull::get(ptrTy));
-    }
+  /// 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 a bitcast of a value to a specific type.
-    void addBitCast(llvm::Constant *value, llvm::Type *type) {
-      add(llvm::ConstantExpr::getBitCast(value, type));
-    }
+  /// Add an integer value of type size_t.
+  void addSize(CharUnits size);
 
-    /// 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 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));
+  }
 
-    /// 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;
-    }
+  /// Add a null pointer of a specific type.
+  void addNullPointer(llvm::PointerType *ptrTy) {
+    add(llvm::ConstantPointerNull::get(ptrTy));
+  }
 
-    /// 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));
-    }
+  /// Add a bitcast of a value to a specific type.
+  void addBitCast(llvm::Constant *value, llvm::Type *type) {
+    add(llvm::ConstantExpr::getBitCast(value, type));
+  }
 
-    /// 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;
-    }
+  /// 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));
+  }
 
-    /// 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;
+  /// 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);
+  }
 
-    ConstantArrayBuilder beginArray(llvm::Type *eltTy = nullptr);
-    ConstantStructBuilder beginStruct(llvm::StructType *structTy = nullptr);
+  /// Return the offset from the start of the initializer to the
+  /// next position, assuming no padding is required prior to it.
+  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());
+  }
 
-  private:
-    void getGEPIndicesTo(llvm::SmallVectorImpl<llvm::Constant*> &indices,
-                         size_t position) const;
+  /// 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) {}
   };
 
-  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());
-    }
+  /// 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;
+  }
 
-    /// 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)...);
-    }
+  /// 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));
+  }
 
-    /// 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());
-    }
-  };
+  /// 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;
+  }
 
-  ConstantArrayBuilder beginArray(llvm::Type *eltTy = nullptr);
+  /// 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;
+  }
 
-  ConstantStructBuilder beginStruct(llvm::StructType *structTy = nullptr);
+protected:
+  llvm::Constant *finishArray(llvm::Type *eltTy);
+  llvm::Constant *finishStruct(llvm::StructType *structTy);
 
 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 getGEPIndicesTo(llvm::SmallVectorImpl<llvm::Constant*> &indices,
+                       size_t position) const;
 
-  void setGlobalInitializer(llvm::GlobalVariable *GV,
-                            llvm::Constant *initializer);
+  llvm::Constant *getRelativeOffset(llvm::IntegerType *offsetType,
+                                    llvm::Constant *target);
 
-  void resolveSelfReferences(llvm::GlobalVariable *GV);
+  CharUnits getOffsetFromGlobalTo(size_t index) const;
 };
 
-/// A helper class of ConstantInitBuilder, used for building constant
-/// array initializers.
-class ConstantArrayBuilder
-    : public ConstantInitBuilder::AggregateBuilder<ConstantArrayBuilder> {
+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());
+  }
+};
+
+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;
-  friend class ConstantInitBuilder;
-  template <class Impl> friend class ConstantInitBuilder::AggregateBuilder;
-  ConstantArrayBuilder(ConstantInitBuilder &builder,
-                       AggregateBuilderBase *parent, llvm::Type *eltTy)
-    : AggregateBuilder(builder, parent), EltTy(eltTy) {}
+
+  template <class, class>
+  friend class ConstantAggregateBuilderTemplateBase;
+
+protected:
+  ConstantArrayBuilderTemplateBase(InitBuilder &builder,
+                                   AggregateBuilderBase *parent,
+                                   llvm::Type *eltTy)
+    : super(builder, parent), EltTy(eltTy) {}
+
 public:
   size_t size() const {
-    assert(!Finished);
-    assert(!Frozen);
-    assert(Begin <= getBuffer().size());
-    return getBuffer().size() - Begin;
+    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;
   }
 
   bool empty() const {
@@ -319,45 +394,121 @@ public:
 private:
   /// Form an array constant from the values that have been added to this
   /// builder.
-  llvm::Constant *finishImpl();
+  llvm::Constant *finishImpl() {
+    return AggregateBuilderBase::finishArray(EltTy);
+  }
 };
 
-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 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) {}
+
+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;
+  template <class Impl, class Traits>
+  friend class 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 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) {}
+    : public ConstantStructBuilderTemplateBase<ConstantInitBuilderTraits> {
+  template <class Traits>
+  friend class ConstantInitBuilderTemplateBase;
+  template <class Impl, class Traits>
+  friend class ConstantAggregateBuilderTemplateBase;
 
-  /// Finish the struct.
-  llvm::Constant *finishImpl();
+  ConstantStructBuilder(ConstantInitBuilder &builder,
+                        ConstantAggregateBuilderBase *parent,
+                        llvm::StructType *structTy)
+    : ConstantStructBuilderTemplateBase(builder, parent, structTy) {}
 };
 
-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
 

Modified: cfe/trunk/lib/CodeGen/ConstantInitBuilder.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/ConstantInitBuilder.cpp?rev=296979&r1=296978&r2=296979&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/ConstantInitBuilder.cpp (original)
+++ cfe/trunk/lib/CodeGen/ConstantInitBuilder.cpp Sat Mar  4 15:26:29 2017
@@ -20,12 +20,12 @@ 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) {
+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,
@@ -40,15 +40,15 @@ ConstantInitBuilder::createGlobal(llvm::
   return GV;
 }
 
-void ConstantInitBuilder::setGlobalInitializer(llvm::GlobalVariable *GV,
-                                               llvm::Constant *initializer) {
+void ConstantInitBuilderBase::setGlobalInitializer(llvm::GlobalVariable *GV,
+                                                   llvm::Constant *initializer){
   GV->setInitializer(initializer);
 
   if (!SelfReferences.empty())
     resolveSelfReferences(GV);
 }
 
-void ConstantInitBuilder::resolveSelfReferences(llvm::GlobalVariable *GV) {
+void ConstantInitBuilderBase::resolveSelfReferences(llvm::GlobalVariable *GV) {
   for (auto &entry : SelfReferences) {
     llvm::Constant *resolvedReference =
       llvm::ConstantExpr::getInBoundsGetElementPtr(
@@ -58,13 +58,31 @@ void ConstantInitBuilder::resolveSelfRef
   }
 }
 
-void ConstantInitBuilder::AggregateBuilderBase::addSize(CharUnits size) {
+void ConstantAggregateBuilderBase::addSize(CharUnits size) {
   add(Builder.CGM.getSize(size));
 }
 
 llvm::Constant *
-ConstantInitBuilder::AggregateBuilderBase::getAddrOfCurrentPosition(
-                                                            llvm::Type *type) {
+ConstantAggregateBuilderBase::getRelativeOffset(llvm::IntegerType *offsetType,
+                                                llvm::Constant *target) {
+  // Compute the address of the relative-address slot.
+  auto base = getAddrOfCurrentPosition(offsetType);
+
+  // 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::getAddrOfCurrentPosition(llvm::Type *type) {
   // Make a global variable.  We will replace this with a GEP to this
   // position after installing the initializer.
   auto dummy =
@@ -77,7 +95,7 @@ ConstantInitBuilder::AggregateBuilderBas
   return dummy;
 }
 
-void ConstantInitBuilder::AggregateBuilderBase::getGEPIndicesTo(
+void ConstantAggregateBuilderBase::getGEPIndicesTo(
                                llvm::SmallVectorImpl<llvm::Constant*> &indices,
                                size_t position) const {
   // Recurse on the parent builder if present.
@@ -97,22 +115,64 @@ void ConstantInitBuilder::AggregateBuild
                                            position - Begin));
 }
 
-llvm::Constant *ConstantArrayBuilder::finishImpl() {
+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();
+      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))
+          (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();
+  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 *ConstantStructBuilder::finishImpl() {
+llvm::Constant *
+ConstantAggregateBuilderBase::finishStruct(llvm::StructType *ty) {
   markFinished();
 
   auto &buffer = getBuffer();
@@ -120,8 +180,8 @@ llvm::Constant *ConstantStructBuilder::f
   auto elts = llvm::makeArrayRef(buffer).slice(Begin);
 
   llvm::Constant *constant;
-  if (Ty) {
-    constant = llvm::ConstantStruct::get(Ty, elts);
+  if (ty) {
+    constant = llvm::ConstantStruct::get(ty, elts);
   } else {
     constant = llvm::ConstantStruct::getAnon(elts, /*packed*/ false);
   }




More information about the cfe-commits mailing list