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