19#ifndef MLIR_IR_OPDEFINITION_H
20#define MLIR_IR_OPDEFINITION_H
25#include "llvm/Support/PointerLikeTypeTraits.h"
57 std::optional<ParseResult>
impl;
68 Region ®ion, OpBuilder &builder, Location loc,
69 function_ref<Operation *(OpBuilder &, Location)> buildTerminatorOp);
71 Region ®ion, Builder &builder, Location loc,
72 function_ref<Operation *(OpBuilder &, Location)> buildTerminatorOp);
85template <
class Op,
class =
void>
91 using type =
typename Op::Properties;
119 state->
print(os, flags);
122 state->print(os, asmState);
143 InFlightDiagnostic
emitError(
const Twine &message = {});
147 InFlightDiagnostic
emitWarning(
const Twine &message = {});
151 InFlightDiagnostic
emitRemark(
const Twine &message = {});
165 typename Iterator = ForwardIterator,
typename FnT,
167 std::enable_if_t<llvm::function_traits<std::decay_t<FnT>>::num_args == 1,
170 return state->walk<Order, Iterator>(std::forward<FnT>(callback));
194 template <
typename FnT,
typename RetT = detail::walkResultType<FnT>>
195 std::enable_if_t<llvm::function_traits<std::decay_t<FnT>>::num_args == 2,
198 return state->walk(std::forward<FnT>(callback));
239 static void printOpName(Operation *op, OpAsmPrinter &p,
240 StringRef defaultDialect);
252 return emptyProperties;
264 return lhs.getOperation() ==
rhs.getOperation();
267 return lhs.getOperation() !=
rhs.getOperation();
277 LLVM_DUMP_METHOD
void dump()
const { llvm::errs() << *
this <<
"\n"; }
281 return isa<Attribute>(pu) ? cast<Attribute>(pu).getContext()
282 : cast<Value>(pu).getContext();
295template <
typename To>
297 :
public CastInfo<To, mlir::OpFoldResult::PointerUnion> {};
299template <
typename To>
301 :
public CastInfo<To, const mlir::OpFoldResult::PointerUnion> {};
309 if (
Value value = llvm::dyn_cast_if_present<Value>(ofr))
312 llvm::dyn_cast_if_present<Attribute>(ofr).print(os);
331LogicalResult
foldCommutative(Operation *op, ArrayRef<Attribute> operands,
332 SmallVectorImpl<OpFoldResult> &results);
367 StringRef valueGroupName,
368 size_t expectedCount);
378template <
typename ConcreteType,
template <
typename>
class TraitType>
383 auto *concrete =
static_cast<ConcreteType *
>(
this);
384 return concrete->getOperation();
395template <
typename ConcreteType,
template <
typename>
class TraitType>
437template <
typename ConcreteType>
441 return cast<ConcreteType>(op).verifyInvariantsImpl();
447template <
typename ConcreteType>
462template <
typename ConcreteType>
482 static_assert(N > 1,
"use ZeroOperands/OneOperand for N < 2");
484 template <
typename ConcreteType>
502 template <
typename ConcreteType>
504 AtLeastNOperands<N>::Impl> {
514template <
typename ConcreteType>
524template <
typename ConcreteType>
535template <
typename ConcreteType,
template <
typename>
class TraitType>
556template <
typename ConcreteType>
563 template <
typename OpT>
578 static_assert(N > 1,
"use ZeroRegions/OneRegion for N < 2");
580 template <
typename ConcreteType>
595 template <
typename ConcreteType>
597 AtLeastNRegions<N>::Impl> {
607template <
typename ConcreteType>
617template <
typename ConcreteType>
628template <
typename ConcreteType,
template <
typename>
class TraitType>
643 template <
typename ValuesT>
673template <
typename ConcreteType>
697template <
typename ResultType>
702 template <
typename ConcreteType>
704 :
public TraitBase<ConcreteType, OneTypedResult<ResultType>::Impl> {
707 return cast<mlir::TypedValue<ResultType>>(
727 static_assert(N > 1,
"use ZeroResults/OneResult for N < 2");
729 template <
typename ConcreteType>
747 template <
typename ConcreteType>
749 AtLeastNResults<N>::Impl> {
759template <
typename ConcreteType>
769template <
typename ConcreteType>
773template <
typename ConcreteType>
783template <
typename ConcreteType>
794template <
typename ConcreteType,
template <
typename>
class TraitType>
822template <
typename ConcreteType>
840 static_assert(N > 1,
"use ZeroSuccessors/OneSuccessor for N < 2");
842 template <
typename ConcreteType>
844 NSuccessors<N>::Impl> {
857 template <
typename ConcreteType>
860 AtLeastNSuccessors<N>::Impl> {
870template <
typename ConcreteType>
881template <
typename ConcreteType>
895 << i <<
" to have 0 or 1 blocks";
897 if (!ConcreteType::template hasTrait<NoTerminator>()) {
900 return op->
emitOpError() <<
"expects a non-empty block";
908 assert(!region.
empty() &&
"unexpected empty region");
909 return ®ion.
front();
923 template <
typename OpT,
typename T =
void>
925 std::enable_if_t<OpT::template hasTrait<OneRegion>(), T>;
927 template <
typename OpT = ConcreteType>
931 template <
typename OpT = ConcreteType>
935 template <
typename OpT = ConcreteType>
941 template <
typename OpT = ConcreteType>
947 template <
typename OpT = ConcreteType>
951 template <
typename OpT = ConcreteType>
963template <
typename TerminatorOpType>
965 template <
typename ConcreteType>
967 TerminatorOpType>::Impl> {
973 TerminatorOpType::build(builder, state);
988 if (isa<TerminatorOpType>(terminator))
991 return op->
emitOpError(
"expects regions to end with '" +
992 TerminatorOpType::getOperationName() +
996 <<
"in custom textual format, the absence of terminator implies "
998 << TerminatorOpType::getOperationName() <<
'\'';
1030template <
class Op,
bool hasTerminator =
1031 llvm::is_detected<has_implicit_terminator_t, Op>::value>
1033 static constexpr bool value = std::is_base_of<
1035 typename Op::ImplicitTerminatorOpT>::template Impl<Op>,
1050template <
typename ConcreteType>
1061template <
typename ConcreteType>
1063 :
public TraitBase<ConcreteType, SameOperandsAndResultShape> {
1073template <
typename ConcreteType>
1075 :
public TraitBase<ConcreteType, SameOperandsElementType> {
1085template <
typename ConcreteType>
1087 :
public TraitBase<ConcreteType, SameOperandsAndResultElementType> {
1099template <
typename ConcreteType>
1101 :
public TraitBase<ConcreteType, SameOperandsAndResultType> {
1110template <
typename ConcreteType>
1112 :
public TraitBase<ConcreteType, SameOperandsAndResultRank> {
1121template <
typename ConcreteType>
1131template <
typename ConcreteType>
1133 :
public TraitBase<ConcreteType, ResultsAreFloatLike> {
1142template <
typename ConcreteType>
1144 :
public TraitBase<ConcreteType, ResultsAreSignlessIntegerLike> {
1152template <
typename ConcreteType>
1163template <
typename ConcreteType>
1167 static_assert(ConcreteType::template hasTrait<OneResult>(),
1168 "expected operation to produce one result");
1169 static_assert(ConcreteType::template hasTrait<OneOperand>(),
1170 "expected operation to take one operand");
1171 static_assert(ConcreteType::template hasTrait<SameOperandsAndResultType>(),
1172 "expected operation to preserve type");
1186template <
typename ConcreteType>
1190 static_assert(ConcreteType::template hasTrait<OneResult>(),
1191 "expected operation to produce one result");
1192 static_assert(ConcreteType::template hasTrait<OneOperand>() ||
1193 ConcreteType::template hasTrait<NOperands<2>::Impl>(),
1194 "expected operation to take one or two operands");
1195 static_assert(ConcreteType::template hasTrait<SameOperandsAndResultType>(),
1196 "expected operation to preserve type");
1209template <
typename ConcreteType>
1211 :
public TraitBase<ConcreteType, OperandsAreFloatLike> {
1220template <
typename ConcreteType>
1222 :
public TraitBase<ConcreteType, OperandsAreSignlessIntegerLike> {
1231template <
typename ConcreteType>
1242template <
typename ConcreteType>
1246 static_assert(ConcreteType::template hasTrait<OneResult>(),
1247 "expected operation to produce one result");
1248 static_assert(ConcreteType::template hasTrait<ZeroOperands>(),
1249 "expected operation to take zero operands");
1260template <
typename ConcreteType>
1262 :
public TraitBase<ConcreteType, IsIsolatedFromAbove> {
1274template <
typename ConcreteType>
1278 static_assert(!ConcreteType::template hasTrait<ZeroRegions>(),
1279 "expected operation to have one or more regions");
1289template <
typename ConcreteType>
1291 :
public TraitBase<ConcreteType, AutomaticAllocationScope> {
1294 static_assert(!ConcreteType::template hasTrait<ZeroRegions>(),
1295 "expected operation to have one or more regions");
1302template <
typename... ParentOpTypes>
1304 template <
typename ConcreteType>
1308 if (llvm::isa_and_nonnull<ParentOpTypes...>(op->
getParentOp()))
1312 <<
"expects parent op "
1313 << (
sizeof...(ParentOpTypes) != 1 ?
"to be one of '" :
"'")
1314 <<
llvm::ArrayRef({ParentOpTypes::getOperationName()...}) <<
"'";
1317 template <
typename ParentOpType =
1318 std::tuple_element_t<0, std::tuple<ParentOpTypes...>>>
1319 std::enable_if_t<
sizeof...(ParentOpTypes) == 1, ParentOpType>
1322 return llvm::cast<ParentOpType>(parent);
1337template <
typename ConcreteType>
1344 return ::mlir::OpTrait::impl::verifyOperandSizeAttr(
1350template <
typename ConcreteType>
1357 return ::mlir::OpTrait::impl::verifyResultSizeAttr(
1364template <
typename ConcrentType>
1367 return ::mlir::OpTrait::impl::verifyNoRegionArguments(op);
1376template <
typename ConcrentType>
1412template <
typename ConcreteType>
1415 return ::mlir::OpTrait::impl::verifyElementwise(op);
1441template <
typename ConcreteType>
1445 ConcreteType::template hasTrait<Elementwise>(),
1446 "`Scalarizable` trait is only applicable to `Elementwise` ops.");
1461template <
typename ConcreteType>
1465 ConcreteType::template hasTrait<Elementwise>(),
1466 "`Vectorizable` trait is only applicable to `Elementwise` ops.");
1502template <
typename ConcreteType>
1506 ConcreteType::template hasTrait<Elementwise>(),
1507 "`Tensorizable` trait is only applicable to `Elementwise` ops.");
1530template <
template <
typename T>
class... Traits>
1533 for (
unsigned i = 0, e =
sizeof...(Traits); i != e; ++i)
1534 if (traitIDs[i] == traitID)
1549template <
typename T,
typename... Args>
1552template <
typename T>
1554 llvm::is_detected<has_single_result_fold_trait, T>;
1556template <
typename T,
typename... Args>
1558 decltype(T::foldTrait(std::declval<Operation *>(),
1561template <
typename T>
1564template <
typename T>
1566 std::disjunction<detect_has_fold_trait<T>,
1571template <
typename Trait>
1572static std::enable_if_t<detect_has_single_result_fold_trait<Trait>::value,
1577 "expected trait on non single-result operation to implement the "
1578 "general `foldTrait` method");
1581 if (!results.empty())
1586 results.push_back(
result);
1593template <
typename Trait>
1594static std::enable_if_t<detect_has_fold_trait<Trait>::value, LogicalResult>
1599 return results.empty() ? Trait::foldTrait(op, operands, results) : failure();
1601template <
typename Trait>
1602static inline std::enable_if_t<!detect_has_any_fold_trait<Trait>::value,
1610template <
typename... Ts>
1621template <
typename T,
typename... Args>
1623template <
typename T>
1627template <
typename T,
typename... Args>
1629 decltype(T::verifyRegionTrait(std::declval<Operation *>()));
1630template <
typename T>
1632 llvm::is_detected<has_verify_region_trait, T>;
1635template <
typename T>
1638 return T::verifyTrait(op);
1644template <
typename... Ts>
1650template <
typename T>
1653 return T::verifyRegionTrait(op);
1660template <
typename... Ts>
1673template <
typename ConcreteType,
template <
typename T>
class... Traits>
1682 template <
template <
typename T>
class Trait>
1684 return llvm::is_one_of<Trait<ConcreteType>, Traits<ConcreteType>...>::value;
1703 llvm::report_fatal_error(
1704 "classof on '" + ConcreteType::getOperationName() +
1705 "' failed due to the operation not being registered");
1711 template <
typename T>
1712 static std::enable_if_t<std::is_base_of<OpState, T>::value,
bool>
1731 return static_cast<const void *
>((
Operation *)*
this);
1735 reinterpret_cast<Operation *
>(
const_cast<void *
>(pointer)));
1740 template <
typename... Models>
1742 std::optional<RegisteredOperationName> info =
1745 llvm::report_fatal_error(
1746 "Attempting to attach an interface to an unregistered operation " +
1747 ConcreteType::getOperationName() +
".");
1748 (checkInterfaceTarget<Models>(), ...);
1749 info->attachInterface<Models...>();
1756 template <
typename PropertiesTy>
1757 static LogicalResult
1760 return setPropertiesFromAttribute(prop, attr,
emitError);
1766 template <
typename PropertiesTy>
1768 const PropertiesTy &prop) {
1769 return getPropertiesAsAttribute(ctx, prop);
1775 template <
typename PropertiesTy>
1782 template <
typename T,
typename... Args>
1783 using has_single_result_fold_t =
1785 template <
typename T>
1786 constexpr static bool has_single_result_fold_v =
1787 llvm::is_detected<has_single_result_fold_t, T>::value;
1789 template <
typename T,
typename... Args>
1790 using has_fold_t =
decltype(std::declval<T>().fold(
1793 template <
typename T>
1794 constexpr static bool has_fold_v = llvm::is_detected<has_fold_t, T>::value;
1797 template <
typename T,
typename... Args>
1798 using has_fold_adaptor_single_result_fold_t =
1799 decltype(std::declval<T>().fold(std::declval<typename T::FoldAdaptor>()));
1801 constexpr static bool has_fold_adaptor_single_result_v =
1802 llvm::is_detected<has_fold_adaptor_single_result_fold_t, T>::value;
1804 template <
typename T,
typename... Args>
1805 using has_fold_adaptor_fold_t =
decltype(std::declval<T>().fold(
1806 std::declval<typename T::FoldAdaptor>(),
1809 constexpr static bool has_fold_adaptor_v =
1810 llvm::is_detected<has_fold_adaptor_fold_t, T>::value;
1813 template <
typename T,
typename... Args>
1815 decltype(std::declval<T>().print(std::declval<OpAsmPrinter &>()));
1816 template <
typename T>
1817 using detect_has_print = llvm::is_detected<has_print, T>;
1821 template <
typename T,
typename... Args>
1822 using has_print_properties =
1826 template <
typename T>
1827 using detect_has_print_properties =
1828 llvm::is_detected<has_print_properties, T>;
1831 template <
typename T,
typename... Args>
1833 std::declval<OpAsmParser &>(), std::declval<T &>()));
1834 template <
typename T>
1835 using detect_has_parse_properties =
1836 llvm::is_detected<has_parse_properties, T>;
1839 template <
typename T>
1840 using has_concrete_entity_t =
typename T::ConcreteEntity;
1845 return !std::is_same_v<
1855 template <
typename T,
1856 bool = llvm::is_detected<has_concrete_entity_t, T>::value>
1857 struct InterfaceTargetOrOpT {
1858 using type =
typename T::ConcreteEntity;
1860 template <
typename T>
1861 struct InterfaceTargetOrOpT<T,
false> {
1862 using type = ConcreteType;
1868 template <
typename T>
1869 static void checkInterfaceTarget() {
1870 static_assert(std::is_same<typename InterfaceTargetOrOpT<T>::type,
1871 ConcreteType>::value,
1872 "attaching an interface to the wrong op kind");
1877 static detail::InterfaceMap getInterfaceMap() {
1886 if constexpr (llvm::is_one_of<OpTrait::OneResult<ConcreteType>,
1887 Traits<ConcreteType>...>::value &&
1888 (has_single_result_fold_v<ConcreteType> ||
1889 has_fold_adaptor_single_result_v<ConcreteType>))
1890 return [](Operation *op, ArrayRef<Attribute> operands,
1891 SmallVectorImpl<OpFoldResult> &results) {
1892 return foldSingleResultHook<ConcreteType>(op, operands, results);
1895 if constexpr (has_fold_v<ConcreteType> || has_fold_adaptor_v<ConcreteType>)
1896 return [](Operation *op, ArrayRef<Attribute> operands,
1897 SmallVectorImpl<OpFoldResult> &results) {
1898 return foldHook<ConcreteType>(op, operands, results);
1901 return [](Operation *op, ArrayRef<Attribute> operands,
1902 SmallVectorImpl<OpFoldResult> &results) {
1905 op, operands, results);
1910 template <
typename ConcreteOpT>
1911 static LogicalResult
1912 foldSingleResultHook(Operation *op, ArrayRef<Attribute> operands,
1913 SmallVectorImpl<OpFoldResult> &results) {
1915 if constexpr (has_fold_adaptor_single_result_v<ConcreteOpT>) {
1916 result = cast<ConcreteOpT>(op).fold(
1917 typename ConcreteOpT::FoldAdaptor(operands, cast<ConcreteOpT>(op)));
1919 result = cast<ConcreteOpT>(op).fold(operands);
1925 llvm::dyn_cast_if_present<Value>(
result) == op->getResult(0)) {
1927 op, operands, results)))
1931 results.push_back(
result);
1935 template <
typename ConcreteOpT>
1936 static LogicalResult foldHook(Operation *op, ArrayRef<Attribute> operands,
1937 SmallVectorImpl<OpFoldResult> &results) {
1938 auto result = LogicalResult::failure();
1939 if constexpr (has_fold_adaptor_v<ConcreteOpT>) {
1940 result = cast<ConcreteOpT>(op).fold(
1941 typename ConcreteOpT::FoldAdaptor(operands, cast<ConcreteOpT>(op)),
1944 result = cast<ConcreteOpT>(op).fold(operands, results);
1951 op, operands, results)))
1964 if constexpr (detect_has_print<ConcreteType>::value)
1965 return [](Operation *op, OpAsmPrinter &p, StringRef defaultDialect) {
1967 return cast<ConcreteType>(op).print(p);
1969 return [](Operation *op, OpAsmPrinter &printer, StringRef defaultDialect) {
1975 template <
typename T>
1977 template <
typename T = ConcreteType>
1983 .template as<InferredProperties<T> *>();
1987 template <
typename T = ConcreteType>
1995 template <
typename T>
1997 const T &properties,
1999 if constexpr (detect_has_print_properties<T>::value)
2002 p, ConcreteType::getPropertiesAsAttr(ctx, properties), elidedProps);
2009 template <
typename T = ConcreteType>
2012 if constexpr (detect_has_parse_properties<InferredProperties<T>>::value) {
2025 if (!propertyDictionary)
2026 propertyDictionary = DictionaryAttr::get(
result.getContext());
2030 << propertyDictionary <<
" for op " <<
result.name.getStringRef()
2038 return ConcreteOpType::setPropertiesFromParsedAttr(
2046 return ConcreteType::populateDefaultAttrs;
2049 static LogicalResult verifyInvariants(Operation *op) {
2050 static_assert(hasNoDataMembers(),
2051 "Op class shouldn't define new data members");
2054 failed(cast<ConcreteType>(op).
verify()));
2057 return static_cast<LogicalResult (*)(Operation *)
>(&verifyInvariants);
2060 static LogicalResult verifyRegionInvariants(Operation *op) {
2061 static_assert(hasNoDataMembers(),
2062 "Op class shouldn't define new data members");
2069 return static_cast<LogicalResult (*)(Operation *)
>(&verifyRegionInvariants);
2072 static constexpr bool hasNoDataMembers() {
2075 class EmptyOp :
public Op<EmptyOp, Traits...> {};
2076 return sizeof(ConcreteType) ==
sizeof(EmptyOp);
2080 friend RegisteredOperationName;
2085template <
typename ConcreteType,
typename Traits>
2088 Op<ConcreteType>, OpTrait::TraitBase> {
2107 *dialect, name.
getTypeID(), ConcreteType::getInterfaceID(),
2108 llvm::getTypeName<ConcreteType>());
2113 if (std::optional<RegisteredOperationName> rInfo =
2115 if (
auto *opIface = rInfo->getInterface<ConcreteType>())
2119 return rInfo->getDialect().getRegisteredInterfaceForOp<ConcreteType>(
2125 return dialect->getRegisteredInterfaceForOp<ConcreteType>(name);
2137template <
typename T>
2139 std::enable_if_t<std::is_base_of<mlir::OpState, T>::value &&
2140 !mlir::detail::IsInterface<T>::value>> {
2143 return T::getFromOpaquePointer(pointer);
2147 return T::getFromOpaquePointer(pointer);
2150 return hash_value(val.getAsOpaquePointer());
static llvm::hash_code computeHash(SymbolOpInterface symbolOp)
Computes a hash code to represent symbolOp based on all its attributes except for the symbol name.
false
Parses a map_entries map type from a string format back into its numeric value.
#define MLIR_DECLARE_EXPLICIT_TYPE_ID(CLASS_NAME)
This class provides management for the lifetime of the state used when printing the IR.
Attributes are known-constant values of operations.
Block represents an ordered list of Operations.
OpListType::iterator iterator
OpListType & getOperations()
This class is a general helper class for creating context-global objects like types,...
Dialects are groups of MLIR operations, types and attributes, as well as behavior associated with the...
ImplicitLocOpBuilder maintains a 'current location', allowing use of the create<> method without spec...
This class represents a diagnostic that is inflight and set to be reported.
Diagnostic & attachNote(std::optional< Location > noteLoc=std::nullopt)
Attaches a note to this diagnostic.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
MLIRContext is the top-level object for a collection of MLIR operations.
NamedAttrList is array of NamedAttributes that tracks whether it is sorted and does some basic work t...
The OpAsmParser has methods for interacting with the asm parser: parsing things from it,...
This is a pure-virtual base class that exposes the asmprinter hooks necessary to implement a custom p...
This class helps build Operations.
This class represents a single result from folding an operation.
MLIRContext * getContext() const
LLVM_DUMP_METHOD void dump() const
This class represents the base of an operation interface.
detail::Interface< ConcreteType, Operation *, Traits, Op< ConcreteType >, OpTrait::TraitBase > InterfaceBase
OpInterface< ConcreteType, Traits > Base
static InterfaceBase::Concept * getInterfaceFor(Operation *op)
Returns the impl interface instance for the given operation.
Set of flags used to control the behavior of the various IR print methods (e.g.
This is the concrete base class that holds the operation pointer and has non-generic methods that onl...
void dump()
Dump this operation.
Operation * operator->() const
Shortcut of -> to access a member of Operation.
Operation * getOperation()
Return the operation that this refers to.
static void genericPrintProperties(OpAsmPrinter &p, Attribute properties, ArrayRef< StringRef > elidedProps={})
Print the properties as a Attribute with names not included within 'elidedProps'.
std::enable_if_t< llvm::function_traits< std::decay_t< FnT > >::num_args==2, RetT > walk(FnT &&callback)
Generic walker with a stage aware callback.
static EmptyProperties & getEmptyProperties()
For all ops which don't have properties, we keep a single instance of EmptyProperties to be used wher...
void erase()
Remove this operation from its parent block and delete it.
bool use_empty()
Return true if there are no users of any results of this operation.
LogicalResult verify()
If the concrete type didn't implement a custom verifier hook, just fall back to this one which accept...
void print(raw_ostream &os, OpPrintingFlags flags={})
Print the operation to the given stream.
void print(raw_ostream &os, AsmState &asmState)
static void printOpName(Operation *op, OpAsmPrinter &p, StringRef defaultDialect)
Print an operation name, eliding the dialect prefix if necessary.
LogicalResult verifyRegions()
InFlightDiagnostic emitError(const Twine &message={})
Emit an error about fatal conditions with this operation, reporting up to any diagnostic handlers tha...
MLIRContext * getContext()
Return the context this operation belongs to.
InFlightDiagnostic emitOpError(const Twine &message={})
Emit an error with the op name prefixed, like "'dim' op " which is convenient for verifiers.
InFlightDiagnostic emitWarning(const Twine &message={})
Emit a warning about this operation, reporting up to any diagnostic handlers that may be listening.
static void getCanonicalizationPatterns(RewritePatternSet &results, MLIRContext *context)
This hook returns any canonicalization pattern rewrites that the operation supports,...
static ParseResult genericParseProperties(OpAsmParser &parser, Attribute &result)
Parse properties as a Attribute.
static ParseResult parse(OpAsmParser &parser, OperationState &result)
Parse the custom form of an operation.
InFlightDiagnostic emitRemark(const Twine &message={})
Emit a remark about this operation, reporting up to any diagnostic handlers that may be listening.
OpState(Operation *state)
Mutability management is handled by the OpWrapper/OpConstWrapper classes, so we can cast it away here...
Location getLoc()
The source location the operation was defined or derived from.
static void populateDefaultAttrs(const OperationName &, NamedAttrList &)
This hook populates any unset default attrs.
std::enable_if_t< llvm::function_traits< std::decay_t< FnT > >::num_args==1, RetT > walk(FnT &&callback)
Walk the operation by calling the callback for each nested operation (including this one),...
A trait of region holding operations that defines a new scope for polyhedral optimization purposes.
static LogicalResult verifyTrait(Operation *op)
static LogicalResult verifyTrait(Operation *op)
This class provides the API for ops that are known to have a at least a specified number of operands.
static LogicalResult verifyTrait(Operation *op)
This class provides APIs for ops that are known to have at least a specified number of regions.
static LogicalResult verifyTrait(Operation *op)
This class provides the API for ops that are known to have at least a specified number of results.
static LogicalResult verifyTrait(Operation *op)
This class provides APIs for ops that are known to have at least a specified number of successors.
A trait for operations that have an attribute specifying operand segments.
static StringRef getOperandSegmentSizeAttr()
static LogicalResult verifyTrait(Operation *op)
Similar to AttrSizedOperandSegments but used for results.
static StringRef getResultSegmentSizeAttr()
static LogicalResult verifyTrait(Operation *op)
A trait of region holding operations that define a new scope for automatic allocations,...
static LogicalResult verifyTrait(Operation *op)
This class provides the API for a sub-set of ops that are known to be constant-like.
static LogicalResult verifyTrait(Operation *op)
static LogicalResult verifyTrait(Operation *op)
std::enable_if_t< sizeof...(ParentOpTypes)==1, ParentOpType > getParentOp()
This class adds property that the operation is commutative.
static LogicalResult foldTrait(Operation *op, ArrayRef< Attribute > operands, SmallVectorImpl< OpFoldResult > &results)
This class adds property that the operation is idempotent.
static OpFoldResult foldTrait(Operation *op, ArrayRef< Attribute > operands)
static LogicalResult verifyTrait(Operation *op)
This class adds property that the operation is an involution.
static LogicalResult verifyTrait(Operation *op)
static OpFoldResult foldTrait(Operation *op, ArrayRef< Attribute > operands)
This class provides the API for ops that are known to be isolated from above.
static LogicalResult verifyRegionTrait(Operation *op)
This class provides the API for ops that are known to be terminators.
static LogicalResult verifyTrait(Operation *op)
static LogicalResult verifyTrait(Operation *op)
This class provides the API for ops that are known to have a specified number of operands.
static LogicalResult verifyTrait(Operation *op)
This class provides the API for ops that are known to have a specified number of regions.
static LogicalResult verifyTrait(Operation *op)
This class provides the API for ops that are known to have a specified number of results.
static LogicalResult verifyTrait(Operation *op)
This class provides the API for ops that are known to have a specified number of successors.
This class indicates that the regions associated with this op don't have terminators.
This class provides the API for ops that are known to have exactly one SSA operand.
void setOperand(Value value)
static LogicalResult verifyTrait(Operation *op)
This class provides APIs for ops that are known to have a single region.
static LogicalResult verifyTrait(Operation *op)
auto getOps()
Returns a range of operations within the region of this operation.
This class provides return value APIs for ops that are known to have a single result.
static LogicalResult verifyTrait(Operation *op)
void replaceAllUsesWith(Operation *op)
Replace all uses of 'this' value with the result of 'op'.
void replaceAllUsesWith(Value newValue)
Replace all uses of 'this' value with the new value, updating anything in the IR that uses 'this' to ...
This class provides APIs for ops that are known to have a single successor.
void setSuccessor(Block *succ)
static LogicalResult verifyTrait(Operation *op)
This class provides return value APIs for ops that are known to have a single result.
mlir::TypedValue< ResultType > getResult()
This trait is used for return value APIs for ops that are known to have a specific type other than Ty...
verifyInvariantsImpl verifies the invariants like the types, attrs, .etc.
static LogicalResult verifyTrait(Operation *op)
This class verifies that all operands of the specified op have a float type, a vector thereof,...
static LogicalResult verifyTrait(Operation *op)
This class verifies that all operands of the specified op have a signless integer or index type,...
static LogicalResult verifyTrait(Operation *op)
This class verifies that any results of the specified op have a boolean type, a vector thereof,...
static LogicalResult verifyTrait(Operation *op)
This class verifies that any results of the specified op have a floating point type,...
static LogicalResult verifyTrait(Operation *op)
This class verifies that any results of the specified op have a signless integer or index type,...
static LogicalResult verifyTrait(Operation *op)
This class provides verification for ops that are known to have the same operand and result element t...
static LogicalResult verifyTrait(Operation *op)
This class verifies that op has same ranks for all operands and results types, if known.
static LogicalResult verifyTrait(Operation *op)
This class provides verification for ops that are known to have the same operand and result shape: bo...
static LogicalResult verifyTrait(Operation *op)
This class provides verification for ops that are known to have the same operand and result type.
static LogicalResult verifyTrait(Operation *op)
This class provides verification for ops that are known to have the same operand element type (or the...
static LogicalResult verifyTrait(Operation *op)
This class provides verification for ops that are known to have the same operand shape: all operands ...
static LogicalResult verifyTrait(Operation *op)
This class verifies that all operands of the specified op have the same type.
static LogicalResult verifyTrait(Operation *op)
static void ensureTerminator(Region ®ion, OpBuilder &builder, Location loc)
static void ensureTerminator(Region ®ion, Builder &builder, Location loc)
Ensure that the given region has the terminator required by this trait.
static LogicalResult verifyRegionTrait(Operation *op)
TerminatorOpType ImplicitTerminatorOpT
The type of the operation used as the implicit terminator type.
Helper class for implementing traits.
Operation * getOperation()
Return the ultimate Operation being worked on.
This class provides the API for ops which have an unknown number of SSA operands.
This class provides the API for ops which have an unknown number of regions.
This class provides the API for ops which have an unknown number of results.
This class provides the API for ops which have an unknown number of successors.
This class provides the API for ops that are known to have no SSA operand.
static LogicalResult verifyTrait(Operation *op)
This class provides verification for ops that are known to have zero regions.
static LogicalResult verifyTrait(Operation *op)
This class provides return value APIs for ops that are known to have zero results.
static LogicalResult verifyTrait(Operation *op)
This class provides verification for ops that are known to have zero successors.
static LogicalResult verifyTrait(Operation *op)
This provides public APIs that all operations should have.
Operation * getOperation()
Inherit getOperation from OpState.
static bool classof(Operation *op)
Return true if this "op class" can match against the specified operation.
static LogicalResult setPropertiesFromAttr(PropertiesTy &prop, Attribute attr, function_ref< InFlightDiagnostic()> emitError)
Convert the provided attribute to a property and assigned it to the provided properties.
static ConcreteOpType getFromOpaquePointer(const void *pointer)
LogicalResult verify()
If the concrete type didn't implement a custom verifier hook, just fall back to this one which accept...
InferredProperties< T > & getProperties()
Op(Operation *state)
This is a public constructor to enable access via the llvm::cast family of methods.
ConcreteType ConcreteOpType
Expose the type we are instantiated on to template machinery that may want to introspect traits on th...
static Attribute getPropertiesAsAttr(MLIRContext *ctx, const PropertiesTy &prop)
Convert the provided properties to an attribute.
LogicalResult verifyRegions()
static void printProperties(MLIRContext *ctx, OpAsmPrinter &p, const T &properties, ArrayRef< StringRef > elidedProps={})
Print the operation properties with names not included within 'elidedProps'.
ConcreteType clone()
Create a deep copy of this operation.
const void * getAsOpaquePointer() const
Methods for supporting PointerLikeTypeTraits.
static constexpr bool hasTrait()
Return if this operation contains the provided trait.
static llvm::hash_code computePropertiesHash(const PropertiesTy &prop)
Hash the provided properties.
static constexpr bool hasProperties()
Returns true if this operation defines a Properties inner type.
Op()
This is a public constructor. Any op can be initialized to null.
static ParseResult parseProperties(OpAsmParser &parser, OperationState &result)
Parses 'prop-dict' for the operation.
static void attachInterface(MLIRContext &context)
Attach the given models as implementations of the corresponding interfaces for the concrete operation...
static std::enable_if_t< std::is_base_of< OpState, T >::value, bool > classof(const T *op)
Provide classof support for other OpBase derived classes, such as Interfaces.
typename PropertiesSelector< T >::type InferredProperties
ConcreteType cloneWithoutRegions()
Create a partial copy of this operation without traversing into attached regions.
static void populateDefaultProperties(OperationName opName, InferredProperties< T > &properties)
This hook populates any unset default attrs when mapped to properties.
StringRef getStringRef() const
Return the name of this operation. This always succeeds.
llvm::unique_function< bool(TypeID) const > HasTraitFn
Dialect * getDialect() const
Return the dialect this operation is registered to if the dialect is loaded in the context,...
std::optional< RegisteredOperationName > getRegisteredInfo() const
If this operation is registered, returns the registered information, std::nullopt otherwise.
llvm::unique_function< LogicalResult(Operation *) const > VerifyInvariantsFn
llvm::unique_function< void(const OperationName &, NamedAttrList &) const > PopulateDefaultAttrsFn
llvm::unique_function< LogicalResult(Operation *) const > VerifyRegionInvariantsFn
TypeID getTypeID() const
Return the unique identifier of the derived Op class, or null if not registered.
llvm::unique_function< LogicalResult( Operation *, ArrayRef< Attribute >, SmallVectorImpl< OpFoldResult > &) const > FoldHookFn
llvm::unique_function< void(Operation *, OpAsmPrinter &, StringRef) const > PrintAssemblyFn
Operation is the basic unit of execution within MLIR.
PropertyRef getPropertiesStorage()
Return a generic (but typed) reference to the property type storage.
ResultRange result_range
Support result iteration.
Region & getRegion(unsigned index)
Returns the region held by this operation at position 'index'.
Value getOperand(unsigned idx)
bool hasTrait()
Returns true if the operation was registered with a particular trait, e.g.
operand_range::type_range operand_type_range
void setOperand(unsigned idx, Value value)
unsigned getNumSuccessors()
result_iterator result_begin()
result_range::iterator result_iterator
operand_iterator operand_begin()
OpResult getResult(unsigned idx)
Get the 'idx'th result of this operation.
operand_range::type_iterator operand_type_iterator
operand_type_iterator operand_type_end()
result_range::type_range result_type_range
unsigned getNumRegions()
Returns the number of regions held by this operation.
Operation * getParentOp()
Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...
std::optional< RegisteredOperationName > getRegisteredInfo()
If this operation has a registered operation description, return it.
unsigned getNumOperands()
result_type_iterator result_type_end()
OperandRange operand_range
result_range::type_iterator result_type_iterator
Support result type iteration.
operand_iterator operand_end()
result_type_iterator result_type_begin()
OperationName getName()
The name of an operation is the key identifier for it.
void print(raw_ostream &os, const OpPrintingFlags &flags={})
operand_type_range getOperandTypes()
MutableArrayRef< Region > getRegions()
Returns the regions held by this operation.
result_iterator result_end()
static Operation * create(Location location, OperationName name, TypeRange resultTypes, ValueRange operands, NamedAttrList &&attributes, PropertyRef properties, BlockRange successors, unsigned numRegions)
Create a new Operation with the specific fields.
result_type_range getResultTypes()
operand_range getOperands()
Returns an iterator on the underlying Value's.
void setSuccessor(Block *block, unsigned index)
void replaceAllUsesWith(ValuesT &&values)
Replace all uses of results of this operation with the provided 'values'.
Block * getSuccessor(unsigned index)
SuccessorRange getSuccessors()
result_range getResults()
SuccessorRange::iterator succ_iterator
MLIRContext * getContext()
Return the context this operation is associated with.
operand_range::iterator operand_iterator
InFlightDiagnostic emitOpError(const Twine &message={})
Emit an error with the op name prefixed, like "'dim' op " which is convenient for verifiers.
unsigned getNumResults()
Return the number of results held by this operation.
operand_type_iterator operand_type_begin()
OptionalParseResult()=default
ParseResult value() const
Access the internal ParseResult value.
OptionalParseResult(ParseResult result)
OptionalParseResult(std::nullopt_t)
OptionalParseResult(const InFlightDiagnostic &)
OptionalParseResult(LogicalResult result)
bool has_value() const
Returns true if we contain a valid ParseResult value.
ParseResult operator*() const
This class provides an abstraction over the different types of ranges over Regions.
This class contains a list of basic blocks and a link to the parent operation it is attached to.
iterator_range< OpIterator > getOps()
bool hasOneBlock()
Return true if this region has exactly one block.
This is a "type erased" representation of a registered operation.
static std::optional< RegisteredOperationName > lookup(StringRef name, MLIRContext *ctx)
Lookup the registered operation information for the given operation.
This class implements the successor iterators for Block.
This class provides an efficient unique identifier for a specific C++ type.
static TypeID get()
Construct a type info object for the given type T.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Type getType() const
Return the type of this value.
void replaceAllUsesWith(Value newValue)
Replace all uses of 'this' value with the new value, updating anything in the IR that uses 'this' to ...
This class represents an abstract interface.
Interface< ConcreteType, Operation *, Traits, Op< ConcreteType >, OpTrait::TraitBase > InterfaceBase
typename Traits::Concept Concept
The OpAsmOpInterface, see OpAsmInterface.td for more details.
OpFoldResult foldIdempotent(Operation *op)
LogicalResult verifyResultsAreFloatLike(Operation *op)
LogicalResult verifyAtLeastNResults(Operation *op, unsigned numOperands)
LogicalResult verifyIsIdempotent(Operation *op)
LogicalResult verifyOperandsAreSignlessIntegerLike(Operation *op)
LogicalResult verifyNOperands(Operation *op, unsigned numOperands)
LogicalResult verifyNoRegionArguments(Operation *op)
LogicalResult verifyResultsAreSignlessIntegerLike(Operation *op)
LogicalResult verifyIsInvolution(Operation *op)
LogicalResult verifyOperandsAreFloatLike(Operation *op)
LogicalResult foldCommutative(Operation *op, ArrayRef< Attribute > operands, SmallVectorImpl< OpFoldResult > &results)
LogicalResult verifyZeroRegions(Operation *op)
LogicalResult verifyNSuccessors(Operation *op, unsigned numSuccessors)
LogicalResult verifyOperandSizeAttr(Operation *op, StringRef sizeAttrName)
LogicalResult verifyAtLeastNRegions(Operation *op, unsigned numRegions)
LogicalResult verifyValueSizeAttr(Operation *op, StringRef attrName, StringRef valueGroupName, size_t expectedCount)
LogicalResult verifyZeroResults(Operation *op)
LogicalResult verifySameOperandsAndResultType(Operation *op)
LogicalResult verifySameOperandsShape(Operation *op)
LogicalResult verifyAtLeastNSuccessors(Operation *op, unsigned numSuccessors)
LogicalResult verifyIsTerminator(Operation *op)
LogicalResult verifyAtLeastNOperands(Operation *op, unsigned numOperands)
LogicalResult verifyZeroOperands(Operation *op)
LogicalResult verifyElementwise(Operation *op)
LogicalResult verifyOneRegion(Operation *op)
LogicalResult verifySameOperandsAndResultRank(Operation *op)
LogicalResult verifyOneOperand(Operation *op)
LogicalResult verifyIsIsolatedFromAbove(Operation *op)
Check for any values used by operations regions attached to the specified "IsIsolatedFromAbove" opera...
LogicalResult verifyZeroSuccessors(Operation *op)
LogicalResult verifySameOperandsElementType(Operation *op)
LogicalResult verifyOneSuccessor(Operation *op)
LogicalResult verifySameOperandsAndResultElementType(Operation *op)
OpFoldResult foldInvolution(Operation *op)
LogicalResult verifyResultsAreBoolLike(Operation *op)
LogicalResult verifyNResults(Operation *op, unsigned numOperands)
LogicalResult verifyResultSizeAttr(Operation *op, StringRef sizeAttrName)
LogicalResult verifyNRegions(Operation *op, unsigned numRegions)
LogicalResult verifyOneResult(Operation *op)
LogicalResult verifySameTypeOperands(Operation *op)
LogicalResult verifySameOperandsAndResultShape(Operation *op)
bool hasElementwiseMappableTraits(Operation *op)
Together, Elementwise, Scalarizable, Vectorizable, and Tensorizable provide an easy way for scalar op...
typename T::ImplicitTerminatorOpT has_implicit_terminator_t
Check is an op defines the ImplicitTerminatorOpT member.
decltype(walk(nullptr, std::declval< FnT >())) walkResultType
Utility to provide the return type of a templated walk method.
void handleUseOfUndefinedPromisedInterface(Dialect &dialect, TypeID interfaceRequestorID, TypeID interfaceID, StringRef interfaceName)
Checks if the given interface, which is attempting to be used, is a promised interface of this dialec...
void ensureRegionTerminator(Region ®ion, OpBuilder &builder, Location loc, function_ref< Operation *(OpBuilder &, Location)> buildTerminatorOp)
Insert an operation, generated by buildTerminatorOp, at the end of the region's only block if it does...
llvm::is_detected< has_single_result_fold_trait, T > detect_has_single_result_fold_trait
decltype(T::verifyTrait(std::declval< Operation * >())) has_verify_trait
Trait to check if T provides a verifyTrait method.
LogicalResult verifyRegionTrait(Operation *op)
Verify the given trait if it provides a region verifier.
std::disjunction< detect_has_fold_trait< T >, detect_has_single_result_fold_trait< T > > detect_has_any_fold_trait
Trait to check if T provides any foldTrait method.
bool hasTrait(TypeID traitID)
Returns true if this given Trait ID matches the IDs of any of the provided trait types Traits.
static std::enable_if_t< detect_has_single_result_fold_trait< Trait >::value, LogicalResult > foldTrait(Operation *op, ArrayRef< Attribute > operands, SmallVectorImpl< OpFoldResult > &results)
Returns the result of folding a trait that implements a foldTrait function that is specialized for op...
LogicalResult verifyTraits(Operation *op)
Given a set of traits, return the result of verifying the given operation.
decltype(T::foldTrait( std::declval< Operation * >(), std::declval< ArrayRef< Attribute > >())) has_single_result_fold_trait
Trait to check if T provides a 'foldTrait' method for single result operations.
llvm::is_detected< has_verify_region_trait, T > detect_has_verify_region_trait
llvm::is_detected< has_verify_trait, T > detect_has_verify_trait
decltype(T::foldTrait(std::declval< Operation * >(), std::declval< ArrayRef< Attribute > >(), std::declval< SmallVectorImpl< OpFoldResult > & >())) has_fold_trait
Trait to check if T provides a general 'foldTrait' method.
static LogicalResult foldTraits(Operation *op, ArrayRef< Attribute > operands, SmallVectorImpl< OpFoldResult > &results)
Given a tuple type containing a set of traits, return the result of folding the given operation.
llvm::is_detected< has_fold_trait, T > detect_has_fold_trait
LogicalResult verifyRegionTraits(Operation *op)
Given a set of traits, return the result of verifying the regions of the given operation.
decltype(T::verifyRegionTrait(std::declval< Operation * >())) has_verify_region_trait
Trait to check if T provides a verifyTrait method.
LogicalResult verifyTrait(Operation *op)
Verify the given trait if it provides a verifier.
Include the generated interface declarations.
raw_ostream & operator<<(raw_ostream &os, const AliasResult &result)
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
bool operator==(StringAttr lhs, std::nullptr_t)
Define comparisons for StringAttr against nullptr and itself to avoid the StringRef overloads from be...
WalkOrder
Traversal order for region, block and operation walk utilities.
bool operator!=(RegionBranchPoint lhs, RegionBranchPoint rhs)
std::conditional_t< std::is_same_v< Ty, mlir::Type >, mlir::Value, detail::TypedValue< Ty > > TypedValue
If Ty is mlir::Type this will select Value instead of having a wrapper around it.
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...
llvm::function_ref< Fn > function_ref
static bool isEqual(T lhs, T rhs)
static T getTombstoneKey()
static unsigned getHashValue(T val)
Structure used by default as a "marker" when no "Properties" are set on an Operation.
bool operator!=(const EmptyProperties &) const
bool operator==(const EmptyProperties &) const
This trait tags element-wise ops on vectors or tensors.
static LogicalResult verifyTrait(Operation *op)
This class provides a verifier for ops that are expecting their parent to be one of the given parent ...
This trait provides a verifier for ops that are expecting their regions to not have any arguments.
static LogicalResult verifyTrait(Operation *op)
This trait tags Elementwise operatons that can be systematically scalarized.
static LogicalResult verifyTrait(Operation *op)
This class provides APIs and verifiers for ops with regions having a single block that must terminate...
This class provides APIs and verifiers for ops with regions having a single block.
Region & getBodyRegion(unsigned idx=0)
enable_if_single_region< OpT > insert(Block::iterator insertPt, Operation *op)
Block * getBody(unsigned idx=0)
enable_if_single_region< OpT, Block::iterator > begin()
enable_if_single_region< OpT > insert(Operation *insertPt, Operation *op)
Insert the operation at the given insertion point.
enable_if_single_region< OpT > push_back(Operation *op)
Insert the operation into the back of the body.
static LogicalResult verifyTrait(Operation *op)
std::enable_if_t< OpT::template hasTrait< OneRegion >(), T > enable_if_single_region
The following are a set of methods only enabled when the parent operation has a single region.
enable_if_single_region< OpT, Block::iterator > end()
enable_if_single_region< OpT, Operation & > front()
This trait tags Elementwise operatons that can be systematically tensorized.
static LogicalResult verifyTrait(Operation *op)
This trait tags Elementwise operatons that can be systematically vectorized.
static LogicalResult verifyTrait(Operation *op)
Utility trait base that provides accessors for derived traits that have multiple operands.
Value getOperand(unsigned i)
Return the operand at index 'i'.
Operation::operand_type_iterator operand_type_iterator
operand_type_range getOperandTypes()
operand_type_iterator operand_type_begin()
Operand type access.
Operation::operand_range operand_range
Operation::operand_type_range operand_type_range
unsigned getNumOperands()
Return the number of operands.
operand_iterator operand_begin()
Operand iterator access.
operand_type_iterator operand_type_end()
void setOperand(unsigned i, Value value)
Set the operand at index 'i' to 'value'.
Operation::operand_iterator operand_iterator
operand_iterator operand_end()
operand_range getOperands()
Utility trait base that provides accessors for derived traits that have multiple regions.
MutableArrayRef< Region > region_iterator
unsigned getNumRegions()
Return the number of regions.
region_iterator region_begin()
Region iterator access.
region_range getRegions()
region_iterator region_end()
Region & getRegion(unsigned i)
Return the region at index.
Utility trait base that provides accessors for derived traits that have multiple results.
result_type_iterator result_type_end()
result_type_range getResultTypes()
result_type_iterator result_type_begin()
Result type access.
result_iterator result_end()
Value getResult(unsigned i)
Return the result at index 'i'.
Operation::result_type_iterator result_type_iterator
void replaceAllUsesWith(ValuesT &&values)
Replace all uses of results of this operation with the provided 'values'.
Operation::result_iterator result_iterator
result_iterator result_begin()
Result iterator access.
Operation::result_type_range result_type_range
unsigned getNumResults()
Return the number of results.
result_range getResults()
Type getType(unsigned i)
Return the type of the i-th result.
Operation::result_range result_range
Utility trait base that provides accessors for derived traits that have multiple successors.
void setSuccessor(Block *block, unsigned i)
Set the successor at index.
succ_iterator succ_begin()
Successor iterator access.
unsigned getNumSuccessors()
Return the number of successors.
SuccessorRange succ_range
Block * getSuccessor(unsigned i)
Return the successor at index.
Operation::succ_iterator succ_iterator
succ_range getSuccessors()
static constexpr bool value
Support to check if an operation has the SingleBlockImplicitTerminator trait.
static constexpr bool value
This represents an operation in an abstracted form, suitable for use with the builder APIs.
typename Op::Properties type
Traits to detect whether an Operation defined a Properties type, otherwise it'll default to EmptyProp...