const unsigned char SubclassID;
protected:
+ /// \brief Active type of storage.
+ enum StorageType { Uniqued, Distinct, Temporary };
+
/// \brief Storage flag for non-uniqued, otherwise unowned, metadata.
- bool IsDistinctInContext : 1;
+ StorageType Storage : 2;
// TODO: expose remaining bits to subclasses.
unsigned short SubclassData16;
public:
enum MetadataKind {
MDTupleKind,
- MDNodeFwdDeclKind,
+ MDLocationKind,
ConstantAsMetadataKind,
LocalAsMetadataKind,
MDStringKind
};
protected:
- Metadata(unsigned ID)
- : SubclassID(ID), IsDistinctInContext(false), SubclassData16(0),
- SubclassData32(0) {}
+ Metadata(unsigned ID, StorageType Storage)
+ : SubclassID(ID), Storage(Storage), SubclassData16(0), SubclassData32(0) {
+ }
~Metadata() {}
- /// \brief Store this in a big non-uniqued untyped bucket.
- bool isStoredDistinctInContext() const { return IsDistinctInContext; }
-
/// \brief Default handling of a changed operand, which asserts.
///
/// If subclasses pass themselves in as owners to a tracking node reference,
MetadataAsValue(Type *Ty, Metadata *MD);
~MetadataAsValue();
+ /// \brief Drop use of metadata (during teardown).
+ void dropUse() { MD = nullptr; }
+
public:
static MetadataAsValue *get(LLVMContext &Context, Metadata *MD);
static MetadataAsValue *getIfExists(LLVMContext &Context, Metadata *MD);
typedef MetadataTracking::OwnerTy OwnerTy;
private:
+ LLVMContext &Context;
uint64_t NextIndex;
SmallDenseMap<void *, std::pair<OwnerTy, uint64_t>, 4> UseMap;
public:
- ReplaceableMetadataImpl() : NextIndex(0) {}
+ ReplaceableMetadataImpl(LLVMContext &Context)
+ : Context(Context), NextIndex(0) {}
~ReplaceableMetadataImpl() {
assert(UseMap.empty() && "Cannot destroy in-use replaceable metadata");
}
+ LLVMContext &getContext() const { return Context; }
+
/// \brief Replace all uses of this with MD.
///
/// Replace all uses of this with \c MD, which is allowed to be null.
Value *V;
+ /// \brief Drop users without RAUW (during teardown).
+ void dropUsers() {
+ ReplaceableMetadataImpl::resolveAllUses(/* ResolveUsers */ false);
+ }
+
protected:
ValueAsMetadata(unsigned ID, Value *V)
- : Metadata(ID), V(V) {
+ : Metadata(ID, Uniqued), ReplaceableMetadataImpl(V->getContext()), V(V) {
assert(V && "Expected valid value");
}
~ValueAsMetadata() {}
MDString &operator=(const MDString &) LLVM_DELETED_FUNCTION;
StringMapEntry<MDString> *Entry;
- MDString() : Metadata(MDStringKind), Entry(nullptr) {}
- MDString(MDString &&) : Metadata(MDStringKind) {}
+ MDString() : Metadata(MDStringKind, Uniqued), Entry(nullptr) {}
+ MDString(MDString &&) : Metadata(MDStringKind, Uniqued) {}
public:
static MDString *get(LLVMContext &Context, StringRef Str);
static SimpleType getSimplifiedValue(const MDOperand &MD) { return MD.get(); }
};
+/// \brief Pointer to the context, with optional RAUW support.
+///
+/// Either a raw (non-null) pointer to the \a LLVMContext, or an owned pointer
+/// to \a ReplaceableMetadataImpl (which has a reference to \a LLVMContext).
+class ContextAndReplaceableUses {
+ PointerUnion<LLVMContext *, ReplaceableMetadataImpl *> Ptr;
+
+ ContextAndReplaceableUses() LLVM_DELETED_FUNCTION;
+ ContextAndReplaceableUses(ContextAndReplaceableUses &&)
+ LLVM_DELETED_FUNCTION;
+ ContextAndReplaceableUses(const ContextAndReplaceableUses &)
+ LLVM_DELETED_FUNCTION;
+ ContextAndReplaceableUses &
+ operator=(ContextAndReplaceableUses &&) LLVM_DELETED_FUNCTION;
+ ContextAndReplaceableUses &
+ operator=(const ContextAndReplaceableUses &) LLVM_DELETED_FUNCTION;
+
+public:
+ ContextAndReplaceableUses(LLVMContext &Context) : Ptr(&Context) {}
+ ContextAndReplaceableUses(
+ std::unique_ptr<ReplaceableMetadataImpl> ReplaceableUses)
+ : Ptr(ReplaceableUses.release()) {
+ assert(getReplaceableUses() && "Expected non-null replaceable uses");
+ }
+ ~ContextAndReplaceableUses() { delete getReplaceableUses(); }
+
+ operator LLVMContext &() { return getContext(); }
+
+ /// \brief Whether this contains RAUW support.
+ bool hasReplaceableUses() const {
+ return Ptr.is<ReplaceableMetadataImpl *>();
+ }
+ LLVMContext &getContext() const {
+ if (hasReplaceableUses())
+ return getReplaceableUses()->getContext();
+ return *Ptr.get<LLVMContext *>();
+ }
+ ReplaceableMetadataImpl *getReplaceableUses() const {
+ if (hasReplaceableUses())
+ return Ptr.get<ReplaceableMetadataImpl *>();
+ return nullptr;
+ }
+
+ /// \brief Assign RAUW support to this.
+ ///
+ /// Make this replaceable, taking ownership of \c ReplaceableUses (which must
+ /// not be null).
+ void
+ makeReplaceable(std::unique_ptr<ReplaceableMetadataImpl> ReplaceableUses) {
+ assert(ReplaceableUses && "Expected non-null replaceable uses");
+ assert(&ReplaceableUses->getContext() == &getContext() &&
+ "Expected same context");
+ delete getReplaceableUses();
+ Ptr = ReplaceableUses.release();
+ }
+
+ /// \brief Drop RAUW support.
+ ///
+ /// Cede ownership of RAUW support, returning it.
+ std::unique_ptr<ReplaceableMetadataImpl> takeReplaceableUses() {
+ assert(hasReplaceableUses() && "Expected to own replaceable uses");
+ std::unique_ptr<ReplaceableMetadataImpl> ReplaceableUses(
+ getReplaceableUses());
+ Ptr = &ReplaceableUses->getContext();
+ return ReplaceableUses;
+ }
+};
+
//===----------------------------------------------------------------------===//
/// \brief Tuple of metadata.
class MDNode : public Metadata {
+ friend class ReplaceableMetadataImpl;
+
MDNode(const MDNode &) LLVM_DELETED_FUNCTION;
void operator=(const MDNode &) LLVM_DELETED_FUNCTION;
void *operator new(size_t) LLVM_DELETED_FUNCTION;
- LLVMContext &Context;
+protected:
+ ContextAndReplaceableUses Context;
+
+private:
unsigned NumOperands;
protected:
unsigned MDNodeSubclassData;
void *operator new(size_t Size, unsigned NumOps);
-
- /// \brief Required by std, but never called.
void operator delete(void *Mem);
/// \brief Required by std, but never called.
llvm_unreachable("Constructor throws?");
}
- MDNode(LLVMContext &Context, unsigned ID, ArrayRef<Metadata *> MDs);
+ MDNode(LLVMContext &Context, unsigned ID, StorageType Storage,
+ ArrayRef<Metadata *> MDs);
~MDNode() {}
void dropAllReferences();
- static MDNode *getMDNode(LLVMContext &C, ArrayRef<Metadata *> MDs,
- bool Insert = true);
-
MDOperand *mutable_begin() { return mutable_end() - NumOperands; }
MDOperand *mutable_end() { return reinterpret_cast<MDOperand *>(this); }
public:
- static MDNode *get(LLVMContext &Context, ArrayRef<Metadata *> MDs) {
- return getMDNode(Context, MDs, true);
- }
-
- static MDNode *getIfExists(LLVMContext &Context, ArrayRef<Metadata *> MDs) {
- return getMDNode(Context, MDs, false);
- }
-
- /// \brief Return a distinct node.
- ///
- /// Return a distinct node -- i.e., a node that is not uniqued.
- static MDNode *getDistinct(LLVMContext &Context, ArrayRef<Metadata *> MDs);
-
- /// \brief Return a temporary MDNode
- ///
- /// For use in constructing cyclic MDNode structures. A temporary MDNode is
- /// not uniqued, may be RAUW'd, and must be manually deleted with
- /// deleteTemporary.
- static MDNodeFwdDecl *getTemporary(LLVMContext &Context,
+ static inline MDTuple *get(LLVMContext &Context, ArrayRef<Metadata *> MDs);
+ static inline MDTuple *getIfExists(LLVMContext &Context,
ArrayRef<Metadata *> MDs);
+ static inline MDTuple *getDistinct(LLVMContext &Context,
+ ArrayRef<Metadata *> MDs);
+ static inline MDTuple *getTemporary(LLVMContext &Context,
+ ArrayRef<Metadata *> MDs);
/// \brief Deallocate a node created by getTemporary.
///
/// The node must not have any users.
static void deleteTemporary(MDNode *N);
- LLVMContext &getContext() const { return Context; }
+ LLVMContext &getContext() const { return Context.getContext(); }
/// \brief Replace a specific operand.
void replaceOperandWith(unsigned I, Metadata *New);
/// \brief Check if node is fully resolved.
- bool isResolved() const;
+ ///
+ /// If \a isTemporary(), this always returns \c false; if \a isDistinct(),
+ /// this always returns \c true.
+ ///
+ /// If \a isUniqued(), returns \c true if this has already dropped RAUW
+ /// support (because all operands are resolved).
+ ///
+ /// As forward declarations are resolved, their containers should get
+ /// resolved automatically. However, if this (or one of its operands) is
+ /// involved in a cycle, \a resolveCycles() needs to be called explicitly.
+ bool isResolved() const { return !Context.hasReplaceableUses(); }
- /// \brief Check if node is distinct.
+ bool isUniqued() const { return Storage == Uniqued; }
+ bool isDistinct() const { return Storage == Distinct; }
+ bool isTemporary() const { return Storage == Temporary; }
+
+ /// \brief RAUW a temporary.
///
- /// Distinct nodes are not uniqued, and will not be returned by \a
- /// MDNode::get().
- bool isDistinct() const {
- return isStoredDistinctInContext() || isa<MDNodeFwdDecl>(this);
+ /// \pre \a isTemporary() must be \c true.
+ void replaceAllUsesWith(Metadata *MD) {
+ assert(isTemporary() && "Expected temporary node");
+ assert(!isResolved() && "Expected RAUW support");
+ Context.getReplaceableUses()->replaceAllUsesWith(MD);
}
protected:
/// \brief Methods for support type inquiry through isa, cast, and dyn_cast:
static bool classof(const Metadata *MD) {
return MD->getMetadataID() == MDTupleKind ||
- MD->getMetadataID() == MDNodeFwdDeclKind;
+ MD->getMetadataID() == MDLocationKind;
}
/// \brief Check whether MDNode is a vtable access.
/// for implementing sub-types of \a MDNode that can be uniqued like
/// constants.
///
-/// There is limited support for RAUW at construction time. At
-/// construction time, if any operands are an instance of \a
-/// MDNodeFwdDecl (or another unresolved \a UniquableMDNode, which
-/// indicates an \a MDNodeFwdDecl in its path), the node itself will be
-/// unresolved. As soon as all operands become resolved, it will drop
-/// RAUW support permanently.
+/// There is limited support for RAUW at construction time. At construction
+/// time, if any operand is a temporary node (or an unresolved uniqued node,
+/// which indicates a transitive temporary operand), the node itself will be
+/// unresolved. As soon as all operands become resolved, it will drop RAUW
+/// support permanently.
///
/// If an unresolved node is part of a cycle, \a resolveCycles() needs
-/// to be called on some member of the cycle when each \a MDNodeFwdDecl
-/// has been removed.
+/// to be called on some member of the cycle once all temporary nodes have been
+/// replaced.
class UniquableMDNode : public MDNode {
friend class ReplaceableMetadataImpl;
friend class MDNode;
friend class LLVMContextImpl;
- /// \brief Support RAUW as long as one of its arguments is replaceable.
- ///
- /// FIXME: Save memory by storing this in a pointer union with the
- /// LLVMContext, and adding an LLVMContext reference to RMI.
- std::unique_ptr<ReplaceableMetadataImpl> ReplaceableUses;
-
protected:
/// \brief Create a new node.
///
/// If \c AllowRAUW, then if any operands are unresolved support RAUW. RAUW
/// will be dropped once all operands have been resolved (or if \a
/// resolveCycles() is called).
- UniquableMDNode(LLVMContext &C, unsigned ID, ArrayRef<Metadata *> Vals,
- bool AllowRAUW);
- ~UniquableMDNode();
+ UniquableMDNode(LLVMContext &C, unsigned ID, StorageType Storage,
+ ArrayRef<Metadata *> Vals);
+ ~UniquableMDNode() {}
void storeDistinctInContext();
+ template <class T, class StoreT>
+ static T *storeImpl(T *N, StorageType Storage, StoreT &Store);
public:
static bool classof(const Metadata *MD) {
- return MD->getMetadataID() == MDTupleKind;
+ return MD->getMetadataID() == MDTupleKind ||
+ MD->getMetadataID() == MDLocationKind;
}
- /// \brief Check whether any operands are forward declarations.
- ///
- /// Returns \c true as long as any operands (or their operands, etc.) are \a
- /// MDNodeFwdDecl.
- ///
- /// As forward declarations are resolved, their containers should get
- /// resolved automatically. However, if this (or one of its operands) is
- /// involved in a cycle, \a resolveCycles() needs to be called explicitly.
- bool isResolved() const { return !ReplaceableUses; }
-
/// \brief Resolve cycles.
///
/// Once all forward declarations have been resolved, force cycles to be
/// resolved.
///
- /// \pre No operands (or operands' operands, etc.) are \a MDNodeFwdDecl.
+ /// \pre No operands (or operands' operands, etc.) have \a isTemporary().
void resolveCycles();
private:
void resolve();
void resolveAfterOperandChange(Metadata *Old, Metadata *New);
void decrementUnresolvedOperandCount();
+
+ void deleteAsSubclass();
+ UniquableMDNode *uniquify();
+ void eraseFromStore();
};
/// \brief Tuple of metadata.
class MDTuple : public UniquableMDNode {
friend class LLVMContextImpl;
friend class UniquableMDNode;
- friend class MDNode;
- MDTuple(LLVMContext &C, ArrayRef<Metadata *> Vals, bool AllowRAUW)
- : UniquableMDNode(C, MDTupleKind, Vals, AllowRAUW) {}
- ~MDTuple();
+ MDTuple(LLVMContext &C, StorageType Storage, unsigned Hash,
+ ArrayRef<Metadata *> Vals)
+ : UniquableMDNode(C, MDTupleKind, Storage, Vals) {
+ setHash(Hash);
+ }
+ ~MDTuple() { dropAllReferences(); }
void setHash(unsigned Hash) { MDNodeSubclassData = Hash; }
void recalculateHash();
+ static MDTuple *getImpl(LLVMContext &Context, ArrayRef<Metadata *> MDs,
+ StorageType Storage, bool ShouldCreate = true);
+
public:
/// \brief Get the hash, if any.
unsigned getHash() const { return MDNodeSubclassData; }
+ static MDTuple *get(LLVMContext &Context, ArrayRef<Metadata *> MDs) {
+ return getImpl(Context, MDs, Uniqued);
+ }
+ static MDTuple *getIfExists(LLVMContext &Context, ArrayRef<Metadata *> MDs) {
+ return getImpl(Context, MDs, Uniqued, /* ShouldCreate */ false);
+ }
+
+ /// \brief Return a distinct node.
+ ///
+ /// Return a distinct node -- i.e., a node that is not uniqued.
+ static MDTuple *getDistinct(LLVMContext &Context, ArrayRef<Metadata *> MDs) {
+ return getImpl(Context, MDs, Distinct);
+ }
+
+ /// \brief Return a temporary node.
+ ///
+ /// For use in constructing cyclic MDNode structures. A temporary MDNode is
+ /// not uniqued, may be RAUW'd, and must be manually deleted with
+ /// deleteTemporary.
+ static MDTuple *getTemporary(LLVMContext &Context, ArrayRef<Metadata *> MDs) {
+ return getImpl(Context, MDs, Temporary);
+ }
+
static bool classof(const Metadata *MD) {
return MD->getMetadataID() == MDTupleKind;
}
+
+private:
+ MDTuple *uniquifyImpl();
+ void eraseFromStoreImpl();
};
-/// \brief Forward declaration of metadata.
+MDTuple *MDNode::get(LLVMContext &Context, ArrayRef<Metadata *> MDs) {
+ return MDTuple::get(Context, MDs);
+}
+MDTuple *MDNode::getIfExists(LLVMContext &Context, ArrayRef<Metadata *> MDs) {
+ return MDTuple::getIfExists(Context, MDs);
+}
+MDTuple *MDNode::getDistinct(LLVMContext &Context, ArrayRef<Metadata *> MDs) {
+ return MDTuple::getDistinct(Context, MDs);
+}
+MDTuple *MDNode::getTemporary(LLVMContext &Context, ArrayRef<Metadata *> MDs) {
+ return MDTuple::getTemporary(Context, MDs);
+}
+
+/// \brief Debug location.
///
-/// Forward declaration of metadata, in the form of a basic tuple. Unlike \a
-/// MDTuple, this class has full support for RAUW, is not owned, is not
-/// uniqued, and is suitable for forward references.
-class MDNodeFwdDecl : public MDNode, ReplaceableMetadataImpl {
- friend class Metadata;
- friend class MDNode;
- friend class ReplaceableMetadataImpl;
+/// A debug location in source code, used for debug info and otherwise.
+class MDLocation : public UniquableMDNode {
+ friend class LLVMContextImpl;
+ friend class UniquableMDNode;
- MDNodeFwdDecl(LLVMContext &C, ArrayRef<Metadata *> Vals)
- : MDNode(C, MDNodeFwdDeclKind, Vals) {}
- ~MDNodeFwdDecl() { dropAllReferences(); }
+ MDLocation(LLVMContext &C, StorageType Storage, unsigned Line,
+ unsigned Column, ArrayRef<Metadata *> MDs);
+ ~MDLocation() { dropAllReferences(); }
+
+ static MDLocation *getImpl(LLVMContext &Context, unsigned Line,
+ unsigned Column, Metadata *Scope,
+ Metadata *InlinedAt, StorageType Storage,
+ bool ShouldCreate = true);
+
+ // Disallow replacing operands.
+ void replaceOperandWith(unsigned I, Metadata *New) LLVM_DELETED_FUNCTION;
public:
+ static MDLocation *get(LLVMContext &Context, unsigned Line, unsigned Column,
+ Metadata *Scope, Metadata *InlinedAt = nullptr) {
+ return getImpl(Context, Line, Column, Scope, InlinedAt, Uniqued);
+ }
+ static MDLocation *getIfExists(LLVMContext &Context, unsigned Line,
+ unsigned Column, Metadata *Scope,
+ Metadata *InlinedAt = nullptr) {
+ return getImpl(Context, Line, Column, Scope, InlinedAt, Uniqued,
+ /* ShouldCreate */ false);
+ }
+ static MDLocation *getDistinct(LLVMContext &Context, unsigned Line,
+ unsigned Column, Metadata *Scope,
+ Metadata *InlinedAt = nullptr) {
+ return getImpl(Context, Line, Column, Scope, InlinedAt, Distinct);
+ }
+
+ unsigned getLine() const { return MDNodeSubclassData; }
+ unsigned getColumn() const { return SubclassData16; }
+ Metadata *getScope() const { return getOperand(0); }
+ Metadata *getInlinedAt() const {
+ if (getNumOperands() == 2)
+ return getOperand(1);
+ return nullptr;
+ }
+
static bool classof(const Metadata *MD) {
- return MD->getMetadataID() == MDNodeFwdDeclKind;
+ return MD->getMetadataID() == MDLocationKind;
}
- using ReplaceableMetadataImpl::replaceAllUsesWith;
+private:
+ MDLocation *uniquifyImpl();
+ void eraseFromStoreImpl();
};
//===----------------------------------------------------------------------===//