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. 20 Operation *Value::getDefiningOp() const { 21 if (auto result = dyn_cast<OpResult>()) 22 return result.getOwner(); 23 return nullptr; 24 } 25 26 Location Value::getLoc() const { 27 if (auto *op = getDefiningOp()) 28 return op->getLoc(); 29 30 return cast<BlockArgument>().getLoc(); 31 } 32 33 void Value::setLoc(Location loc) { 34 if (auto *op = getDefiningOp()) 35 return op->setLoc(loc); 36 37 return cast<BlockArgument>().setLoc(loc); 38 } 39 40 /// Return the Region in which this Value is defined. 41 Region *Value::getParentRegion() { 42 if (auto *op = getDefiningOp()) 43 return op->getParentRegion(); 44 return cast<BlockArgument>().getOwner()->getParent(); 45 } 46 47 /// Return the Block in which this Value is defined. 48 Block *Value::getParentBlock() { 49 if (Operation *op = getDefiningOp()) 50 return op->getBlock(); 51 return cast<BlockArgument>().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. When this returns 60 /// there are zero uses of 'this'. 61 void Value::replaceAllUsesWith(Value newValue) const { 62 return getUseList()->replaceAllUsesWith(newValue); 63 } 64 65 /// Replace all uses of 'this' value with the new value, updating anything in 66 /// the IR that uses 'this' to use the other value instead except if the user is 67 /// listed in 'exceptions' . 68 void Value::replaceAllUsesExcept( 69 Value newValue, const SmallPtrSetImpl<Operation *> &exceptions) const { 70 for (OpOperand &use : llvm::make_early_inc_range(getUses())) { 71 if (exceptions.count(use.getOwner()) == 0) 72 use.set(newValue); 73 } 74 } 75 76 /// Replace all uses of 'this' value with 'newValue', updating anything in the 77 /// IR that uses 'this' to use the other value instead except if the user is 78 /// 'exceptedUser'. 79 void Value::replaceAllUsesExcept(Value newValue, 80 Operation *exceptedUser) const { 81 for (OpOperand &use : llvm::make_early_inc_range(getUses())) { 82 if (use.getOwner() != exceptedUser) 83 use.set(newValue); 84 } 85 } 86 87 /// Replace all uses of 'this' value with 'newValue' if the given callback 88 /// returns true. 89 void Value::replaceUsesWithIf(Value newValue, 90 function_ref<bool(OpOperand &)> shouldReplace) { 91 for (OpOperand &use : llvm::make_early_inc_range(getUses())) 92 if (shouldReplace(use)) 93 use.set(newValue); 94 } 95 96 /// Returns true if the value is used outside of the given block. 97 bool Value::isUsedOutsideOfBlock(Block *block) { 98 return llvm::any_of(getUsers(), [block](Operation *user) { 99 return user->getBlock() != block; 100 }); 101 } 102 103 //===----------------------------------------------------------------------===// 104 // OpResult 105 //===----------------------------------------------------------------------===// 106 107 /// Returns the parent operation of this trailing result. 108 Operation *OpResultImpl::getOwner() const { 109 // We need to do some arithmetic to get the operation pointer. Results are 110 // stored in reverse order before the operation, so move the trailing owner up 111 // to the start of the array. A rough diagram of the memory layout is: 112 // 113 // | Out-of-Line results | Inline results | Operation | 114 // 115 // Given that the results are reverse order we use the result number to know 116 // how far to jump to get to the operation. So if we are currently the 0th 117 // result, the layout would be: 118 // 119 // | Inline result 0 | Operation 120 // 121 // ^-- To get the base address of the operation, we add the result count + 1. 122 if (const auto *result = dyn_cast<InlineOpResult>(this)) { 123 result += result->getResultNumber() + 1; 124 return reinterpret_cast<Operation *>(const_cast<InlineOpResult *>(result)); 125 } 126 127 // Out-of-line results are stored in an array just before the inline results. 128 const OutOfLineOpResult *outOfLineIt = (const OutOfLineOpResult *)(this); 129 outOfLineIt += (outOfLineIt->outOfLineIndex + 1); 130 131 // Move the owner past the inline results to get to the operation. 132 const auto *inlineIt = reinterpret_cast<const InlineOpResult *>(outOfLineIt); 133 inlineIt += getMaxInlineResults(); 134 return reinterpret_cast<Operation *>(const_cast<InlineOpResult *>(inlineIt)); 135 } 136 137 OpResultImpl *OpResultImpl::getNextResultAtOffset(intptr_t offset) { 138 if (offset == 0) 139 return this; 140 // We need to do some arithmetic to get the next result given that results are 141 // in reverse order, and that we need to account for the different types of 142 // results. As a reminder, the rough diagram of the memory layout is: 143 // 144 // | Out-of-Line results | Inline results | Operation | 145 // 146 // So an example operation with two results would look something like: 147 // 148 // | Inline result 1 | Inline result 0 | Operation | 149 // 150 151 // Handle the case where this result is an inline result. 152 OpResultImpl *result = this; 153 if (auto *inlineResult = dyn_cast<InlineOpResult>(this)) { 154 // Check to see how many results there are after this one before the start 155 // of the out-of-line results. If the desired offset is less than the number 156 // remaining, we can directly use the offset from the current result 157 // pointer. The following diagrams highlight the two situations. 158 // 159 // | Out-of-Line results | Inline results | Operation | 160 // ^- Say we are here. 161 // ^- If our destination is here, we can use the 162 // offset directly. 163 // 164 intptr_t leftBeforeTrailing = 165 getMaxInlineResults() - inlineResult->getResultNumber() - 1; 166 if (leftBeforeTrailing >= offset) 167 return inlineResult - offset; 168 169 // Otherwise, adjust the current result pointer to the end (start in memory) 170 // of the inline result array. 171 // 172 // | Out-of-Line results | Inline results | Operation | 173 // ^- Say we are here. 174 // ^- If our destination is here, we need to first jump to 175 // the end (start in memory) of the inline result array. 176 // 177 result = inlineResult - leftBeforeTrailing; 178 offset -= leftBeforeTrailing; 179 } 180 181 // If we land here, the current result is an out-of-line result and we can 182 // offset directly. 183 return reinterpret_cast<OutOfLineOpResult *>(result) - offset; 184 } 185 186 /// Given a number of operation results, returns the number that need to be 187 /// stored inline. 188 unsigned OpResult::getNumInline(unsigned numResults) { 189 return std::min(numResults, OpResultImpl::getMaxInlineResults()); 190 } 191 192 /// Given a number of operation results, returns the number that need to be 193 /// stored as trailing. 194 unsigned OpResult::getNumTrailing(unsigned numResults) { 195 // If we can pack all of the results, there is no need for additional storage. 196 unsigned maxInline = OpResultImpl::getMaxInlineResults(); 197 return numResults <= maxInline ? 0 : numResults - maxInline; 198 } 199 200 //===----------------------------------------------------------------------===// 201 // BlockOperand 202 //===----------------------------------------------------------------------===// 203 204 /// Provide the use list that is attached to the given block. 205 IRObjectWithUseList<BlockOperand> *BlockOperand::getUseList(Block *value) { 206 return value; 207 } 208 209 /// Return which operand this is in the operand list. 210 unsigned BlockOperand::getOperandNumber() { 211 return this - &getOwner()->getBlockOperands()[0]; 212 } 213 214 //===----------------------------------------------------------------------===// 215 // OpOperand 216 //===----------------------------------------------------------------------===// 217 218 /// Provide the use list that is attached to the given value. 219 IRObjectWithUseList<OpOperand> *OpOperand::getUseList(Value value) { 220 return value.getUseList(); 221 } 222 223 /// Return the current value being used by this operand. 224 Value OpOperand::get() const { 225 return IROperand<OpOperand, OpaqueValue>::get(); 226 } 227 228 /// Set the operand to the given value. 229 void OpOperand::set(Value value) { 230 IROperand<OpOperand, OpaqueValue>::set(value); 231 } 232 233 /// Return which operand this is in the operand list. 234 unsigned OpOperand::getOperandNumber() { 235 return this - &getOwner()->getOpOperands()[0]; 236 } 237 238 //===----------------------------------------------------------------------===// 239 // OpaqueValue 240 //===----------------------------------------------------------------------===// 241 242 /// Implicit conversion from 'Value'. 243 OpaqueValue::OpaqueValue(Value value) : impl(value.getAsOpaquePointer()) {} 244 245 /// Implicit conversion back to 'Value'. 246 OpaqueValue::operator Value() const { 247 return Value::getFromOpaquePointer(impl); 248 } 249