r297050 - Further fixes and improvements to the ConstantInitBuilder API.

John McCall via cfe-commits cfe-commits at lists.llvm.org
Mon Mar 6 11:04:16 PST 2017


Author: rjmccall
Date: Mon Mar  6 13:04:16 2017
New Revision: 297050

URL: http://llvm.org/viewvc/llvm-project?rev=297050&view=rev
Log:
Further fixes and improvements to the ConstantInitBuilder API.

Added:
    cfe/trunk/include/clang/CodeGen/ConstantInitFuture.h
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=297050&r1=297049&r2=297050&view=diff
==============================================================================
--- cfe/trunk/include/clang/CodeGen/ConstantInitBuilder.h (original)
+++ cfe/trunk/include/clang/CodeGen/ConstantInitBuilder.h Mon Mar  6 13:04:16 2017
@@ -21,6 +21,7 @@
 #include "llvm/IR/Constants.h"
 #include "llvm/IR/GlobalValue.h"
 #include "clang/AST/CharUnits.h"
+#include "clang/CodeGen/ConstantInitFuture.h"
 
 #include <vector>
 
@@ -60,18 +61,17 @@ class ConstantInitBuilderBase {
   std::vector<SelfReference> SelfReferences;
   bool Frozen = false;
 
+  friend class ConstantInitFuture;
   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) {}
 
   ~ConstantInitBuilderBase() {
     assert(Buffer.empty() && "didn't claim all values out of buffer");
+    assert(SelfReferences.empty() && "didn't apply all self-references");
   }
 
 private:
@@ -83,10 +83,14 @@ private:
                                        = 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
@@ -99,6 +103,7 @@ protected:
   mutable size_t CachedOffsetEnd = 0;
   bool Finished = false;
   bool Frozen = false;
+  bool Packed = false;
   mutable CharUnits CachedOffsetFromGlobal;
 
   llvm::SmallVectorImpl<llvm::Constant*> &getBuffer() {
@@ -150,17 +155,32 @@ public:
   // 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) {
+      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();
-    auto &buffer = Builder.Buffer;
-    buffer.erase(buffer.begin() + Begin, buffer.end());
+    Builder.abandon(Begin);
   }
 
   /// Add a new value to this initializer.
@@ -224,6 +244,9 @@ public:
 
   /// 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");
@@ -253,6 +276,9 @@ public:
     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,
@@ -354,6 +380,19 @@ public:
     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>
@@ -379,18 +418,6 @@ protected:
                                    llvm::Type *eltTy)
     : super(builder, parent), EltTy(eltTy) {}
 
-public:
-  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;
-  }
-
-  bool empty() const {
-    return size() == 0;
-  }
-
 private:
   /// Form an array constant from the values that have been added to this
   /// builder.
@@ -425,7 +452,22 @@ protected:
   ConstantStructBuilderTemplateBase(InitBuilder &builder,
                                     AggregateBuilderBase *parent,
                                     llvm::StructType *structTy)
-    : super(builder, parent), StructTy(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

Added: cfe/trunk/include/clang/CodeGen/ConstantInitFuture.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/CodeGen/ConstantInitFuture.h?rev=297050&view=auto
==============================================================================
--- cfe/trunk/include/clang/CodeGen/ConstantInitFuture.h (added)
+++ cfe/trunk/include/clang/CodeGen/ConstantInitFuture.h Mon Mar  6 13:04:16 2017
@@ -0,0 +1,111 @@
+//===- ConstantInitFuture.h - "Future" constant initializers ----*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This class defines the ConstantInitFuture class.  This is split out
+// from ConstantInitBuilder.h in order to allow APIs to work with it
+// without having to include that entire header.  This is particularly
+// important because it is often useful to be able to default-construct
+// a future in, say, a default argument.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_CODEGEN_CONSTANTINITFUTURE_H
+#define LLVM_CLANG_CODEGEN_CONSTANTINITFUTURE_H
+
+#include "llvm/ADT/PointerUnion.h"
+#include "llvm/IR/Constant.h"
+
+// Forward-declare ConstantInitBuilderBase and give it a
+// PointerLikeTypeTraits specialization so that we can safely use it
+// in a PointerUnion below.
+namespace clang {
+namespace CodeGen {
+class ConstantInitBuilderBase;
+}
+}
+namespace llvm {
+template <>
+class PointerLikeTypeTraits< ::clang::CodeGen::ConstantInitBuilderBase*> {
+public:
+  using T = ::clang::CodeGen::ConstantInitBuilderBase*;
+
+  static inline void *getAsVoidPointer(T p) { return p; }
+  static inline T getFromVoidPointer(void *p) {return static_cast<T>(p);}
+  enum { NumLowBitsAvailable = 2 };
+};
+}
+
+namespace clang {
+namespace CodeGen {
+
+/// A "future" for a completed constant initializer, which can be passed
+/// around independently of any sub-builders (but not the original parent).
+class ConstantInitFuture {
+  using PairTy = llvm::PointerUnion<ConstantInitBuilderBase*, llvm::Constant*>;
+
+  PairTy Data;
+
+  friend class ConstantInitBuilderBase;
+  explicit ConstantInitFuture(ConstantInitBuilderBase *builder);
+
+public:
+  ConstantInitFuture() {}
+
+  /// A future can be explicitly created from a fixed initializer.
+  explicit ConstantInitFuture(llvm::Constant *initializer) : Data(initializer) {
+    assert(initializer && "creating null future");
+  }
+
+  /// Is this future non-null?
+  explicit operator bool() const { return bool(Data); }
+
+  /// Return the type of the initializer.
+  llvm::Type *getType() const;
+
+  /// Abandon this initializer.
+  void abandon();
+
+  /// Install the initializer into a global variable.  This cannot
+  /// be called multiple times.
+  void installInGlobal(llvm::GlobalVariable *global);
+
+  void *getOpaqueValue() const { return Data.getOpaqueValue(); }
+  static ConstantInitFuture getFromOpaqueValue(void *value) {
+    ConstantInitFuture result;
+    result.Data = PairTy::getFromOpaqueValue(value);
+    return result;
+  }
+  enum {
+    NumLowBitsAvailable =
+      llvm::PointerLikeTypeTraits<PairTy>::NumLowBitsAvailable
+  };
+};
+
+}  // end namespace CodeGen
+}  // end namespace clang
+
+namespace llvm {
+
+template <>
+class PointerLikeTypeTraits< ::clang::CodeGen::ConstantInitFuture> {
+public:
+  using T = ::clang::CodeGen::ConstantInitFuture;
+
+  static inline void *getAsVoidPointer(T future) {
+    return future.getOpaqueValue();
+  }
+  static inline T getFromVoidPointer(void *p) {
+    return T::getFromOpaqueValue(p);
+  }
+  enum { NumLowBitsAvailable = T::NumLowBitsAvailable };
+};
+
+} // end namespace llvm
+
+#endif

Modified: cfe/trunk/lib/CodeGen/ConstantInitBuilder.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/ConstantInitBuilder.cpp?rev=297050&r1=297049&r2=297050&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/ConstantInitBuilder.cpp (original)
+++ cfe/trunk/lib/CodeGen/ConstantInitBuilder.cpp Mon Mar  6 13:04:16 2017
@@ -19,6 +19,51 @@
 using namespace clang;
 using namespace CodeGen;
 
+llvm::Type *ConstantInitFuture::getType() const {
+  assert(Data && "dereferencing null future");
+  if (Data.is<llvm::Constant*>()) {
+    return Data.get<llvm::Constant*>()->getType();
+  } else {
+    return Data.get<ConstantInitBuilderBase*>()->Buffer[0]->getType();
+  }
+}
+
+void ConstantInitFuture::abandon() {
+  assert(Data && "abandoning null future");
+  if (auto builder = Data.dyn_cast<ConstantInitBuilderBase*>()) {
+    builder->abandon(0);
+  }
+  Data = nullptr;
+}
+
+void ConstantInitFuture::installInGlobal(llvm::GlobalVariable *GV) {
+  assert(Data && "installing null future");
+  if (Data.is<llvm::Constant*>()) {
+    GV->setInitializer(Data.get<llvm::Constant*>());
+  } else {
+    auto &builder = *Data.get<ConstantInitBuilderBase*>();
+    assert(builder.Buffer.size() == 1);
+    builder.setGlobalInitializer(GV, builder.Buffer[0]);
+    builder.Buffer.clear();
+    Data = nullptr;
+  }
+}
+
+ConstantInitFuture
+ConstantInitBuilderBase::createFuture(llvm::Constant *initializer) {
+  assert(Buffer.empty() && "buffer not current empty");
+  Buffer.push_back(initializer);
+  return ConstantInitFuture(this);
+}
+
+// Only used in this file.
+inline ConstantInitFuture::ConstantInitFuture(ConstantInitBuilderBase *builder)
+    : Data(builder) {
+  assert(!builder->Frozen);
+  assert(builder->Buffer.size() == 1);
+  assert(builder->Buffer[0] != nullptr);
+}
+
 llvm::GlobalVariable *
 ConstantInitBuilderBase::createGlobal(llvm::Constant *initializer,
                                       const llvm::Twine &name,
@@ -53,8 +98,27 @@ void ConstantInitBuilderBase::resolveSel
     llvm::Constant *resolvedReference =
       llvm::ConstantExpr::getInBoundsGetElementPtr(
         GV->getValueType(), GV, entry.Indices);
-    entry.Dummy->replaceAllUsesWith(resolvedReference);
-    entry.Dummy->eraseFromParent();
+    auto dummy = entry.Dummy;
+    dummy->replaceAllUsesWith(resolvedReference);
+    dummy->eraseFromParent();
+  }
+  SelfReferences.clear();
+}
+
+void ConstantInitBuilderBase::abandon(size_t newEnd) {
+  // Remove all the entries we've added.
+  Buffer.erase(Buffer.begin() + newEnd, Buffer.end());
+
+  // If we're abandoning all the way to the beginning, destroy
+  // all the self-references, because we might not get another
+  // opportunity.
+  if (newEnd == 0) {
+    for (auto &entry : SelfReferences) {
+      auto dummy = entry.Dummy;
+      dummy->replaceAllUsesWith(llvm::UndefValue::get(dummy->getType()));
+      dummy->eraseFromParent();
+    }
+    SelfReferences.clear();
   }
 }
 
@@ -115,6 +179,27 @@ void ConstantAggregateBuilderBase::getGE
                                            position - Begin));
 }
 
+ConstantAggregateBuilderBase::PlaceholderPosition
+ConstantAggregateBuilderBase::addPlaceholderWithSize(llvm::Type *type) {
+  // Bring the offset up to the last field.
+  CharUnits offset = getNextOffsetFromGlobal();
+
+  // Create the placeholder.
+  auto position = addPlaceholder();
+
+  // Advance the offset past that field.
+  auto &layout = Builder.CGM.getDataLayout();
+  if (!Packed)
+    offset = offset.alignTo(CharUnits::fromQuantity(
+                                layout.getABITypeAlignment(type)));
+  offset += CharUnits::fromQuantity(layout.getTypeStoreSize(type));
+
+  CachedOffsetEnd = Builder.Buffer.size();
+  CachedOffsetFromGlobal = offset;
+
+  return position;
+}
+
 CharUnits ConstantAggregateBuilderBase::getOffsetFromGlobalTo(size_t end) const{
   size_t cacheEnd = CachedOffsetEnd;
   assert(cacheEnd <= end);
@@ -144,8 +229,9 @@ CharUnits ConstantAggregateBuilderBase::
       assert(element != nullptr &&
              "cannot compute offset when a placeholder is present");
       llvm::Type *elementType = element->getType();
-      offset = offset.alignTo(CharUnits::fromQuantity(
-                                layout.getABITypeAlignment(elementType)));
+      if (!Packed)
+        offset = offset.alignTo(CharUnits::fromQuantity(
+                                  layout.getABITypeAlignment(elementType)));
       offset += CharUnits::fromQuantity(layout.getTypeStoreSize(elementType));
     } while (++cacheEnd != end);
   }
@@ -176,14 +262,17 @@ ConstantAggregateBuilderBase::finishStru
   markFinished();
 
   auto &buffer = getBuffer();
-  assert(Begin < buffer.size() && "didn't add any struct elements?");
   auto elts = llvm::makeArrayRef(buffer).slice(Begin);
 
+  if (ty == nullptr && elts.empty())
+    ty = llvm::StructType::get(Builder.CGM.getLLVMContext(), {}, Packed);
+
   llvm::Constant *constant;
   if (ty) {
+    assert(ty->isPacked() == Packed);
     constant = llvm::ConstantStruct::get(ty, elts);
   } else {
-    constant = llvm::ConstantStruct::getAnon(elts, /*packed*/ false);
+    constant = llvm::ConstantStruct::getAnon(elts, Packed);
   }
 
   buffer.erase(buffer.begin() + Begin, buffer.end());




More information about the cfe-commits mailing list