From c10ef2df5ccb216fb2f1edecb460599b73b42a49 Mon Sep 17 00:00:00 2001 From: "Duncan P. N. Exon Smith" Date: Tue, 20 Jan 2015 00:57:33 +0000 Subject: [PATCH] IR: Detect whether to call recalculateHash() via SFINAE, NFC Rather than relying on updating switch statements correctly, detect whether `setHash()` exists in the subclass. If so, call `recalculateHash()` and `setHash(0)` appropriately. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@226531 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/IR/Metadata.h | 14 +++++++++++ lib/IR/Metadata.cpp | 51 ++++++++++++++++++++++++-------------- 2 files changed, 47 insertions(+), 18 deletions(-) diff --git a/include/llvm/IR/Metadata.h b/include/llvm/IR/Metadata.h index 09ef18eb2be..3fa1661f74d 100644 --- a/include/llvm/IR/Metadata.h +++ b/include/llvm/IR/Metadata.h @@ -825,6 +825,20 @@ private: MDNode *uniquify(); void eraseFromStore(); + template struct HasCachedHash; + template + static void dispatchRecalculateHash(NodeTy *N, std::true_type) { + N->recalculateHash(); + } + template + static void dispatchRecalculateHash(NodeTy *N, std::false_type) {} + template + static void dispatchResetHash(NodeTy *N, std::true_type) { + N->setHash(0); + } + template + static void dispatchResetHash(NodeTy *N, std::false_type) {} + public: typedef const MDOperand *op_iterator; typedef iterator_range op_range; diff --git a/lib/IR/Metadata.cpp b/lib/IR/Metadata.cpp index 5f5708565d4..97976308fcd 100644 --- a/lib/IR/Metadata.cpp +++ b/lib/IR/Metadata.cpp @@ -620,26 +620,31 @@ static T *uniquifyImpl(T *N, DenseSet &Store) { return N; } -MDNode *MDNode::uniquify() { - // Recalculate hash, if necessary. - switch (getMetadataID()) { - default: - break; - case MDTupleKind: - cast(this)->recalculateHash(); - break; - case GenericDwarfNodeKind: - cast(this)->recalculateHash(); - break; - } +template struct MDNode::HasCachedHash { + typedef char Yes[1]; + typedef char No[2]; + template struct SFINAE {}; + template + static Yes &check(SFINAE *); + template static No &check(...); + + static const bool value = sizeof(check(nullptr)) == sizeof(Yes); +}; + +MDNode *MDNode::uniquify() { // Try to insert into uniquing store. switch (getMetadataID()) { default: llvm_unreachable("Invalid subclass of MDNode"); #define HANDLE_MDNODE_LEAF(CLASS) \ - case CLASS##Kind: \ - return uniquifyImpl(cast(this), getContext().pImpl->CLASS##s); + case CLASS##Kind: { \ + CLASS *SubclassThis = cast(this); \ + std::integral_constant::value> \ + ShouldRecalculateHash; \ + dispatchRecalculateHash(SubclassThis, ShouldRecalculateHash); \ + return uniquifyImpl(SubclassThis, getContext().pImpl->CLASS##s); \ + } #include "llvm/IR/Metadata.def" } } @@ -774,10 +779,20 @@ void MDNode::deleteTemporary(MDNode *N) { void MDNode::storeDistinctInContext() { assert(isResolved() && "Expected resolved nodes"); Storage = Distinct; - if (auto *T = dyn_cast(this)) - T->setHash(0); - else if (auto *G = dyn_cast(this)) - G->setHash(0); + + // Reset the hash. + switch (getMetadataID()) { + default: + llvm_unreachable("Invalid subclass of MDNode"); +#define HANDLE_MDNODE_LEAF(CLASS) \ + case CLASS##Kind: { \ + std::integral_constant::value> ShouldResetHash; \ + dispatchResetHash(cast(this), ShouldResetHash); \ + break; \ + } +#include "llvm/IR/Metadata.def" + } + getContext().pImpl->DistinctMDNodes.insert(this); }