From 880df8f6ad8d801d2d3fd761d25d69b059f3f4da Mon Sep 17 00:00:00 2001 From: River Riddle Date: Thu, 25 Apr 2019 21:01:21 -0700 Subject: [PATCH] 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 --- mlir/include/mlir/IR/MLIRContext.h | 9 +- mlir/include/mlir/IR/TypeSupport.h | 189 +++------------------- mlir/include/mlir/IR/Types.h | 5 +- mlir/include/mlir/Support/StorageUniquer.h | 252 +++++++++++++++++++++++++++++ mlir/lib/IR/MLIRContext.cpp | 128 +-------------- mlir/lib/Support/CMakeLists.txt | 1 + mlir/lib/Support/StorageUniquer.cpp | 181 +++++++++++++++++++++ 7 files changed, 468 insertions(+), 297 deletions(-) create mode 100644 mlir/include/mlir/Support/StorageUniquer.h create mode 100644 mlir/lib/Support/StorageUniquer.cpp diff --git a/mlir/include/mlir/IR/MLIRContext.h b/mlir/include/mlir/IR/MLIRContext.h index 85eb62d..ed2640d 100644 --- a/mlir/include/mlir/IR/MLIRContext.h +++ b/mlir/include/mlir/IR/MLIRContext.h @@ -25,9 +25,10 @@ namespace mlir { class AbstractOperation; -class MLIRContextImpl; -class Location; class Dialect; +class Location; +class MLIRContextImpl; +class StorageUniquer; /// MLIRContext is the top-level object for a collection of MLIR modules. It /// holds immortal uniqued objects like types, and the tables used to unique @@ -93,6 +94,10 @@ public: // MLIRContextImpl type. MLIRContextImpl &getImpl() { return *impl.get(); } + /// Returns the storage uniquer used for constructing type storage instances. + /// This should not be used directly. + StorageUniquer &getTypeUniquer(); + private: const std::unique_ptr impl; diff --git a/mlir/include/mlir/IR/TypeSupport.h b/mlir/include/mlir/IR/TypeSupport.h index 3c6c877..f174d6d 100644 --- a/mlir/include/mlir/IR/TypeSupport.h +++ b/mlir/include/mlir/IR/TypeSupport.h @@ -23,9 +23,7 @@ #define MLIR_IR_TYPE_SUPPORT_H #include "mlir/IR/MLIRContext.h" -#include "mlir/Support/LLVM.h" -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/DenseSet.h" +#include "mlir/Support/StorageUniquer.h" #include "llvm/ADT/StringRef.h" #include @@ -51,15 +49,16 @@ class TypeUniquer; } // end namespace detail /// Base storage class appearing in a Type. -class TypeStorage { +class TypeStorage : public StorageUniquer::BaseStorage { friend detail::TypeUniquer; + friend StorageUniquer; protected: /// This constructor is used by derived classes as part of the TypeUniquer. /// When using this constructor, the initializeTypeInfo function must be /// invoked afterwards for the storage to be valid. TypeStorage(unsigned subclassData = 0) - : dialect(nullptr), kind(0), subclassData(subclassData) {} + : dialect(nullptr), subclassData(subclassData) {} public: /// Get the dialect that this type is registered to. @@ -67,10 +66,6 @@ public: assert(dialect && "Malformed type storage object."); return *dialect; } - - /// Get the kind classification of this type. - unsigned getKind() const { return kind; } - /// Get the subclass data. unsigned getSubclassData() const { return subclassData; } @@ -78,25 +73,13 @@ public: void setSubclassData(unsigned val) { subclassData = val; } private: - // Constructor used for simple type storage that have no subclass data. This - // constructor should not be used by derived storage classes. - TypeStorage(const Dialect &dialect, unsigned kind) - : dialect(&dialect), kind(kind), subclassData(0) {} - - // Initialize an existing type storage with a kind and a context. This is used - // by the TypeUniquer when initializing a newly constructed derived type - // storage object. - void initializeTypeInfo(const Dialect &newDialect, unsigned newKind) { - dialect = &newDialect; - kind = newKind; - } + // Set the dialect for this storage instance. This is used by the TypeUniquer + // when initializing a newly constructed type storage object. + void initializeDialect(const Dialect &newDialect) { dialect = &newDialect; } /// The registered information for the current type. const Dialect *dialect; - /// Classification of the subclass, used for type checking. - unsigned kind; - /// Space for subclasses to store data. unsigned subclassData; }; @@ -111,37 +94,7 @@ using DefaultTypeStorage = TypeStorage; // This is a utility allocator used to allocate memory for instances of derived // Types. -class TypeStorageAllocator { -public: - /// Copy the specified array of elements into memory managed by our bump - /// pointer allocator. This assumes the elements are all PODs. - template ArrayRef copyInto(ArrayRef elements) { - if (elements.empty()) - return llvm::None; - auto result = allocator.Allocate(elements.size()); - std::uninitialized_copy(elements.begin(), elements.end(), result); - return ArrayRef(result, elements.size()); - } - - /// Copy the provided string into memory managed by our bump pointer - /// allocator. - StringRef copyInto(StringRef str) { - auto result = copyInto(ArrayRef(str.data(), str.size())); - return StringRef(result.data(), str.size()); - } - - // Allocate an instance of the provided type. - template T *allocate() { return allocator.Allocate(); } - - /// Allocate 'size' bytes of 'alignment' aligned memory. - void *allocate(size_t size, size_t alignment) { - return allocator.Allocate(size, alignment); - } - -private: - /// The raw allocator for type storage objects. - llvm::BumpPtrAllocator allocator; -}; +using TypeStorageAllocator = StorageUniquer::StorageAllocator; //===----------------------------------------------------------------------===// // TypeUniquer @@ -157,30 +110,13 @@ public: static typename std::enable_if< !std::is_same::value, T>::type get(MLIRContext *ctx, unsigned kind, Args &&... args) { + // Lookup an instance of this complex storage type. using ImplType = typename T::ImplType; - - // Construct a value of the derived key type. - auto derivedKey = getKey(args...); - - // Create a hash of the kind and the derived key. - unsigned hashValue = getHash(kind, derivedKey); - - // Generate an equality function for the derived storage. - std::function isEqual = - [&derivedKey](const TypeStorage *existing) { - return static_cast(*existing) == derivedKey; - }; - - // Generate a constructor function for the derived storage. - std::function constructorFn = - [&](TypeStorageAllocator &allocator) { - TypeStorage *storage = ImplType::construct(allocator, derivedKey); - storage->initializeTypeInfo(lookupDialectForType(ctx), kind); - return storage; - }; - - // Get an instance for the derived storage. - return T(getImpl(ctx, kind, hashValue, isEqual, constructorFn)); + return ctx->getTypeUniquer().getComplex( + [&](ImplType *storage) { + storage->initializeDialect(lookupDialectForType(ctx)); + }, + kind, std::forward(args)...); } /// Get an uniqued instance of a type T. This overload is used for derived @@ -190,27 +126,15 @@ public: static typename std::enable_if< std::is_same::value, T>::type get(MLIRContext *ctx, unsigned kind) { - auto constructorFn = [=](TypeStorageAllocator &allocator) { - return new (allocator.allocate()) - DefaultTypeStorage(lookupDialectForType(ctx), kind); - }; - return T(getImpl(ctx, kind, constructorFn)); + // Lookup an instance of this simple storage type. + return ctx->getTypeUniquer().getSimple( + [&](TypeStorage *storage) { + storage->initializeDialect(lookupDialectForType(ctx)); + }, + kind); } private: - /// Implementation for getting/creating an instance of a derived type with - /// complex storage. - static TypeStorage * - getImpl(MLIRContext *ctx, unsigned kind, unsigned hashValue, - llvm::function_ref isEqual, - std::function constructorFn); - - /// Implementation for getting/creating an instance of a derived type with - /// default storage. - static TypeStorage * - getImpl(MLIRContext *ctx, unsigned kind, - std::function constructorFn); - /// Get the dialect that the type 'T' was registered with. template static const Dialect &lookupDialectForType(MLIRContext *ctx) { @@ -220,79 +144,6 @@ private: /// Get the dialect that registered the type with the provided typeid. static const Dialect &lookupDialectForType(MLIRContext *ctx, const TypeID *const typeID); - - //===--------------------------------------------------------------------===// - // Util - //===--------------------------------------------------------------------===// - - /// Utilities for detecting if specific traits hold for a given type 'T'. - template using void_t = void; - template class Op, class... Args> - struct detector { - using value_t = std::false_type; - }; - template