1cde4d5a6SJacques Pienaar //===- StorageUniquer.cpp - Common Storage Class Uniquer ------------------===//
2880df8f6SRiver Riddle //
330857107SMehdi Amini // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
456222a06SMehdi Amini // See https://llvm.org/LICENSE.txt for license information.
556222a06SMehdi Amini // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6880df8f6SRiver Riddle //
756222a06SMehdi Amini //===----------------------------------------------------------------------===//
8880df8f6SRiver Riddle
9880df8f6SRiver Riddle #include "mlir/Support/StorageUniquer.h"
105b1345ffSMehdi Amini
11880df8f6SRiver Riddle #include "mlir/Support/LLVM.h"
12f3df3b58SRiver Riddle #include "mlir/Support/ThreadLocalCache.h"
1386646be3SRiver Riddle #include "mlir/Support/TypeID.h"
14880df8f6SRiver Riddle #include "llvm/Support/RWMutex.h"
15880df8f6SRiver Riddle
16880df8f6SRiver Riddle using namespace mlir;
17880df8f6SRiver Riddle using namespace mlir::detail;
18880df8f6SRiver Riddle
1986646be3SRiver Riddle namespace {
20250f43d3SRiver Riddle /// This class represents a uniquer for storage instances of a specific type
21250f43d3SRiver Riddle /// that has parametric storage. It contains all of the necessary data to unique
22250f43d3SRiver Riddle /// storage instances in a thread safe way. This allows for the main uniquer to
23250f43d3SRiver Riddle /// bucket each of the individual sub-types removing the need to lock the main
24250f43d3SRiver Riddle /// uniquer itself.
2567f52f35SRiver Riddle class ParametricStorageUniquer {
2667f52f35SRiver Riddle public:
27880df8f6SRiver Riddle using BaseStorage = StorageUniquer::BaseStorage;
28880df8f6SRiver Riddle using StorageAllocator = StorageUniquer::StorageAllocator;
29880df8f6SRiver Riddle
30880df8f6SRiver Riddle /// A lookup key for derived instances of storage objects.
31880df8f6SRiver Riddle struct LookupKey {
32880df8f6SRiver Riddle /// The known hash value of the key.
33880df8f6SRiver Riddle unsigned hashValue;
34880df8f6SRiver Riddle
35880df8f6SRiver Riddle /// An equality function for comparing with an existing storage instance.
364562e389SRiver Riddle function_ref<bool(const BaseStorage *)> isEqual;
37880df8f6SRiver Riddle };
38880df8f6SRiver Riddle
3967f52f35SRiver Riddle private:
40880df8f6SRiver Riddle /// A utility wrapper object representing a hashed storage object. This class
41880df8f6SRiver Riddle /// contains a storage object and an existing computed hash value.
42880df8f6SRiver Riddle struct HashedStorage {
HashedStorage__anon242314e60111::ParametricStorageUniquer::HashedStorage43f3df3b58SRiver Riddle HashedStorage(unsigned hashValue = 0, BaseStorage *storage = nullptr)
44f3df3b58SRiver Riddle : hashValue(hashValue), storage(storage) {}
45880df8f6SRiver Riddle unsigned hashValue;
46880df8f6SRiver Riddle BaseStorage *storage;
47880df8f6SRiver Riddle };
48880df8f6SRiver Riddle
49880df8f6SRiver Riddle /// Storage info for derived TypeStorage objects.
507961511eSRiver Riddle struct StorageKeyInfo {
getEmptyKey__anon242314e60111::ParametricStorageUniquer::StorageKeyInfo517961511eSRiver Riddle static inline HashedStorage getEmptyKey() {
52f3df3b58SRiver Riddle return HashedStorage(0, DenseMapInfo<BaseStorage *>::getEmptyKey());
53880df8f6SRiver Riddle }
getTombstoneKey__anon242314e60111::ParametricStorageUniquer::StorageKeyInfo547961511eSRiver Riddle static inline HashedStorage getTombstoneKey() {
55f3df3b58SRiver Riddle return HashedStorage(0, DenseMapInfo<BaseStorage *>::getTombstoneKey());
56880df8f6SRiver Riddle }
57880df8f6SRiver Riddle
getHashValue__anon242314e60111::ParametricStorageUniquer::StorageKeyInfo587961511eSRiver Riddle static inline unsigned getHashValue(const HashedStorage &key) {
59880df8f6SRiver Riddle return key.hashValue;
60880df8f6SRiver Riddle }
getHashValue__anon242314e60111::ParametricStorageUniquer::StorageKeyInfo617961511eSRiver Riddle static inline unsigned getHashValue(const LookupKey &key) {
627961511eSRiver Riddle return key.hashValue;
637961511eSRiver Riddle }
64880df8f6SRiver Riddle
isEqual__anon242314e60111::ParametricStorageUniquer::StorageKeyInfo657961511eSRiver Riddle static inline bool isEqual(const HashedStorage &lhs,
667961511eSRiver Riddle const HashedStorage &rhs) {
67880df8f6SRiver Riddle return lhs.storage == rhs.storage;
68880df8f6SRiver Riddle }
isEqual__anon242314e60111::ParametricStorageUniquer::StorageKeyInfo697961511eSRiver Riddle static inline bool isEqual(const LookupKey &lhs, const HashedStorage &rhs) {
70880df8f6SRiver Riddle if (isEqual(rhs, getEmptyKey()) || isEqual(rhs, getTombstoneKey()))
71880df8f6SRiver Riddle return false;
72250f43d3SRiver Riddle // Invoke the equality function on the lookup key.
73250f43d3SRiver Riddle return lhs.isEqual(rhs.storage);
74880df8f6SRiver Riddle }
75880df8f6SRiver Riddle };
764562e389SRiver Riddle using StorageTypeSet = DenseSet<HashedStorage, StorageKeyInfo>;
7767f52f35SRiver Riddle
7867f52f35SRiver Riddle /// This class represents a single shard of the uniquer. The uniquer uses a
7967f52f35SRiver Riddle /// set of shards to allow for multiple threads to create instances with less
8067f52f35SRiver Riddle /// lock contention.
8167f52f35SRiver Riddle struct Shard {
8267f52f35SRiver Riddle /// The set containing the allocated storage instances.
83250f43d3SRiver Riddle StorageTypeSet instances;
84880df8f6SRiver Riddle
8567f52f35SRiver Riddle #if LLVM_ENABLE_THREADS != 0
8667f52f35SRiver Riddle /// A mutex to keep uniquing thread-safe.
8767f52f35SRiver Riddle llvm::sys::SmartRWMutex<true> mutex;
8867f52f35SRiver Riddle #endif
8967f52f35SRiver Riddle };
9067f52f35SRiver Riddle
9167f52f35SRiver Riddle /// Get or create an instance of a param derived type in an thread-unsafe
9267f52f35SRiver Riddle /// fashion.
getOrCreateUnsafe(Shard & shard,LookupKey & key,function_ref<BaseStorage * ()> ctorFn)939f991ed3SRiver Riddle BaseStorage *getOrCreateUnsafe(Shard &shard, LookupKey &key,
949f991ed3SRiver Riddle function_ref<BaseStorage *()> ctorFn) {
9567f52f35SRiver Riddle auto existing = shard.instances.insert_as({key.hashValue}, key);
9667f52f35SRiver Riddle BaseStorage *&storage = existing.first->storage;
9767f52f35SRiver Riddle if (existing.second)
989f991ed3SRiver Riddle storage = ctorFn();
9967f52f35SRiver Riddle return storage;
10067f52f35SRiver Riddle }
10167f52f35SRiver Riddle
10231bb8efdSRiver Riddle /// Destroy all of the storage instances within the given shard.
destroyShardInstances(Shard & shard)10331bb8efdSRiver Riddle void destroyShardInstances(Shard &shard) {
10431bb8efdSRiver Riddle if (!destructorFn)
10531bb8efdSRiver Riddle return;
10631bb8efdSRiver Riddle for (HashedStorage &instance : shard.instances)
10731bb8efdSRiver Riddle destructorFn(instance.storage);
10831bb8efdSRiver Riddle }
10931bb8efdSRiver Riddle
11067f52f35SRiver Riddle public:
11167f52f35SRiver Riddle #if LLVM_ENABLE_THREADS != 0
11267f52f35SRiver Riddle /// Initialize the storage uniquer with a given number of storage shards to
11331bb8efdSRiver Riddle /// use. The provided shard number is required to be a valid power of 2. The
11431bb8efdSRiver Riddle /// destructor function is used to destroy any allocated storage instances.
ParametricStorageUniquer(function_ref<void (BaseStorage *)> destructorFn,size_t numShards=8)11531bb8efdSRiver Riddle ParametricStorageUniquer(function_ref<void(BaseStorage *)> destructorFn,
11631bb8efdSRiver Riddle size_t numShards = 8)
11731bb8efdSRiver Riddle : shards(new std::atomic<Shard *>[numShards]), numShards(numShards),
11831bb8efdSRiver Riddle destructorFn(destructorFn) {
11967f52f35SRiver Riddle assert(llvm::isPowerOf2_64(numShards) &&
12067f52f35SRiver Riddle "the number of shards is required to be a power of 2");
12167f52f35SRiver Riddle for (size_t i = 0; i < numShards; i++)
12267f52f35SRiver Riddle shards[i].store(nullptr, std::memory_order_relaxed);
12367f52f35SRiver Riddle }
~ParametricStorageUniquer()12467f52f35SRiver Riddle ~ParametricStorageUniquer() {
12567f52f35SRiver Riddle // Free all of the allocated shards.
12631bb8efdSRiver Riddle for (size_t i = 0; i != numShards; ++i) {
12731bb8efdSRiver Riddle if (Shard *shard = shards[i].load()) {
12831bb8efdSRiver Riddle destroyShardInstances(*shard);
12967f52f35SRiver Riddle delete shard;
13067f52f35SRiver Riddle }
13131bb8efdSRiver Riddle }
13231bb8efdSRiver Riddle }
13367f52f35SRiver Riddle /// Get or create an instance of a parametric type.
getOrCreate(bool threadingIsEnabled,unsigned hashValue,function_ref<bool (const BaseStorage *)> isEqual,function_ref<BaseStorage * ()> ctorFn)1349f991ed3SRiver Riddle BaseStorage *getOrCreate(bool threadingIsEnabled, unsigned hashValue,
13567f52f35SRiver Riddle function_ref<bool(const BaseStorage *)> isEqual,
1369f991ed3SRiver Riddle function_ref<BaseStorage *()> ctorFn) {
13767f52f35SRiver Riddle Shard &shard = getShard(hashValue);
13867f52f35SRiver Riddle ParametricStorageUniquer::LookupKey lookupKey{hashValue, isEqual};
13967f52f35SRiver Riddle if (!threadingIsEnabled)
14067f52f35SRiver Riddle return getOrCreateUnsafe(shard, lookupKey, ctorFn);
14167f52f35SRiver Riddle
14267f52f35SRiver Riddle // Check for a instance of this object in the local cache.
14367f52f35SRiver Riddle auto localIt = localCache->insert_as({hashValue}, lookupKey);
14467f52f35SRiver Riddle BaseStorage *&localInst = localIt.first->storage;
14567f52f35SRiver Riddle if (localInst)
14667f52f35SRiver Riddle return localInst;
14767f52f35SRiver Riddle
14867f52f35SRiver Riddle // Check for an existing instance in read-only mode.
14967f52f35SRiver Riddle {
15067f52f35SRiver Riddle llvm::sys::SmartScopedReader<true> typeLock(shard.mutex);
15167f52f35SRiver Riddle auto it = shard.instances.find_as(lookupKey);
15267f52f35SRiver Riddle if (it != shard.instances.end())
15367f52f35SRiver Riddle return localInst = it->storage;
15467f52f35SRiver Riddle }
15567f52f35SRiver Riddle
15667f52f35SRiver Riddle // Acquire a writer-lock so that we can safely create the new storage
15767f52f35SRiver Riddle // instance.
15867f52f35SRiver Riddle llvm::sys::SmartScopedWriter<true> typeLock(shard.mutex);
15967f52f35SRiver Riddle return localInst = getOrCreateUnsafe(shard, lookupKey, ctorFn);
16067f52f35SRiver Riddle }
1619f991ed3SRiver Riddle
16267f52f35SRiver Riddle /// Run a mutation function on the provided storage object in a thread-safe
16367f52f35SRiver Riddle /// way.
mutate(bool threadingIsEnabled,BaseStorage * storage,function_ref<LogicalResult ()> mutationFn)1649f991ed3SRiver Riddle LogicalResult mutate(bool threadingIsEnabled, BaseStorage *storage,
1659f991ed3SRiver Riddle function_ref<LogicalResult()> mutationFn) {
16667f52f35SRiver Riddle if (!threadingIsEnabled)
1679f991ed3SRiver Riddle return mutationFn();
16867f52f35SRiver Riddle
1699f991ed3SRiver Riddle // Get a shard to use for mutating this storage instance. It doesn't need to
1709f991ed3SRiver Riddle // be the same shard as the original allocation, but does need to be
1719f991ed3SRiver Riddle // deterministic.
1729f991ed3SRiver Riddle Shard &shard = getShard(llvm::hash_value(storage));
17367f52f35SRiver Riddle llvm::sys::SmartScopedWriter<true> lock(shard.mutex);
1749f991ed3SRiver Riddle return mutationFn();
17567f52f35SRiver Riddle }
17667f52f35SRiver Riddle
17767f52f35SRiver Riddle private:
17867f52f35SRiver Riddle /// Return the shard used for the given hash value.
getShard(unsigned hashValue)17967f52f35SRiver Riddle Shard &getShard(unsigned hashValue) {
18067f52f35SRiver Riddle // Get a shard number from the provided hashvalue.
18167f52f35SRiver Riddle unsigned shardNum = hashValue & (numShards - 1);
18267f52f35SRiver Riddle
18367f52f35SRiver Riddle // Try to acquire an already initialized shard.
18467f52f35SRiver Riddle Shard *shard = shards[shardNum].load(std::memory_order_acquire);
18567f52f35SRiver Riddle if (shard)
18667f52f35SRiver Riddle return *shard;
18767f52f35SRiver Riddle
18867f52f35SRiver Riddle // Otherwise, try to allocate a new shard.
18967f52f35SRiver Riddle Shard *newShard = new Shard();
19067f52f35SRiver Riddle if (shards[shardNum].compare_exchange_strong(shard, newShard))
19167f52f35SRiver Riddle return *newShard;
19267f52f35SRiver Riddle
19367f52f35SRiver Riddle // If one was allocated before we can initialize ours, delete ours.
19467f52f35SRiver Riddle delete newShard;
19567f52f35SRiver Riddle return *shard;
19667f52f35SRiver Riddle }
19767f52f35SRiver Riddle
198f3df3b58SRiver Riddle /// A thread local cache for storage objects. This helps to reduce the lock
199f3df3b58SRiver Riddle /// contention when an object already existing in the cache.
200f3df3b58SRiver Riddle ThreadLocalCache<StorageTypeSet> localCache;
201f3df3b58SRiver Riddle
20267f52f35SRiver Riddle /// A set of uniquer shards to allow for further bucketing accesses for
20367f52f35SRiver Riddle /// instances of this storage type. Each shard is lazily initialized to reduce
20467f52f35SRiver Riddle /// the overhead when only a small amount of shards are in use.
20567f52f35SRiver Riddle std::unique_ptr<std::atomic<Shard *>[]> shards;
206880df8f6SRiver Riddle
20767f52f35SRiver Riddle /// The number of available shards.
20867f52f35SRiver Riddle size_t numShards;
20967f52f35SRiver Riddle
21031bb8efdSRiver Riddle /// Function to used to destruct any allocated storage instances.
21131bb8efdSRiver Riddle function_ref<void(BaseStorage *)> destructorFn;
21231bb8efdSRiver Riddle
21367f52f35SRiver Riddle #else
21467f52f35SRiver Riddle /// If multi-threading is disabled, ignore the shard parameter as we will
21531bb8efdSRiver Riddle /// always use one shard. The destructor function is used to destroy any
21631bb8efdSRiver Riddle /// allocated storage instances.
21731bb8efdSRiver Riddle ParametricStorageUniquer(function_ref<void(BaseStorage *)> destructorFn,
21831bb8efdSRiver Riddle size_t numShards = 0)
21931bb8efdSRiver Riddle : destructorFn(destructorFn) {}
22031bb8efdSRiver Riddle ~ParametricStorageUniquer() { destroyShardInstances(shard); }
22167f52f35SRiver Riddle
22267f52f35SRiver Riddle /// Get or create an instance of a parametric type.
22367f52f35SRiver Riddle BaseStorage *
22467f52f35SRiver Riddle getOrCreate(bool threadingIsEnabled, unsigned hashValue,
22567f52f35SRiver Riddle function_ref<bool(const BaseStorage *)> isEqual,
226*ceff9524SAlexandre Ganea function_ref<BaseStorage *()> ctorFn) {
22767f52f35SRiver Riddle ParametricStorageUniquer::LookupKey lookupKey{hashValue, isEqual};
22867f52f35SRiver Riddle return getOrCreateUnsafe(shard, lookupKey, ctorFn);
22967f52f35SRiver Riddle }
23067f52f35SRiver Riddle /// Run a mutation function on the provided storage object in a thread-safe
23167f52f35SRiver Riddle /// way.
23267f52f35SRiver Riddle LogicalResult
23367f52f35SRiver Riddle mutate(bool threadingIsEnabled, BaseStorage *storage,
234*ceff9524SAlexandre Ganea function_ref<LogicalResult()> mutationFn) {
235*ceff9524SAlexandre Ganea return mutationFn();
23667f52f35SRiver Riddle }
23767f52f35SRiver Riddle
23867f52f35SRiver Riddle private:
23967f52f35SRiver Riddle /// The main uniquer shard that is used for allocating storage instances.
24067f52f35SRiver Riddle Shard shard;
24131bb8efdSRiver Riddle
24231bb8efdSRiver Riddle /// Function to used to destruct any allocated storage instances.
24331bb8efdSRiver Riddle function_ref<void(BaseStorage *)> destructorFn;
24467f52f35SRiver Riddle #endif
24586646be3SRiver Riddle };
246be0a7e9fSMehdi Amini } // namespace
24786646be3SRiver Riddle
24886646be3SRiver Riddle namespace mlir {
24986646be3SRiver Riddle namespace detail {
25086646be3SRiver Riddle /// This is the implementation of the StorageUniquer class.
25186646be3SRiver Riddle struct StorageUniquerImpl {
25286646be3SRiver Riddle using BaseStorage = StorageUniquer::BaseStorage;
25386646be3SRiver Riddle using StorageAllocator = StorageUniquer::StorageAllocator;
25486646be3SRiver Riddle
255250f43d3SRiver Riddle //===--------------------------------------------------------------------===//
256250f43d3SRiver Riddle // Parametric Storage
257250f43d3SRiver Riddle //===--------------------------------------------------------------------===//
258250f43d3SRiver Riddle
25997e77ac0SMehdi Amini /// Check if an instance of a parametric storage class exists.
hasParametricStoragemlir::detail::StorageUniquerImpl26097e77ac0SMehdi Amini bool hasParametricStorage(TypeID id) { return parametricUniquers.count(id); }
26197e77ac0SMehdi Amini
262250f43d3SRiver Riddle /// Get or create an instance of a parametric type.
26386646be3SRiver Riddle BaseStorage *
getOrCreatemlir::detail::StorageUniquerImpl264250f43d3SRiver Riddle getOrCreate(TypeID id, unsigned hashValue,
26586646be3SRiver Riddle function_ref<bool(const BaseStorage *)> isEqual,
26686646be3SRiver Riddle function_ref<BaseStorage *(StorageAllocator &)> ctorFn) {
267250f43d3SRiver Riddle assert(parametricUniquers.count(id) &&
268250f43d3SRiver Riddle "creating unregistered storage instance");
269250f43d3SRiver Riddle ParametricStorageUniquer &storageUniquer = *parametricUniquers[id];
2709f991ed3SRiver Riddle return storageUniquer.getOrCreate(
2719f991ed3SRiver Riddle threadingIsEnabled, hashValue, isEqual,
2729f991ed3SRiver Riddle [&] { return ctorFn(getThreadSafeAllocator()); });
27386646be3SRiver Riddle }
27486646be3SRiver Riddle
27567f52f35SRiver Riddle /// Run a mutation function on the provided storage object in a thread-safe
27667f52f35SRiver Riddle /// way.
27786646be3SRiver Riddle LogicalResult
mutatemlir::detail::StorageUniquerImpl27867f52f35SRiver Riddle mutate(TypeID id, BaseStorage *storage,
27986646be3SRiver Riddle function_ref<LogicalResult(StorageAllocator &)> mutationFn) {
280250f43d3SRiver Riddle assert(parametricUniquers.count(id) &&
281250f43d3SRiver Riddle "mutating unregistered storage instance");
282250f43d3SRiver Riddle ParametricStorageUniquer &storageUniquer = *parametricUniquers[id];
2839f991ed3SRiver Riddle return storageUniquer.mutate(threadingIsEnabled, storage, [&] {
2849f991ed3SRiver Riddle return mutationFn(getThreadSafeAllocator());
2859f991ed3SRiver Riddle });
2869f991ed3SRiver Riddle }
2879f991ed3SRiver Riddle
2889f991ed3SRiver Riddle /// Return an allocator that can be used to safely allocate instances on the
2899f991ed3SRiver Riddle /// current thread.
getThreadSafeAllocatormlir::detail::StorageUniquerImpl2909f991ed3SRiver Riddle StorageAllocator &getThreadSafeAllocator() {
2919f991ed3SRiver Riddle #if LLVM_ENABLE_THREADS != 0
2929f991ed3SRiver Riddle if (!threadingIsEnabled)
2939f991ed3SRiver Riddle return allocator;
2949f991ed3SRiver Riddle
2959f991ed3SRiver Riddle // If the allocator has not been initialized, create a new one.
2969f991ed3SRiver Riddle StorageAllocator *&threadAllocator = threadSafeAllocator.get();
2979f991ed3SRiver Riddle if (!threadAllocator) {
2989f991ed3SRiver Riddle threadAllocator = new StorageAllocator();
2999f991ed3SRiver Riddle
3009f991ed3SRiver Riddle // Record this allocator, given that we don't want it to be destroyed when
3019f991ed3SRiver Riddle // the thread dies.
3029f991ed3SRiver Riddle llvm::sys::SmartScopedLock<true> lock(threadAllocatorMutex);
3039f991ed3SRiver Riddle threadAllocators.push_back(
3049f991ed3SRiver Riddle std::unique_ptr<StorageAllocator>(threadAllocator));
3059f991ed3SRiver Riddle }
3069f991ed3SRiver Riddle
3079f991ed3SRiver Riddle return *threadAllocator;
3089f991ed3SRiver Riddle #else
3099f991ed3SRiver Riddle return allocator;
3109f991ed3SRiver Riddle #endif
31186646be3SRiver Riddle }
31286646be3SRiver Riddle
31386646be3SRiver Riddle //===--------------------------------------------------------------------===//
314250f43d3SRiver Riddle // Singleton Storage
315250f43d3SRiver Riddle //===--------------------------------------------------------------------===//
316250f43d3SRiver Riddle
317250f43d3SRiver Riddle /// Get or create an instance of a singleton storage class.
getSingletonmlir::detail::StorageUniquerImpl318250f43d3SRiver Riddle BaseStorage *getSingleton(TypeID id) {
319250f43d3SRiver Riddle BaseStorage *singletonInstance = singletonInstances[id];
320250f43d3SRiver Riddle assert(singletonInstance && "expected singleton instance to exist");
321250f43d3SRiver Riddle return singletonInstance;
322250f43d3SRiver Riddle }
323250f43d3SRiver Riddle
32497e77ac0SMehdi Amini /// Check if an instance of a singleton storage class exists.
hasSingletonmlir::detail::StorageUniquerImpl32567f52f35SRiver Riddle bool hasSingleton(TypeID id) const { return singletonInstances.count(id); }
32697e77ac0SMehdi Amini
327250f43d3SRiver Riddle //===--------------------------------------------------------------------===//
32886646be3SRiver Riddle // Instance Storage
32986646be3SRiver Riddle //===--------------------------------------------------------------------===//
33086646be3SRiver Riddle
3319f991ed3SRiver Riddle #if LLVM_ENABLE_THREADS != 0
3329f991ed3SRiver Riddle /// A thread local set of allocators used for uniquing parametric instances,
3339f991ed3SRiver Riddle /// or other data allocated in thread volatile situations.
3349f991ed3SRiver Riddle ThreadLocalCache<StorageAllocator *> threadSafeAllocator;
3359f991ed3SRiver Riddle
3369f991ed3SRiver Riddle /// All of the allocators that have been created for thread based allocation.
3379f991ed3SRiver Riddle std::vector<std::unique_ptr<StorageAllocator>> threadAllocators;
3389f991ed3SRiver Riddle
3399f991ed3SRiver Riddle /// A mutex used for safely adding a new thread allocator.
3409f991ed3SRiver Riddle llvm::sys::SmartMutex<true> threadAllocatorMutex;
3419f991ed3SRiver Riddle #endif
3429f991ed3SRiver Riddle
3439f991ed3SRiver Riddle /// Main allocator used for uniquing singleton instances, and other state when
3449f991ed3SRiver Riddle /// thread safety is guaranteed.
3459f991ed3SRiver Riddle StorageAllocator allocator;
3469f991ed3SRiver Riddle
34786646be3SRiver Riddle /// Map of type ids to the storage uniquer to use for registered objects.
348250f43d3SRiver Riddle DenseMap<TypeID, std::unique_ptr<ParametricStorageUniquer>>
349250f43d3SRiver Riddle parametricUniquers;
350250f43d3SRiver Riddle
351250f43d3SRiver Riddle /// Map of type ids to a singleton instance when the storage class is a
352250f43d3SRiver Riddle /// singleton.
353250f43d3SRiver Riddle DenseMap<TypeID, BaseStorage *> singletonInstances;
354250f43d3SRiver Riddle
355cb9ae002SRiver Riddle /// Flag specifying if multi-threading is enabled within the uniquer.
356cb9ae002SRiver Riddle bool threadingIsEnabled = true;
357880df8f6SRiver Riddle };
358be0a7e9fSMehdi Amini } // namespace detail
359880df8f6SRiver Riddle } // namespace mlir
360880df8f6SRiver Riddle
StorageUniquer()361880df8f6SRiver Riddle StorageUniquer::StorageUniquer() : impl(new StorageUniquerImpl()) {}
362e5639b3fSMehdi Amini StorageUniquer::~StorageUniquer() = default;
363880df8f6SRiver Riddle
364cb9ae002SRiver Riddle /// Set the flag specifying if multi-threading is disabled within the uniquer.
disableMultithreading(bool disable)365cb9ae002SRiver Riddle void StorageUniquer::disableMultithreading(bool disable) {
366cb9ae002SRiver Riddle impl->threadingIsEnabled = !disable;
367cb9ae002SRiver Riddle }
368cb9ae002SRiver Riddle
369880df8f6SRiver Riddle /// Implementation for getting/creating an instance of a derived type with
370250f43d3SRiver Riddle /// parametric storage.
getParametricStorageTypeImpl(TypeID id,unsigned hashValue,function_ref<bool (const BaseStorage *)> isEqual,function_ref<BaseStorage * (StorageAllocator &)> ctorFn)371250f43d3SRiver Riddle auto StorageUniquer::getParametricStorageTypeImpl(
372250f43d3SRiver Riddle TypeID id, unsigned hashValue,
3734562e389SRiver Riddle function_ref<bool(const BaseStorage *)> isEqual,
3741fc6efafSRiver Riddle function_ref<BaseStorage *(StorageAllocator &)> ctorFn) -> BaseStorage * {
375250f43d3SRiver Riddle return impl->getOrCreate(id, hashValue, isEqual, ctorFn);
376880df8f6SRiver Riddle }
377880df8f6SRiver Riddle
378250f43d3SRiver Riddle /// Implementation for registering an instance of a derived type with
379250f43d3SRiver Riddle /// parametric storage.
registerParametricStorageTypeImpl(TypeID id,function_ref<void (BaseStorage *)> destructorFn)38031bb8efdSRiver Riddle void StorageUniquer::registerParametricStorageTypeImpl(
38131bb8efdSRiver Riddle TypeID id, function_ref<void(BaseStorage *)> destructorFn) {
382250f43d3SRiver Riddle impl->parametricUniquers.try_emplace(
38331bb8efdSRiver Riddle id, std::make_unique<ParametricStorageUniquer>(destructorFn));
384880df8f6SRiver Riddle }
3850f89ef30SRiver Riddle
386250f43d3SRiver Riddle /// Implementation for getting an instance of a derived type with default
3870f89ef30SRiver Riddle /// storage.
getSingletonImpl(TypeID id)388250f43d3SRiver Riddle auto StorageUniquer::getSingletonImpl(TypeID id) -> BaseStorage * {
389250f43d3SRiver Riddle return impl->getSingleton(id);
390250f43d3SRiver Riddle }
391250f43d3SRiver Riddle
39297e77ac0SMehdi Amini /// Test is the storage singleton is initialized.
isSingletonStorageInitialized(TypeID id)39397e77ac0SMehdi Amini bool StorageUniquer::isSingletonStorageInitialized(TypeID id) {
39497e77ac0SMehdi Amini return impl->hasSingleton(id);
39597e77ac0SMehdi Amini }
39697e77ac0SMehdi Amini
39797e77ac0SMehdi Amini /// Test is the parametric storage is initialized.
isParametricStorageInitialized(TypeID id)39897e77ac0SMehdi Amini bool StorageUniquer::isParametricStorageInitialized(TypeID id) {
39997e77ac0SMehdi Amini return impl->hasParametricStorage(id);
40097e77ac0SMehdi Amini }
40197e77ac0SMehdi Amini
402250f43d3SRiver Riddle /// Implementation for registering an instance of a derived type with default
403250f43d3SRiver Riddle /// storage.
registerSingletonImpl(TypeID id,function_ref<BaseStorage * (StorageAllocator &)> ctorFn)404250f43d3SRiver Riddle void StorageUniquer::registerSingletonImpl(
405250f43d3SRiver Riddle TypeID id, function_ref<BaseStorage *(StorageAllocator &)> ctorFn) {
406250f43d3SRiver Riddle assert(!impl->singletonInstances.count(id) &&
407250f43d3SRiver Riddle "storage class already registered");
4089f991ed3SRiver Riddle impl->singletonInstances.try_emplace(id, ctorFn(impl->allocator));
409250f43d3SRiver Riddle }
410250f43d3SRiver Riddle
411a5182991SAlex Zinenko /// Implementation for mutating an instance of a derived storage.
mutateImpl(TypeID id,BaseStorage * storage,function_ref<LogicalResult (StorageAllocator &)> mutationFn)412a5182991SAlex Zinenko LogicalResult StorageUniquer::mutateImpl(
41367f52f35SRiver Riddle TypeID id, BaseStorage *storage,
41467f52f35SRiver Riddle function_ref<LogicalResult(StorageAllocator &)> mutationFn) {
41567f52f35SRiver Riddle return impl->mutate(id, storage, mutationFn);
416a5182991SAlex Zinenko }
417