1 //===- BlockSupport.h -------------------------------------------*- 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 a number of support types for the Block class. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #ifndef MLIR_IR_BLOCKSUPPORT_H 14 #define MLIR_IR_BLOCKSUPPORT_H 15 16 #include "mlir/IR/Value.h" 17 #include "llvm/ADT/PointerUnion.h" 18 #include "llvm/ADT/ilist.h" 19 #include "llvm/ADT/ilist_node.h" 20 21 namespace mlir { 22 class Block; 23 24 //===----------------------------------------------------------------------===// 25 // BlockOperand 26 //===----------------------------------------------------------------------===// 27 28 /// A block operand represents an operand that holds a reference to a Block, 29 /// e.g. for terminator operations. 30 class BlockOperand : public IROperand<BlockOperand, Block *> { 31 public: 32 using IROperand<BlockOperand, Block *>::IROperand; 33 34 /// Provide the use list that is attached to the given block. 35 static IRObjectWithUseList<BlockOperand> *getUseList(Block *value); 36 37 /// Return which operand this is in the BlockOperand list of the Operation. 38 unsigned getOperandNumber(); 39 }; 40 41 //===----------------------------------------------------------------------===// 42 // Predecessors 43 //===----------------------------------------------------------------------===// 44 45 /// Implement a predecessor iterator for blocks. This works by walking the use 46 /// lists of the blocks. The entries on this list are the BlockOperands that 47 /// are embedded into terminator operations. From the operand, we can get the 48 /// terminator that contains it, and its parent block is the predecessor. 49 class PredecessorIterator final 50 : public llvm::mapped_iterator<ValueUseIterator<BlockOperand>, 51 Block *(*)(BlockOperand &)> { 52 static Block *unwrap(BlockOperand &value); 53 54 public: 55 /// Initializes the operand type iterator to the specified operand iterator. PredecessorIterator(ValueUseIterator<BlockOperand> it)56 PredecessorIterator(ValueUseIterator<BlockOperand> it) 57 : llvm::mapped_iterator<ValueUseIterator<BlockOperand>, 58 Block *(*)(BlockOperand &)>(it, &unwrap) {} PredecessorIterator(BlockOperand * operand)59 explicit PredecessorIterator(BlockOperand *operand) 60 : PredecessorIterator(ValueUseIterator<BlockOperand>(operand)) {} 61 62 /// Get the successor number in the predecessor terminator. 63 unsigned getSuccessorIndex() const; 64 }; 65 66 //===----------------------------------------------------------------------===// 67 // Successors 68 //===----------------------------------------------------------------------===// 69 70 /// This class implements the successor iterators for Block. 71 class SuccessorRange final 72 : public llvm::detail::indexed_accessor_range_base< 73 SuccessorRange, BlockOperand *, Block *, Block *, Block *> { 74 public: 75 using RangeBaseT::RangeBaseT; 76 SuccessorRange(); 77 SuccessorRange(Block *block); 78 SuccessorRange(Operation *term); 79 80 private: 81 /// See `llvm::detail::indexed_accessor_range_base` for details. offset_base(BlockOperand * object,ptrdiff_t index)82 static BlockOperand *offset_base(BlockOperand *object, ptrdiff_t index) { 83 return object + index; 84 } 85 /// See `llvm::detail::indexed_accessor_range_base` for details. dereference_iterator(BlockOperand * object,ptrdiff_t index)86 static Block *dereference_iterator(BlockOperand *object, ptrdiff_t index) { 87 return object[index].get(); 88 } 89 90 /// Allow access to `offset_base` and `dereference_iterator`. 91 friend RangeBaseT; 92 }; 93 94 //===----------------------------------------------------------------------===// 95 // BlockRange 96 //===----------------------------------------------------------------------===// 97 98 /// This class provides an abstraction over the different types of ranges over 99 /// Blocks. In many cases, this prevents the need to explicitly materialize a 100 /// SmallVector/std::vector. This class should be used in places that are not 101 /// suitable for a more derived type (e.g. ArrayRef) or a template range 102 /// parameter. 103 class BlockRange final 104 : public llvm::detail::indexed_accessor_range_base< 105 BlockRange, llvm::PointerUnion<BlockOperand *, Block *const *>, 106 Block *, Block *, Block *> { 107 public: 108 using RangeBaseT::RangeBaseT; 109 BlockRange(ArrayRef<Block *> blocks = llvm::None); 110 BlockRange(SuccessorRange successors); 111 template <typename Arg, 112 typename = typename std::enable_if_t< 113 std::is_constructible<ArrayRef<Block *>, Arg>::value>> BlockRange(Arg && arg)114 BlockRange(Arg &&arg) 115 : BlockRange(ArrayRef<Block *>(std::forward<Arg>(arg))) {} BlockRange(std::initializer_list<Block * > blocks)116 BlockRange(std::initializer_list<Block *> blocks) 117 : BlockRange(ArrayRef<Block *>(blocks)) {} 118 119 private: 120 /// The owner of the range is either: 121 /// * A pointer to the first element of an array of block operands. 122 /// * A pointer to the first element of an array of Block *. 123 using OwnerT = llvm::PointerUnion<BlockOperand *, Block *const *>; 124 125 /// See `llvm::detail::indexed_accessor_range_base` for details. 126 static OwnerT offset_base(OwnerT object, ptrdiff_t index); 127 128 /// See `llvm::detail::indexed_accessor_range_base` for details. 129 static Block *dereference_iterator(OwnerT object, ptrdiff_t index); 130 131 /// Allow access to `offset_base` and `dereference_iterator`. 132 friend RangeBaseT; 133 }; 134 135 //===----------------------------------------------------------------------===// 136 // Operation Iterators 137 //===----------------------------------------------------------------------===// 138 139 namespace detail { 140 /// A utility iterator that filters out operations that are not 'OpT'. 141 template <typename OpT, typename IteratorT> 142 class op_filter_iterator 143 : public llvm::filter_iterator<IteratorT, bool (*)(Operation &)> { filter(Operation & op)144 static bool filter(Operation &op) { return llvm::isa<OpT>(op); } 145 146 public: op_filter_iterator(IteratorT it,IteratorT end)147 op_filter_iterator(IteratorT it, IteratorT end) 148 : llvm::filter_iterator<IteratorT, bool (*)(Operation &)>(it, end, 149 &filter) {} 150 151 /// Allow implicit conversion to the underlying iterator. 152 operator const IteratorT &() const { return this->wrapped(); } 153 }; 154 155 /// This class provides iteration over the held operations of a block for a 156 /// specific operation type. 157 template <typename OpT, typename IteratorT> 158 class op_iterator 159 : public llvm::mapped_iterator<op_filter_iterator<OpT, IteratorT>, 160 OpT (*)(Operation &)> { unwrap(Operation & op)161 static OpT unwrap(Operation &op) { return cast<OpT>(op); } 162 163 public: 164 /// Initializes the iterator to the specified filter iterator. op_iterator(op_filter_iterator<OpT,IteratorT> it)165 op_iterator(op_filter_iterator<OpT, IteratorT> it) 166 : llvm::mapped_iterator<op_filter_iterator<OpT, IteratorT>, 167 OpT (*)(Operation &)>(it, &unwrap) {} 168 169 /// Allow implicit conversion to the underlying block iterator. 170 operator const IteratorT &() const { return this->wrapped(); } 171 }; 172 } // namespace detail 173 } // namespace mlir 174 175 namespace llvm { 176 177 /// Provide support for hashing successor ranges. 178 template <> 179 struct DenseMapInfo<mlir::SuccessorRange> { 180 static mlir::SuccessorRange getEmptyKey() { 181 auto *pointer = llvm::DenseMapInfo<mlir::BlockOperand *>::getEmptyKey(); 182 return mlir::SuccessorRange(pointer, 0); 183 } 184 static mlir::SuccessorRange getTombstoneKey() { 185 auto *pointer = llvm::DenseMapInfo<mlir::BlockOperand *>::getTombstoneKey(); 186 return mlir::SuccessorRange(pointer, 0); 187 } 188 static unsigned getHashValue(mlir::SuccessorRange value) { 189 return llvm::hash_combine_range(value.begin(), value.end()); 190 } 191 static bool isEqual(mlir::SuccessorRange lhs, mlir::SuccessorRange rhs) { 192 if (rhs.getBase() == getEmptyKey().getBase()) 193 return lhs.getBase() == getEmptyKey().getBase(); 194 if (rhs.getBase() == getTombstoneKey().getBase()) 195 return lhs.getBase() == getTombstoneKey().getBase(); 196 return lhs == rhs; 197 } 198 }; 199 200 //===----------------------------------------------------------------------===// 201 // ilist_traits for Operation 202 //===----------------------------------------------------------------------===// 203 204 namespace ilist_detail { 205 // Explicitly define the node access for the operation list so that we can 206 // break the dependence on the Operation class in this header. This allows for 207 // operations to have trailing Regions without a circular include 208 // dependence. 209 template <> 210 struct SpecificNodeAccess< 211 typename compute_node_options<::mlir::Operation>::type> : NodeAccess { 212 protected: 213 using OptionsT = typename compute_node_options<mlir::Operation>::type; 214 using pointer = typename OptionsT::pointer; 215 using const_pointer = typename OptionsT::const_pointer; 216 using node_type = ilist_node_impl<OptionsT>; 217 218 static node_type *getNodePtr(pointer N); 219 static const node_type *getNodePtr(const_pointer N); 220 221 static pointer getValuePtr(node_type *N); 222 static const_pointer getValuePtr(const node_type *N); 223 }; 224 } // namespace ilist_detail 225 226 template <> 227 struct ilist_traits<::mlir::Operation> { 228 using Operation = ::mlir::Operation; 229 using op_iterator = simple_ilist<Operation>::iterator; 230 231 static void deleteNode(Operation *op); 232 void addNodeToList(Operation *op); 233 void removeNodeFromList(Operation *op); 234 void transferNodesFromList(ilist_traits<Operation> &otherList, 235 op_iterator first, op_iterator last); 236 237 private: 238 mlir::Block *getContainingBlock(); 239 }; 240 241 //===----------------------------------------------------------------------===// 242 // ilist_traits for Block 243 //===----------------------------------------------------------------------===// 244 245 template <> 246 struct ilist_traits<::mlir::Block> : public ilist_alloc_traits<::mlir::Block> { 247 using Block = ::mlir::Block; 248 using block_iterator = simple_ilist<::mlir::Block>::iterator; 249 250 void addNodeToList(Block *block); 251 void removeNodeFromList(Block *block); 252 void transferNodesFromList(ilist_traits<Block> &otherList, 253 block_iterator first, block_iterator last); 254 255 private: 256 mlir::Region *getParentRegion(); 257 }; 258 259 } // namespace llvm 260 261 #endif // MLIR_IR_BLOCKSUPPORT_H 262