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