[mlir] Update Attributes to use the new casting infra
authorRiver Riddle <riddleriver@gmail.com>
Tue, 20 Sep 2022 23:42:59 +0000 (16:42 -0700)
committerRiver Riddle <riddleriver@gmail.com>
Wed, 21 Sep 2022 06:45:33 +0000 (23:45 -0700)
This allows for using the llvm namespace cast methods instead
of the ones on the Attribute class. The Attribute class methods
are kept for now, but we'll want to remove these eventually
(with a really long lead time).

Differential Revision: https://reviews.llvm.org/D134327

mlir/include/mlir/IR/Attributes.h

index 50738b2..6200fd1 100644 (file)
@@ -47,11 +47,11 @@ public:
 
   bool operator!() const { return impl == nullptr; }
 
-  template <typename U>
-  bool isa() const;
-  template <typename First, typename Second, typename... Rest>
+  /// Casting utility functions. These are deprecated and will be removed,
+  /// please prefer using the `llvm` namespace variants instead.
+  template <typename... Tys>
   bool isa() const;
-  template <typename First, typename... Rest>
+  template <typename... Tys>
   bool isa_and_nonnull() const;
   template <typename U>
   U dyn_cast() const;
@@ -100,6 +100,9 @@ public:
     return impl->getAbstractAttribute();
   }
 
+  /// Return the internal Attribute implementation.
+  ImplType *getImpl() const { return impl; }
+
 protected:
   ImplType *impl{nullptr};
 };
@@ -109,34 +112,29 @@ inline raw_ostream &operator<<(raw_ostream &os, Attribute attr) {
   return os;
 }
 
-template <typename U>
-bool Attribute::isa() const {
-  assert(impl && "isa<> used on a null attribute.");
-  return U::classof(*this);
-}
-
-template <typename First, typename Second, typename... Rest>
+template <typename... Tys>
 bool Attribute::isa() const {
-  return isa<First>() || isa<Second, Rest...>();
+  return llvm::isa<Tys...>(*this);
 }
 
-template <typename First, typename... Rest>
+template <typename... Tys>
 bool Attribute::isa_and_nonnull() const {
-  return impl && isa<First, Rest...>();
+  return llvm::isa_and_present<Tys...>(*this);
 }
 
 template <typename U>
 U Attribute::dyn_cast() const {
-  return isa<U>() ? U(impl) : U(nullptr);
+  return llvm::dyn_cast<U>(*this);
 }
+
 template <typename U>
 U Attribute::dyn_cast_or_null() const {
-  return (impl && isa<U>()) ? U(impl) : U(nullptr);
+  return llvm::dyn_cast_if_present<U>(*this);
 }
+
 template <typename U>
 U Attribute::cast() const {
-  assert(isa<U>());
-  return U(impl);
+  return llvm::cast<U>(*this);
 }
 
 inline ::llvm::hash_code hash_value(Attribute arg) {
@@ -318,6 +316,31 @@ struct DenseMapInfo<mlir::NamedAttribute> {
   }
 };
 
+/// Add support for llvm style casts. We provide a cast between To and From if
+/// From is mlir::Attribute or derives from it.
+template <typename To, typename From>
+struct CastInfo<To, From,
+                std::enable_if_t<std::is_same_v<mlir::Attribute,
+                                                std::remove_const_t<From>> ||
+                                 std::is_base_of_v<mlir::Attribute, From>>>
+    : NullableValueCastFailed<To>,
+      DefaultDoCastIfPossible<To, From, CastInfo<To, From>> {
+  /// Arguments are taken as mlir::Attribute here and not as `From`, because
+  /// when casting from an intermediate type of the hierarchy to one of its
+  /// children, the val.getTypeID() inside T::classof will use the static
+  /// getTypeID of the parent instead of the non-static Type::getTypeID that
+  /// returns the dynamic ID. This means that T::classof would end up comparing
+  /// the static TypeID of the children to the static TypeID of its parent,
+  /// making it impossible to downcast from the parent to the child.
+  static inline bool isPossible(mlir::Attribute ty) {
+    /// Return a constant true instead of a dynamic true when casting to self or
+    /// up the hierarchy.
+    return std::is_same_v<To, std::remove_const_t<From>> ||
+           std::is_base_of_v<To, From> || To::classof(ty);
+  }
+  static inline To doCast(mlir::Attribute attr) { return To(attr.getImpl()); }
+};
+
 } // namespace llvm
 
 #endif