IR: Extract MDNodeOpsKey, NFC

Make the MDTuple operand hashing logic reusable.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@226519 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Duncan P. N. Exon Smith 2015-01-19 22:53:18 +00:00
parent ce8f144e00
commit fce53dd939
3 changed files with 84 additions and 50 deletions

View File

@ -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<Metadata *, 8> 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<Metadata *> Ops) {
return hash_combine_range(Ops.begin(), Ops.end());
}
// ConstantsContext anchors
void UnaryConstantExpr::anchor() { }

View File

@ -167,35 +167,62 @@ struct FunctionTypeKeyInfo {
}
};
/// \brief Structure for hashing arbitrary MDNode operands.
class MDNodeOpsKey {
ArrayRef<Metadata *> RawOps;
ArrayRef<MDOperand> Ops;
unsigned Hash;
protected:
MDNodeOpsKey(ArrayRef<Metadata *> Ops)
: RawOps(Ops), Hash(calculateHash(Ops)) {}
template <class NodeTy>
MDNodeOpsKey(NodeTy *N)
: Ops(N->op_begin(), N->op_end()), Hash(N->getHash()) {}
template <class NodeTy> 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 <class T>
static bool compareOps(ArrayRef<T> 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<Metadata *> 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<Metadata *> RawOps;
ArrayRef<MDOperand> Ops;
unsigned Hash;
KeyTy(ArrayRef<Metadata *> 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<Metadata *> 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 <class T>
static bool compareOps(ArrayRef<T> 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<MDTuple *>::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;
}

View File

@ -515,15 +515,7 @@ void UniquableMDNode::resolveCycles() {
}
void MDTuple::recalculateHash() {
setHash(hash_combine_range(op_begin(), op_end()));
#ifndef NDEBUG
{
SmallVector<Metadata *, 8> 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<MDOperand *>(Ref) - op_begin();
assert(Op < getNumOperands() && "Expected valid operand");
@ -687,7 +662,7 @@ MDTuple *MDTuple::getImpl(LLVMContext &Context, ArrayRef<Metadata *> MDs,
return N;
if (!ShouldCreate)
return nullptr;
Hash = Key.Hash;
Hash = Key.getHash();
} else {
assert(ShouldCreate && "Expected non-uniqued nodes to always be created");
}