Skip to content
Snippets Groups Projects
Commit 6c303ed5 authored by John McCall's avatar John McCall
Browse files

Further fixes and improvements to the ConstantInitBuilder API.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@297050 91177308-0d34-0410-b5e6-96231b3b80d8
parent e4de5812
No related branches found
No related tags found
No related merge requests found
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include "llvm/IR/Constants.h" #include "llvm/IR/Constants.h"
#include "llvm/IR/GlobalValue.h" #include "llvm/IR/GlobalValue.h"
#include "clang/AST/CharUnits.h" #include "clang/AST/CharUnits.h"
#include "clang/CodeGen/ConstantInitFuture.h"
#include <vector> #include <vector>
...@@ -60,18 +61,17 @@ class ConstantInitBuilderBase { ...@@ -60,18 +61,17 @@ class ConstantInitBuilderBase {
std::vector<SelfReference> SelfReferences; std::vector<SelfReference> SelfReferences;
bool Frozen = false; bool Frozen = false;
friend class ConstantInitFuture;
friend class ConstantAggregateBuilderBase; friend class ConstantAggregateBuilderBase;
template <class, class> template <class, class>
friend class ConstantAggregateBuilderTemplateBase; friend class ConstantAggregateBuilderTemplateBase;
// The rule for CachedOffset is that anything which removes elements
// from the Buffer
protected: protected:
explicit ConstantInitBuilderBase(CodeGenModule &CGM) : CGM(CGM) {} explicit ConstantInitBuilderBase(CodeGenModule &CGM) : CGM(CGM) {}
~ConstantInitBuilderBase() { ~ConstantInitBuilderBase() {
assert(Buffer.empty() && "didn't claim all values out of buffer"); assert(Buffer.empty() && "didn't claim all values out of buffer");
assert(SelfReferences.empty() && "didn't apply all self-references");
} }
private: private:
...@@ -83,10 +83,14 @@ private: ...@@ -83,10 +83,14 @@ private:
= llvm::GlobalValue::InternalLinkage, = llvm::GlobalValue::InternalLinkage,
unsigned addressSpace = 0); unsigned addressSpace = 0);
ConstantInitFuture createFuture(llvm::Constant *initializer);
void setGlobalInitializer(llvm::GlobalVariable *GV, void setGlobalInitializer(llvm::GlobalVariable *GV,
llvm::Constant *initializer); llvm::Constant *initializer);
void resolveSelfReferences(llvm::GlobalVariable *GV); void resolveSelfReferences(llvm::GlobalVariable *GV);
void abandon(size_t newEnd);
}; };
/// A concrete base class for struct and array aggregate /// A concrete base class for struct and array aggregate
...@@ -99,6 +103,7 @@ protected: ...@@ -99,6 +103,7 @@ protected:
mutable size_t CachedOffsetEnd = 0; mutable size_t CachedOffsetEnd = 0;
bool Finished = false; bool Finished = false;
bool Frozen = false; bool Frozen = false;
bool Packed = false;
mutable CharUnits CachedOffsetFromGlobal; mutable CharUnits CachedOffsetFromGlobal;
llvm::SmallVectorImpl<llvm::Constant*> &getBuffer() { llvm::SmallVectorImpl<llvm::Constant*> &getBuffer() {
...@@ -150,17 +155,32 @@ public: ...@@ -150,17 +155,32 @@ public:
// properly to satisfy the assert in the destructor. // properly to satisfy the assert in the destructor.
ConstantAggregateBuilderBase(ConstantAggregateBuilderBase &&other) ConstantAggregateBuilderBase(ConstantAggregateBuilderBase &&other)
: Builder(other.Builder), Parent(other.Parent), Begin(other.Begin), : 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; other.Finished = true;
} }
ConstantAggregateBuilderBase &operator=(ConstantAggregateBuilderBase &&other) ConstantAggregateBuilderBase &operator=(ConstantAggregateBuilderBase &&other)
= delete; = 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. /// Abandon this builder completely.
void abandon() { void abandon() {
markFinished(); markFinished();
auto &buffer = Builder.Buffer; Builder.abandon(Begin);
buffer.erase(buffer.begin() + Begin, buffer.end());
} }
/// Add a new value to this initializer. /// Add a new value to this initializer.
...@@ -224,6 +244,9 @@ public: ...@@ -224,6 +244,9 @@ public:
/// Return the offset from the start of the initializer to the /// Return the offset from the start of the initializer to the
/// next position, assuming no padding is required prior to it. /// 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 { CharUnits getNextOffsetFromGlobal() const {
assert(!Finished && "cannot add more values after finishing builder"); assert(!Finished && "cannot add more values after finishing builder");
assert(!Frozen && "cannot add values while subbuilder is active"); assert(!Frozen && "cannot add values while subbuilder is active");
...@@ -253,6 +276,9 @@ public: ...@@ -253,6 +276,9 @@ public:
return Builder.Buffer.size() - 1; 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. /// Fill a previously-added placeholder.
void fillPlaceholderWithInt(PlaceholderPosition position, void fillPlaceholderWithInt(PlaceholderPosition position,
llvm::IntegerType *type, uint64_t value, llvm::IntegerType *type, uint64_t value,
...@@ -354,6 +380,19 @@ public: ...@@ -354,6 +380,19 @@ public:
assert(!this->Parent && "finishing non-root builder"); assert(!this->Parent && "finishing non-root builder");
return this->Builder.setGlobalInitializer(global, asImpl().finishImpl()); 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> template <class Traits>
...@@ -379,18 +418,6 @@ protected: ...@@ -379,18 +418,6 @@ protected:
llvm::Type *eltTy) llvm::Type *eltTy)
: super(builder, parent), EltTy(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: private:
/// Form an array constant from the values that have been added to this /// Form an array constant from the values that have been added to this
/// builder. /// builder.
...@@ -425,7 +452,22 @@ protected: ...@@ -425,7 +452,22 @@ protected:
ConstantStructBuilderTemplateBase(InitBuilder &builder, ConstantStructBuilderTemplateBase(InitBuilder &builder,
AggregateBuilderBase *parent, AggregateBuilderBase *parent,
llvm::StructType *structTy) 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: private:
/// Form an array constant from the values that have been added to this /// Form an array constant from the values that have been added to this
......
//===- 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
...@@ -19,6 +19,51 @@ ...@@ -19,6 +19,51 @@
using namespace clang; using namespace clang;
using namespace CodeGen; 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 * llvm::GlobalVariable *
ConstantInitBuilderBase::createGlobal(llvm::Constant *initializer, ConstantInitBuilderBase::createGlobal(llvm::Constant *initializer,
const llvm::Twine &name, const llvm::Twine &name,
...@@ -53,8 +98,27 @@ void ConstantInitBuilderBase::resolveSelfReferences(llvm::GlobalVariable *GV) { ...@@ -53,8 +98,27 @@ void ConstantInitBuilderBase::resolveSelfReferences(llvm::GlobalVariable *GV) {
llvm::Constant *resolvedReference = llvm::Constant *resolvedReference =
llvm::ConstantExpr::getInBoundsGetElementPtr( llvm::ConstantExpr::getInBoundsGetElementPtr(
GV->getValueType(), GV, entry.Indices); GV->getValueType(), GV, entry.Indices);
entry.Dummy->replaceAllUsesWith(resolvedReference); auto dummy = entry.Dummy;
entry.Dummy->eraseFromParent(); 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::getGEPIndicesTo( ...@@ -115,6 +179,27 @@ void ConstantAggregateBuilderBase::getGEPIndicesTo(
position - Begin)); 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{ CharUnits ConstantAggregateBuilderBase::getOffsetFromGlobalTo(size_t end) const{
size_t cacheEnd = CachedOffsetEnd; size_t cacheEnd = CachedOffsetEnd;
assert(cacheEnd <= end); assert(cacheEnd <= end);
...@@ -144,8 +229,9 @@ CharUnits ConstantAggregateBuilderBase::getOffsetFromGlobalTo(size_t end) const{ ...@@ -144,8 +229,9 @@ CharUnits ConstantAggregateBuilderBase::getOffsetFromGlobalTo(size_t end) const{
assert(element != nullptr && assert(element != nullptr &&
"cannot compute offset when a placeholder is present"); "cannot compute offset when a placeholder is present");
llvm::Type *elementType = element->getType(); llvm::Type *elementType = element->getType();
offset = offset.alignTo(CharUnits::fromQuantity( if (!Packed)
layout.getABITypeAlignment(elementType))); offset = offset.alignTo(CharUnits::fromQuantity(
layout.getABITypeAlignment(elementType)));
offset += CharUnits::fromQuantity(layout.getTypeStoreSize(elementType)); offset += CharUnits::fromQuantity(layout.getTypeStoreSize(elementType));
} while (++cacheEnd != end); } while (++cacheEnd != end);
} }
...@@ -176,14 +262,17 @@ ConstantAggregateBuilderBase::finishStruct(llvm::StructType *ty) { ...@@ -176,14 +262,17 @@ ConstantAggregateBuilderBase::finishStruct(llvm::StructType *ty) {
markFinished(); markFinished();
auto &buffer = getBuffer(); auto &buffer = getBuffer();
assert(Begin < buffer.size() && "didn't add any struct elements?");
auto elts = llvm::makeArrayRef(buffer).slice(Begin); auto elts = llvm::makeArrayRef(buffer).slice(Begin);
if (ty == nullptr && elts.empty())
ty = llvm::StructType::get(Builder.CGM.getLLVMContext(), {}, Packed);
llvm::Constant *constant; llvm::Constant *constant;
if (ty) { if (ty) {
assert(ty->isPacked() == Packed);
constant = llvm::ConstantStruct::get(ty, elts); constant = llvm::ConstantStruct::get(ty, elts);
} else { } else {
constant = llvm::ConstantStruct::getAnon(elts, /*packed*/ false); constant = llvm::ConstantStruct::getAnon(elts, Packed);
} }
buffer.erase(buffer.begin() + Begin, buffer.end()); buffer.erase(buffer.begin() + Begin, buffer.end());
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment