summaryrefslogtreecommitdiffstats
path: root/mlir/lib/Support
diff options
context:
space:
mode:
authorRiver Riddle <riverriddle@google.com>2019-04-25 21:01:21 -0700
committerMehdi Amini <joker.eph@gmail.com>2019-05-06 08:17:08 -0700
commit880df8f6ad8d801d2d3fd761d25d69b059f3f4da (patch)
tree225b141c278fc7f88e3a964e39722dd0a3b9cf17 /mlir/lib/Support
parent6749c21d6ec263891e9bb55a7203f2d2a8bb4d5f (diff)
downloadbcm5719-llvm-880df8f6ad8d801d2d3fd761d25d69b059f3f4da.tar.gz
bcm5719-llvm-880df8f6ad8d801d2d3fd761d25d69b059f3f4da.zip
Refactor the generic storage object uniquing functionality from TypeUniquer into its own class 'StorageUniquer'. This is the first step in supporting dialect extensible attributes.
-- PiperOrigin-RevId: 245358744
Diffstat (limited to 'mlir/lib/Support')
-rw-r--r--mlir/lib/Support/CMakeLists.txt1
-rw-r--r--mlir/lib/Support/StorageUniquer.cpp181
2 files changed, 182 insertions, 0 deletions
diff --git a/mlir/lib/Support/CMakeLists.txt b/mlir/lib/Support/CMakeLists.txt
index 2d69b4d44ed..97da45b2060 100644
--- a/mlir/lib/Support/CMakeLists.txt
+++ b/mlir/lib/Support/CMakeLists.txt
@@ -1,5 +1,6 @@
add_llvm_library(MLIRSupport
FileUtilities.cpp
+ StorageUniquer.cpp
ADDITIONAL_HEADER_DIRS
${MLIR_MAIN_INCLUDE_DIR}/mlir/Support
diff --git a/mlir/lib/Support/StorageUniquer.cpp b/mlir/lib/Support/StorageUniquer.cpp
new file mode 100644
index 00000000000..14d8f393e08
--- /dev/null
+++ b/mlir/lib/Support/StorageUniquer.cpp
@@ -0,0 +1,181 @@
+//===- StorageUniquer.cpp - Common Storage Class Uniquer --------*- C++ -*-===//
+//
+// Copyright 2019 The MLIR Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// =============================================================================
+
+#include "mlir/Support/StorageUniquer.h"
+#include "mlir/Support/LLVM.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/RWMutex.h"
+
+using namespace mlir;
+using namespace mlir::detail;
+
+namespace mlir {
+namespace detail {
+/// This is the implementation of the StorageUniquer class.
+struct StorageUniquerImpl {
+ using BaseStorage = StorageUniquer::BaseStorage;
+ using StorageAllocator = StorageUniquer::StorageAllocator;
+
+ /// A lookup key for derived instances of storage objects.
+ struct LookupKey {
+ /// The known derived kind for the storage.
+ unsigned kind;
+
+ /// The known hash value of the key.
+ unsigned hashValue;
+
+ /// An equality function for comparing with an existing storage instance.
+ llvm::function_ref<bool(const BaseStorage *)> isEqual;
+ };
+
+ /// A utility wrapper object representing a hashed storage object. This class
+ /// contains a storage object and an existing computed hash value.
+ struct HashedStorage {
+ unsigned hashValue;
+ BaseStorage *storage;
+ };
+
+ /// Get or create an instance of a complex derived type.
+ BaseStorage *
+ getOrCreate(unsigned kind, unsigned hashValue,
+ llvm::function_ref<bool(const BaseStorage *)> isEqual,
+ llvm::function_ref<BaseStorage *(StorageAllocator &)> ctorFn) {
+ LookupKey lookupKey{kind, hashValue, isEqual};
+
+ // Check for an existing instance in read-only mode.
+ {
+ llvm::sys::SmartScopedReader<true> typeLock(mutex);
+ auto it = storageTypes.find_as(lookupKey);
+ if (it != storageTypes.end())
+ return it->storage;
+ }
+
+ // Acquire a writer-lock so that we can safely create the new type instance.
+ llvm::sys::SmartScopedWriter<true> typeLock(mutex);
+
+ // Check for an existing instance again here, because another writer thread
+ // may have already created one.
+ auto existing = storageTypes.insert_as({}, lookupKey);
+ if (!existing.second)
+ return existing.first->storage;
+
+ // Otherwise, construct and initialize the derived storage for this type
+ // instance.
+ BaseStorage *storage = initializeStorage(kind, ctorFn);
+ *existing.first = HashedStorage{hashValue, storage};
+ return storage;
+ }
+
+ /// Get or create an instance of a simple derived type.
+ BaseStorage *
+ getOrCreate(unsigned kind,
+ llvm::function_ref<BaseStorage *(StorageAllocator &)> ctorFn) {
+ // Check for an existing instance in read-only mode.
+ {
+ llvm::sys::SmartScopedReader<true> typeLock(mutex);
+ auto it = simpleTypes.find(kind);
+ if (it != simpleTypes.end())
+ return it->second;
+ }
+
+ // Acquire a writer-lock so that we can safely create the new type instance.
+ llvm::sys::SmartScopedWriter<true> typeLock(mutex);
+
+ // Check for an existing instance again here, because another writer thread
+ // may have already created one.
+ auto &result = simpleTypes[kind];
+ if (result)
+ return result;
+
+ // Otherwise, create and return a new storage instance.
+ return result = initializeStorage(kind, ctorFn);
+ }
+
+ //===--------------------------------------------------------------------===//
+ // Instance Storage
+ //===--------------------------------------------------------------------===//
+
+ /// Utility to create and initialize a storage instance.
+ BaseStorage *initializeStorage(
+ unsigned kind,
+ llvm::function_ref<BaseStorage *(StorageAllocator &)> ctorFn) {
+ BaseStorage *storage = ctorFn(allocator);
+ storage->kind = kind;
+ return storage;
+ }
+
+ /// Storage info for derived TypeStorage objects.
+ struct StorageKeyInfo : DenseMapInfo<HashedStorage> {
+ static HashedStorage getEmptyKey() {
+ return HashedStorage{0, DenseMapInfo<BaseStorage *>::getEmptyKey()};
+ }
+ static HashedStorage getTombstoneKey() {
+ return HashedStorage{0, DenseMapInfo<BaseStorage *>::getTombstoneKey()};
+ }
+
+ static unsigned getHashValue(const HashedStorage &key) {
+ return key.hashValue;
+ }
+ static unsigned getHashValue(LookupKey key) { return key.hashValue; }
+
+ static bool isEqual(const HashedStorage &lhs, const HashedStorage &rhs) {
+ return lhs.storage == rhs.storage;
+ }
+ static bool isEqual(const LookupKey &lhs, const HashedStorage &rhs) {
+ if (isEqual(rhs, getEmptyKey()) || isEqual(rhs, getTombstoneKey()))
+ return false;
+ // If the lookup kind matches the kind of the storage, then invoke the
+ // equality function on the lookup key.
+ return lhs.kind == rhs.storage->getKind() && lhs.isEqual(rhs.storage);
+ }
+ };
+
+ // Unique types with specific hashing or storage constraints.
+ using StorageTypeSet = llvm::DenseSet<HashedStorage, StorageKeyInfo>;
+ StorageTypeSet storageTypes;
+
+ // Unique types with just the kind.
+ DenseMap<unsigned, BaseStorage *> simpleTypes;
+
+ // Allocator to use when constructing derived type instances.
+ StorageUniquer::StorageAllocator allocator;
+
+ // A mutex to keep type uniquing thread-safe.
+ llvm::sys::SmartRWMutex<true> mutex;
+};
+} // end namespace detail
+} // namespace mlir
+
+StorageUniquer::StorageUniquer() : impl(new StorageUniquerImpl()) {}
+StorageUniquer::~StorageUniquer() {}
+
+/// Implementation for getting/creating an instance of a derived type with
+/// complex storage.
+auto StorageUniquer::getImpl(
+ unsigned kind, unsigned hashValue,
+ llvm::function_ref<bool(const BaseStorage *)> isEqual,
+ std::function<BaseStorage *(StorageAllocator &)> ctorFn) -> BaseStorage * {
+ return impl->getOrCreate(kind, hashValue, isEqual, ctorFn);
+}
+
+/// Implementation for getting/creating an instance of a derived type with
+/// default storage.
+auto StorageUniquer::getImpl(
+ unsigned kind, std::function<BaseStorage *(StorageAllocator &)> ctorFn)
+ -> BaseStorage * {
+ return impl->getOrCreate(kind, ctorFn);
+}
OpenPOWER on IntegriCloud