diff --git a/lib/IR/LLVMContextImpl.cpp b/lib/IR/LLVMContextImpl.cpp index 01a786dbfda..2fa6780e569 100644 --- a/lib/IR/LLVMContextImpl.cpp +++ b/lib/IR/LLVMContextImpl.cpp @@ -163,6 +163,40 @@ LLVMContextImpl::~LLVMContextImpl() { MDStringCache.clear(); } +namespace llvm { +/// \brief Make MDOperand transparent for hashing. +/// +/// This overload of an implementation detail of the hashing library makes +/// MDOperand hash to the same value as a \a Metadata pointer. +/// +/// Note that overloading \a hash_value() as follows: +/// +/// \code +/// size_t hash_value(const MDOperand &X) { return hash_value(X.get()); } +/// \endcode +/// +/// does not cause MDOperand to be transparent. In particular, a bare pointer +/// doesn't get hashed before it's combined, whereas \a MDOperand would. +static const Metadata *get_hashable_data(const MDOperand &X) { return X.get(); } +} + +unsigned MDNodeOpsKey::calculateHash(MDNode *N) { + unsigned Hash = hash_combine_range(N->op_begin(), N->op_end()); +#ifndef NDEBUG + { + SmallVector MDs(N->op_begin(), N->op_end()); + unsigned RawHash = calculateHash(MDs); + assert(Hash == RawHash && + "Expected hash of MDOperand to equal hash of Metadata*"); + } +#endif + return Hash; +} + +unsigned MDNodeOpsKey::calculateHash(ArrayRef Ops) { + return hash_combine_range(Ops.begin(), Ops.end()); +} + // ConstantsContext anchors void UnaryConstantExpr::anchor() { } diff --git a/lib/IR/LLVMContextImpl.h b/lib/IR/LLVMContextImpl.h index 45f86093f52..729e48be083 100644 --- a/lib/IR/LLVMContextImpl.h +++ b/lib/IR/LLVMContextImpl.h @@ -167,35 +167,62 @@ struct FunctionTypeKeyInfo { } }; +/// \brief Structure for hashing arbitrary MDNode operands. +class MDNodeOpsKey { + ArrayRef RawOps; + ArrayRef Ops; + + unsigned Hash; + +protected: + MDNodeOpsKey(ArrayRef Ops) + : RawOps(Ops), Hash(calculateHash(Ops)) {} + + template + MDNodeOpsKey(NodeTy *N) + : Ops(N->op_begin(), N->op_end()), Hash(N->getHash()) {} + + template bool compareOps(const NodeTy *RHS) const { + if (getHash() != RHS->getHash()) + return false; + + assert((RawOps.empty() || Ops.empty()) && "Two sets of operands?"); + return RawOps.empty() ? compareOps(Ops, RHS) : compareOps(RawOps, RHS); + } + + static unsigned calculateHash(MDNode *N); + +private: + template + static bool compareOps(ArrayRef Ops, const MDNode *RHS) { + if (Ops.size() != RHS->getNumOperands()) + return false; + return std::equal(Ops.begin(), Ops.end(), RHS->op_begin()); + } + + static unsigned calculateHash(ArrayRef Ops); + +public: + unsigned getHash() const { return Hash; } +}; + /// \brief DenseMapInfo for MDTuple. /// /// Note that we don't need the is-function-local bit, since that's implicit in /// the operands. struct MDTupleInfo { - struct KeyTy { - ArrayRef RawOps; - ArrayRef Ops; - unsigned Hash; - - KeyTy(ArrayRef Ops) - : RawOps(Ops), Hash(hash_combine_range(Ops.begin(), Ops.end())) {} - - KeyTy(MDTuple *N) - : Ops(N->op_begin(), N->op_end()), Hash(N->getHash()) {} + struct KeyTy : MDNodeOpsKey { + KeyTy(ArrayRef Ops) : MDNodeOpsKey(Ops) {} + KeyTy(MDTuple *N) : MDNodeOpsKey(N) {} bool operator==(const MDTuple *RHS) const { if (RHS == getEmptyKey() || RHS == getTombstoneKey()) return false; - if (Hash != RHS->getHash()) - return false; - assert((RawOps.empty() || Ops.empty()) && "Two sets of operands?"); - return RawOps.empty() ? compareOps(Ops, RHS) : compareOps(RawOps, RHS); + return compareOps(RHS); } - template - static bool compareOps(ArrayRef Ops, const MDTuple *RHS) { - if (Ops.size() != RHS->getNumOperands()) - return false; - return std::equal(Ops.begin(), Ops.end(), RHS->op_begin()); + + static unsigned calculateHash(MDTuple *N) { + return MDNodeOpsKey::calculateHash(N); } }; static inline MDTuple *getEmptyKey() { @@ -204,10 +231,8 @@ struct MDTupleInfo { static inline MDTuple *getTombstoneKey() { return DenseMapInfo::getTombstoneKey(); } - static unsigned getHashValue(const KeyTy &Key) { return Key.Hash; } - static unsigned getHashValue(const MDTuple *U) { - return U->getHash(); - } + static unsigned getHashValue(const KeyTy &Key) { return Key.getHash(); } + static unsigned getHashValue(const MDTuple *U) { return U->getHash(); } static bool isEqual(const KeyTy &LHS, const MDTuple *RHS) { return LHS == RHS; } diff --git a/lib/IR/Metadata.cpp b/lib/IR/Metadata.cpp index e9265eb96ad..8253a4e6a96 100644 --- a/lib/IR/Metadata.cpp +++ b/lib/IR/Metadata.cpp @@ -515,15 +515,7 @@ void UniquableMDNode::resolveCycles() { } void MDTuple::recalculateHash() { - setHash(hash_combine_range(op_begin(), op_end())); -#ifndef NDEBUG - { - SmallVector MDs(op_begin(), op_end()); - unsigned RawHash = hash_combine_range(MDs.begin(), MDs.end()); - assert(getHash() == RawHash && - "Expected hash of MDOperand to equal hash of Metadata*"); - } -#endif + setHash(MDTupleInfo::KeyTy::calculateHash(this)); } void MDNode::dropAllReferences() { @@ -536,23 +528,6 @@ void MDNode::dropAllReferences() { } } -namespace llvm { -/// \brief Make MDOperand transparent for hashing. -/// -/// This overload of an implementation detail of the hashing library makes -/// MDOperand hash to the same value as a \a Metadata pointer. -/// -/// Note that overloading \a hash_value() as follows: -/// -/// \code -/// size_t hash_value(const MDOperand &X) { return hash_value(X.get()); } -/// \endcode -/// -/// does not cause MDOperand to be transparent. In particular, a bare pointer -/// doesn't get hashed before it's combined, whereas \a MDOperand would. -static const Metadata *get_hashable_data(const MDOperand &X) { return X.get(); } -} - void UniquableMDNode::handleChangedOperand(void *Ref, Metadata *New) { unsigned Op = static_cast(Ref) - op_begin(); assert(Op < getNumOperands() && "Expected valid operand"); @@ -687,7 +662,7 @@ MDTuple *MDTuple::getImpl(LLVMContext &Context, ArrayRef MDs, return N; if (!ShouldCreate) return nullptr; - Hash = Key.Hash; + Hash = Key.getHash(); } else { assert(ShouldCreate && "Expected non-uniqued nodes to always be created"); }