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