//===- Value.cpp - MLIR Value Classes -------------------------------------===// // // Part of the MLIR Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "mlir/IR/Value.h" #include "mlir/IR/Block.h" #include "mlir/IR/Operation.h" #include "mlir/IR/StandardTypes.h" using namespace mlir; /// Construct a value. Value::Value(detail::BlockArgumentImpl *impl) : ownerAndKind(impl, Kind::BlockArgument) {} Value::Value(Operation *op, unsigned resultNo) { assert(op->getNumResults() > resultNo && "invalid result number"); if (LLVM_LIKELY(canPackResultInline(resultNo))) { ownerAndKind = {op, static_cast(resultNo)}; return; } // If we can't pack the result directly, we need to represent this as a // trailing result. unsigned trailingResultNo = resultNo - static_cast(Kind::TrailingOpResult); ownerAndKind = {op->getTrailingResult(trailingResultNo), Kind::TrailingOpResult}; } /// Return the type of this value. Type Value::getType() const { if (BlockArgument arg = dyn_cast()) return arg.getType(); // If this is an operation result, query the parent operation. OpResult result = cast(); Operation *owner = result.getOwner(); if (owner->hasSingleResult) return owner->resultType; return owner->resultType.cast().getType(result.getResultNumber()); } /// Mutate the type of this Value to be of the specified type. void Value::setType(Type newType) { if (BlockArgument arg = dyn_cast()) return arg.setType(newType); OpResult result = cast(); // If the owner has a single result, simply update it directly. Operation *owner = result.getOwner(); if (owner->hasSingleResult) { owner->resultType = newType; return; } unsigned resultNo = result.getResultNumber(); // Otherwise, rebuild the tuple if the new type is different from the current. auto curTypes = owner->resultType.cast().getTypes(); if (curTypes[resultNo] == newType) return; auto newTypes = llvm::to_vector<4>(curTypes); newTypes[resultNo] = newType; owner->resultType = TupleType::get(newTypes, newType.getContext()); } /// If this value is the result of an Operation, return the operation that /// defines it. Operation *Value::getDefiningOp() const { if (auto result = dyn_cast()) return result.getOwner(); return nullptr; } Location Value::getLoc() const { if (auto *op = getDefiningOp()) return op->getLoc(); return UnknownLoc::get(getContext()); } /// Return the Region in which this Value is defined. Region *Value::getParentRegion() { if (auto *op = getDefiningOp()) return op->getParentRegion(); return cast().getOwner()->getParent(); } //===----------------------------------------------------------------------===// // Value::UseLists //===----------------------------------------------------------------------===// /// Provide the use list that is attached to this value. IRObjectWithUseList *Value::getUseList() const { if (BlockArgument arg = dyn_cast()) return arg.getImpl(); return cast().getOwner(); } /// Drop all uses of this object from their respective owners. void Value::dropAllUses() const { if (BlockArgument arg = dyn_cast()) return arg.getImpl()->dropAllUses(); return cast().getOwner()->dropAllUses(*this); } /// Replace all uses of 'this' value with the new value, updating anything in /// the IR that uses 'this' to use the other value instead. When this returns /// there are zero uses of 'this'. void Value::replaceAllUsesWith(Value newValue) const { if (BlockArgument arg = dyn_cast()) return arg.getImpl()->replaceAllUsesWith(newValue); IRMultiObjectWithUseList *useList = cast().getOwner(); useList->replaceAllUsesWith(*this, newValue); } //===--------------------------------------------------------------------===// // Uses auto Value::use_begin() const -> use_iterator { if (BlockArgument arg = dyn_cast()) return arg.getImpl()->use_begin(); return cast().getOwner()->use_begin(*this); } /// Returns true if this value has exactly one use. bool Value::hasOneUse() const { if (BlockArgument arg = dyn_cast()) return arg.getImpl()->hasOneUse(); return cast().getOwner()->hasOneUse(*this); } /// Returns true if this value has no uses. bool Value::use_empty() const { if (BlockArgument arg = dyn_cast()) return arg.getImpl()->use_empty(); return cast().getOwner()->use_empty(*this); } //===----------------------------------------------------------------------===// // OpResult //===----------------------------------------------------------------------===// /// Returns the operation that owns this result. Operation *OpResult::getOwner() const { // If the result is in-place, the `owner` is the operation. if (LLVM_LIKELY(getKind() != Kind::TrailingOpResult)) return reinterpret_cast(ownerAndKind.getPointer()); // Otherwise, we need to do some arithmetic to get the operation pointer. // Move the trailing owner to the start of the array. auto *trailingIt = static_cast(ownerAndKind.getPointer()); trailingIt -= trailingIt->trailingResultNumber; // This point is the first trailing object after the operation. So all we need // to do here is adjust for the operation size. return reinterpret_cast(trailingIt) - 1; } /// Return the result number of this result. unsigned OpResult::getResultNumber() const { // If the result is in-place, we can use the kind directly. if (LLVM_LIKELY(getKind() != Kind::TrailingOpResult)) return static_cast(ownerAndKind.getInt()); // Otherwise, we add the number of inline results to the trailing owner. auto *trailingIt = static_cast(ownerAndKind.getPointer()); unsigned trailingNumber = trailingIt->trailingResultNumber; return trailingNumber + static_cast(Kind::TrailingOpResult); } /// Given a number of operation results, returns the number that need to be /// stored as trailing. unsigned OpResult::getNumTrailing(unsigned numResults) { // If we can pack all of the results, there is no need for additional storage. if (numResults <= static_cast(Kind::TrailingOpResult)) return 0; return numResults - static_cast(Kind::TrailingOpResult); } //===----------------------------------------------------------------------===// // BlockOperand //===----------------------------------------------------------------------===// /// Provide the use list that is attached to the given block. IRObjectWithUseList *BlockOperand::getUseList(Block *value) { return value; } /// Return which operand this is in the operand list. unsigned BlockOperand::getOperandNumber() { return this - &getOwner()->getBlockOperands()[0]; } //===----------------------------------------------------------------------===// // OpOperand //===----------------------------------------------------------------------===// /// Provide the use list that is attached to the given value. IRObjectWithUseList *OpOperand::getUseList(Value value) { return value.getUseList(); } /// Return the current value being used by this operand. Value OpOperand::get() const { return IROperand::get(); } /// Set the operand to the given value. void OpOperand::set(Value value) { IROperand::set(value); } /// Return which operand this is in the operand list. unsigned OpOperand::getOperandNumber() { return this - &getOwner()->getOpOperands()[0]; } //===----------------------------------------------------------------------===// // detail::OpaqueValue //===----------------------------------------------------------------------===// /// Implicit conversion from 'Value'. detail::OpaqueValue::OpaqueValue(Value value) : impl(value.getAsOpaquePointer()) {} /// Implicit conversion back to 'Value'. detail::OpaqueValue::operator Value() const { return Value::getFromOpaquePointer(impl); }