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