ReImplement the Value classes as value-typed objects wrapping an internal pointer storage.

This will enable future commits to reimplement the internal implementation of OpResult without needing to change all of the existing users. This is part of a chain of commits optimizing the size of operation results.

PiperOrigin-RevId: 286924059
Change-Id: I6e98b2f4b698030d44eb0981019774811d81bc12
This commit is contained in:
A. Unique TensorFlower 2019-12-23 11:49:50 -08:00 committed by TensorFlower Gardener
parent f0a8988032
commit 0fd31271b2
30 changed files with 159 additions and 369 deletions

View File

@ -96,8 +96,7 @@ struct PythonValueHandle {
operator ValueHandle &() { return value; } operator ValueHandle &() { return value; }
std::string str() const { std::string str() const {
return std::to_string( return std::to_string(reinterpret_cast<intptr_t>(value.getValue()));
reinterpret_cast<intptr_t>(value.getValue().getAsOpaquePointer()));
} }
PythonValueHandle call(const std::vector<PythonValueHandle> &args) { PythonValueHandle call(const std::vector<PythonValueHandle> &args) {

View File

@ -24,7 +24,9 @@
#ifndef MLIR_ANALYSIS_AFFINE_ANALYSIS_H #ifndef MLIR_ANALYSIS_AFFINE_ANALYSIS_H
#define MLIR_ANALYSIS_AFFINE_ANALYSIS_H #define MLIR_ANALYSIS_AFFINE_ANALYSIS_H
#include "mlir/IR/Value.h" #include "mlir/Support/LLVM.h"
#include "mlir/Support/LogicalResult.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/Optional.h" #include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/SmallVector.h"
@ -35,9 +37,10 @@ class AffineForOp;
class AffineValueMap; class AffineValueMap;
class FlatAffineConstraints; class FlatAffineConstraints;
class Operation; class Operation;
class Value;
// TODO(riverriddle) Remove this after Value is value-typed. // TODO(riverriddle) Remove this after Value is value-typed.
using ValuePtr = Value; using ValuePtr = Value *;
/// Returns in `affineApplyOps`, the sequence of those AffineApplyOp /// Returns in `affineApplyOps`, the sequence of those AffineApplyOp
/// Operations that are reachable via a search starting from `operands` and /// Operations that are reachable via a search starting from `operands` and

View File

@ -42,7 +42,7 @@ class Region;
class Value; class Value;
// TODO(riverriddle) Remove this after Value is value-typed. // TODO(riverriddle) Remove this after Value is value-typed.
using ValuePtr = Value; using ValuePtr = Value *;
/// Represents an analysis for computing liveness information from a /// Represents an analysis for computing liveness information from a
/// given top-level operation. The analysis iterates over all associated /// given top-level operation. The analysis iterates over all associated

View File

@ -37,7 +37,7 @@ class Operation;
class Value; class Value;
// TODO(riverriddle) Remove this after Value is value-typed. // TODO(riverriddle) Remove this after Value is value-typed.
using ValuePtr = Value; using ValuePtr = Value *;
/// Returns the trip count of the loop as an affine map with its corresponding /// Returns the trip count of the loop as an affine map with its corresponding
/// operands if the latter is expressible as an affine expression, and nullptr /// operands if the latter is expressible as an affine expression, and nullptr

View File

@ -31,7 +31,7 @@ class RewritePattern;
class Value; class Value;
// TODO(riverriddle) Remove this after Value is value-typed. // TODO(riverriddle) Remove this after Value is value-typed.
using ValuePtr = Value; using ValuePtr = Value *;
// Owning list of rewriting patterns. // Owning list of rewriting patterns.
class OwningRewritePatternList; class OwningRewritePatternList;

View File

@ -25,7 +25,7 @@ struct LogicalResult;
class Value; class Value;
// TODO(riverriddle) Remove this after Value is value-typed. // TODO(riverriddle) Remove this after Value is value-typed.
using ValuePtr = Value; using ValuePtr = Value *;
namespace loop { namespace loop {
class ForOp; class ForOp;

View File

@ -35,7 +35,7 @@ class Value;
class VectorType; class VectorType;
// TODO(riverriddle) Remove this after Value is value-typed. // TODO(riverriddle) Remove this after Value is value-typed.
using ValuePtr = Value; using ValuePtr = Value *;
/// Computes and returns the multi-dimensional ratio of `superShape` to /// Computes and returns the multi-dimensional ratio of `superShape` to
/// `subShape`. This is calculated by performing a traversal from minor to major /// `subShape`. This is calculated by performing a traversal from minor to major

View File

@ -338,7 +338,6 @@ public:
/// Implicit conversion useful for automatic conversion to Container<Value>. /// Implicit conversion useful for automatic conversion to Container<Value>.
operator ValuePtr() const { return getValue(); } operator ValuePtr() const { return getValue(); }
operator bool() const { return hasValue(); }
/// Generic mlir::Op create. This is the key to being extensible to the whole /// Generic mlir::Op create. This is the key to being extensible to the whole
/// of MLIR without duplicating the type system or the op definitions. /// of MLIR without duplicating the type system or the op definitions.

View File

@ -72,7 +72,7 @@ public:
//===--------------------------------------------------------------------===// //===--------------------------------------------------------------------===//
// This is the list of arguments to the block. // This is the list of arguments to the block.
using BlockArgListType = MutableArrayRef<BlockArgumentPtr>; using BlockArgListType = ArrayRef<BlockArgumentPtr>;
BlockArgListType getArguments() { return arguments; } BlockArgListType getArguments() { return arguments; }

View File

@ -37,18 +37,14 @@ public:
/// Inserts a new mapping for 'from' to 'to'. If there is an existing mapping, /// Inserts a new mapping for 'from' to 'to'. If there is an existing mapping,
/// it is overwritten. /// it is overwritten.
void map(Block *from, Block *to) { valueMap[from] = to; } void map(Block *from, Block *to) { valueMap[from] = to; }
void map(Value from, Value to) { void map(ValuePtr from, ValuePtr to) { valueMap[from] = to; }
valueMap[from.getAsOpaquePointer()] = to.getAsOpaquePointer();
}
/// Erases a mapping for 'from'. /// Erases a mapping for 'from'.
void erase(Block *from) { valueMap.erase(from); } void erase(IRObjectWithUseList *from) { valueMap.erase(from); }
void erase(Value from) { valueMap.erase(from.getAsOpaquePointer()); }
/// Checks to see if a mapping for 'from' exists. /// Checks to see if a mapping for 'from' exists.
bool contains(Block *from) const { return valueMap.count(from); } bool contains(IRObjectWithUseList *from) const {
bool contains(Value from) const { return valueMap.count(from);
return valueMap.count(from.getAsOpaquePointer());
} }
/// Lookup a mapped value within the map. If a mapping for the provided value /// Lookup a mapped value within the map. If a mapping for the provided value
@ -56,19 +52,23 @@ public:
Block *lookupOrNull(Block *from) const { Block *lookupOrNull(Block *from) const {
return lookupOrValue(from, (Block *)nullptr); return lookupOrValue(from, (Block *)nullptr);
} }
Value lookupOrNull(Value from) const { return lookupOrValue(from, Value()); } ValuePtr lookupOrNull(ValuePtr from) const {
return lookupOrValue(from, (ValuePtr) nullptr);
}
/// Lookup a mapped value within the map. If a mapping for the provided value /// Lookup a mapped value within the map. If a mapping for the provided value
/// does not exist then return the provided value. /// does not exist then return the provided value.
Block *lookupOrDefault(Block *from) const { Block *lookupOrDefault(Block *from) const {
return lookupOrValue(from, from); return lookupOrValue(from, from);
} }
Value lookupOrDefault(Value from) const { return lookupOrValue(from, from); } ValuePtr lookupOrDefault(ValuePtr from) const {
return lookupOrValue(from, from);
}
/// Lookup a mapped value within the map. This asserts the provided value /// Lookup a mapped value within the map. This asserts the provided value
/// exists within the map. /// exists within the map.
template <typename T> T lookup(T from) const { template <typename T> T *lookup(T *from) const {
auto result = lookupOrNull(from); auto *result = lookupOrNull(from);
assert(result && "expected 'from' to be contained within the map"); assert(result && "expected 'from' to be contained within the map");
return result; return result;
} }
@ -78,18 +78,14 @@ public:
private: private:
/// Utility lookupOrValue that looks up an existing key or returns the /// Utility lookupOrValue that looks up an existing key or returns the
/// provided value. /// provided value. This function assumes that if a mapping does exist, then
Block *lookupOrValue(Block *from, Block *value) const { /// it is of 'T' type.
template <typename T> T *lookupOrValue(T *from, T *value) const {
auto it = valueMap.find(from); auto it = valueMap.find(from);
return it != valueMap.end() ? reinterpret_cast<Block *>(it->second) : value; return it != valueMap.end() ? static_cast<T *>(it->second) : value;
}
Value lookupOrValue(Value from, Value value) const {
auto it = valueMap.find(from.getAsOpaquePointer());
return it != valueMap.end() ? Value::getFromOpaquePointer(it->second)
: value;
} }
DenseMap<void *, void *> valueMap; DenseMap<IRObjectWithUseList *, IRObjectWithUseList *> valueMap;
}; };
} // end namespace mlir } // end namespace mlir

View File

@ -151,14 +151,17 @@ private:
// Make the implementations convenient to use. // Make the implementations convenient to use.
inline OpAsmPrinter &operator<<(OpAsmPrinter &p, ValueRef value) { inline OpAsmPrinter &operator<<(OpAsmPrinter &p, ValueRef value) {
p.printOperand(value); p.printOperand(&value);
return p; return p;
} }
inline OpAsmPrinter &operator<<(OpAsmPrinter &p, ValuePtr value) {
return p << *value;
}
template <typename T, template <typename T, typename std::enable_if<
typename std::enable_if<std::is_convertible<T &, ValueRange>::value && std::is_convertible<T &, ValueRange>::value &&
!std::is_convertible<T &, Value &>::value, !std::is_convertible<T &, ValuePtr>::value,
T>::type * = nullptr> T>::type * = nullptr>
inline OpAsmPrinter &operator<<(OpAsmPrinter &p, const T &values) { inline OpAsmPrinter &operator<<(OpAsmPrinter &p, const T &values) {
p.printOperands(values); p.printOperands(values);
return p; return p;
@ -178,7 +181,8 @@ inline OpAsmPrinter &operator<<(OpAsmPrinter &p, Attribute attr) {
// even if it isn't exactly one of them. For example, we want to print // even if it isn't exactly one of them. For example, we want to print
// FunctionType with the Type version above, not have it match this. // FunctionType with the Type version above, not have it match this.
template <typename T, typename std::enable_if< template <typename T, typename std::enable_if<
!std::is_convertible<T &, Value &>::value && !std::is_convertible<T &, ValueRef>::value &&
!std::is_convertible<T &, ValuePtr>::value &&
!std::is_convertible<T &, Type &>::value && !std::is_convertible<T &, Type &>::value &&
!std::is_convertible<T &, Attribute &>::value && !std::is_convertible<T &, Attribute &>::value &&
!std::is_convertible<T &, ValueRange>::value && !std::is_convertible<T &, ValueRange>::value &&

View File

@ -255,7 +255,7 @@ public:
unsigned getNumResults() { return numResults; } unsigned getNumResults() { return numResults; }
ValuePtr getResult(unsigned idx) { return getOpResult(idx); } ValuePtr getResult(unsigned idx) { return &getOpResult(idx); }
/// Support result iteration. /// Support result iteration.
using result_range = ResultRange; using result_range = ResultRange;

View File

@ -534,8 +534,8 @@ private:
/// This class implements iteration on the types of a given range of values. /// This class implements iteration on the types of a given range of values.
template <typename ValueIteratorT> template <typename ValueIteratorT>
class ValueTypeIterator final class ValueTypeIterator final
: public llvm::mapped_iterator<ValueIteratorT, Type (*)(Value)> { : public llvm::mapped_iterator<ValueIteratorT, Type (*)(ValuePtr)> {
static Type unwrap(Value value) { return value.getType(); } static Type unwrap(ValuePtr value) { return value->getType(); }
public: public:
using reference = Type; using reference = Type;
@ -545,7 +545,8 @@ public:
/// Initializes the type iterator to the specified value iterator. /// Initializes the type iterator to the specified value iterator.
ValueTypeIterator(ValueIteratorT it) ValueTypeIterator(ValueIteratorT it)
: llvm::mapped_iterator<ValueIteratorT, Type (*)(Value)>(it, &unwrap) {} : llvm::mapped_iterator<ValueIteratorT, Type (*)(ValuePtr)>(it, &unwrap) {
}
}; };
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
@ -554,7 +555,7 @@ public:
/// This class implements the operand iterators for the Operation class. /// This class implements the operand iterators for the Operation class.
class OperandRange final class OperandRange final
: public detail::indexed_accessor_range_base<OperandRange, OpOperand *, : public detail::indexed_accessor_range_base<OperandRange, OpOperand *,
Value, Value, Value> { ValuePtr, ValuePtr, ValuePtr> {
public: public:
using RangeBaseT::RangeBaseT; using RangeBaseT::RangeBaseT;
OperandRange(Operation *op); OperandRange(Operation *op);
@ -569,7 +570,7 @@ private:
return object + index; return object + index;
} }
/// See `detail::indexed_accessor_range_base` for details. /// See `detail::indexed_accessor_range_base` for details.
static Value dereference_iterator(OpOperand *object, ptrdiff_t index) { static ValuePtr dereference_iterator(OpOperand *object, ptrdiff_t index) {
return object[index].get(); return object[index].get();
} }
@ -582,8 +583,8 @@ private:
/// This class implements the result iterators for the Operation class. /// This class implements the result iterators for the Operation class.
class ResultRange final class ResultRange final
: public detail::indexed_accessor_range_base<ResultRange, OpResult *, Value, : public detail::indexed_accessor_range_base<ResultRange, OpResultPtr,
Value, Value> { ValuePtr, ValuePtr, ValuePtr> {
public: public:
using RangeBaseT::RangeBaseT; using RangeBaseT::RangeBaseT;
ResultRange(Operation *op); ResultRange(Operation *op);
@ -594,12 +595,12 @@ public:
private: private:
/// See `detail::indexed_accessor_range_base` for details. /// See `detail::indexed_accessor_range_base` for details.
static OpResult *offset_base(OpResult *object, ptrdiff_t index) { static OpResultPtr offset_base(OpResultPtr object, ptrdiff_t index) {
return object + index; return object + index;
} }
/// See `detail::indexed_accessor_range_base` for details. /// See `detail::indexed_accessor_range_base` for details.
static Value dereference_iterator(OpResult *object, ptrdiff_t index) { static ValuePtr dereference_iterator(OpResultPtr object, ptrdiff_t index) {
return object[index]; return &object[index];
} }
/// Allow access to `offset_base` and `dereference_iterator`. /// Allow access to `offset_base` and `dereference_iterator`.
@ -616,24 +617,25 @@ private:
/// parameter. /// parameter.
class ValueRange final class ValueRange final
: public detail::indexed_accessor_range_base< : public detail::indexed_accessor_range_base<
ValueRange, PointerUnion<const Value *, OpOperand *, OpResult *>, ValueRange, PointerUnion<ValuePtr const *, OpOperand *, OpResultPtr>,
Value, Value, Value> { ValuePtr, ValuePtr, ValuePtr> {
public: public:
using RangeBaseT::RangeBaseT; using RangeBaseT::RangeBaseT;
template <typename Arg, template <typename Arg,
typename = typename std::enable_if_t< typename = typename std::enable_if_t<
std::is_constructible<ArrayRef<Value>, Arg>::value && std::is_constructible<ArrayRef<ValuePtr>, Arg>::value &&
!std::is_convertible<Arg, Value>::value>> !std::is_convertible<Arg, ValuePtr>::value>>
ValueRange(Arg &&arg) : ValueRange(ArrayRef<Value>(std::forward<Arg>(arg))) {} ValueRange(Arg &&arg)
ValueRange(const Value &value) : ValueRange(&value, /*count=*/1) {} : ValueRange(ArrayRef<ValuePtr>(std::forward<Arg>(arg))) {}
ValueRange(const std::initializer_list<Value> &values) ValueRange(ValuePtr const &value) : ValueRange(&value, /*count=*/1) {}
: ValueRange(ArrayRef<Value>(values)) {} ValueRange(const std::initializer_list<ValuePtr> &values)
: ValueRange(ArrayRef<ValuePtr>(values)) {}
ValueRange(iterator_range<OperandRange::iterator> values) ValueRange(iterator_range<OperandRange::iterator> values)
: ValueRange(OperandRange(values)) {} : ValueRange(OperandRange(values)) {}
ValueRange(iterator_range<ResultRange::iterator> values) ValueRange(iterator_range<ResultRange::iterator> values)
: ValueRange(ResultRange(values)) {} : ValueRange(ResultRange(values)) {}
ValueRange(ArrayRef<Value> values = llvm::None); ValueRange(ArrayRef<ValuePtr> values = llvm::None);
ValueRange(OperandRange values); ValueRange(OperandRange values);
ValueRange(ResultRange values); ValueRange(ResultRange values);
@ -644,12 +646,12 @@ public:
private: private:
/// The type representing the owner of this range. This is either a list of /// The type representing the owner of this range. This is either a list of
/// values, operands, or results. /// values, operands, or results.
using OwnerT = PointerUnion<const Value *, OpOperand *, OpResult *>; using OwnerT = PointerUnion<ValuePtr const *, OpOperand *, OpResultPtr>;
/// See `detail::indexed_accessor_range_base` for details. /// See `detail::indexed_accessor_range_base` for details.
static OwnerT offset_base(const OwnerT &owner, ptrdiff_t index); static OwnerT offset_base(const OwnerT &owner, ptrdiff_t index);
/// See `detail::indexed_accessor_range_base` for details. /// See `detail::indexed_accessor_range_base` for details.
static Value dereference_iterator(const OwnerT &owner, ptrdiff_t index); static ValuePtr dereference_iterator(const OwnerT &owner, ptrdiff_t index);
/// Allow access to `offset_base` and `dereference_iterator`. /// Allow access to `offset_base` and `dereference_iterator`.
friend RangeBaseT; friend RangeBaseT;

View File

@ -42,6 +42,7 @@ Type getElementTypeOrSelf(Type type);
/// Return the element type or return the type itself. /// Return the element type or return the type itself.
Type getElementTypeOrSelf(Attribute attr); Type getElementTypeOrSelf(Attribute attr);
Type getElementTypeOrSelf(ValuePtr val); Type getElementTypeOrSelf(ValuePtr val);
Type getElementTypeOrSelf(ValueRef val);
/// Get the types within a nested Tuple. A helper for the class method that /// Get the types within a nested Tuple. A helper for the class method that
/// handles storage concerns, which is tricky to do in tablegen. /// handles storage concerns, which is tricky to do in tablegen.

View File

@ -30,7 +30,6 @@ namespace mlir {
class IROperand; class IROperand;
class Operation; class Operation;
class Value;
template <typename OperandType> class ValueUseIterator; template <typename OperandType> class ValueUseIterator;
template <typename OperandType> class ValueUserIterator; template <typename OperandType> class ValueUserIterator;
@ -177,22 +176,6 @@ private:
} }
}; };
/// A reference to a value, suitable for use as an operand of an operation.
class OpOperand : public IROperand {
public:
OpOperand(Operation *owner) : IROperand(owner) {}
OpOperand(Operation *owner, Value value);
/// Return the current value being used by this operand.
Value get();
/// Set the current value being used by this operand.
void set(Value newValue);
/// Return which operand this is in the operand list of the User.
unsigned getOperandNumber();
};
/// A reference to a value, suitable for use as an operand of an operation, /// A reference to a value, suitable for use as an operand of an operation,
/// operation, etc. IRValueTy is the root type to use for values this tracks, /// operation, etc. IRValueTy is the root type to use for values this tracks,
/// and SSAUserTy is the type that will contain operands. /// and SSAUserTy is the type that will contain operands.

View File

@ -34,101 +34,40 @@ class OpResult;
class Region; class Region;
class Value; class Value;
namespace detail { /// Using directives that simplify the transition of Value to being value typed.
/// The internal implementation of a Value. using BlockArgumentPtr = BlockArgument *;
class ValueImpl : public IRObjectWithUseList { using OpResultPtr = OpResult *;
protected: using ValueRef = Value &;
/// This enumerates all of the SSA value kinds. using ValuePtr = Value *;
enum class Kind {
BlockArgument,
OpResult,
};
ValueImpl(Kind kind, Type type) : typeAndKind(type, kind) {} /// Operands contain a Value.
using OpOperand = IROperandImpl<Value>;
private: /// This is the common base class for all SSA values in the MLIR system,
/// The type of the value and its kind. /// representing a computable value that has a type and a set of users.
llvm::PointerIntPair<Type, 1, Kind> typeAndKind;
/// Allow access to 'typeAndKind'.
friend Value;
};
/// The internal implementation of a BlockArgument.
class BlockArgumentImpl : public ValueImpl {
BlockArgumentImpl(Type type, Block *owner)
: ValueImpl(Kind::BlockArgument, type), owner(owner) {}
/// The owner of this argument.
Block *owner;
/// Allow access to owner and constructor.
friend BlockArgument;
};
class OpResultImpl : public ValueImpl {
OpResultImpl(Type type, Operation *owner)
: ValueImpl(Kind::OpResult, type), owner(owner) {}
/// The owner of this result.
Operation *owner;
/// Allow access to owner and the constructor.
friend OpResult;
};
} // end namespace detail
/// This class represents an instance of an SSA value in the MLIR system,
/// representing a computable value that has a type and a set of users. An SSA
/// value is either a BlockArgument or the result of an operation. Note: This
/// class has value-type semantics and is just a simple wrapper around a
/// ValueImpl that is either owner by a block(in the case of a BlockArgument) or
/// an Operation(in the case of an OpResult).
/// ///
class Value { class Value : public IRObjectWithUseList {
public: public:
/// This enumerates all of the SSA value kinds in the MLIR system. /// This enumerates all of the SSA value kinds in the MLIR system.
enum class Kind { enum class Kind {
BlockArgument, BlockArgument, // block argument
OpResult, OpResult, // operation result
}; };
Value(std::nullptr_t) : impl(nullptr) {}
Value(detail::ValueImpl *impl = nullptr) : impl(impl) {}
Value(const Value &) = default;
Value &operator=(const Value &) = default;
~Value() {} ~Value() {}
template <typename U> bool isa() const { template <typename U> bool isa() const { return U::classof(this); }
assert(impl && "isa<> used on a null type."); template <typename U> U *dyn_cast() const {
return U::classof(*this); return isa<U>() ? (U *)this : nullptr;
} }
template <typename U> U dyn_cast() const { template <typename U> U *cast() const {
return isa<U>() ? U(impl) : U(nullptr);
}
template <typename U> U dyn_cast_or_null() const {
return (impl && isa<U>()) ? U(impl) : U(nullptr);
}
template <typename U> U cast() const {
assert(isa<U>()); assert(isa<U>());
return U(impl); return (U *)this;
} }
/// Temporary methods to enable transition of Value to being used as a Kind getKind() const { return typeAndKind.getInt(); }
/// value-type.
/// TODO(riverriddle) Remove these when all usages have been removed.
Value operator*() const { return *this; }
Value *operator->() const { return (Value *)this; }
operator bool() const { return impl; } Type getType() const { return typeAndKind.getPointer(); }
bool operator==(const Value &other) const { return impl == other.impl; }
bool operator!=(const Value &other) const { return !(*this == other); }
/// Return the kind of this value.
Kind getKind() const { return (Kind)impl->typeAndKind.getInt(); }
/// Return the type of this value.
Type getType() const { return impl->typeAndKind.getPointer(); }
/// Utility to get the associated MLIRContext that this value is defined in. /// Utility to get the associated MLIRContext that this value is defined in.
MLIRContext *getContext() const { return getType().getContext(); } MLIRContext *getContext() const { return getType().getContext(); }
@ -139,18 +78,18 @@ public:
/// completely invalid IR very easily. It is strongly recommended that you /// completely invalid IR very easily. It is strongly recommended that you
/// recreate IR objects with the right types instead of mutating them in /// recreate IR objects with the right types instead of mutating them in
/// place. /// place.
void setType(Type newType) { impl->typeAndKind.setPointer(newType); } void setType(Type newType) { typeAndKind.setPointer(newType); }
/// Replace all uses of 'this' value with the new value, updating anything in /// 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 /// the IR that uses 'this' to use the other value instead. When this returns
/// there are zero uses of 'this'. /// there are zero uses of 'this'.
void replaceAllUsesWith(Value newValue) const { void replaceAllUsesWith(ValuePtr newValue) {
impl->replaceAllUsesWith(newValue.impl); IRObjectWithUseList::replaceAllUsesWith(newValue);
} }
/// If this value is the result of an operation, return the operation that /// If this value is the result of an operation, return the operation that
/// defines it. /// defines it.
Operation *getDefiningOp() const; Operation *getDefiningOp();
/// If this value is the result of an operation, use it as a location, /// If this value is the result of an operation, use it as a location,
/// otherwise return an unknown location. /// otherwise return an unknown location.
@ -168,51 +107,24 @@ public:
/// Returns a range of all uses, which is useful for iterating over all uses. /// Returns a range of all uses, which is useful for iterating over all uses.
inline use_range getUses(); inline use_range getUses();
using user_iterator = ValueUserIterator<IROperand>;
using user_range = iterator_range<user_iterator>;
user_iterator user_begin() const { return impl->user_begin(); }
user_iterator user_end() const { return impl->user_end(); }
/// Returns a range of all users.
user_range getUsers() const { return impl->getUsers(); }
/// Returns true if this value has no uses.
bool use_empty() const { return impl->use_empty(); }
/// Returns true if this value has exactly one use.
bool hasOneUse() const { return impl->hasOneUse(); }
/// Drop all uses of this object from their respective owners.
void dropAllUses() const { impl->dropAllUses(); }
void print(raw_ostream &os); void print(raw_ostream &os);
void dump(); void dump();
/// Methods for supporting PointerLikeTypeTraits.
void *getAsOpaquePointer() const { return static_cast<void *>(impl); }
static Value getFromOpaquePointer(const void *pointer) {
return reinterpret_cast<detail::ValueImpl *>(const_cast<void *>(pointer));
}
friend ::llvm::hash_code hash_value(Value arg);
protected: protected:
/// The internal implementation of this value. Value(Kind kind, Type type) : typeAndKind(type, kind) {}
mutable detail::ValueImpl *impl;
/// Allow access to 'impl'. private:
friend OpOperand; llvm::PointerIntPair<Type, 1, Kind> typeAndKind;
}; };
inline raw_ostream &operator<<(raw_ostream &os, Value value) { inline raw_ostream &operator<<(raw_ostream &os, ValueRef value) {
value.print(os); value.print(os);
return os; return os;
} }
// Utility functions for iterating through Value uses. // Utility functions for iterating through Value uses.
inline auto Value::use_begin() -> use_iterator { inline auto Value::use_begin() -> use_iterator {
return use_iterator((OpOperand *)impl->getFirstUse()); return use_iterator((OpOperand *)getFirstUse());
} }
inline auto Value::use_end() -> use_iterator { return use_iterator(nullptr); } inline auto Value::use_end() -> use_iterator { return use_iterator(nullptr); }
@ -224,154 +136,47 @@ inline auto Value::getUses() -> iterator_range<use_iterator> {
/// Block arguments are values. /// Block arguments are values.
class BlockArgument : public Value { class BlockArgument : public Value {
public: public:
using Value::Value; static bool classof(const Value *value) {
return const_cast<Value *>(value)->getKind() == Kind::BlockArgument;
/// Temporary methods to enable transition of Value to being used as a
/// value-type.
/// TODO(riverriddle) Remove this when all usages have been removed.
BlockArgument *operator->() { return this; }
static bool classof(Value value) {
return value.getKind() == Kind::BlockArgument;
} }
/// Returns the block that owns this argument. Block *getOwner() { return owner; }
Block *getOwner() const { return getImpl()->owner; }
/// Returns the number of this argument. /// Returns the number of this argument.
unsigned getArgNumber() const; unsigned getArgNumber();
private: private:
/// Allocate a new argument with the given type and owner. friend class Block; // For access to private constructor.
static BlockArgument create(Type type, Block *owner) { BlockArgument(Type type, Block *owner)
return new detail::BlockArgumentImpl(type, owner); : Value(Value::Kind::BlockArgument, type), owner(owner) {}
}
/// Destroy and deallocate this argument. /// The owner of this operand.
void destroy() { delete getImpl(); } /// TODO: can encode this more efficiently to avoid the space hit of this
/// through bitpacking shenanigans.
/// Get a raw pointer to the internal implementation. Block *const owner;
detail::BlockArgumentImpl *getImpl() const {
return reinterpret_cast<detail::BlockArgumentImpl *>(impl);
}
/// Allow access to `create` and `destroy`.
friend Block;
}; };
/// This is a value defined by a result of an operation. /// This is a value defined by a result of an operation.
class OpResult : public Value { class OpResult : public Value {
public: public:
using Value::Value; OpResult(Type type, Operation *owner)
: Value(Value::Kind::OpResult, type), owner(owner) {}
/// Temporary methods to enable transition of Value to being used as a static bool classof(const Value *value) {
/// value-type. return const_cast<Value *>(value)->getKind() == Kind::OpResult;
/// TODO(riverriddle) Remove these when all usages have been removed. }
OpResult *operator*() { return this; }
OpResult *operator->() { return this; }
static bool classof(Value value) { return value.getKind() == Kind::OpResult; } Operation *getOwner() { return owner; }
/// Returns the operation that owns this result.
Operation *getOwner() const { return getImpl()->owner; }
/// Returns the number of this result. /// Returns the number of this result.
unsigned getResultNumber() const; unsigned getResultNumber();
private: private:
/// Allocate a new result with the given type and owner. /// The owner of this operand.
static OpResult create(Type type, Operation *owner) { /// TODO: can encode this more efficiently to avoid the space hit of this
return new detail::OpResultImpl(type, owner); /// through bitpacking shenanigans.
} Operation *const owner;
/// Destroy and deallocate this result.
void destroy() { delete getImpl(); }
/// Get a raw pointer to the internal implementation.
detail::OpResultImpl *getImpl() const {
return reinterpret_cast<detail::OpResultImpl *>(impl);
}
/// Allow access to `create` and `destroy`.
friend Operation;
}; };
/// Make Value hashable.
inline ::llvm::hash_code hash_value(Value arg) {
return ::llvm::hash_value(arg.impl);
}
/// Using directives that simplify the transition of Value to being value typed.
using BlockArgumentPtr = BlockArgument;
using OpResultPtr = OpResult;
using ValueRef = Value;
using ValuePtr = Value;
} // namespace mlir } // namespace mlir
namespace llvm {
template <> struct DenseMapInfo<mlir::Value> {
static mlir::Value getEmptyKey() {
auto pointer = llvm::DenseMapInfo<void *>::getEmptyKey();
return mlir::Value(static_cast<mlir::detail::ValueImpl *>(pointer));
}
static mlir::Value getTombstoneKey() {
auto pointer = llvm::DenseMapInfo<void *>::getTombstoneKey();
return mlir::Value(static_cast<mlir::detail::ValueImpl *>(pointer));
}
static unsigned getHashValue(mlir::Value val) {
return mlir::hash_value(val);
}
static bool isEqual(mlir::Value LHS, mlir::Value RHS) { return LHS == RHS; }
};
/// Allow stealing the low bits of a value.
template <> struct PointerLikeTypeTraits<mlir::Value> {
public:
static inline void *getAsVoidPointer(mlir::Value I) {
return const_cast<void *>(I.getAsOpaquePointer());
}
static inline mlir::Value getFromVoidPointer(void *P) {
return mlir::Value::getFromOpaquePointer(P);
}
enum {
NumLowBitsAvailable =
PointerLikeTypeTraits<mlir::detail::ValueImpl *>::NumLowBitsAvailable
};
};
template <> struct DenseMapInfo<mlir::BlockArgument> {
static mlir::BlockArgument getEmptyKey() {
auto pointer = llvm::DenseMapInfo<void *>::getEmptyKey();
return mlir::BlockArgument(static_cast<mlir::detail::ValueImpl *>(pointer));
}
static mlir::BlockArgument getTombstoneKey() {
auto pointer = llvm::DenseMapInfo<void *>::getTombstoneKey();
return mlir::BlockArgument(static_cast<mlir::detail::ValueImpl *>(pointer));
}
static unsigned getHashValue(mlir::BlockArgument val) {
return mlir::hash_value(val);
}
static bool isEqual(mlir::BlockArgument LHS, mlir::BlockArgument RHS) {
return LHS == RHS;
}
};
/// Allow stealing the low bits of a value.
template <> struct PointerLikeTypeTraits<mlir::BlockArgument> {
public:
static inline void *getAsVoidPointer(mlir::Value I) {
return const_cast<void *>(I.getAsOpaquePointer());
}
static inline mlir::BlockArgument getFromVoidPointer(void *P) {
return mlir::Value::getFromOpaquePointer(P).cast<mlir::BlockArgument>();
}
enum {
NumLowBitsAvailable =
PointerLikeTypeTraits<mlir::detail::ValueImpl *>::NumLowBitsAvailable
};
};
} // end namespace llvm
#endif #endif

View File

@ -1974,7 +1974,7 @@ void FlatAffineConstraints::addLocalFloorDiv(ArrayRef<int64_t> dividend,
bool FlatAffineConstraints::findId(ValueRef id, unsigned *pos) const { bool FlatAffineConstraints::findId(ValueRef id, unsigned *pos) const {
unsigned i = 0; unsigned i = 0;
for (const auto &mayBeId : ids) { for (const auto &mayBeId : ids) {
if (mayBeId.hasValue() && mayBeId.getValue() == id) { if (mayBeId.hasValue() && mayBeId.getValue() == &id) {
*pos = i; *pos = i;
return true; return true;
} }
@ -1985,7 +1985,7 @@ bool FlatAffineConstraints::findId(ValueRef id, unsigned *pos) const {
bool FlatAffineConstraints::containsId(ValueRef id) const { bool FlatAffineConstraints::containsId(ValueRef id) const {
return llvm::any_of(ids, [&](const Optional<ValuePtr> &mayBeId) { return llvm::any_of(ids, [&](const Optional<ValuePtr> &mayBeId) {
return mayBeId.hasValue() && mayBeId.getValue() == id; return mayBeId.hasValue() && mayBeId.getValue() == &id;
}); });
} }

View File

@ -138,7 +138,7 @@ bool DominanceInfo::properlyDominates(ValuePtr a, Operation *b) {
// block arguments properly dominate all operations in their own block, so // block arguments properly dominate all operations in their own block, so
// we use a dominates check here, not a properlyDominates check. // we use a dominates check here, not a properlyDominates check.
return dominates(a.cast<BlockArgument>()->getOwner(), b->getBlock()); return dominates(cast<BlockArgument>(a)->getOwner(), b->getBlock());
} }
DominanceInfoNode *DominanceInfo::getNode(Block *a) { DominanceInfoNode *DominanceInfo::getNode(Block *a) {

View File

@ -183,7 +183,7 @@ Liveness::OperationListT Liveness::resolveLiveness(ValuePtr value) const {
if (Operation *defOp = value->getDefiningOp()) if (Operation *defOp = value->getDefiningOp())
currentBlock = defOp->getBlock(); currentBlock = defOp->getBlock();
else else
currentBlock = value.cast<BlockArgument>()->getOwner(); currentBlock = cast<BlockArgument>(value)->getOwner();
toProcess.push_back(currentBlock); toProcess.push_back(currentBlock);
visited.insert(currentBlock); visited.insert(currentBlock);
@ -281,7 +281,7 @@ void Liveness::print(raw_ostream &os) const {
if (Operation *defOp = value->getDefiningOp()) if (Operation *defOp = value->getDefiningOp())
os << "val_" << defOp->getName(); os << "val_" << defOp->getName();
else { else {
auto blockArg = value.cast<BlockArgument>(); auto blockArg = cast<BlockArgument>(value);
os << "arg" << blockArg->getArgNumber() << "@" os << "arg" << blockArg->getArgNumber() << "@"
<< blockIds[blockArg->getOwner()]; << blockIds[blockArg->getOwner()];
} }

View File

@ -105,7 +105,7 @@ static void getBackwardSliceImpl(Operation *op,
for (auto en : llvm::enumerate(op->getOperands())) { for (auto en : llvm::enumerate(op->getOperands())) {
auto operand = en.value(); auto operand = en.value();
if (auto blockArg = operand.dyn_cast<BlockArgument>()) { if (auto blockArg = dyn_cast<BlockArgument>(operand)) {
if (auto affIv = getForInductionVarOwner(operand)) { if (auto affIv = getForInductionVarOwner(operand)) {
auto *affOp = affIv.getOperation(); auto *affOp = affIv.getOperation();
if (backwardSlice->count(affOp) == 0) if (backwardSlice->count(affOp) == 0)

View File

@ -116,7 +116,7 @@ static bool isFunctionRegion(Region *region) {
/// function. A value of index type defined at the top level is always a valid /// function. A value of index type defined at the top level is always a valid
/// symbol. /// symbol.
bool mlir::isTopLevelValue(ValuePtr value) { bool mlir::isTopLevelValue(ValuePtr value) {
if (auto arg = value.dyn_cast<BlockArgument>()) if (auto arg = dyn_cast<BlockArgument>(value))
return isFunctionRegion(arg->getOwner()->getParent()); return isFunctionRegion(arg->getOwner()->getParent());
return isFunctionRegion(value->getDefiningOp()->getParentRegion()); return isFunctionRegion(value->getDefiningOp()->getParentRegion());
} }
@ -143,7 +143,7 @@ bool mlir::isValidDim(ValuePtr value) {
return false; return false;
} }
// This value has to be a block argument for a FuncOp or an affine.for. // This value has to be a block argument for a FuncOp or an affine.for.
auto *parentOp = value.cast<BlockArgument>()->getOwner()->getParentOp(); auto *parentOp = cast<BlockArgument>(value)->getOwner()->getParentOp();
return isa<FuncOp>(parentOp) || isa<AffineForOp>(parentOp); return isa<FuncOp>(parentOp) || isa<AffineForOp>(parentOp);
} }
@ -1580,7 +1580,7 @@ bool mlir::isForInductionVar(ValuePtr val) {
/// Returns the loop parent of an induction variable. If the provided value is /// Returns the loop parent of an induction variable. If the provided value is
/// not an induction variable, then return nullptr. /// not an induction variable, then return nullptr.
AffineForOp mlir::getForInductionVarOwner(ValuePtr val) { AffineForOp mlir::getForInductionVarOwner(ValuePtr val) {
auto ivArg = val.dyn_cast<BlockArgument>(); auto ivArg = dyn_cast<BlockArgument>(val);
if (!ivArg || !ivArg->getOwner()) if (!ivArg || !ivArg->getOwner())
return AffineForOp(); return AffineForOp();
auto *containingInst = ivArg->getOwner()->getParent()->getParentOp(); auto *containingInst = ivArg->getOwner()->getParent()->getParentOp();

View File

@ -50,7 +50,7 @@ static StringRef toStringRef(LinalgDependenceGraph::DependenceType dt) {
} }
ValuePtr Aliases::find(ValuePtr v) { ValuePtr Aliases::find(ValuePtr v) {
if (v.isa<BlockArgument>()) if (isa<BlockArgument>(v))
return v; return v;
auto it = aliases.find(v); auto it = aliases.find(v);
@ -60,7 +60,7 @@ ValuePtr Aliases::find(ValuePtr v) {
} }
while (true) { while (true) {
if (v.isa<BlockArgument>()) if (isa<BlockArgument>(v))
return v; return v;
if (auto alloc = dyn_cast_or_null<AllocOp>(v->getDefiningOp())) { if (auto alloc = dyn_cast_or_null<AllocOp>(v->getDefiningOp())) {
if (isStrided(alloc.getType())) if (isStrided(alloc.getType()))

View File

@ -145,7 +145,7 @@ LogicalResult ForOp::moveOutOfLoop(ArrayRef<Operation *> ops) {
} }
ForOp mlir::loop::getForInductionVarOwner(ValuePtr val) { ForOp mlir::loop::getForInductionVarOwner(ValuePtr val) {
auto ivArg = val.dyn_cast<BlockArgument>(); auto ivArg = dyn_cast<BlockArgument>(val);
if (!ivArg) if (!ivArg)
return ForOp(); return ForOp();
assert(ivArg->getOwner() && "unlinked block argument"); assert(ivArg->getOwner() && "unlinked block argument");

View File

@ -518,7 +518,7 @@ void Serializer::printValueIDMap(raw_ostream &os) {
<< "id = " << valueIDPair.second << ' '; << "id = " << valueIDPair.second << ' ';
if (auto *op = val->getDefiningOp()) { if (auto *op = val->getDefiningOp()) {
os << "from op '" << op->getName() << "'"; os << "from op '" << op->getName() << "'";
} else if (auto arg = val.dyn_cast<BlockArgument>()) { } else if (auto arg = dyn_cast<BlockArgument>(val)) {
Block *block = arg->getOwner(); Block *block = arg->getOwner();
os << "from argument of block " << block << ' '; os << "from argument of block " << block << ' ';
os << " in op '" << block->getParentOp()->getName() << "'"; os << " in op '" << block->getParentOp()->getName() << "'";

View File

@ -1621,7 +1621,7 @@ void OperationPrinter::numberValuesInRegion(Region &region) {
void OperationPrinter::numberValuesInBlock(Block &block) { void OperationPrinter::numberValuesInBlock(Block &block) {
auto setArgNameFn = [&](ValuePtr arg, StringRef name) { auto setArgNameFn = [&](ValuePtr arg, StringRef name) {
assert(!valueIDs.count(arg) && "arg numbered multiple times"); assert(!valueIDs.count(arg) && "arg numbered multiple times");
assert(arg.cast<BlockArgument>()->getOwner() == &block && assert(cast<BlockArgument>(arg)->getOwner() == &block &&
"arg not defined in 'block'"); "arg not defined in 'block'");
setValueName(arg, name); setValueName(arg, name);
}; };
@ -1667,7 +1667,7 @@ void OperationPrinter::numberValuesInOp(Operation &op) {
setValueName(result, name); setValueName(result, name);
// Record the result number for groups not anchored at 0. // Record the result number for groups not anchored at 0.
if (int resultNo = result.cast<OpResult>()->getResultNumber()) if (int resultNo = cast<OpResult>(result)->getResultNumber())
resultGroups.push_back(resultNo); resultGroups.push_back(resultNo);
}; };
@ -1840,7 +1840,7 @@ void OperationPrinter::printValueIDImpl(ValuePtr value, bool printResultNo,
// If this is a reference to the result of a multi-result operation or // If this is a reference to the result of a multi-result operation or
// operation, print out the # identifier and make sure to map our lookup // operation, print out the # identifier and make sure to map our lookup
// to the first result of the operation. // to the first result of the operation.
if (OpResultPtr result = value.dyn_cast<OpResult>()) if (OpResultPtr result = dyn_cast<OpResult>(value))
getResultIDAndNumber(result, lookupValue, resultNo); getResultIDAndNumber(result, lookupValue, resultNo);
auto it = valueIDs.find(lookupValue); auto it = valueIDs.find(lookupValue);

View File

@ -25,10 +25,10 @@ using namespace mlir;
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
/// Returns the number of this argument. /// Returns the number of this argument.
unsigned BlockArgument::getArgNumber() const { unsigned BlockArgument::getArgNumber() {
// Arguments are not stored in place, so we have to find it within the list. // Arguments are not stored in place, so we have to find it within the list.
auto argList = getOwner()->getArguments(); auto argList = getOwner()->getArguments();
return std::distance(argList.begin(), llvm::find(argList, *this)); return std::distance(argList.begin(), llvm::find(argList, this));
} }
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
@ -38,8 +38,7 @@ unsigned BlockArgument::getArgNumber() const {
Block::~Block() { Block::~Block() {
assert(!verifyOpOrder() && "Expected valid operation ordering."); assert(!verifyOpOrder() && "Expected valid operation ordering.");
clear(); clear();
for (BlockArgument arg : arguments) llvm::DeleteContainerPointers(arguments);
arg.destroy();
} }
Region *Block::getParent() const { return parentValidOpOrderPair.getPointer(); } Region *Block::getParent() const { return parentValidOpOrderPair.getPointer(); }
@ -153,7 +152,7 @@ void Block::recomputeOpOrder() {
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
BlockArgumentPtr Block::addArgument(Type type) { BlockArgumentPtr Block::addArgument(Type type) {
BlockArgument arg = BlockArgument::create(type, this); auto *arg = new BlockArgument(type, this);
arguments.push_back(arg); arguments.push_back(arg);
return arg; return arg;
} }
@ -173,7 +172,7 @@ void Block::eraseArgument(unsigned index, bool updatePredTerms) {
assert(index < arguments.size()); assert(index < arguments.size());
// Delete the argument. // Delete the argument.
arguments[index].destroy(); delete arguments[index];
arguments.erase(arguments.begin() + index); arguments.erase(arguments.begin() + index);
// If we aren't updating predecessors, there is nothing left to do. // If we aren't updating predecessors, there is nothing left to do.

View File

@ -77,29 +77,23 @@ OperationName OperationName::getFromOpaquePointer(void *pointer) {
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
/// Return the result number of this result. /// Return the result number of this result.
unsigned OpResult::getResultNumber() const { unsigned OpResult::getResultNumber() {
// Results are not stored in place, so we have to find it within the list. // Results are always stored consecutively, so use pointer subtraction to
auto resList = getOwner()->getOpResults(); // figure out what number this is.
return std::distance(resList.begin(), llvm::find(resList, *this)); return this - &getOwner()->getOpResults()[0];
} }
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// OpOperand // OpOperand
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
OpOperand::OpOperand(Operation *owner, Value value) // TODO: This namespace is only required because of a bug in GCC<7.0.
: IROperand(owner, value.impl) {} namespace mlir {
/// Return the current value being used by this operand.
Value OpOperand::get() { return (detail::ValueImpl *)IROperand::get(); }
/// Set the current value being used by this operand.
void OpOperand::set(Value newValue) { IROperand::set(newValue.impl); }
/// Return which operand this is in the operand list. /// Return which operand this is in the operand list.
unsigned OpOperand::getOperandNumber() { template <> unsigned OpOperand::getOperandNumber() {
return this - &getOwner()->getOpOperands()[0]; return this - &getOwner()->getOpOperands()[0];
} }
} // end namespace mlir
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// BlockOperand // BlockOperand
@ -194,7 +188,7 @@ Operation *Operation::create(Location location, OperationName name,
auto instResults = op->getOpResults(); auto instResults = op->getOpResults();
for (unsigned i = 0, e = resultTypes.size(); i != e; ++i) for (unsigned i = 0, e = resultTypes.size(); i != e; ++i)
new (&instResults[i]) OpResult(OpResult::create(resultTypes[i], op)); new (&instResults[i]) OpResult(resultTypes[i], op);
auto opOperands = op->getOpOperands(); auto opOperands = op->getOpOperands();
@ -271,7 +265,7 @@ Operation::~Operation() {
getOperandStorage().~OperandStorage(); getOperandStorage().~OperandStorage();
for (auto &result : getOpResults()) for (auto &result : getOpResults())
result.destroy(); result.~OpResult();
// Explicitly run the destructors for the successors. // Explicitly run the destructors for the successors.
for (auto &successor : getBlockOperands()) for (auto &successor : getBlockOperands())

View File

@ -164,7 +164,7 @@ ResultRange::ResultRange(Operation *op)
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// ValueRange // ValueRange
ValueRange::ValueRange(ArrayRef<Value> values) ValueRange::ValueRange(ArrayRef<ValuePtr> values)
: ValueRange(values.data(), values.size()) {} : ValueRange(values.data(), values.size()) {}
ValueRange::ValueRange(OperandRange values) ValueRange::ValueRange(OperandRange values)
: ValueRange(values.begin().getBase(), values.size()) {} : ValueRange(values.begin().getBase(), values.size()) {}
@ -176,18 +176,19 @@ ValueRange::OwnerT ValueRange::offset_base(const OwnerT &owner,
ptrdiff_t index) { ptrdiff_t index) {
if (OpOperand *operand = owner.dyn_cast<OpOperand *>()) if (OpOperand *operand = owner.dyn_cast<OpOperand *>())
return operand + index; return operand + index;
if (OpResult *result = owner.dyn_cast<OpResult *>()) if (OpResultPtr result = owner.dyn_cast<OpResultPtr>())
return result + index; return result + index;
return owner.get<const Value *>() + index; return owner.get<ValuePtr const *>() + index;
} }
/// See `detail::indexed_accessor_range_base` for details. /// See `detail::indexed_accessor_range_base` for details.
Value ValueRange::dereference_iterator(const OwnerT &owner, ptrdiff_t index) { ValuePtr ValueRange::dereference_iterator(const OwnerT &owner,
ptrdiff_t index) {
// Operands access the held value via 'get'. // Operands access the held value via 'get'.
if (OpOperand *operand = owner.dyn_cast<OpOperand *>()) if (OpOperand *operand = owner.dyn_cast<OpOperand *>())
return operand[index].get(); return operand[index].get();
// An OpResult is a value, so we can return it directly. // An OpResult is a value, so we can return it directly.
if (OpResult *result = owner.dyn_cast<OpResult *>()) if (OpResultPtr result = owner.dyn_cast<OpResultPtr>())
return result[index]; return &result[index];
// Otherwise, this is a raw value array so just index directly. // Otherwise, this is a raw value array so just index directly.
return owner.get<const Value *>()[index]; return owner.get<ValuePtr const *>()[index];
} }

View File

@ -37,6 +37,10 @@ Type mlir::getElementTypeOrSelf(ValuePtr val) {
return getElementTypeOrSelf(val->getType()); return getElementTypeOrSelf(val->getType());
} }
Type mlir::getElementTypeOrSelf(ValueRef val) {
return getElementTypeOrSelf(val.getType());
}
Type mlir::getElementTypeOrSelf(Attribute attr) { Type mlir::getElementTypeOrSelf(Attribute attr) {
return getElementTypeOrSelf(attr.getType()); return getElementTypeOrSelf(attr.getType());
} }

View File

@ -22,8 +22,8 @@ using namespace mlir;
/// If this value is the result of an Operation, return the operation that /// If this value is the result of an Operation, return the operation that
/// defines it. /// defines it.
Operation *Value::getDefiningOp() const { Operation *Value::getDefiningOp() {
if (auto result = dyn_cast<OpResult>()) if (auto *result = dyn_cast<OpResult>())
return result->getOwner(); return result->getOwner();
return nullptr; return nullptr;
} }