xref: /llvm-project/mlir/include/mlir/IR/Value.h (revision fac349a169976f822fb27f03e623fa0d28aec1f3)
1 //===- Value.h - Base of the SSA Value hierarchy ----------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file defines generic Value type and manipulation utilities.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #ifndef MLIR_IR_VALUE_H
14 #define MLIR_IR_VALUE_H
15 
16 #include "mlir/IR/Types.h"
17 #include "mlir/IR/UseDefLists.h"
18 #include "mlir/Support/LLVM.h"
19 #include "llvm/Support/PointerLikeTypeTraits.h"
20 
21 namespace mlir {
22 class AsmState;
23 class Block;
24 class BlockArgument;
25 class Operation;
26 class OpOperand;
27 class OpPrintingFlags;
28 class OpResult;
29 class Region;
30 class Value;
31 
32 //===----------------------------------------------------------------------===//
33 // Value
34 //===----------------------------------------------------------------------===//
35 
36 namespace detail {
37 
38 /// The base class for all derived Value classes. It contains all of the
39 /// components that are shared across Value classes.
40 class alignas(8) ValueImpl : public IRObjectWithUseList<OpOperand> {
41 public:
42   /// The enumeration represents the various different kinds of values the
43   /// internal representation may take. We use all of the bits from Type that we
44   /// can to store indices inline.
45   enum class Kind {
46     /// The first N kinds are all inline operation results. An inline operation
47     /// result means that the kind represents the result number. This removes
48     /// the need to store an additional index value. The derived class here is
49     /// an `OpResultImpl`.
50     InlineOpResult = 0,
51 
52     /// The next kind represents a 'out-of-line' operation result. This is for
53     /// results with numbers larger than we can represent inline. The derived
54     /// class here is an `OpResultImpl`.
55     OutOfLineOpResult = 6,
56 
57     /// The last kind represents a block argument. The derived class here is an
58     /// `BlockArgumentImpl`.
59     BlockArgument = 7
60   };
61 
62   /// Return the type of this value.
getType()63   Type getType() const { return typeAndKind.getPointer(); }
64 
65   /// Set the type of this value.
setType(Type type)66   void setType(Type type) { return typeAndKind.setPointer(type); }
67 
68   /// Return the kind of this value.
getKind()69   Kind getKind() const { return typeAndKind.getInt(); }
70 
71 protected:
ValueImpl(Type type,Kind kind)72   ValueImpl(Type type, Kind kind) : typeAndKind(type, kind) {}
73 
74   /// Expose a few methods explicitly for the debugger to call for
75   /// visualization.
76 #ifndef NDEBUG
debug_getType()77   LLVM_DUMP_METHOD Type debug_getType() const { return getType(); }
debug_getKind()78   LLVM_DUMP_METHOD Kind debug_getKind() const { return getKind(); }
79 
80 #endif
81 
82   /// The type of this result and the kind.
83   llvm::PointerIntPair<Type, 3, Kind> typeAndKind;
84 };
85 } // namespace detail
86 
87 /// This class represents an instance of an SSA value in the MLIR system,
88 /// representing a computable value that has a type and a set of users. An SSA
89 /// value is either a BlockArgument or the result of an operation. Note: This
90 /// class has value-type semantics and is just a simple wrapper around a
91 /// ValueImpl that is either owner by a block(in the case of a BlockArgument) or
92 /// an Operation(in the case of an OpResult).
93 /// As most IR constructs, this isn't const-correct, but we keep method
94 /// consistent and as such method that immediately modify this Value aren't
95 /// marked `const` (include modifying the Value use-list).
96 class Value {
97 public:
impl(impl)98   constexpr Value(detail::ValueImpl *impl = nullptr) : impl(impl) {}
99 
100   template <typename U>
101   [[deprecated("Use mlir::isa<U>() instead")]]
isa()102   bool isa() const {
103     return llvm::isa<U>(*this);
104   }
105 
106   template <typename U>
107   [[deprecated("Use mlir::dyn_cast<U>() instead")]]
dyn_cast()108   U dyn_cast() const {
109     return llvm::dyn_cast<U>(*this);
110   }
111 
112   template <typename U>
113   [[deprecated("Use mlir::dyn_cast_or_null<U>() instead")]]
dyn_cast_or_null()114   U dyn_cast_or_null() const {
115     return llvm::dyn_cast_or_null<U>(*this);
116   }
117 
118   template <typename U>
119   [[deprecated("Use mlir::cast<U>() instead")]]
cast()120   U cast() const {
121     return llvm::cast<U>(*this);
122   }
123 
124   explicit operator bool() const { return impl; }
125   bool operator==(const Value &other) const { return impl == other.impl; }
126   bool operator!=(const Value &other) const { return !(*this == other); }
127 
128   /// Return the type of this value.
getType()129   Type getType() const { return impl->getType(); }
130 
131   /// Utility to get the associated MLIRContext that this value is defined in.
getContext()132   MLIRContext *getContext() const { return getType().getContext(); }
133 
134   /// Mutate the type of this Value to be of the specified type.
135   ///
136   /// Note that this is an extremely dangerous operation which can create
137   /// completely invalid IR very easily.  It is strongly recommended that you
138   /// recreate IR objects with the right types instead of mutating them in
139   /// place.
setType(Type newType)140   void setType(Type newType) { impl->setType(newType); }
141 
142   /// If this value is the result of an operation, return the operation that
143   /// defines it.
144   Operation *getDefiningOp() const;
145 
146   /// If this value is the result of an operation of type OpTy, return the
147   /// operation that defines it.
148   template <typename OpTy>
getDefiningOp()149   OpTy getDefiningOp() const {
150     return llvm::dyn_cast_or_null<OpTy>(getDefiningOp());
151   }
152 
153   /// Return the location of this value.
154   Location getLoc() const;
155   void setLoc(Location loc);
156 
157   /// Return the Region in which this Value is defined.
158   Region *getParentRegion();
159 
160   /// Return the Block in which this Value is defined.
161   Block *getParentBlock();
162 
163   //===--------------------------------------------------------------------===//
164   // UseLists
165   //===--------------------------------------------------------------------===//
166 
167   /// Drop all uses of this object from their respective owners.
dropAllUses()168   void dropAllUses() { return impl->dropAllUses(); }
169 
170   /// Replace all uses of 'this' value with the new value, updating anything in
171   /// the IR that uses 'this' to use the other value instead.  When this returns
172   /// there are zero uses of 'this'.
replaceAllUsesWith(Value newValue)173   void replaceAllUsesWith(Value newValue) {
174     impl->replaceAllUsesWith(newValue);
175   }
176 
177   /// Replace all uses of 'this' value with 'newValue', updating anything in the
178   /// IR that uses 'this' to use the other value instead except if the user is
179   /// listed in 'exceptions' .
180   void replaceAllUsesExcept(Value newValue,
181                             const SmallPtrSetImpl<Operation *> &exceptions);
182 
183   /// Replace all uses of 'this' value with 'newValue', updating anything in the
184   /// IR that uses 'this' to use the other value instead except if the user is
185   /// 'exceptedUser'.
186   void replaceAllUsesExcept(Value newValue, Operation *exceptedUser);
187 
188   /// Replace all uses of 'this' value with 'newValue' if the given callback
189   /// returns true.
190   void replaceUsesWithIf(Value newValue,
191                          function_ref<bool(OpOperand &)> shouldReplace);
192 
193   /// Returns true if the value is used outside of the given block.
194   bool isUsedOutsideOfBlock(Block *block) const;
195 
196   /// Shuffle the use list order according to the provided indices. It is
197   /// responsibility of the caller to make sure that the indices map the current
198   /// use-list chain to another valid use-list chain.
199   void shuffleUseList(ArrayRef<unsigned> indices);
200 
201   //===--------------------------------------------------------------------===//
202   // Uses
203 
204   /// This class implements an iterator over the uses of a value.
205   using use_iterator = ValueUseIterator<OpOperand>;
206   using use_range = iterator_range<use_iterator>;
207 
use_begin()208   use_iterator use_begin() const { return impl->use_begin(); }
use_end()209   use_iterator use_end() const { return use_iterator(); }
210 
211   /// Returns a range of all uses, which is useful for iterating over all uses.
getUses()212   use_range getUses() const { return {use_begin(), use_end()}; }
213 
214   /// Returns true if this value has exactly one use.
hasOneUse()215   bool hasOneUse() const { return impl->hasOneUse(); }
216 
217   /// Returns true if this value has no uses.
use_empty()218   bool use_empty() const { return impl->use_empty(); }
219 
220   //===--------------------------------------------------------------------===//
221   // Users
222 
223   using user_iterator = ValueUserIterator<use_iterator, OpOperand>;
224   using user_range = iterator_range<user_iterator>;
225 
user_begin()226   user_iterator user_begin() const { return use_begin(); }
user_end()227   user_iterator user_end() const { return use_end(); }
getUsers()228   user_range getUsers() const { return {user_begin(), user_end()}; }
229 
230   //===--------------------------------------------------------------------===//
231   // Utilities
232 
233   void print(raw_ostream &os) const;
234   void print(raw_ostream &os, const OpPrintingFlags &flags) const;
235   void print(raw_ostream &os, AsmState &state) const;
236   void dump() const;
237 
238   /// Print this value as if it were an operand.
239   void printAsOperand(raw_ostream &os, AsmState &state) const;
240   void printAsOperand(raw_ostream &os, const OpPrintingFlags &flags) const;
241 
242   /// Methods for supporting PointerLikeTypeTraits.
getAsOpaquePointer()243   void *getAsOpaquePointer() const { return impl; }
getFromOpaquePointer(const void * pointer)244   static Value getFromOpaquePointer(const void *pointer) {
245     return reinterpret_cast<detail::ValueImpl *>(const_cast<void *>(pointer));
246   }
getImpl()247   detail::ValueImpl *getImpl() const { return impl; }
248 
249   friend ::llvm::hash_code hash_value(Value arg);
250 
251 protected:
252   /// A pointer to the internal implementation of the value.
253   detail::ValueImpl *impl;
254 };
255 
256 inline raw_ostream &operator<<(raw_ostream &os, Value value) {
257   value.print(os);
258   return os;
259 }
260 
261 //===----------------------------------------------------------------------===//
262 // OpOperand
263 //===----------------------------------------------------------------------===//
264 
265 /// This class represents an operand of an operation. Instances of this class
266 /// contain a reference to a specific `Value`.
267 class OpOperand : public IROperand<OpOperand, Value> {
268 public:
269   /// Provide the use list that is attached to the given value.
getUseList(Value value)270   static IRObjectWithUseList<OpOperand> *getUseList(Value value) {
271     return value.getImpl();
272   }
273 
274   /// Return which operand this is in the OpOperand list of the Operation.
275   unsigned getOperandNumber();
276 
277   /// Set the current value being used by this operand.
assign(Value value)278   void assign(Value value) { set(value); }
279 
280 private:
281   /// Keep the constructor private and accessible to the OperandStorage class
282   /// only to avoid hard-to-debug typo/programming mistakes.
283   friend class OperandStorage;
284   using IROperand<OpOperand, Value>::IROperand;
285 };
286 
287 //===----------------------------------------------------------------------===//
288 // BlockArgument
289 //===----------------------------------------------------------------------===//
290 
291 namespace detail {
292 /// The internal implementation of a BlockArgument.
293 class BlockArgumentImpl : public ValueImpl {
294 public:
classof(const ValueImpl * value)295   static bool classof(const ValueImpl *value) {
296     return value->getKind() == ValueImpl::Kind::BlockArgument;
297   }
298 
299 private:
BlockArgumentImpl(Type type,Block * owner,int64_t index,Location loc)300   BlockArgumentImpl(Type type, Block *owner, int64_t index, Location loc)
301       : ValueImpl(type, Kind::BlockArgument), owner(owner), index(index),
302         loc(loc) {}
303 
304   /// The owner of this argument.
305   Block *owner;
306 
307   /// The position in the argument list.
308   int64_t index;
309 
310   /// The source location of this argument.
311   Location loc;
312 
313   /// Allow access to owner and constructor.
314   friend BlockArgument;
315 };
316 } // namespace detail
317 
318 /// This class represents an argument of a Block.
319 class BlockArgument : public Value {
320 public:
321   using Value::Value;
322 
classof(Value value)323   static bool classof(Value value) {
324     return llvm::isa<detail::BlockArgumentImpl>(value.getImpl());
325   }
326 
327   /// Returns the block that owns this argument.
getOwner()328   Block *getOwner() const { return getImpl()->owner; }
329 
330   /// Returns the number of this argument.
getArgNumber()331   unsigned getArgNumber() const { return getImpl()->index; }
332 
333   /// Return the location for this argument.
getLoc()334   Location getLoc() const { return getImpl()->loc; }
setLoc(Location loc)335   void setLoc(Location loc) { getImpl()->loc = loc; }
336 
337 private:
338   /// Allocate a new argument with the given type and owner.
create(Type type,Block * owner,int64_t index,Location loc)339   static BlockArgument create(Type type, Block *owner, int64_t index,
340                               Location loc) {
341     return new detail::BlockArgumentImpl(type, owner, index, loc);
342   }
343 
344   /// Destroy and deallocate this argument.
destroy()345   void destroy() { delete getImpl(); }
346 
347   /// Get a raw pointer to the internal implementation.
getImpl()348   detail::BlockArgumentImpl *getImpl() const {
349     return reinterpret_cast<detail::BlockArgumentImpl *>(impl);
350   }
351 
352   /// Cache the position in the block argument list.
setArgNumber(int64_t index)353   void setArgNumber(int64_t index) { getImpl()->index = index; }
354 
355   /// Allow access to `create`, `destroy` and `setArgNumber`.
356   friend Block;
357 
358   /// Allow access to 'getImpl'.
359   friend Value;
360 };
361 
362 //===----------------------------------------------------------------------===//
363 // OpResult
364 //===----------------------------------------------------------------------===//
365 
366 namespace detail {
367 /// This class provides the implementation for an operation result.
368 class alignas(8) OpResultImpl : public ValueImpl {
369 public:
370   using ValueImpl::ValueImpl;
371 
classof(const ValueImpl * value)372   static bool classof(const ValueImpl *value) {
373     return value->getKind() != ValueImpl::Kind::BlockArgument;
374   }
375 
376   /// Returns the parent operation of this result.
377   Operation *getOwner() const;
378 
379   /// Returns the result number of this op result.
380   unsigned getResultNumber() const;
381 
382   /// Returns the next operation result at `offset` after this result. This
383   /// method is useful when indexing the result storage of an operation, given
384   /// that there is more than one kind of operation result (with the different
385   /// kinds having different sizes) and that operations are stored in reverse
386   /// order.
387   OpResultImpl *getNextResultAtOffset(intptr_t offset);
388 
389   /// Returns the maximum number of results that can be stored inline.
getMaxInlineResults()390   static unsigned getMaxInlineResults() {
391     return static_cast<unsigned>(Kind::OutOfLineOpResult);
392   }
393 };
394 
395 /// This class provides the implementation for an operation result whose index
396 /// can be represented "inline" in the underlying ValueImpl.
397 struct InlineOpResult : public OpResultImpl {
398 public:
InlineOpResultInlineOpResult399   InlineOpResult(Type type, unsigned resultNo)
400       : OpResultImpl(type, static_cast<ValueImpl::Kind>(resultNo)) {
401     assert(resultNo < getMaxInlineResults());
402   }
403 
404   /// Return the result number of this op result.
getResultNumberInlineOpResult405   unsigned getResultNumber() const { return static_cast<unsigned>(getKind()); }
406 
classofInlineOpResult407   static bool classof(const OpResultImpl *value) {
408     return value->getKind() != ValueImpl::Kind::OutOfLineOpResult;
409   }
410 };
411 
412 /// This class provides the implementation for an operation result whose index
413 /// cannot be represented "inline", and thus requires an additional index field.
414 class OutOfLineOpResult : public OpResultImpl {
415 public:
OutOfLineOpResult(Type type,uint64_t outOfLineIndex)416   OutOfLineOpResult(Type type, uint64_t outOfLineIndex)
417       : OpResultImpl(type, Kind::OutOfLineOpResult),
418         outOfLineIndex(outOfLineIndex) {}
419 
classof(const OpResultImpl * value)420   static bool classof(const OpResultImpl *value) {
421     return value->getKind() == ValueImpl::Kind::OutOfLineOpResult;
422   }
423 
424   /// Return the result number of this op result.
getResultNumber()425   unsigned getResultNumber() const {
426     return outOfLineIndex + getMaxInlineResults();
427   }
428 
429   /// The trailing result number, or the offset from the beginning of the
430   /// `OutOfLineOpResult` array.
431   uint64_t outOfLineIndex;
432 };
433 
434 /// Return the result number of this op result.
getResultNumber()435 inline unsigned OpResultImpl::getResultNumber() const {
436   if (const auto *outOfLineResult = dyn_cast<OutOfLineOpResult>(this))
437     return outOfLineResult->getResultNumber();
438   return cast<InlineOpResult>(this)->getResultNumber();
439 }
440 
441 /// TypedValue is a Value with a statically know type.
442 /// TypedValue can be null/empty
443 template <typename Ty>
444 struct TypedValue : Value {
445   using Value::Value;
446 
classofTypedValue447   static bool classof(Value value) { return llvm::isa<Ty>(value.getType()); }
448 
449   /// Return the known Type
getTypeTypedValue450   Ty getType() const { return llvm::cast<Ty>(Value::getType()); }
setTypeTypedValue451   void setType(Ty ty) { Value::setType(ty); }
452 };
453 
454 } // namespace detail
455 
456 /// This is a value defined by a result of an operation.
457 class OpResult : public Value {
458 public:
459   using Value::Value;
460 
classof(Value value)461   static bool classof(Value value) {
462     return llvm::isa<detail::OpResultImpl>(value.getImpl());
463   }
464 
465   /// Returns the operation that owns this result.
getOwner()466   Operation *getOwner() const { return getImpl()->getOwner(); }
467 
468   /// Returns the number of this result.
getResultNumber()469   unsigned getResultNumber() const { return getImpl()->getResultNumber(); }
470 
471 private:
472   /// Get a raw pointer to the internal implementation.
getImpl()473   detail::OpResultImpl *getImpl() const {
474     return reinterpret_cast<detail::OpResultImpl *>(impl);
475   }
476 
477   /// Given a number of operation results, returns the number that need to be
478   /// stored inline.
479   static unsigned getNumInline(unsigned numResults);
480 
481   /// Given a number of operation results, returns the number that need to be
482   /// stored as trailing.
483   static unsigned getNumTrailing(unsigned numResults);
484 
485   /// Allow access to constructor.
486   friend Operation;
487 };
488 
489 /// Make Value hashable.
hash_value(Value arg)490 inline ::llvm::hash_code hash_value(Value arg) {
491   return ::llvm::hash_value(arg.getImpl());
492 }
493 
494 template <typename Ty, typename Value = mlir::Value>
495 /// If Ty is mlir::Type this will select `Value` instead of having a wrapper
496 /// around it. This helps resolve ambiguous conversion issues.
497 using TypedValue = std::conditional_t<std::is_same_v<Ty, mlir::Type>,
498                                       mlir::Value, detail::TypedValue<Ty>>;
499 
500 } // namespace mlir
501 
502 namespace llvm {
503 
504 template <>
505 struct DenseMapInfo<mlir::Value> {
506   static mlir::Value getEmptyKey() {
507     void *pointer = llvm::DenseMapInfo<void *>::getEmptyKey();
508     return mlir::Value::getFromOpaquePointer(pointer);
509   }
510   static mlir::Value getTombstoneKey() {
511     void *pointer = llvm::DenseMapInfo<void *>::getTombstoneKey();
512     return mlir::Value::getFromOpaquePointer(pointer);
513   }
514   static unsigned getHashValue(mlir::Value val) {
515     return mlir::hash_value(val);
516   }
517   static bool isEqual(mlir::Value lhs, mlir::Value rhs) { return lhs == rhs; }
518 };
519 template <>
520 struct DenseMapInfo<mlir::BlockArgument> : public DenseMapInfo<mlir::Value> {
521   static mlir::BlockArgument getEmptyKey() {
522     void *pointer = llvm::DenseMapInfo<void *>::getEmptyKey();
523     return reinterpret_cast<mlir::detail::BlockArgumentImpl *>(pointer);
524   }
525   static mlir::BlockArgument getTombstoneKey() {
526     void *pointer = llvm::DenseMapInfo<void *>::getTombstoneKey();
527     return reinterpret_cast<mlir::detail::BlockArgumentImpl *>(pointer);
528   }
529 };
530 template <>
531 struct DenseMapInfo<mlir::OpResult> : public DenseMapInfo<mlir::Value> {
532   static mlir::OpResult getEmptyKey() {
533     void *pointer = llvm::DenseMapInfo<void *>::getEmptyKey();
534     return reinterpret_cast<mlir::detail::OpResultImpl *>(pointer);
535   }
536   static mlir::OpResult getTombstoneKey() {
537     void *pointer = llvm::DenseMapInfo<void *>::getTombstoneKey();
538     return reinterpret_cast<mlir::detail::OpResultImpl *>(pointer);
539   }
540 };
541 template <typename T>
542 struct DenseMapInfo<mlir::detail::TypedValue<T>>
543     : public DenseMapInfo<mlir::Value> {
544   static mlir::detail::TypedValue<T> getEmptyKey() {
545     void *pointer = llvm::DenseMapInfo<void *>::getEmptyKey();
546     return reinterpret_cast<mlir::detail::ValueImpl *>(pointer);
547   }
548   static mlir::detail::TypedValue<T> getTombstoneKey() {
549     void *pointer = llvm::DenseMapInfo<void *>::getTombstoneKey();
550     return reinterpret_cast<mlir::detail::ValueImpl *>(pointer);
551   }
552 };
553 
554 /// Allow stealing the low bits of a value.
555 template <>
556 struct PointerLikeTypeTraits<mlir::Value> {
557 public:
558   static inline void *getAsVoidPointer(mlir::Value value) {
559     return const_cast<void *>(value.getAsOpaquePointer());
560   }
561   static inline mlir::Value getFromVoidPointer(void *pointer) {
562     return mlir::Value::getFromOpaquePointer(pointer);
563   }
564   enum {
565     NumLowBitsAvailable =
566         PointerLikeTypeTraits<mlir::detail::ValueImpl *>::NumLowBitsAvailable
567   };
568 };
569 template <>
570 struct PointerLikeTypeTraits<mlir::BlockArgument>
571     : public PointerLikeTypeTraits<mlir::Value> {
572 public:
573   static inline mlir::BlockArgument getFromVoidPointer(void *pointer) {
574     return reinterpret_cast<mlir::detail::BlockArgumentImpl *>(pointer);
575   }
576 };
577 template <>
578 struct PointerLikeTypeTraits<mlir::OpResult>
579     : public PointerLikeTypeTraits<mlir::Value> {
580 public:
581   static inline mlir::OpResult getFromVoidPointer(void *pointer) {
582     return reinterpret_cast<mlir::detail::OpResultImpl *>(pointer);
583   }
584 };
585 template <typename T>
586 struct PointerLikeTypeTraits<mlir::detail::TypedValue<T>>
587     : public PointerLikeTypeTraits<mlir::Value> {
588 public:
589   static inline mlir::detail::TypedValue<T> getFromVoidPointer(void *pointer) {
590     return reinterpret_cast<mlir::detail::ValueImpl *>(pointer);
591   }
592 };
593 
594 /// Add support for llvm style casts. We provide a cast between To and From if
595 /// From is mlir::Value or derives from it.
596 template <typename To, typename From>
597 struct CastInfo<
598     To, From,
599     std::enable_if_t<std::is_same_v<mlir::Value, std::remove_const_t<From>> ||
600                      std::is_base_of_v<mlir::Value, From>>>
601     : NullableValueCastFailed<To>,
602       DefaultDoCastIfPossible<To, From, CastInfo<To, From>> {
603   /// Arguments are taken as mlir::Value here and not as `From`, because
604   /// when casting from an intermediate type of the hierarchy to one of its
605   /// children, the val.getKind() inside T::classof will use the static
606   /// getKind() of the parent instead of the non-static ValueImpl::getKind()
607   /// that returns the dynamic type. This means that T::classof would end up
608   /// comparing the static Kind of the children to the static Kind of its
609   /// parent, making it impossible to downcast from the parent to the child.
610   static inline bool isPossible(mlir::Value ty) {
611     /// Return a constant true instead of a dynamic true when casting to self or
612     /// up the hierarchy.
613     if constexpr (std::is_base_of_v<To, From>) {
614       return true;
615     } else {
616       return To::classof(ty);
617     }
618   }
619   static inline To doCast(mlir::Value value) { return To(value.getImpl()); }
620 };
621 
622 } // namespace llvm
623 
624 #endif
625