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. |
63 | Type getType() const { return typeAndKind.getPointer(); } |
64 | |
65 | /// Set the type of this value. |
66 | void setType(Type type) { return typeAndKind.setPointer(type); } |
67 | |
68 | /// Return the kind of this value. |
69 | Kind getKind() const { return typeAndKind.getInt(); } |
70 | |
71 | protected: |
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 |
77 | LLVM_DUMP_METHOD Type debug_getType() const { return getType(); } |
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: |
98 | constexpr Value(detail::ValueImpl *impl = nullptr) : impl(impl) {} |
99 | |
100 | template <typename U> |
101 | [[deprecated("Use isa<U>() instead" )]] |
102 | bool isa() const { |
103 | return llvm::isa<U>(*this); |
104 | } |
105 | |
106 | template <typename U> |
107 | [[deprecated("Use dyn_cast<U>() instead" )]] |
108 | U dyn_cast() const { |
109 | return llvm::dyn_cast<U>(*this); |
110 | } |
111 | |
112 | template <typename U> |
113 | [[deprecated("Use dyn_cast_or_null<U>() instead" )]] |
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 cast<U>() instead" )]] |
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. |
129 | Type getType() const { return impl->getType(); } |
130 | |
131 | /// Utility to get the associated MLIRContext that this value is defined in. |
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. |
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> |
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. |
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'. |
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 | |
208 | use_iterator use_begin() const { return impl->use_begin(); } |
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. |
212 | use_range getUses() const { return {use_begin(), use_end()}; } |
213 | |
214 | /// Returns true if this value has exactly one use. |
215 | bool hasOneUse() const { return impl->hasOneUse(); } |
216 | |
217 | /// Returns true if this value has no uses. |
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 | |
226 | user_iterator user_begin() const { return use_begin(); } |
227 | user_iterator user_end() const { return use_end(); } |
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. |
243 | void *getAsOpaquePointer() const { return impl; } |
244 | static Value getFromOpaquePointer(const void *pointer) { |
245 | return reinterpret_cast<detail::ValueImpl *>(const_cast<void *>(pointer)); |
246 | } |
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. |
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. |
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: |
295 | static bool classof(const ValueImpl *value) { |
296 | return value->getKind() == ValueImpl::Kind::BlockArgument; |
297 | } |
298 | |
299 | private: |
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 | |
323 | static bool classof(Value value) { |
324 | return llvm::isa<detail::BlockArgumentImpl>(Val: value.getImpl()); |
325 | } |
326 | |
327 | /// Returns the block that owns this argument. |
328 | Block *getOwner() const { return getImpl()->owner; } |
329 | |
330 | /// Returns the number of this argument. |
331 | unsigned getArgNumber() const { return getImpl()->index; } |
332 | |
333 | /// Return the location for this argument. |
334 | Location getLoc() const { return getImpl()->loc; } |
335 | void setLoc(Location loc) { getImpl()->loc = loc; } |
336 | |
337 | private: |
338 | /// Allocate a new argument with the given type and owner. |
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. |
345 | void destroy() { delete getImpl(); } |
346 | |
347 | /// Get a raw pointer to the internal implementation. |
348 | detail::BlockArgumentImpl *getImpl() const { |
349 | return reinterpret_cast<detail::BlockArgumentImpl *>(impl); |
350 | } |
351 | |
352 | /// Cache the position in the block argument list. |
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 | |
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. |
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: |
399 | 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. |
405 | unsigned getResultNumber() const { return static_cast<unsigned>(getKind()); } |
406 | |
407 | 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: |
416 | OutOfLineOpResult(Type type, uint64_t outOfLineIndex) |
417 | : OpResultImpl(type, Kind::OutOfLineOpResult), |
418 | outOfLineIndex(outOfLineIndex) {} |
419 | |
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. |
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. |
435 | inline unsigned OpResultImpl::getResultNumber() const { |
436 | if (const auto *outOfLineResult = dyn_cast<OutOfLineOpResult>(Val: this)) |
437 | return outOfLineResult->getResultNumber(); |
438 | return cast<InlineOpResult>(Val: 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 | |
447 | static bool classof(Value value) { return llvm::isa<Ty>(value.getType()); } |
448 | |
449 | /// Return the known Type |
450 | Ty getType() const { return llvm::cast<Ty>(Value::getType()); } |
451 | 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 | |
461 | static bool classof(Value value) { |
462 | return llvm::isa<detail::OpResultImpl>(Val: value.getImpl()); |
463 | } |
464 | |
465 | /// Returns the operation that owns this result. |
466 | Operation *getOwner() const { return getImpl()->getOwner(); } |
467 | |
468 | /// Returns the number of this result. |
469 | unsigned getResultNumber() const { return getImpl()->getResultNumber(); } |
470 | |
471 | private: |
472 | /// Get a raw pointer to the internal implementation. |
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. |
490 | inline ::llvm::hash_code hash_value(Value arg) { |
491 | return ::llvm::hash_value(ptr: 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(arg: 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 | |