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()); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits