MLIR  22.0.0git
Value.cpp
Go to the documentation of this file.
1 //===- Value.cpp - MLIR Value Classes -------------------------------------===//
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 #include "mlir/IR/Value.h"
10 #include "mlir/IR/Block.h"
11 #include "mlir/IR/Operation.h"
12 
13 using namespace mlir;
14 using namespace mlir::detail;
15 
16 /// If this value is the result of an Operation, return the operation that
17 /// defines it.
19  if (auto result = llvm::dyn_cast<OpResult>(*this))
20  return result.getOwner();
21  return nullptr;
22 }
23 
25  if (auto *op = getDefiningOp())
26  return op->getLoc();
27 
28  return llvm::cast<BlockArgument>(*this).getLoc();
29 }
30 
32  if (auto *op = getDefiningOp())
33  return op->setLoc(loc);
34 
35  return llvm::cast<BlockArgument>(*this).setLoc(loc);
36 }
37 
38 /// Return the Region in which this Value is defined.
40  if (auto *op = getDefiningOp())
41  return op->getParentRegion();
42  return llvm::cast<BlockArgument>(*this).getOwner()->getParent();
43 }
44 
45 /// Return the Block in which this Value is defined.
47  if (Operation *op = getDefiningOp())
48  return op->getBlock();
49  return llvm::cast<BlockArgument>(*this).getOwner();
50 }
51 
52 unsigned Value::getNumUses() const {
53  return (unsigned)std::distance(use_begin(), use_end());
54 }
55 
56 bool Value::hasNUses(unsigned n) const {
57  return hasNItems(use_begin(), use_end(), n);
58 }
59 
60 bool Value::hasNUsesOrMore(unsigned n) const {
61  return hasNItemsOrMore(use_begin(), use_end(), n);
62 }
63 
64 //===----------------------------------------------------------------------===//
65 // Value::UseLists
66 //===----------------------------------------------------------------------===//
67 
68 /// Replace all uses of 'this' value with the new value, updating anything in
69 /// the IR that uses 'this' to use the other value instead except if the user is
70 /// listed in 'exceptions' .
72  Value newValue, const SmallPtrSetImpl<Operation *> &exceptions) {
73  for (OpOperand &use : llvm::make_early_inc_range(getUses())) {
74  if (exceptions.count(use.getOwner()) == 0)
75  use.set(newValue);
76  }
77 }
78 
79 /// Replace all uses of 'this' value with 'newValue', updating anything in the
80 /// IR that uses 'this' to use the other value instead except if the user is
81 /// 'exceptedUser'.
82 void Value::replaceAllUsesExcept(Value newValue, Operation *exceptedUser) {
83  for (OpOperand &use : llvm::make_early_inc_range(getUses())) {
84  if (use.getOwner() != exceptedUser)
85  use.set(newValue);
86  }
87 }
88 
89 /// Replace all uses of 'this' value with 'newValue' if the given callback
90 /// returns true.
92  function_ref<bool(OpOperand &)> shouldReplace) {
93  for (OpOperand &use : llvm::make_early_inc_range(getUses()))
94  if (shouldReplace(use))
95  use.set(newValue);
96 }
97 
98 /// Returns true if the value is used outside of the given block.
99 bool Value::isUsedOutsideOfBlock(Block *block) const {
100  return llvm::any_of(getUsers(), [block](Operation *user) {
101  return user->getBlock() != block;
102  });
103 }
104 
105 /// Shuffles the use-list order according to the provided indices.
107  getImpl()->shuffleUseList(indices);
108 }
109 
110 //===----------------------------------------------------------------------===//
111 // OpResult
112 //===----------------------------------------------------------------------===//
113 
114 /// Returns the parent operation of this trailing result.
116  // We need to do some arithmetic to get the operation pointer. Results are
117  // stored in reverse order before the operation, so move the trailing owner up
118  // to the start of the array. A rough diagram of the memory layout is:
119  //
120  // | Out-of-Line results | Inline results | Operation |
121  //
122  // Given that the results are reverse order we use the result number to know
123  // how far to jump to get to the operation. So if we are currently the 0th
124  // result, the layout would be:
125  //
126  // | Inline result 0 | Operation
127  //
128  // ^-- To get the base address of the operation, we add the result count + 1.
129  if (const auto *result = dyn_cast<InlineOpResult>(this)) {
130  result += result->getResultNumber() + 1;
131  return reinterpret_cast<Operation *>(const_cast<InlineOpResult *>(result));
132  }
133 
134  // Out-of-line results are stored in an array just before the inline results.
135  const OutOfLineOpResult *outOfLineIt = (const OutOfLineOpResult *)(this);
136  outOfLineIt += (outOfLineIt->outOfLineIndex + 1);
137 
138  // Move the owner past the inline results to get to the operation.
139  const auto *inlineIt = reinterpret_cast<const InlineOpResult *>(outOfLineIt);
140  inlineIt += getMaxInlineResults();
141  return reinterpret_cast<Operation *>(const_cast<InlineOpResult *>(inlineIt));
142 }
143 
145  if (offset == 0)
146  return this;
147  // We need to do some arithmetic to get the next result given that results are
148  // in reverse order, and that we need to account for the different types of
149  // results. As a reminder, the rough diagram of the memory layout is:
150  //
151  // | Out-of-Line results | Inline results | Operation |
152  //
153  // So an example operation with two results would look something like:
154  //
155  // | Inline result 1 | Inline result 0 | Operation |
156  //
157 
158  // Handle the case where this result is an inline result.
159  OpResultImpl *result = this;
160  if (auto *inlineResult = dyn_cast<InlineOpResult>(this)) {
161  // Check to see how many results there are after this one before the start
162  // of the out-of-line results. If the desired offset is less than the number
163  // remaining, we can directly use the offset from the current result
164  // pointer. The following diagrams highlight the two situations.
165  //
166  // | Out-of-Line results | Inline results | Operation |
167  // ^- Say we are here.
168  // ^- If our destination is here, we can use the
169  // offset directly.
170  //
171  intptr_t leftBeforeTrailing =
172  getMaxInlineResults() - inlineResult->getResultNumber() - 1;
173  if (leftBeforeTrailing >= offset)
174  return inlineResult - offset;
175 
176  // Otherwise, adjust the current result pointer to the end (start in memory)
177  // of the inline result array.
178  //
179  // | Out-of-Line results | Inline results | Operation |
180  // ^- Say we are here.
181  // ^- If our destination is here, we need to first jump to
182  // the end (start in memory) of the inline result array.
183  //
184  result = inlineResult - leftBeforeTrailing;
185  offset -= leftBeforeTrailing;
186  }
187 
188  // If we land here, the current result is an out-of-line result and we can
189  // offset directly.
190  return reinterpret_cast<OutOfLineOpResult *>(result) - offset;
191 }
192 
193 /// Given a number of operation results, returns the number that need to be
194 /// stored inline.
195 unsigned OpResult::getNumInline(unsigned numResults) {
196  return std::min(numResults, OpResultImpl::getMaxInlineResults());
197 }
198 
199 /// Given a number of operation results, returns the number that need to be
200 /// stored as trailing.
201 unsigned OpResult::getNumTrailing(unsigned numResults) {
202  // If we can pack all of the results, there is no need for additional storage.
203  unsigned maxInline = OpResultImpl::getMaxInlineResults();
204  return numResults <= maxInline ? 0 : numResults - maxInline;
205 }
206 
207 //===----------------------------------------------------------------------===//
208 // BlockOperand
209 //===----------------------------------------------------------------------===//
210 
211 /// Provide the use list that is attached to the given block.
213  return value;
214 }
215 
216 /// Return which operand this is in the operand list.
218  return this - &getOwner()->getBlockOperands()[0];
219 }
220 
221 //===----------------------------------------------------------------------===//
222 // OpOperand
223 //===----------------------------------------------------------------------===//
224 
225 /// Return which operand this is in the operand list.
227  return this - &getOwner()->getOpOperands()[0];
228 }
static Value min(ImplicitLocOpBuilder &builder, Value value, Value bound)
unsigned getOperandNumber()
Return which operand this is in the BlockOperand list of the Operation.
Definition: Value.cpp:217
static IRObjectWithUseList< BlockOperand > * getUseList(Block *value)
Provide the use list that is attached to the given block.
Definition: Value.cpp:212
Block represents an ordered list of Operations.
Definition: Block.h:33
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
Definition: Location.h:76
This class represents an operand of an operation.
Definition: Value.h:257
unsigned getOperandNumber()
Return which operand this is in the OpOperand list of the Operation.
Definition: Value.cpp:226
Operation is the basic unit of execution within MLIR.
Definition: Operation.h:88
Block * getBlock()
Returns the operation block that contains this operation.
Definition: Operation.h:213
This class contains a list of basic blocks and a link to the parent operation it is attached to.
Definition: Region.h:26
Region * getParentRegion()
Return the region containing this region or nullptr if the region is attached to a top-level operatio...
Definition: Region.cpp:45
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition: Value.h:96
void setLoc(Location loc)
Definition: Value.cpp:31
bool hasNUsesOrMore(unsigned n) const
Return true if this value has n uses or more.
Definition: Value.cpp:60
void replaceUsesWithIf(Value newValue, function_ref< bool(OpOperand &)> shouldReplace)
Replace all uses of 'this' value with 'newValue' if the given callback returns true.
Definition: Value.cpp:91
void shuffleUseList(ArrayRef< unsigned > indices)
Shuffle the use list order according to the provided indices.
Definition: Value.cpp:106
Block * getParentBlock()
Return the Block in which this Value is defined.
Definition: Value.cpp:46
void replaceAllUsesExcept(Value newValue, const SmallPtrSetImpl< Operation * > &exceptions)
Replace all uses of 'this' value with 'newValue', updating anything in the IR that uses 'this' to use...
Definition: Value.cpp:71
unsigned getNumUses() const
This method computes the number of uses of this Value.
Definition: Value.cpp:52
bool hasNUses(unsigned n) const
Return true if this Value has exactly n uses.
Definition: Value.cpp:56
bool isUsedOutsideOfBlock(Block *block) const
Returns true if the value is used outside of the given block.
Definition: Value.cpp:99
Location getLoc() const
Return the location of this value.
Definition: Value.cpp:24
Operation * getDefiningOp() const
If this value is the result of an operation, return the operation that defines it.
Definition: Value.cpp:18
Region * getParentRegion()
Return the Region in which this Value is defined.
Definition: Value.cpp:39
This class provides the implementation for an operation result.
Definition: Value.h:358
OpResultImpl * getNextResultAtOffset(intptr_t offset)
Returns the next operation result at offset after this result.
Definition: Value.cpp:144
Operation * getOwner() const
Returns the parent operation of this result.
Definition: Value.cpp:115
static unsigned getMaxInlineResults()
Returns the maximum number of results that can be stored inline.
Definition: Value.h:380
This class provides the implementation for an operation result whose index cannot be represented "inl...
Definition: Value.h:404
uint64_t outOfLineIndex
The trailing result number, or the offset from the beginning of the OutOfLineOpResult array.
Definition: Value.h:421
AttrTypeReplacer.
Include the generated interface declarations.
This class provides the implementation for an operation result whose index can be represented "inline...
Definition: Value.h:387