MLIR 24.0.0git
OpDefinition.h
Go to the documentation of this file.
1//===- OpDefinition.h - Classes for defining concrete Op types --*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file implements helper classes for implementing the "Op" types. This
10// includes the Op type, which is the base class for Op class definitions,
11// as well as number of traits in the OpTrait namespace that provide a
12// declarative way to specify properties of Ops.
13//
14// The purpose of these types are to allow light-weight implementation of
15// concrete ops (like DimOp) with very little boilerplate.
16//
17//===----------------------------------------------------------------------===//
18
19#ifndef MLIR_IR_OPDEFINITION_H
20#define MLIR_IR_OPDEFINITION_H
21
22#include "mlir/IR/Dialect.h"
23#include "mlir/IR/ODSSupport.h"
24#include "mlir/IR/Operation.h"
25#include "llvm/Support/PointerLikeTypeTraits.h"
26
27#include <optional>
28#include <type_traits>
29
30namespace mlir {
31class Builder;
32class OpBuilder;
34
35/// This class implements `Optional` functionality for ParseResult. We don't
36/// directly use Optional here, because it provides an implicit conversion
37/// to 'bool' which we want to avoid. This class is used to implement tri-state
38/// 'parseOptional' functions that may have a failure mode when parsing that
39/// shouldn't be attributed to "not present".
41public:
47 OptionalParseResult(std::nullopt_t) : impl(std::nullopt) {}
48
49 /// Returns true if we contain a valid ParseResult value.
50 bool has_value() const { return impl.has_value(); }
51
52 /// Access the internal ParseResult value.
53 ParseResult value() const { return *impl; }
54 ParseResult operator*() const { return value(); }
55
56private:
57 std::optional<ParseResult> impl;
58};
59
60// These functions are out-of-line utilities, which avoids them being template
61// instantiated/duplicated.
62namespace impl {
63/// Insert an operation, generated by `buildTerminatorOp`, at the end of the
64/// region's only block if it does not have a terminator already. If the region
65/// is empty, insert a new block first. `buildTerminatorOp` should return the
66/// terminator operation to insert.
68 Region &region, OpBuilder &builder, Location loc,
69 function_ref<Operation *(OpBuilder &, Location)> buildTerminatorOp);
71 Region &region, Builder &builder, Location loc,
72 function_ref<Operation *(OpBuilder &, Location)> buildTerminatorOp);
73
74} // namespace impl
75
76/// Structure used by default as a "marker" when no "Properties" are set on an
77/// Operation.
79 bool operator==(const EmptyProperties &) const { return true; }
80 bool operator!=(const EmptyProperties &) const { return false; }
81};
82
83/// Traits to detect whether an Operation defined a `Properties` type, otherwise
84/// it'll default to `EmptyProperties`.
85template <class Op, class = void>
89template <class Op>
90struct PropertiesSelector<Op, std::void_t<typename Op::Properties>> {
91 using type = typename Op::Properties;
92};
93
94/// This is the concrete base class that holds the operation pointer and has
95/// non-generic methods that only depend on State (to avoid having them
96/// instantiated on template types that don't affect them.
97///
98/// This also has the fallback implementations of customization hooks for when
99/// they aren't customized.
100class OpState {
101public:
102 /// Ops are pointer-like, so we allow conversion to bool.
103 explicit operator bool() { return getOperation() != nullptr; }
104
105 /// This implicitly converts to Operation*.
106 operator Operation *() const { return state; }
107
108 /// Shortcut of `->` to access a member of Operation.
109 Operation *operator->() const { return state; }
110
111 /// Return the operation that this refers to.
112 Operation *getOperation() { return state; }
113
114 /// Return the context this operation belongs to.
116
117 /// Print the operation to the given stream.
118 void print(raw_ostream &os, OpPrintingFlags flags = {}) {
119 state->print(os, flags);
120 }
121 void print(raw_ostream &os, AsmState &asmState) {
122 state->print(os, asmState);
123 }
124
125 /// Dump this operation.
126#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
127 LLVM_DUMP_METHOD void dump();
128#endif
129
130 /// The source location the operation was defined or derived from.
131 Location getLoc() { return state->getLoc(); }
132
133 /// Return true if there are no users of any results of this operation.
134 bool use_empty() { return state->use_empty(); }
135
136 /// Remove this operation from its parent block and delete it.
137 void erase() { state->erase(); }
138
139 /// Emit an error with the op name prefixed, like "'dim' op " which is
140 /// convenient for verifiers.
141 InFlightDiagnostic emitOpError(const Twine &message = {});
142
143 /// Emit an error about fatal conditions with this operation, reporting up to
144 /// any diagnostic handlers that may be listening.
145 InFlightDiagnostic emitError(const Twine &message = {});
146
147 /// Emit a warning about this operation, reporting up to any diagnostic
148 /// handlers that may be listening.
149 InFlightDiagnostic emitWarning(const Twine &message = {});
150
151 /// Emit a remark about this operation, reporting up to any diagnostic
152 /// handlers that may be listening.
153 InFlightDiagnostic emitRemark(const Twine &message = {});
154
155 /// Walk the operation by calling the callback for each nested operation
156 /// (including this one), block or region, depending on the callback provided.
157 /// The order in which regions, blocks and operations the same nesting level
158 /// are visited (e.g., lexicographical or reverse lexicographical order) is
159 /// determined by 'Iterator'. The walk order for enclosing regions, blocks
160 /// and operations with respect to their nested ones is specified by 'Order'
161 /// (post-order by default). A callback on a block or operation is allowed to
162 /// erase that block or operation if either:
163 /// * the walk is in post-order, or
164 /// * the walk is in pre-order and the walk is skipped after the erasure.
165 /// See Operation::walk for more details.
166 template <WalkOrder Order = WalkOrder::PostOrder,
167 typename Iterator = ForwardIterator, typename FnT,
168 typename RetT = detail::walkResultType<FnT>>
169 std::enable_if_t<llvm::function_traits<std::decay_t<FnT>>::num_args == 1,
170 RetT>
171 walk(FnT &&callback) {
172 return state->walk<Order, Iterator>(std::forward<FnT>(callback));
173 }
174
175 /// Generic walker with a stage aware callback. Walk the operation by calling
176 /// the callback for each nested operation (including this one) N+1 times,
177 /// where N is the number of regions attached to that operation.
178 ///
179 /// The callback method can take any of the following forms:
180 /// void(Operation *, const WalkStage &) : Walk all operation opaquely
181 /// * op.walk([](Operation *nestedOp, const WalkStage &stage) { ...});
182 /// void(OpT, const WalkStage &) : Walk all operations of the given derived
183 /// type.
184 /// * op.walk([](ReturnOp returnOp, const WalkStage &stage) { ...});
185 /// WalkResult(Operation*|OpT, const WalkStage &stage) : Walk operations,
186 /// but allow for interruption/skipping.
187 /// * op.walk([](... op, const WalkStage &stage) {
188 /// // Skip the walk of this op based on some invariant.
189 /// if (some_invariant)
190 /// return WalkResult::skip();
191 /// // Interrupt, i.e cancel, the walk based on some invariant.
192 /// if (another_invariant)
193 /// return WalkResult::interrupt();
194 /// return WalkResult::advance();
195 /// });
196 template <typename FnT, typename RetT = detail::walkResultType<FnT>>
197 std::enable_if_t<llvm::function_traits<std::decay_t<FnT>>::num_args == 2,
198 RetT>
199 walk(FnT &&callback) {
200 return state->walk(std::forward<FnT>(callback));
201 }
202
203 // These are default implementations of customization hooks.
204public:
205 /// This hook returns any canonicalization pattern rewrites that the operation
206 /// supports, for use by the canonicalization pass.
208 MLIRContext *context) {}
209
210 /// This hook populates any unset default attrs.
212
213protected:
214 /// If the concrete type didn't implement a custom verifier hook, just fall
215 /// back to this one which accepts everything.
216 LogicalResult verify() { return success(); }
217 LogicalResult verifyRegions() { return success(); }
218
219 /// Parse the custom form of an operation. Unless overridden, this method will
220 /// first try to get an operation parser from the op's dialect. Otherwise the
221 /// custom assembly form of an op is always rejected. Op implementations
222 /// should implement this to return failure. On success, they should fill in
223 /// result with the fields to use.
224 static ParseResult parse(OpAsmParser &parser, OperationState &result);
225
226 /// Print the operation. Unless overridden, this method will first try to get
227 /// an operation printer from the dialect. Otherwise, it prints the operation
228 /// in generic form.
229 static void print(Operation *op, OpAsmPrinter &p, StringRef defaultDialect);
230
231 /// Parse properties as a Attribute.
232 static ParseResult genericParseProperties(OpAsmParser &parser,
234
235 /// Print the properties as a Attribute with names not included within
236 /// 'elidedProps'
237 static void genericPrintProperties(OpAsmPrinter &p, Attribute properties,
238 ArrayRef<StringRef> elidedProps = {});
239
240 /// Print an operation name, eliding the dialect prefix if necessary.
241 static void printOpName(Operation *op, OpAsmPrinter &p,
242 StringRef defaultDialect);
243
244 /// Mutability management is handled by the OpWrapper/OpConstWrapper classes,
245 /// so we can cast it away here.
246 explicit OpState(Operation *state) : state(state) {}
247
248 /// For all ops which don't have properties, we keep a single instance of
249 /// `EmptyProperties` to be used where a pointer to a struct of properties
250 /// is needed: this allows binding a pointer to the reference without
251 /// triggering UB.
253 static EmptyProperties emptyProperties;
254 return emptyProperties;
255 }
256
257private:
258 Operation *state;
259
260 /// Allow access to internal hook implementation methods.
262};
263
264// Allow comparing operators.
265inline bool operator==(OpState lhs, OpState rhs) {
266 return lhs.getOperation() == rhs.getOperation();
267}
268inline bool operator!=(OpState lhs, OpState rhs) {
269 return lhs.getOperation() != rhs.getOperation();
270}
271
272raw_ostream &operator<<(raw_ostream &os, OpFoldResult ofr);
273
274/// This class represents a single result from folding an operation.
275class OpFoldResult : public PointerUnion<Attribute, Value> {
277
278public:
279 LLVM_DUMP_METHOD void dump() const { llvm::errs() << *this << "\n"; }
280
282 PointerUnion pu = *this;
283 return isa<Attribute>(pu) ? cast<Attribute>(pu).getContext()
284 : cast<Value>(pu).getContext();
285 }
286};
287
288// Temporarily exit the MLIR namespace to add casting support as later code in
289// this uses it. The CastInfo must come after the OpFoldResult definition and
290// before any cast function calls depending on CastInfo.
291
292} // namespace mlir
293
294namespace llvm {
295
296// Allow llvm::cast style functions.
297template <typename To>
298struct CastInfo<To, mlir::OpFoldResult>
299 : public CastInfo<To, mlir::OpFoldResult::PointerUnion> {};
300
301template <typename To>
302struct CastInfo<To, const mlir::OpFoldResult>
303 : public CastInfo<To, const mlir::OpFoldResult::PointerUnion> {};
304
305} // namespace llvm
306
307namespace mlir {
308
309/// Allow printing to a stream.
311 if (Value value = llvm::dyn_cast_if_present<Value>(ofr))
312 value.print(os);
313 else
314 llvm::dyn_cast_if_present<Attribute>(ofr).print(os);
315 return os;
316}
317/// Allow printing to a stream.
319 op.print(os, OpPrintingFlags().useLocalScope());
320 return os;
321}
322
323//===----------------------------------------------------------------------===//
324// Operation Trait Types
325//===----------------------------------------------------------------------===//
326
327namespace OpTrait {
328
329// These functions are out-of-line implementations of the methods in the
330// corresponding trait classes. This avoids them being template
331// instantiated/duplicated.
332namespace impl {
333LogicalResult foldCommutative(Operation *op, ArrayRef<Attribute> operands,
334 SmallVectorImpl<OpFoldResult> &results);
335OpFoldResult foldIdempotent(Operation *op);
336OpFoldResult foldInvolution(Operation *op);
337LogicalResult verifyZeroOperands(Operation *op);
338LogicalResult verifyOneOperand(Operation *op);
339LogicalResult verifyNOperands(Operation *op, unsigned numOperands);
340LogicalResult verifyIsIdempotent(Operation *op);
341LogicalResult verifyIsInvolution(Operation *op);
342LogicalResult verifyAtLeastNOperands(Operation *op, unsigned numOperands);
343LogicalResult verifyOperandsAreFloatLike(Operation *op);
344LogicalResult verifyOperandsAreSignlessIntegerLike(Operation *op);
345LogicalResult verifySameTypeOperands(Operation *op);
346LogicalResult verifyZeroRegions(Operation *op);
347LogicalResult verifyOneRegion(Operation *op);
348LogicalResult verifyNRegions(Operation *op, unsigned numRegions);
349LogicalResult verifyAtLeastNRegions(Operation *op, unsigned numRegions);
350LogicalResult verifyZeroResults(Operation *op);
351LogicalResult verifyOneResult(Operation *op);
352LogicalResult verifyNResults(Operation *op, unsigned numOperands);
353LogicalResult verifyAtLeastNResults(Operation *op, unsigned numOperands);
354LogicalResult verifySameOperandsShape(Operation *op);
355LogicalResult verifySameOperandsAndResultShape(Operation *op);
356LogicalResult verifySameOperandsElementType(Operation *op);
357LogicalResult verifySameOperandsAndResultElementType(Operation *op);
358LogicalResult verifySameOperandsAndResultType(Operation *op);
359LogicalResult verifySameOperandsAndResultRank(Operation *op);
360LogicalResult verifyResultsAreBoolLike(Operation *op);
361LogicalResult verifyResultsAreFloatLike(Operation *op);
362LogicalResult verifyResultsAreSignlessIntegerLike(Operation *op);
363LogicalResult verifyIsTerminator(Operation *op);
364LogicalResult verifyZeroSuccessors(Operation *op);
365LogicalResult verifyOneSuccessor(Operation *op);
366LogicalResult verifyNSuccessors(Operation *op, unsigned numSuccessors);
367LogicalResult verifyAtLeastNSuccessors(Operation *op, unsigned numSuccessors);
368LogicalResult verifyValueSizeAttr(Operation *op, StringRef attrName,
369 StringRef valueGroupName,
370 size_t expectedCount);
371LogicalResult verifyOperandSizeAttr(Operation *op, StringRef sizeAttrName);
372LogicalResult verifyResultSizeAttr(Operation *op, StringRef sizeAttrName);
373LogicalResult verifyNoRegionArguments(Operation *op);
374LogicalResult verifyElementwise(Operation *op);
375LogicalResult verifyIsIsolatedFromAbove(Operation *op);
376} // namespace impl
377
378/// Helper class for implementing traits. Clients are not expected to interact
379/// with this directly, so its members are all protected.
380template <typename ConcreteType, template <typename> class TraitType>
382protected:
383 /// Return the ultimate Operation being worked on.
385 auto *concrete = static_cast<ConcreteType *>(this);
386 return concrete->getOperation();
387 }
388};
389
390//===----------------------------------------------------------------------===//
391// Operand Traits
392//===----------------------------------------------------------------------===//
393
394namespace detail {
395/// Utility trait base that provides accessors for derived traits that have
396/// multiple operands.
397template <typename ConcreteType, template <typename> class TraitType>
398struct MultiOperandTraitBase : public TraitBase<ConcreteType, TraitType> {
403
404 /// Return the number of operands.
405 unsigned getNumOperands() { return this->getOperation()->getNumOperands(); }
406
407 /// Return the operand at index 'i'.
408 Value getOperand(unsigned i) { return this->getOperation()->getOperand(i); }
409
410 /// Set the operand at index 'i' to 'value'.
411 void setOperand(unsigned i, Value value) {
412 this->getOperation()->setOperand(i, value);
413 }
414
415 /// Operand iterator access.
421
422 /// Operand type access.
432};
433} // namespace detail
434
435/// `verifyInvariantsImpl` verifies the invariants like the types, attrs, .etc.
436/// It should be run after core traits and before any other user defined traits.
437/// In order to run it in the correct order, wrap it with OpInvariants trait so
438/// that tblgen will be able to put it in the right order.
439template <typename ConcreteType>
440class OpInvariants : public TraitBase<ConcreteType, OpInvariants> {
441public:
442 static LogicalResult verifyTrait(Operation *op) {
443 return cast<ConcreteType>(op).verifyInvariantsImpl();
444 }
445};
446
447/// This class provides the API for ops that are known to have no
448/// SSA operand.
449template <typename ConcreteType>
450class ZeroOperands : public TraitBase<ConcreteType, ZeroOperands> {
451public:
452 static LogicalResult verifyTrait(Operation *op) {
453 return impl::verifyZeroOperands(op);
454 }
455
456private:
457 // Disable these.
458 void getOperand() {}
459 void setOperand() {}
460};
461
462/// This class provides the API for ops that are known to have exactly one
463/// SSA operand.
464template <typename ConcreteType>
465class OneOperand : public TraitBase<ConcreteType, OneOperand> {
466public:
467 Value getOperand() { return this->getOperation()->getOperand(0); }
468
469 void setOperand(Value value) { this->getOperation()->setOperand(0, value); }
470
471 static LogicalResult verifyTrait(Operation *op) {
472 return impl::verifyOneOperand(op);
473 }
474};
475
476/// This class provides the API for ops that are known to have a specified
477/// number of operands. This is used as a trait like this:
478///
479/// class FooOp : public Op<FooOp, OpTrait::NOperands<2>::Impl> {
480///
481template <unsigned N>
483public:
484 static_assert(N > 1, "use ZeroOperands/OneOperand for N < 2");
485
486 template <typename ConcreteType>
487 class Impl
488 : public detail::MultiOperandTraitBase<ConcreteType, NOperands<N>::Impl> {
489 public:
490 static LogicalResult verifyTrait(Operation *op) {
491 return impl::verifyNOperands(op, N);
492 }
493 };
494};
495
496/// This class provides the API for ops that are known to have a at least a
497/// specified number of operands. This is used as a trait like this:
498///
499/// class FooOp : public Op<FooOp, OpTrait::AtLeastNOperands<2>::Impl> {
500///
501template <unsigned N>
503public:
504 template <typename ConcreteType>
505 class Impl : public detail::MultiOperandTraitBase<ConcreteType,
506 AtLeastNOperands<N>::Impl> {
507 public:
508 static LogicalResult verifyTrait(Operation *op) {
509 return impl::verifyAtLeastNOperands(op, N);
510 }
511 };
512};
513
514/// This class provides the API for ops which have an unknown number of
515/// SSA operands.
516template <typename ConcreteType>
518 : public detail::MultiOperandTraitBase<ConcreteType, VariadicOperands> {};
519
520//===----------------------------------------------------------------------===//
521// Region Traits
522//===----------------------------------------------------------------------===//
523
524/// This class provides verification for ops that are known to have zero
525/// regions.
526template <typename ConcreteType>
527class ZeroRegions : public TraitBase<ConcreteType, ZeroRegions> {
528public:
529 static LogicalResult verifyTrait(Operation *op) {
530 return impl::verifyZeroRegions(op);
531 }
532};
533
534namespace detail {
535/// Utility trait base that provides accessors for derived traits that have
536/// multiple regions.
537template <typename ConcreteType, template <typename> class TraitType>
538struct MultiRegionTraitBase : public TraitBase<ConcreteType, TraitType> {
541
542 /// Return the number of regions.
543 unsigned getNumRegions() { return this->getOperation()->getNumRegions(); }
544
545 /// Return the region at `index`.
546 Region &getRegion(unsigned i) { return this->getOperation()->getRegion(i); }
547
548 /// Region iterator access.
550 return this->getOperation()->region_begin();
551 }
552 region_iterator region_end() { return this->getOperation()->region_end(); }
554};
555} // namespace detail
556
557/// This class provides APIs for ops that are known to have a single region.
558template <typename ConcreteType>
559class OneRegion : public TraitBase<ConcreteType, OneRegion> {
560public:
561 Region &getRegion() { return this->getOperation()->getRegion(0); }
562
563 /// Returns a range of operations within the region of this operation.
564 auto getOps() { return getRegion().getOps(); }
565 template <typename OpT>
566 auto getOps() {
567 return getRegion().template getOps<OpT>();
568 }
569
570 static LogicalResult verifyTrait(Operation *op) {
571 return impl::verifyOneRegion(op);
572 }
573};
574
575/// This class provides the API for ops that are known to have a specified
576/// number of regions.
577template <unsigned N>
578class NRegions {
579public:
580 static_assert(N > 1, "use ZeroRegions/OneRegion for N < 2");
581
582 template <typename ConcreteType>
583 class Impl
584 : public detail::MultiRegionTraitBase<ConcreteType, NRegions<N>::Impl> {
585 public:
586 static LogicalResult verifyTrait(Operation *op) {
587 return impl::verifyNRegions(op, N);
588 }
589 };
590};
591
592/// This class provides APIs for ops that are known to have at least a specified
593/// number of regions.
594template <unsigned N>
596public:
597 template <typename ConcreteType>
598 class Impl : public detail::MultiRegionTraitBase<ConcreteType,
599 AtLeastNRegions<N>::Impl> {
600 public:
601 static LogicalResult verifyTrait(Operation *op) {
602 return impl::verifyAtLeastNRegions(op, N);
603 }
604 };
605};
606
607/// This class provides the API for ops which have an unknown number of
608/// regions.
609template <typename ConcreteType>
611 : public detail::MultiRegionTraitBase<ConcreteType, VariadicRegions> {};
612
613//===----------------------------------------------------------------------===//
614// Result Traits
615//===----------------------------------------------------------------------===//
616
617/// This class provides return value APIs for ops that are known to have
618/// zero results.
619template <typename ConcreteType>
620class ZeroResults : public TraitBase<ConcreteType, ZeroResults> {
621public:
622 static LogicalResult verifyTrait(Operation *op) {
623 return impl::verifyZeroResults(op);
624 }
625};
626
627namespace detail {
628/// Utility trait base that provides accessors for derived traits that have
629/// multiple results.
630template <typename ConcreteType, template <typename> class TraitType>
631struct MultiResultTraitBase : public TraitBase<ConcreteType, TraitType> {
636
637 /// Return the number of results.
638 unsigned getNumResults() { return this->getOperation()->getNumResults(); }
639
640 /// Return the result at index 'i'.
641 Value getResult(unsigned i) { return this->getOperation()->getResult(i); }
642
643 /// Replace all uses of results of this operation with the provided 'values'.
644 /// 'values' may correspond to an existing operation, or a range of 'Value'.
645 template <typename ValuesT>
646 void replaceAllUsesWith(ValuesT &&values) {
647 this->getOperation()->replaceAllUsesWith(std::forward<ValuesT>(values));
648 }
649
650 /// Return the type of the `i`-th result.
651 Type getType(unsigned i) { return getResult(i).getType(); }
652
653 /// Result iterator access.
655 return this->getOperation()->result_begin();
656 }
659
660 /// Result type access.
670};
671} // namespace detail
672
673/// This class provides return value APIs for ops that are known to have a
674/// single result. ResultType is the concrete type returned by getType().
675template <typename ConcreteType>
676class OneResult : public TraitBase<ConcreteType, OneResult> {
677public:
678 /// Replace all uses of 'this' value with the new value, updating anything
679 /// in the IR that uses 'this' to use the other value instead. When this
680 /// returns there are zero uses of 'this'.
681 void replaceAllUsesWith(Value newValue) {
682 this->getOperation()->getResult(0).replaceAllUsesWith(newValue);
683 }
684
685 /// Replace all uses of 'this' value with the result of 'op'.
687 this->getOperation()->replaceAllUsesWith(op);
688 }
689
690 static LogicalResult verifyTrait(Operation *op) {
691 return impl::verifyOneResult(op);
692 }
693};
694
695/// This trait is used for return value APIs for ops that are known to have a
696/// specific type other than `Type`. This allows the "getType()" member to be
697/// more specific for an op. This should be used in conjunction with OneResult,
698/// and occur in the trait list before OneResult.
699template <typename ResultType>
701public:
702 /// This class provides return value APIs for ops that are known to have a
703 /// single result. ResultType is the concrete type returned by getType().
704 template <typename ConcreteType>
705 class Impl
706 : public TraitBase<ConcreteType, OneTypedResult<ResultType>::Impl> {
707 public:
709 return cast<mlir::TypedValue<ResultType>>(
710 this->getOperation()->getResult(0));
711 }
712
713 /// If the operation returns a single value, then the Op can be implicitly
714 /// converted to a Value. This yields the value of the only result.
716
717 ResultType getType() { return getResult().getType(); }
718 };
719};
720
721/// This class provides the API for ops that are known to have a specified
722/// number of results. This is used as a trait like this:
723///
724/// class FooOp : public Op<FooOp, OpTrait::NResults<2>::Impl> {
725///
726template <unsigned N>
727class NResults {
728public:
729 static_assert(N > 1, "use ZeroResults/OneResult for N < 2");
730
731 template <typename ConcreteType>
732 class Impl
733 : public detail::MultiResultTraitBase<ConcreteType, NResults<N>::Impl> {
734 public:
735 static LogicalResult verifyTrait(Operation *op) {
736 return impl::verifyNResults(op, N);
737 }
738 };
739};
740
741/// This class provides the API for ops that are known to have at least a
742/// specified number of results. This is used as a trait like this:
743///
744/// class FooOp : public Op<FooOp, OpTrait::AtLeastNResults<2>::Impl> {
745///
746template <unsigned N>
748public:
749 template <typename ConcreteType>
750 class Impl : public detail::MultiResultTraitBase<ConcreteType,
751 AtLeastNResults<N>::Impl> {
752 public:
753 static LogicalResult verifyTrait(Operation *op) {
754 return impl::verifyAtLeastNResults(op, N);
755 }
756 };
757};
758
759/// This class provides the API for ops which have an unknown number of
760/// results.
761template <typename ConcreteType>
763 : public detail::MultiResultTraitBase<ConcreteType, VariadicResults> {};
764
765//===----------------------------------------------------------------------===//
766// Terminator Traits
767//===----------------------------------------------------------------------===//
768
769/// This class indicates that the regions associated with this op don't have
770/// terminators.
771template <typename ConcreteType>
772class NoTerminator : public TraitBase<ConcreteType, NoTerminator> {};
773
774/// This class provides the API for ops that are known to be terminators.
775template <typename ConcreteType>
776class IsTerminator : public TraitBase<ConcreteType, IsTerminator> {
777public:
778 static LogicalResult verifyTrait(Operation *op) {
779 return impl::verifyIsTerminator(op);
780 }
781};
782
783/// This trait marks operations that are allowed to produce builtin token
784/// values.
785template <typename ConcreteType>
786class TokenProducerTrait : public TraitBase<ConcreteType, TokenProducerTrait> {
787};
788
789/// This trait marks operations that are allowed to consume builtin token
790/// values.
791template <typename ConcreteType>
792class TokenConsumerTrait : public TraitBase<ConcreteType, TokenConsumerTrait> {
793};
794
795/// This class provides verification for ops that are known to have zero
796/// successors.
797template <typename ConcreteType>
798class ZeroSuccessors : public TraitBase<ConcreteType, ZeroSuccessors> {
799public:
800 static LogicalResult verifyTrait(Operation *op) {
802 }
803};
804
805namespace detail {
806/// Utility trait base that provides accessors for derived traits that have
807/// multiple successors.
808template <typename ConcreteType, template <typename> class TraitType>
809struct MultiSuccessorTraitBase : public TraitBase<ConcreteType, TraitType> {
812
813 /// Return the number of successors.
814 unsigned getNumSuccessors() {
815 return this->getOperation()->getNumSuccessors();
816 }
817
818 /// Return the successor at `index`.
819 Block *getSuccessor(unsigned i) {
820 return this->getOperation()->getSuccessor(i);
821 }
822
823 /// Set the successor at `index`.
824 void setSuccessor(Block *block, unsigned i) {
825 return this->getOperation()->setSuccessor(block, i);
826 }
827
828 /// Successor iterator access.
829 succ_iterator succ_begin() { return this->getOperation()->succ_begin(); }
830 succ_iterator succ_end() { return this->getOperation()->succ_end(); }
832};
833} // namespace detail
834
835/// This class provides APIs for ops that are known to have a single successor.
836template <typename ConcreteType>
837class OneSuccessor : public TraitBase<ConcreteType, OneSuccessor> {
838public:
839 Block *getSuccessor() { return this->getOperation()->getSuccessor(0); }
840 void setSuccessor(Block *succ) {
841 this->getOperation()->setSuccessor(succ, 0);
842 }
843
844 static LogicalResult verifyTrait(Operation *op) {
845 return impl::verifyOneSuccessor(op);
846 }
847};
848
849/// This class provides the API for ops that are known to have a specified
850/// number of successors.
851template <unsigned N>
853public:
854 static_assert(N > 1, "use ZeroSuccessors/OneSuccessor for N < 2");
855
856 template <typename ConcreteType>
857 class Impl : public detail::MultiSuccessorTraitBase<ConcreteType,
858 NSuccessors<N>::Impl> {
859 public:
860 static LogicalResult verifyTrait(Operation *op) {
861 return impl::verifyNSuccessors(op, N);
862 }
863 };
864};
865
866/// This class provides APIs for ops that are known to have at least a specified
867/// number of successors.
868template <unsigned N>
870public:
871 template <typename ConcreteType>
872 class Impl
873 : public detail::MultiSuccessorTraitBase<ConcreteType,
874 AtLeastNSuccessors<N>::Impl> {
875 public:
876 static LogicalResult verifyTrait(Operation *op) {
877 return impl::verifyAtLeastNSuccessors(op, N);
878 }
879 };
880};
881
882/// This class provides the API for ops which have an unknown number of
883/// successors.
884template <typename ConcreteType>
886 : public detail::MultiSuccessorTraitBase<ConcreteType, VariadicSuccessors> {
887};
888
889//===----------------------------------------------------------------------===//
890// SingleBlock
891//===----------------------------------------------------------------------===//
892
893/// This class provides APIs and verifiers for ops with regions having a single
894/// block.
895template <typename ConcreteType>
896struct SingleBlock : public TraitBase<ConcreteType, SingleBlock> {
897public:
898 static LogicalResult verifyTrait(Operation *op) {
899 for (unsigned i = 0, e = op->getNumRegions(); i < e; ++i) {
900 Region &region = op->getRegion(i);
901
902 // Empty regions are fine.
903 if (region.empty())
904 continue;
905
906 // Non-empty regions must contain a single basic block.
907 if (!region.hasOneBlock())
908 return op->emitOpError("expects region #")
909 << i << " to have 0 or 1 blocks";
910
911 if (!ConcreteType::template hasTrait<NoTerminator>()) {
912 Block &block = region.front();
913 if (block.empty())
914 return op->emitOpError() << "expects a non-empty block";
915 }
916 }
917 return success();
918 }
919
920 Block *getBody(unsigned idx = 0) {
921 Region &region = this->getOperation()->getRegion(idx);
922 assert(!region.empty() && "unexpected empty region");
923 return &region.front();
924 }
925 Region &getBodyRegion(unsigned idx = 0) {
926 return this->getOperation()->getRegion(idx);
927 }
928
929 //===------------------------------------------------------------------===//
930 // Single Region Utilities
931 //===------------------------------------------------------------------===//
932
933 /// The following are a set of methods only enabled when the parent
934 /// operation has a single region. Each of these methods take an additional
935 /// template parameter that represents the concrete operation so that we
936 /// can use SFINAE to disable the methods for non-single region operations.
937 template <typename OpT, typename T = void>
939 std::enable_if_t<OpT::template hasTrait<OneRegion>(), T>;
940
941 template <typename OpT = ConcreteType>
945 template <typename OpT = ConcreteType>
949 template <typename OpT = ConcreteType>
953
954 /// Insert the operation into the back of the body.
955 template <typename OpT = ConcreteType>
959
960 /// Insert the operation at the given insertion point.
961 template <typename OpT = ConcreteType>
965 template <typename OpT = ConcreteType>
967 getBody()->getOperations().insert(insertPt, op);
968 }
969};
970
971//===----------------------------------------------------------------------===//
972// SingleBlockImplicitTerminator
973//===----------------------------------------------------------------------===//
974
975/// This class provides APIs and verifiers for ops with regions having a single
976/// block that must terminate with `TerminatorOpType`.
977template <typename TerminatorOpType>
979 template <typename ConcreteType>
980 class Impl : public TraitBase<ConcreteType, SingleBlockImplicitTerminator<
981 TerminatorOpType>::Impl> {
982 private:
983 /// Builds a terminator operation without relying on OpBuilder APIs to avoid
984 /// cyclic header inclusion.
985 static Operation *buildTerminator(OpBuilder &builder, Location loc) {
986 OperationState state(loc, TerminatorOpType::getOperationName());
987 TerminatorOpType::build(builder, state);
988 return Operation::create(state);
989 }
990
991 public:
992 /// The type of the operation used as the implicit terminator type.
993 using ImplicitTerminatorOpT = TerminatorOpType;
994
995 static LogicalResult verifyRegionTrait(Operation *op) {
996 for (unsigned i = 0, e = op->getNumRegions(); i < e; ++i) {
997 Region &region = op->getRegion(i);
998 // Empty regions are fine.
999 if (region.empty())
1000 continue;
1001 Operation &terminator = region.front().back();
1002 if (isa<TerminatorOpType>(terminator))
1003 continue;
1004
1005 return op->emitOpError("expects regions to end with '" +
1006 TerminatorOpType::getOperationName() +
1007 "', found '" +
1008 terminator.getName().getStringRef() + "'")
1009 .attachNote()
1010 << "in custom textual format, the absence of terminator implies "
1011 "'"
1012 << TerminatorOpType::getOperationName() << '\'';
1013 }
1014
1015 return success();
1016 }
1017
1018 /// Ensure that the given region has the terminator required by this trait.
1019 /// If OpBuilder is provided, use it to build the terminator and notify the
1020 /// OpBuilder listeners accordingly. If only a Builder is provided, locally
1021 /// construct an OpBuilder with no listeners; this should only be used if no
1022 /// OpBuilder is available at the call site, e.g., in the parser.
1023 static void ensureTerminator(Region &region, Builder &builder,
1024 Location loc) {
1025 ::mlir::impl::ensureRegionTerminator(region, builder, loc,
1026 buildTerminator);
1027 }
1028 static void ensureTerminator(Region &region, OpBuilder &builder,
1029 Location loc) {
1030 ::mlir::impl::ensureRegionTerminator(region, builder, loc,
1031 buildTerminator);
1032 }
1033 };
1034};
1035
1036/// Check is an op defines the `ImplicitTerminatorOpT` member. This is intended
1037/// to be used with `llvm::is_detected`.
1038template <class T>
1039using has_implicit_terminator_t = typename T::ImplicitTerminatorOpT;
1040
1041/// Support to check if an operation has the SingleBlockImplicitTerminator
1042/// trait. We can't just use `hasTrait` because this class is templated on a
1043/// specific terminator op.
1044template <class Op, bool hasTerminator =
1045 llvm::is_detected<has_implicit_terminator_t, Op>::value>
1047 static constexpr bool value = std::is_base_of<
1049 typename Op::ImplicitTerminatorOpT>::template Impl<Op>,
1050 Op>::value;
1051};
1052template <class Op>
1054 static constexpr bool value = false;
1055};
1056
1057//===----------------------------------------------------------------------===//
1058// Misc Traits
1059//===----------------------------------------------------------------------===//
1060
1061/// This class provides verification for ops that are known to have the same
1062/// operand shape: all operands are scalars, vectors/tensors of the same
1063/// shape.
1064template <typename ConcreteType>
1065class SameOperandsShape : public TraitBase<ConcreteType, SameOperandsShape> {
1066public:
1067 static LogicalResult verifyTrait(Operation *op) {
1069 }
1070};
1071
1072/// This class provides verification for ops that are known to have the same
1073/// operand and result shape: both are scalars, vectors/tensors of the same
1074/// shape.
1075template <typename ConcreteType>
1077 : public TraitBase<ConcreteType, SameOperandsAndResultShape> {
1078public:
1079 static LogicalResult verifyTrait(Operation *op) {
1081 }
1082};
1083
1084/// This class provides verification for ops that are known to have the same
1085/// operand element type (or the type itself if it is scalar).
1086///
1087template <typename ConcreteType>
1089 : public TraitBase<ConcreteType, SameOperandsElementType> {
1090public:
1091 static LogicalResult verifyTrait(Operation *op) {
1093 }
1094};
1095
1096/// This class provides verification for ops that are known to have the same
1097/// operand and result element type (or the type itself if it is scalar).
1098///
1099template <typename ConcreteType>
1101 : public TraitBase<ConcreteType, SameOperandsAndResultElementType> {
1102public:
1103 static LogicalResult verifyTrait(Operation *op) {
1105 }
1106};
1107
1108/// This class provides verification for ops that are known to have the same
1109/// operand and result type.
1110///
1111/// Note: this trait subsumes the SameOperandsAndResultShape and
1112/// SameOperandsAndResultElementType traits.
1113template <typename ConcreteType>
1115 : public TraitBase<ConcreteType, SameOperandsAndResultType> {
1116public:
1117 static LogicalResult verifyTrait(Operation *op) {
1119 }
1120};
1121
1122/// This class verifies that op has same ranks for all
1123/// operands and results types, if known.
1124template <typename ConcreteType>
1126 : public TraitBase<ConcreteType, SameOperandsAndResultRank> {
1127public:
1128 static LogicalResult verifyTrait(Operation *op) {
1130 }
1131};
1132
1133/// This class verifies that any results of the specified op have a boolean
1134/// type, a vector thereof, or a tensor thereof.
1135template <typename ConcreteType>
1136class ResultsAreBoolLike : public TraitBase<ConcreteType, ResultsAreBoolLike> {
1137public:
1138 static LogicalResult verifyTrait(Operation *op) {
1140 }
1141};
1142
1143/// This class verifies that any results of the specified op have a floating
1144/// point type, a vector thereof, or a tensor thereof.
1145template <typename ConcreteType>
1147 : public TraitBase<ConcreteType, ResultsAreFloatLike> {
1148public:
1149 static LogicalResult verifyTrait(Operation *op) {
1151 }
1152};
1153
1154/// This class verifies that any results of the specified op have a signless
1155/// integer or index type, a vector thereof, or a tensor thereof.
1156template <typename ConcreteType>
1158 : public TraitBase<ConcreteType, ResultsAreSignlessIntegerLike> {
1159public:
1160 static LogicalResult verifyTrait(Operation *op) {
1162 }
1163};
1164
1165/// This class adds property that the operation is commutative.
1166template <typename ConcreteType>
1167class IsCommutative : public TraitBase<ConcreteType, IsCommutative> {
1168public:
1169 static LogicalResult foldTrait(Operation *op, ArrayRef<Attribute> operands,
1171 return impl::foldCommutative(op, operands, results);
1172 }
1173};
1174
1175/// This class adds property that the operation is an involution.
1176/// This means a unary to unary operation "f" that satisfies f(f(x)) = x
1177template <typename ConcreteType>
1178class IsInvolution : public TraitBase<ConcreteType, IsInvolution> {
1179public:
1180 static LogicalResult verifyTrait(Operation *op) {
1181 static_assert(ConcreteType::template hasTrait<OneResult>(),
1182 "expected operation to produce one result");
1183 static_assert(ConcreteType::template hasTrait<OneOperand>(),
1184 "expected operation to take one operand");
1185 static_assert(ConcreteType::template hasTrait<SameOperandsAndResultType>(),
1186 "expected operation to preserve type");
1187 // Involution requires the operation to be side effect free as well
1188 // but currently this check is under a FIXME and is not actually done.
1189 return impl::verifyIsInvolution(op);
1190 }
1191
1193 return impl::foldInvolution(op);
1194 }
1195};
1196
1197/// This class adds property that the operation is idempotent.
1198/// This means a unary to unary operation "f" that satisfies f(f(x)) = f(x),
1199/// or a binary operation "g" that satisfies g(x, x) = x.
1200template <typename ConcreteType>
1201class IsIdempotent : public TraitBase<ConcreteType, IsIdempotent> {
1202public:
1203 static LogicalResult verifyTrait(Operation *op) {
1204 static_assert(ConcreteType::template hasTrait<OneResult>(),
1205 "expected operation to produce one result");
1206 static_assert(ConcreteType::template hasTrait<OneOperand>() ||
1207 ConcreteType::template hasTrait<NOperands<2>::Impl>(),
1208 "expected operation to take one or two operands");
1209 static_assert(ConcreteType::template hasTrait<SameOperandsAndResultType>(),
1210 "expected operation to preserve type");
1211 // Idempotent requires the operation to be side effect free as well
1212 // but currently this check is under a FIXME and is not actually done.
1213 return impl::verifyIsIdempotent(op);
1214 }
1215
1217 return impl::foldIdempotent(op);
1218 }
1219};
1220
1221/// This class verifies that all operands of the specified op have a float type,
1222/// a vector thereof, or a tensor thereof.
1223template <typename ConcreteType>
1225 : public TraitBase<ConcreteType, OperandsAreFloatLike> {
1226public:
1227 static LogicalResult verifyTrait(Operation *op) {
1229 }
1230};
1231
1232/// This class verifies that all operands of the specified op have a signless
1233/// integer or index type, a vector thereof, or a tensor thereof.
1234template <typename ConcreteType>
1236 : public TraitBase<ConcreteType, OperandsAreSignlessIntegerLike> {
1237public:
1238 static LogicalResult verifyTrait(Operation *op) {
1240 }
1241};
1242
1243/// This class verifies that all operands of the specified op have the same
1244/// type.
1245template <typename ConcreteType>
1246class SameTypeOperands : public TraitBase<ConcreteType, SameTypeOperands> {
1247public:
1248 static LogicalResult verifyTrait(Operation *op) {
1250 }
1251};
1252
1253/// This class provides the API for a sub-set of ops that are known to be
1254/// constant-like. These are non-side effecting operations with one result and
1255/// zero operands that can always be folded to a specific attribute value.
1256template <typename ConcreteType>
1257class ConstantLike : public TraitBase<ConcreteType, ConstantLike> {
1258public:
1259 static LogicalResult verifyTrait(Operation *op) {
1260 static_assert(ConcreteType::template hasTrait<OneResult>(),
1261 "expected operation to produce one result");
1262 static_assert(ConcreteType::template hasTrait<ZeroOperands>(),
1263 "expected operation to take zero operands");
1264 // TODO: We should verify that the operation can always be folded, but this
1265 // requires that the attributes of the op already be verified. We should add
1266 // support for verifying traits "after" the operation to enable this use
1267 // case.
1268 return success();
1269 }
1270};
1271
1272/// This class provides the API for ops that are known to be isolated from
1273/// above.
1274template <typename ConcreteType>
1276 : public TraitBase<ConcreteType, IsIsolatedFromAbove> {
1277public:
1278 static LogicalResult verifyRegionTrait(Operation *op) {
1280 }
1281};
1282
1283/// A trait of region holding operations that defines a new scope for polyhedral
1284/// optimization purposes. Any SSA values of 'index' type that either dominate
1285/// such an operation or are used at the top-level of such an operation
1286/// automatically become valid symbols for the polyhedral scope defined by that
1287/// operation. For more details, see `Traits.md#AffineScope`.
1288template <typename ConcreteType>
1289class AffineScope : public TraitBase<ConcreteType, AffineScope> {
1290public:
1291 static LogicalResult verifyTrait(Operation *op) {
1292 static_assert(!ConcreteType::template hasTrait<ZeroRegions>(),
1293 "expected operation to have one or more regions");
1294 return success();
1295 }
1296};
1297
1298/// A trait of region holding operations that define a new scope for automatic
1299/// allocations, i.e., allocations that are freed when control is transferred
1300/// back from the operation's region. Any operations performing such allocations
1301/// (for eg. memref.alloca) will have their allocations automatically freed at
1302/// their closest enclosing operation with this trait.
1303template <typename ConcreteType>
1305 : public TraitBase<ConcreteType, AutomaticAllocationScope> {
1306public:
1307 static LogicalResult verifyTrait(Operation *op) {
1308 static_assert(!ConcreteType::template hasTrait<ZeroRegions>(),
1309 "expected operation to have one or more regions");
1310 return success();
1311 }
1312};
1313
1314/// This class provides a verifier for ops that are expecting their parent
1315/// to be one of the given parent ops
1316template <typename... ParentOpTypes>
1318 template <typename ConcreteType>
1319 class Impl : public TraitBase<ConcreteType, Impl> {
1320 public:
1321 static LogicalResult verifyTrait(Operation *op) {
1322 if (llvm::isa_and_nonnull<ParentOpTypes...>(op->getParentOp()))
1323 return success();
1324
1325 return op->emitOpError()
1326 << "expects parent op "
1327 << (sizeof...(ParentOpTypes) != 1 ? "to be one of '" : "'")
1328 << llvm::ArrayRef({ParentOpTypes::getOperationName()...}) << "'";
1329 }
1330
1331 template <typename ParentOpType =
1332 std::tuple_element_t<0, std::tuple<ParentOpTypes...>>>
1333 std::enable_if_t<sizeof...(ParentOpTypes) == 1, ParentOpType>
1335 Operation *parent = this->getOperation()->getParentOp();
1336 return llvm::cast<ParentOpType>(parent);
1337 }
1338 };
1339};
1340
1341/// This class provides a verifier for ops that are expecting an ancestor
1342/// (anywhere up the parent chain) to be one of the given op types.
1343template <typename... AncestorOpTypes>
1345 template <typename ConcreteType>
1346 class Impl : public TraitBase<ConcreteType, Impl> {
1347 public:
1348 static LogicalResult verifyTrait(Operation *op) {
1349 if (op->getParentOfType<AncestorOpTypes...>())
1350 return success();
1351
1352 return op->emitOpError()
1353 << "expects ancestor op "
1354 << (sizeof...(AncestorOpTypes) != 1 ? "to be one of '" : "'")
1355 << llvm::ArrayRef({AncestorOpTypes::getOperationName()...}) << "'";
1356 }
1357
1358 template <typename AncestorOpType =
1359 std::tuple_element_t<0, std::tuple<AncestorOpTypes...>>>
1360 std::enable_if_t<sizeof...(AncestorOpTypes) == 1, AncestorOpType>
1362 return this->getOperation()->template getParentOfType<AncestorOpType>();
1363 }
1364 };
1365};
1366
1367/// A trait for operations that have an attribute specifying operand segments.
1368///
1369/// Certain operations can have multiple variadic operands and their size
1370/// relationship is not always known statically. For such cases, we need
1371/// a per-op-instance specification to divide the operands into logical groups
1372/// or segments. This can be modeled by attributes. The attribute will be named
1373/// as `operandSegmentSizes`.
1374///
1375/// This trait verifies the attribute for specifying operand segments has
1376/// the correct type (1D vector) and values (non-negative), etc.
1377template <typename ConcreteType>
1380public:
1381 static StringRef getOperandSegmentSizeAttr() { return "operandSegmentSizes"; }
1382
1383 static LogicalResult verifyTrait(Operation *op) {
1384 return ::mlir::OpTrait::impl::verifyOperandSizeAttr(
1386 }
1387};
1388
1389/// Similar to AttrSizedOperandSegments but used for results.
1390template <typename ConcreteType>
1393public:
1394 static StringRef getResultSegmentSizeAttr() { return "resultSegmentSizes"; }
1395
1396 static LogicalResult verifyTrait(Operation *op) {
1397 return ::mlir::OpTrait::impl::verifyResultSizeAttr(
1399 }
1400};
1401
1402/// This trait provides a verifier for ops that are expecting their regions to
1403/// not have any arguments
1404template <typename ConcrentType>
1406 static LogicalResult verifyTrait(Operation *op) {
1407 return ::mlir::OpTrait::impl::verifyNoRegionArguments(op);
1408 }
1409};
1410
1411// This trait is used to flag operations that consume or produce
1412// values of `MemRef` type where those references can be 'normalized'.
1413// TODO: Right now, the operands of an operation are either all normalizable,
1414// or not. In the future, we may want to allow some of the operands to be
1415// normalizable.
1416template <typename ConcrentType>
1419
1420/// This trait tags element-wise ops on vectors or tensors.
1421///
1422/// NOTE: Not all ops that are "elementwise" in some abstract sense satisfy this
1423/// trait. In particular, broadcasting behavior is not allowed.
1424///
1425/// An `Elementwise` op must satisfy the following properties:
1426///
1427/// 1. If any result is a vector/tensor then at least one operand must also be a
1428/// vector/tensor.
1429/// 2. If any operand is a vector/tensor then there must be at least one result
1430/// and all results must be vectors/tensors.
1431/// 3. All operand and result vector/tensor types must be of the same shape. The
1432/// shape may be dynamic in which case the op's behaviour is undefined for
1433/// non-matching shapes.
1434/// 4. The operation must be elementwise on its vector/tensor operands and
1435/// results. When applied to single-element vectors/tensors, the result must
1436/// be the same per elememnt.
1437///
1438/// TODO: Avoid hardcoding vector/tensor, and generalize this trait to a new
1439/// interface `ElementwiseTypeInterface` that describes the container types for
1440/// which the operation is elementwise.
1441///
1442/// Rationale:
1443/// - 1. and 2. guarantee a well-defined iteration space and exclude the cases
1444/// of 0 non-scalar operands or 0 non-scalar results, which complicate a
1445/// generic definition of the iteration space.
1446/// - 3. guarantees that folding can be done across scalars/vectors/tensors with
1447/// the same pattern, as otherwise lots of special handling for type
1448/// mismatches would be needed.
1449/// - 4. guarantees that no error handling is needed. Higher-level dialects
1450/// should reify any needed guards or error handling code before lowering to
1451/// an `Elementwise` op.
1452template <typename ConcreteType>
1454 static LogicalResult verifyTrait(Operation *op) {
1455 return ::mlir::OpTrait::impl::verifyElementwise(op);
1456 }
1457};
1458
1459/// This trait tags `Elementwise` operatons that can be systematically
1460/// scalarized. All vector/tensor operands and results are then replaced by
1461/// scalars of the respective element type. Semantically, this is the operation
1462/// on a single element of the vector/tensor.
1463///
1464/// Rationale:
1465/// Allow to define the vector/tensor semantics of elementwise operations based
1466/// on the same op's behavior on scalars. This provides a constructive procedure
1467/// for IR transformations to, e.g., create scalar loop bodies from tensor ops.
1468///
1469/// Example:
1470/// ```
1471/// %tensor_select = "arith.select"(%pred_tensor, %true_val, %false_val)
1472/// : (tensor<?xi1>, tensor<?xf32>, tensor<?xf32>)
1473/// -> tensor<?xf32>
1474/// ```
1475/// can be scalarized to
1476///
1477/// ```
1478/// %scalar_select = "arith.select"(%pred, %true_val_scalar, %false_val_scalar)
1479/// : (i1, f32, f32) -> f32
1480/// ```
1481template <typename ConcreteType>
1483 static LogicalResult verifyTrait(Operation *op) {
1484 static_assert(
1485 ConcreteType::template hasTrait<Elementwise>(),
1486 "`Scalarizable` trait is only applicable to `Elementwise` ops.");
1487 return success();
1488 }
1489};
1490
1491/// This trait tags `Elementwise` operatons that can be systematically
1492/// vectorized. All scalar operands and results are then replaced by vectors
1493/// with the respective element type. Semantically, this is the operation on
1494/// multiple elements simultaneously. See also `Tensorizable`.
1495///
1496/// Rationale:
1497/// Provide the reverse to `Scalarizable` which, when chained together, allows
1498/// reasoning about the relationship between the tensor and vector case.
1499/// Additionally, it permits reasoning about promoting scalars to vectors via
1500/// broadcasting in cases like `%select_scalar_pred` below.
1501template <typename ConcreteType>
1503 static LogicalResult verifyTrait(Operation *op) {
1504 static_assert(
1505 ConcreteType::template hasTrait<Elementwise>(),
1506 "`Vectorizable` trait is only applicable to `Elementwise` ops.");
1507 return success();
1508 }
1509};
1510
1511/// This trait tags `Elementwise` operatons that can be systematically
1512/// tensorized. All scalar operands and results are then replaced by tensors
1513/// with the respective element type. Semantically, this is the operation on
1514/// multiple elements simultaneously. See also `Vectorizable`.
1515///
1516/// Rationale:
1517/// Provide the reverse to `Scalarizable` which, when chained together, allows
1518/// reasoning about the relationship between the tensor and vector case.
1519/// Additionally, it permits reasoning about promoting scalars to tensors via
1520/// broadcasting in cases like `%select_scalar_pred` below.
1521///
1522/// Examples:
1523/// ```
1524/// %scalar = "arith.addf"(%a, %b) : (f32, f32) -> f32
1525/// ```
1526/// can be tensorized to
1527/// ```
1528/// %tensor = "arith.addf"(%a, %b) : (tensor<?xf32>, tensor<?xf32>)
1529/// -> tensor<?xf32>
1530/// ```
1531///
1532/// ```
1533/// %scalar_pred = "arith.select"(%pred, %true_val, %false_val)
1534/// : (i1, tensor<?xf32>, tensor<?xf32>) -> tensor<?xf32>
1535/// ```
1536/// can be tensorized to
1537/// ```
1538/// %tensor_pred = "arith.select"(%pred, %true_val, %false_val)
1539/// : (tensor<?xi1>, tensor<?xf32>, tensor<?xf32>)
1540/// -> tensor<?xf32>
1541/// ```
1542template <typename ConcreteType>
1544 static LogicalResult verifyTrait(Operation *op) {
1545 static_assert(
1546 ConcreteType::template hasTrait<Elementwise>(),
1547 "`Tensorizable` trait is only applicable to `Elementwise` ops.");
1548 return success();
1549 }
1550};
1551
1552/// Together, `Elementwise`, `Scalarizable`, `Vectorizable`, and `Tensorizable`
1553/// provide an easy way for scalar operations to conveniently generalize their
1554/// behavior to vectors/tensors, and systematize conversion between these forms.
1556
1557} // namespace OpTrait
1558
1559//===----------------------------------------------------------------------===//
1560// Internal Trait Utilities
1561//===----------------------------------------------------------------------===//
1562
1564//===----------------------------------------------------------------------===//
1565// Trait Existence
1566//===----------------------------------------------------------------------===//
1567
1568/// Returns true if this given Trait ID matches the IDs of any of the provided
1569/// trait types `Traits`.
1570template <template <typename T> class... Traits>
1571inline bool hasTrait(TypeID traitID) {
1572 return ((traitID == TypeID::get<Traits>()) || ...);
1573}
1574template <>
1575inline bool hasTrait<>(TypeID traitID) {
1576 return false;
1577}
1578
1579//===----------------------------------------------------------------------===//
1580// Trait Folding
1581//===----------------------------------------------------------------------===//
1582
1583/// Trait to check if T provides a 'foldTrait' method for single result
1584/// operations.
1585template <typename T, typename... Args>
1586using has_single_result_fold_trait = decltype(T::foldTrait(
1587 std::declval<Operation *>(), std::declval<ArrayRef<Attribute>>()));
1588template <typename T>
1590 llvm::is_detected<has_single_result_fold_trait, T>;
1591/// Trait to check if T provides a general 'foldTrait' method.
1592template <typename T, typename... Args>
1594 decltype(T::foldTrait(std::declval<Operation *>(),
1595 std::declval<ArrayRef<Attribute>>(),
1596 std::declval<SmallVectorImpl<OpFoldResult> &>()));
1597template <typename T>
1598using detect_has_fold_trait = llvm::is_detected<has_fold_trait, T>;
1599/// Trait to check if T provides any `foldTrait` method.
1600template <typename T>
1602 std::disjunction<detect_has_fold_trait<T>,
1604
1605/// Returns the result of folding a trait that implements a `foldTrait` function
1606/// that is specialized for operations that have a single result.
1607template <typename Trait>
1608std::enable_if_t<detect_has_single_result_fold_trait<Trait>::value,
1609 LogicalResult>
1612 assert(op->hasTrait<OpTrait::OneResult>() &&
1613 "expected trait on non single-result operation to implement the "
1614 "general `foldTrait` method");
1615 // If a previous trait has already been folded and replaced this operation, we
1616 // fail to fold this trait.
1617 if (!results.empty())
1618 return failure();
1619
1620 if (OpFoldResult result = Trait::foldTrait(op, operands)) {
1621 if (llvm::dyn_cast_if_present<Value>(result) != op->getResult(0))
1622 results.push_back(result);
1623 return success();
1624 }
1625 return failure();
1626}
1627/// Returns the result of folding a trait that implements a generalized
1628/// `foldTrait` function that is supports any operation type.
1629template <typename Trait>
1630std::enable_if_t<detect_has_fold_trait<Trait>::value, LogicalResult>
1633 // If a previous trait has already been folded and replaced this operation, we
1634 // fail to fold this trait.
1635 return results.empty() ? Trait::foldTrait(op, operands, results) : failure();
1636}
1637template <typename Trait>
1638inline std::enable_if_t<!detect_has_any_fold_trait<Trait>::value, LogicalResult>
1642
1643/// Given a tuple type containing a set of traits, return the result of folding
1644/// the given operation.
1645template <typename... Ts>
1646LogicalResult foldTraits(Operation *op, ArrayRef<Attribute> operands,
1648 // Reuse one no-op specialization for traits without a folder.
1649 return success(
1650 (succeeded(
1652 Ts, void>>(op, operands, results)) ||
1653 ...));
1654}
1655
1656//===----------------------------------------------------------------------===//
1657// Trait Verification
1658//===----------------------------------------------------------------------===//
1659
1660/// Trait to check if T provides a `verifyTrait` method.
1661template <typename T, typename... Args>
1662using has_verify_trait = decltype(T::verifyTrait(std::declval<Operation *>()));
1663template <typename T>
1664using detect_has_verify_trait = llvm::is_detected<has_verify_trait, T>;
1665
1666/// Trait to check if T provides a `verifyTrait` method.
1667template <typename T, typename... Args>
1669 decltype(T::verifyRegionTrait(std::declval<Operation *>()));
1670template <typename T>
1672 llvm::is_detected<has_verify_region_trait, T>;
1673
1674/// Verify the given trait if it provides a verifier.
1675template <typename T>
1676LogicalResult verifyTrait(Operation *op) {
1678 return T::verifyTrait(op);
1679 else
1680 return success();
1681}
1682
1683/// Given a set of traits, return the result of verifying the given operation.
1684template <typename... Ts>
1685LogicalResult verifyTraits(Operation *op) {
1686 // Avoid instantiating an identical no-op verifier for each absent hook.
1687 return success(
1688 (succeeded(verifyTrait<std::conditional_t<
1689 detect_has_verify_trait<Ts>::value, Ts, void>>(op)) &&
1690 ...));
1691}
1692
1693/// Verify the given trait if it provides a region verifier.
1694template <typename T>
1695LogicalResult verifyRegionTrait(Operation *op) {
1697 return T::verifyRegionTrait(op);
1698 else
1699 return success();
1700}
1701
1702/// Given a set of traits, return the result of verifying the regions of the
1703/// given operation.
1704template <typename... Ts>
1705LogicalResult verifyRegionTraits(Operation *op) {
1706 // Avoid instantiating an identical no-op verifier for each absent hook.
1707 return success(
1708 (succeeded(
1709 verifyRegionTrait<std::conditional_t<
1711 ...));
1712}
1713} // namespace op_definition_impl
1714
1715//===----------------------------------------------------------------------===//
1716// Operation Definition classes
1717//===----------------------------------------------------------------------===//
1718
1719/// This provides public APIs that all operations should have. The template
1720/// argument 'ConcreteType' should be the concrete type by CRTP and the others
1721/// are base classes by the policy pattern.
1722template <typename ConcreteType, template <typename T> class... Traits>
1723class Op : public OpState, public Traits<ConcreteType>... {
1724public:
1725 /// Inherit getOperation from `OpState`.
1727 using OpState::verify;
1729
1730 /// Return if this operation contains the provided trait.
1731 template <template <typename T> class Trait>
1732 static constexpr bool hasTrait() {
1733 return llvm::is_one_of<Trait<ConcreteType>, Traits<ConcreteType>...>::value;
1734 }
1735
1736 /// Create a deep copy of this operation.
1737 ConcreteType clone() { return cast<ConcreteType>(getOperation()->clone()); }
1738
1739 /// Create a partial copy of this operation without traversing into attached
1740 /// regions. The new operation will have the same number of regions as the
1741 /// original one, but they will be left empty.
1742 ConcreteType cloneWithoutRegions() {
1743 return cast<ConcreteType>(getOperation()->cloneWithoutRegions());
1744 }
1745
1746 /// Return true if this "op class" can match against the specified operation.
1747 static bool classof(Operation *op) {
1748 if (auto info = op->getRegisteredInfo())
1749 return TypeID::get<ConcreteType>() == info->getTypeID();
1750#ifndef NDEBUG
1751 if (op->getName().getStringRef() == ConcreteType::getOperationName())
1752 llvm::report_fatal_error(
1753 "classof on '" + ConcreteType::getOperationName() +
1754 "' failed due to the operation not being registered");
1755#endif
1756 return false;
1757 }
1758 /// Provide `classof` support for other OpBase derived classes, such as
1759 /// Interfaces.
1760 template <typename T>
1761 static std::enable_if_t<std::is_base_of<OpState, T>::value, bool>
1762 classof(const T *op) {
1763 return classof(const_cast<T *>(op)->getOperation());
1764 }
1765
1766 /// Expose the type we are instantiated on to template machinery that may want
1767 /// to introspect traits on this operation.
1768 using ConcreteOpType = ConcreteType;
1769
1770 /// This is a public constructor. Any op can be initialized to null.
1771 explicit Op() : OpState(nullptr) {}
1772 Op(std::nullptr_t) : OpState(nullptr) {}
1773
1774 /// This is a public constructor to enable access via the llvm::cast family of
1775 /// methods. This should not be used directly.
1776 explicit Op(Operation *state) : OpState(state) {}
1777
1778 /// Methods for supporting PointerLikeTypeTraits.
1779 const void *getAsOpaquePointer() const {
1780 return static_cast<const void *>((Operation *)*this);
1781 }
1782 static ConcreteOpType getFromOpaquePointer(const void *pointer) {
1783 return ConcreteOpType(
1784 reinterpret_cast<Operation *>(const_cast<void *>(pointer)));
1785 }
1786
1787 /// Attach the given models as implementations of the corresponding
1788 /// interfaces for the concrete operation.
1789 template <typename... Models>
1790 static void attachInterface(MLIRContext &context) {
1791 std::optional<RegisteredOperationName> info =
1793 if (!info)
1794 llvm::report_fatal_error(
1795 "Attempting to attach an interface to an unregistered operation " +
1796 ConcreteType::getOperationName() + ".");
1797 (checkInterfaceTarget<Models>(), ...);
1798 info->attachInterface<Models...>();
1799 }
1800 /// Convert the provided attribute to a property and assigned it to the
1801 /// provided properties. This default implementation forwards to a free
1802 /// function `setPropertiesFromAttribute` that can be looked up with ADL in
1803 /// the namespace where the properties are defined. It can also be overridden
1804 /// in the derived ConcreteOp.
1805 template <typename PropertiesTy>
1806 static LogicalResult
1807 setPropertiesFromAttr(PropertiesTy &prop, Attribute attr,
1809 return setPropertiesFromAttribute(prop, attr, emitError);
1810 }
1811 /// Convert the provided properties to an attribute. This default
1812 /// implementation forwards to a free function `getPropertiesAsAttribute` that
1813 /// can be looked up with ADL in the namespace where the properties are
1814 /// defined. It can also be overridden in the derived ConcreteOp.
1815 template <typename PropertiesTy>
1817 const PropertiesTy &prop) {
1818 return getPropertiesAsAttribute(ctx, prop);
1819 }
1820 /// Hash the provided properties. This default implementation forwards to a
1821 /// free function `computeHash` that can be looked up with ADL in the
1822 /// namespace where the properties are defined. It can also be overridden in
1823 /// the derived ConcreteOp.
1824 template <typename PropertiesTy>
1825 static llvm::hash_code computePropertiesHash(const PropertiesTy &prop) {
1826 return computeHash(prop);
1827 }
1828
1829private:
1830 /// Trait to check if T provides a 'fold' method for a single result op.
1831 template <typename T, typename... Args>
1832 using has_single_result_fold_t =
1833 decltype(std::declval<T>().fold(std::declval<ArrayRef<Attribute>>()));
1834 template <typename T>
1835 constexpr static bool has_single_result_fold_v =
1836 llvm::is_detected<has_single_result_fold_t, T>::value;
1837 /// Trait to check if T provides a general 'fold' method.
1838 template <typename T, typename... Args>
1839 using has_fold_t = decltype(std::declval<T>().fold(
1840 std::declval<ArrayRef<Attribute>>(),
1841 std::declval<SmallVectorImpl<OpFoldResult> &>()));
1842 template <typename T>
1843 constexpr static bool has_fold_v = llvm::is_detected<has_fold_t, T>::value;
1844 /// Trait to check if T provides a 'fold' method with a FoldAdaptor for a
1845 /// single result op.
1846 template <typename T, typename... Args>
1847 using has_fold_adaptor_single_result_fold_t =
1848 decltype(std::declval<T>().fold(std::declval<typename T::FoldAdaptor>()));
1849 template <class T>
1850 constexpr static bool has_fold_adaptor_single_result_v =
1851 llvm::is_detected<has_fold_adaptor_single_result_fold_t, T>::value;
1852 /// Trait to check if T provides a general 'fold' method with a FoldAdaptor.
1853 template <typename T, typename... Args>
1854 using has_fold_adaptor_fold_t = decltype(std::declval<T>().fold(
1855 std::declval<typename T::FoldAdaptor>(),
1856 std::declval<SmallVectorImpl<OpFoldResult> &>()));
1857 template <class T>
1858 constexpr static bool has_fold_adaptor_v =
1859 llvm::is_detected<has_fold_adaptor_fold_t, T>::value;
1860
1861 /// Trait to check if T provides a 'print' method.
1862 template <typename T, typename... Args>
1863 using has_print =
1864 decltype(std::declval<T>().print(std::declval<OpAsmPrinter &>()));
1865 template <typename T>
1866 using detect_has_print = llvm::is_detected<has_print, T>;
1867
1868 /// Trait to check if printProperties(OpAsmPrinter, T, ArrayRef<StringRef>)
1869 /// exist
1870 template <typename T, typename... Args>
1871 using has_print_properties =
1872 decltype(printProperties(std::declval<OpAsmPrinter &>(),
1873 std::declval<T>(),
1874 std::declval<ArrayRef<StringRef>>()));
1875 template <typename T>
1876 using detect_has_print_properties =
1877 llvm::is_detected<has_print_properties, T>;
1878
1879 /// Trait to check if T provides a generated printer for the key-value
1880 /// spelling of `prop-dict`.
1881 template <typename T, typename... Args>
1882 using has_print_properties_as_key_value_list =
1883 decltype(T::_odsPrintPropertiesAsKeyValueList(
1884 std::declval<MLIRContext *>(), std::declval<OpAsmPrinter &>(),
1885 std::declval<const typename PropertiesSelector<T>::type &>(),
1886 std::declval<ArrayRef<StringRef>>()));
1887 template <typename T>
1888 using detect_has_print_properties_as_key_value_list =
1889 llvm::is_detected<has_print_properties_as_key_value_list, T>;
1890
1891 /// Trait to check if parseProperties(OpAsmParser, T) exist
1892 template <typename T, typename... Args>
1893 using has_parse_properties = decltype(parseProperties(
1894 std::declval<OpAsmParser &>(), std::declval<T &>()));
1895 template <typename T>
1896 using detect_has_parse_properties =
1897 llvm::is_detected<has_parse_properties, T>;
1898
1899 /// Trait to check if T provides a generated parser for the key-value
1900 /// spelling of `prop-dict`.
1901 template <typename T, typename... Args>
1902 using has_parse_properties_from_key_value_list =
1903 decltype(T::parsePropertiesFromKeyValueList(
1904 std::declval<OpAsmParser &>(), std::declval<OperationState &>()));
1905 template <typename T>
1906 using detect_has_parse_properties_from_key_value_list =
1907 llvm::is_detected<has_parse_properties_from_key_value_list, T>;
1908
1909 /// Trait to check if T provides a 'ConcreteEntity' type alias.
1910 template <typename T>
1911 using has_concrete_entity_t = typename T::ConcreteEntity;
1912
1913public:
1914 /// Returns true if this operation defines a `Properties` inner type.
1915 static constexpr bool hasProperties() {
1916 return !std::is_same_v<
1917 typename ConcreteType::template InferredProperties<ConcreteType>,
1919 }
1920
1921private:
1922 /// A struct-wrapped type alias to T::ConcreteEntity if provided and to
1923 /// ConcreteType otherwise. This is akin to std::conditional but doesn't fail
1924 /// on the missing typedef. Useful for checking if the interface is targeting
1925 /// the right class.
1926 template <typename T,
1927 bool = llvm::is_detected<has_concrete_entity_t, T>::value>
1928 struct InterfaceTargetOrOpT {
1929 using type = typename T::ConcreteEntity;
1930 };
1931 template <typename T>
1932 struct InterfaceTargetOrOpT<T, false> {
1933 using type = ConcreteType;
1934 };
1935
1936 /// A hook for static assertion that the external interface model T is
1937 /// targeting the concrete type of this op. The model can also be a fallback
1938 /// model that works for every op.
1939 template <typename T>
1940 static void checkInterfaceTarget() {
1941 static_assert(std::is_same<typename InterfaceTargetOrOpT<T>::type,
1942 ConcreteType>::value,
1943 "attaching an interface to the wrong op kind");
1944 }
1945
1946 /// Returns an interface map containing the interfaces registered to this
1947 /// operation.
1948 static detail::InterfaceMap getInterfaceMap() {
1949 return detail::InterfaceMap::template get<Traits<ConcreteType>...>();
1950 }
1951
1952 using FoldHookFn = LogicalResult (*)(Operation *, ArrayRef<Attribute>,
1953 SmallVectorImpl<OpFoldResult> &);
1954 using HasTraitFn = bool (*)(TypeID);
1955 using PrintAssemblyFn = void (*)(Operation *, OpAsmPrinter &, StringRef);
1956 using VerifyInvariantsFn = LogicalResult (*)(Operation *);
1957
1958 /// Return the internal implementations of each of the OperationName hooks.
1959 static constexpr FoldHookFn getFoldHookFn() {
1960 // If the operation is single result and defines a `fold` method.
1961 if constexpr (llvm::is_one_of<OpTrait::OneResult<ConcreteType>,
1962 Traits<ConcreteType>...>::value &&
1963 (has_single_result_fold_v<ConcreteType> ||
1964 has_fold_adaptor_single_result_v<ConcreteType>))
1965 return [](Operation *op, ArrayRef<Attribute> operands,
1966 SmallVectorImpl<OpFoldResult> &results) {
1967 return foldSingleResultHook<ConcreteType>(op, operands, results);
1968 };
1969 // The operation is not single result and defines a `fold` method.
1970 if constexpr (has_fold_v<ConcreteType> || has_fold_adaptor_v<ConcreteType>)
1971 return [](Operation *op, ArrayRef<Attribute> operands,
1972 SmallVectorImpl<OpFoldResult> &results) {
1973 return foldHook<ConcreteType>(op, operands, results);
1974 };
1975 // The operation does not define a `fold` method.
1976 return [](Operation *op, ArrayRef<Attribute> operands,
1977 SmallVectorImpl<OpFoldResult> &results) {
1978 // In this case, we only need to fold the traits of the operation.
1980 op, operands, results);
1981 };
1982 }
1983 /// Return the result of folding a single result operation that defines a
1984 /// `fold` method.
1985 template <typename ConcreteOpT>
1986 static LogicalResult
1987 foldSingleResultHook(Operation *op, ArrayRef<Attribute> operands,
1988 SmallVectorImpl<OpFoldResult> &results) {
1989 OpFoldResult result;
1990 if constexpr (has_fold_adaptor_single_result_v<ConcreteOpT>) {
1991 result = cast<ConcreteOpT>(op).fold(
1992 typename ConcreteOpT::FoldAdaptor(operands, cast<ConcreteOpT>(op)));
1993 } else {
1994 result = cast<ConcreteOpT>(op).fold(operands);
1995 }
1996
1997 // If the fold failed or was in-place, try to fold the traits of the
1998 // operation.
1999 if (!result ||
2000 llvm::dyn_cast_if_present<Value>(result) == op->getResult(0)) {
2001 if (succeeded(op_definition_impl::foldTraits<Traits<ConcreteType>...>(
2002 op, operands, results)))
2003 return success();
2004 return success(static_cast<bool>(result));
2005 }
2006 results.push_back(result);
2007 return success();
2008 }
2009 /// Return the result of folding an operation that defines a `fold` method.
2010 template <typename ConcreteOpT>
2011 static LogicalResult foldHook(Operation *op, ArrayRef<Attribute> operands,
2012 SmallVectorImpl<OpFoldResult> &results) {
2013 auto result = LogicalResult::failure();
2014 if constexpr (has_fold_adaptor_v<ConcreteOpT>) {
2015 result = cast<ConcreteOpT>(op).fold(
2016 typename ConcreteOpT::FoldAdaptor(operands, cast<ConcreteOpT>(op)),
2017 results);
2018 } else {
2019 result = cast<ConcreteOpT>(op).fold(operands, results);
2020 }
2021
2022 // If the fold failed or was in-place, try to fold the traits of the
2023 // operation.
2024 if (failed(result) || results.empty()) {
2025 if (succeeded(op_definition_impl::foldTraits<Traits<ConcreteType>...>(
2026 op, operands, results)))
2027 return success();
2028 }
2029 return result;
2030 }
2031
2032 static constexpr HasTraitFn getHasTraitFn() {
2033 return
2034 [](TypeID id) { return op_definition_impl::hasTrait<Traits...>(id); };
2035 }
2036 static constexpr PrintAssemblyFn getPrintAssemblyFn() {
2037 if constexpr (detect_has_print<ConcreteType>::value)
2038 return [](Operation *op, OpAsmPrinter &p, StringRef defaultDialect) {
2039 OpState::printOpName(op, p, defaultDialect);
2040 return cast<ConcreteType>(op).print(p);
2041 };
2042 return [](Operation *op, OpAsmPrinter &printer, StringRef defaultDialect) {
2043 return OpState::print(op, printer, defaultDialect);
2044 };
2045 }
2046
2047public:
2048 template <typename T>
2050 template <typename T = ConcreteType>
2052 if constexpr (!hasProperties())
2053 return getEmptyProperties();
2054 return *getOperation()
2056 .template as<InferredProperties<T> *>();
2057 }
2058
2059 /// This hook populates any unset default attrs when mapped to properties.
2060 template <typename T = ConcreteType>
2062 InferredProperties<T> &properties) {}
2063
2064 /// Print the operation properties with names not included within
2065 /// 'elidedProps'. Unless overridden, this method first tries to dispatch to a
2066 /// `printProperties` free-function, then to the generated per-field printer,
2067 /// and finally converts the properties to an Attribute.
2068 template <typename T>
2070 const T &properties,
2071 ArrayRef<StringRef> elidedProps = {}) {
2072 if constexpr (detect_has_print_properties<T>::value)
2073 return printProperties(p, properties, elidedProps);
2074 if constexpr (detect_has_print_properties_as_key_value_list<
2075 ConcreteType>::value)
2076 return ConcreteType::_odsPrintPropertiesAsKeyValueList(ctx, p, properties,
2077 elidedProps);
2079 p, ConcreteType::getPropertiesAsAttr(ctx, properties), elidedProps);
2080 }
2081
2082 /// Parses 'prop-dict' for the operation. Generated parsers accept a keyed
2083 /// list whose values use their custom assembly parsers, as well as the
2084 /// legacy generic '<{ ... }>' dictionary syntax. The resulting properties
2085 /// are stored within the property structure of 'result', accessible via
2086 /// 'getOrAddProperties'.
2087 template <typename T = ConcreteType>
2088 static ParseResult parseProperties(OpAsmParser &parser,
2090 if constexpr (detect_has_parse_properties<InferredProperties<T>>::value) {
2091 return parseProperties(
2092 parser, result.getOrAddProperties<InferredProperties<T>>());
2093 }
2094
2095 if constexpr (detect_has_parse_properties_from_key_value_list<T>::value)
2096 return T::parsePropertiesFromKeyValueList(parser, result);
2097
2098 Attribute propertyDictionary;
2099 if (genericParseProperties(parser, propertyDictionary))
2100 return failure();
2101
2102 // The generated 'setPropertiesFromParsedAttr', like
2103 // 'setPropertiesFromAttr', expects a 'DictionaryAttr' that is not null.
2104 // Use an empty dictionary in the case that the whole dictionary is
2105 // optional.
2106 if (!propertyDictionary)
2107 propertyDictionary = DictionaryAttr::get(result.getContext());
2108
2109 auto emitError = [&]() {
2110 return mlir::emitError(result.location, "invalid properties ")
2111 << propertyDictionary << " for op " << result.name.getStringRef()
2112 << ": ";
2113 };
2114
2115 // Copy the data from the dictionary attribute into the property struct of
2116 // the operation. This method is generated by ODS by default if there are
2117 // any occurrences of 'prop-dict' in the assembly format and should set
2118 // any properties that aren't parsed elsewhere.
2119 return ConcreteOpType::setPropertiesFromParsedAttr(
2120 result.getOrAddProperties<InferredProperties<T>>(), propertyDictionary,
2121 emitError);
2122 }
2123
2124private:
2125 /// Implementation of `PopulateDefaultAttrsFn` OperationName hook.
2126 static OperationName::PopulateDefaultAttrsFn getPopulateDefaultAttrsFn() {
2127 return ConcreteType::populateDefaultAttrs;
2128 }
2129 /// Implementation of `VerifyInvariantsFn` OperationName hook.
2130 static LogicalResult verifyInvariants(Operation *op) {
2131 static_assert(hasNoDataMembers(),
2132 "Op class shouldn't define new data members");
2133 return failure(
2134 failed(op_definition_impl::verifyTraits<Traits<ConcreteType>...>(op)) ||
2135 failed(cast<ConcreteType>(op).verify()));
2136 }
2137 static constexpr VerifyInvariantsFn getVerifyInvariantsFn() {
2138 return &verifyInvariants;
2139 }
2140 /// Implementation of `VerifyRegionInvariantsFn` OperationName hook.
2141 static LogicalResult verifyRegionInvariants(Operation *op) {
2142 static_assert(hasNoDataMembers(),
2143 "Op class shouldn't define new data members");
2144 return failure(
2145 failed(op_definition_impl::verifyRegionTraits<Traits<ConcreteType>...>(
2146 op)) ||
2147 failed(cast<ConcreteType>(op).verifyRegions()));
2148 }
2149 static constexpr VerifyInvariantsFn getVerifyRegionInvariantsFn() {
2150 return &verifyRegionInvariants;
2151 }
2152
2153 static constexpr bool hasNoDataMembers() {
2154 // Compare with the existing base instead of instantiating the traits again
2155 // for an otherwise unused operation type.
2156 return sizeof(ConcreteType) == sizeof(Op);
2157 }
2158
2159 /// Allow access to internal implementation methods.
2160 friend RegisteredOperationName;
2161};
2162
2163/// This class represents the base of an operation interface. See the definition
2164/// of `detail::Interface` for requirements on the `Traits` type.
2165template <typename ConcreteType, typename Traits>
2167 : public detail::Interface<ConcreteType, Operation *, Traits,
2168 Op<ConcreteType>, OpTrait::TraitBase> {
2169public:
2171 using InterfaceBase = detail::Interface<ConcreteType, Operation *, Traits,
2173
2174 /// Inherit the base class constructor.
2176
2177protected:
2178 /// Returns the impl interface instance for the given operation.
2180 OperationName name = op->getName();
2181
2182#ifndef NDEBUG
2183 // Check that the current interface isn't an unresolved promise for the
2184 // given operation.
2185 if (Dialect *dialect = name.getDialect()) {
2187 *dialect, name.getTypeID(), ConcreteType::getInterfaceID(),
2188 llvm::getTypeName<ConcreteType>());
2189 }
2190#endif
2191
2192 // Access the raw interface from the operation info.
2193 if (std::optional<RegisteredOperationName> rInfo =
2194 name.getRegisteredInfo()) {
2195 if (auto *opIface = rInfo->getInterface<ConcreteType>())
2196 return opIface;
2197 // Fallback to the dialect to provide it with a chance to implement this
2198 // interface for this operation.
2199 return rInfo->getDialect().getRegisteredInterfaceForOp<ConcreteType>(
2200 op->getName());
2201 }
2202 // Fallback to the dialect to provide it with a chance to implement this
2203 // interface for this operation.
2204 if (Dialect *dialect = name.getDialect())
2205 return dialect->getRegisteredInterfaceForOp<ConcreteType>(name);
2206 return nullptr;
2207 }
2208
2209 /// Allow access to `getInterfaceFor`.
2211};
2212
2213} // namespace mlir
2214
2215namespace llvm {
2216
2217template <typename T>
2219 std::enable_if_t<std::is_base_of<mlir::OpState, T>::value &&
2220 !mlir::detail::IsInterface<T>::value>> {
2221 static unsigned getHashValue(T val) {
2222 return hash_value(val.getAsOpaquePointer());
2223 }
2224 static bool isEqual(T lhs, T rhs) { return lhs == rhs; }
2225};
2226} // namespace llvm
2227
2229
2230#endif
return success()
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)
Definition TypeID.h:321
This class provides management for the lifetime of the state used when printing the IR.
Definition AsmState.h:542
Attributes are known-constant values of operations.
Definition Attributes.h:25
Block represents an ordered list of Operations.
Definition Block.h:34
OpListType::iterator iterator
Definition Block.h:165
bool empty()
Definition Block.h:173
OpListType & getOperations()
Definition Block.h:162
Operation & back()
Definition Block.h:177
iterator end()
Definition Block.h:169
iterator begin()
Definition Block.h:168
This class is a general helper class for creating context-global objects like types,...
Definition Builders.h:51
Dialects are groups of MLIR operations, types and attributes, as well as behavior associated with the...
Definition Dialect.h:38
ImplicitLocOpBuilder maintains a 'current location', allowing use of the create<> method without spec...
Definition Builders.h:632
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...
Definition Location.h:76
MLIRContext is the top-level object for a collection of MLIR operations.
Definition MLIRContext.h:71
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.
Definition Builders.h:210
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...
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.
LLVM_DUMP_METHOD void dump()
Dump this operation.
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 LogicalResult verifyTrait(Operation *op)
Similar to AttrSizedOperandSegments but used for results.
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...(AncestorOpTypes)==1, AncestorOpType > getAncestorOp()
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 &region, OpBuilder &builder, Location loc)
static void ensureTerminator(Region &region, 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.
This trait marks operations that are allowed to consume builtin token values.
This trait marks operations that are allowed to produce builtin token values.
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.
Op(std::nullptr_t)
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.
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< void(const OperationName &, NamedAttrList &) const > PopulateDefaultAttrsFn
TypeID getTypeID() const
Return the unique identifier of the derived Op class, or null if not registered.
Operation is the basic unit of execution within MLIR.
Definition Operation.h:87
PropertyRef getPropertiesStorage()
Return a generic (but typed) reference to the property type storage.
Definition Operation.h:955
ResultRange result_range
Support result iteration.
Definition Operation.h:437
Region & getRegion(unsigned index)
Returns the region held by this operation at position 'index'.
Definition Operation.h:740
Value getOperand(unsigned idx)
Definition Operation.h:377
bool hasTrait()
Returns true if the operation was registered with a particular trait, e.g.
Definition Operation.h:803
operand_range::type_range operand_type_range
Definition Operation.h:421
void setOperand(unsigned idx, Value value)
Definition Operation.h:378
unsigned getNumSuccessors()
Definition Operation.h:760
result_iterator result_begin()
Definition Operation.h:440
result_range::iterator result_iterator
Definition Operation.h:438
operand_iterator operand_begin()
Definition Operation.h:401
OpResult getResult(unsigned idx)
Get the 'idx'th result of this operation.
Definition Operation.h:434
operand_range::type_iterator operand_type_iterator
Definition Operation.h:420
operand_type_iterator operand_type_end()
Definition Operation.h:423
result_range::type_range result_type_range
Definition Operation.h:452
unsigned getNumRegions()
Returns the number of regions held by this operation.
Definition Operation.h:728
Operation * getParentOp()
Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...
Definition Operation.h:251
std::optional< RegisteredOperationName > getRegisteredInfo()
If this operation has a registered operation description, return it.
Definition Operation.h:119
unsigned getNumOperands()
Definition Operation.h:373
result_type_iterator result_type_end()
Definition Operation.h:454
OperandRange operand_range
Definition Operation.h:398
OpTy getParentOfType()
Return the closest surrounding parent operation that is of type 'OpTy'.
Definition Operation.h:255
result_range::type_iterator result_type_iterator
Support result type iteration.
Definition Operation.h:451
operand_iterator operand_end()
Definition Operation.h:402
result_type_iterator result_type_begin()
Definition Operation.h:453
OperationName getName()
The name of an operation is the key identifier for it.
Definition Operation.h:115
void print(raw_ostream &os, const OpPrintingFlags &flags={})
operand_type_range getOperandTypes()
Definition Operation.h:424
MutableArrayRef< Region > getRegions()
Returns the regions held by this operation.
Definition Operation.h:731
result_iterator result_end()
Definition Operation.h:441
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.
Definition Operation.cpp:65
result_type_range getResultTypes()
Definition Operation.h:455
operand_range getOperands()
Returns an iterator on the underlying Value's.
Definition Operation.h:405
void setSuccessor(Block *block, unsigned index)
void replaceAllUsesWith(ValuesT &&values)
Replace all uses of results of this operation with the provided 'values'.
Definition Operation.h:297
Block * getSuccessor(unsigned index)
Definition Operation.h:762
SuccessorRange getSuccessors()
Definition Operation.h:757
result_range getResults()
Definition Operation.h:442
SuccessorRange::iterator succ_iterator
Definition Operation.h:754
MLIRContext * getContext()
Return the context this operation is associated with.
Definition Operation.h:233
operand_range::iterator operand_iterator
Definition Operation.h:399
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.
Definition Operation.h:431
operand_type_iterator operand_type_begin()
Definition Operation.h:422
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.
Definition Region.h:363
This class contains a list of basic blocks and a link to the parent operation it is attached to.
Definition Region.h:26
Block & front()
Definition Region.h:65
iterator_range< OpIterator > getOps()
Definition Region.h:180
bool empty()
Definition Region.h:60
bool hasOneBlock()
Return true if this region has exactly one block.
Definition Region.h:68
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.
Definition TypeID.h:107
static TypeID get()
Construct a type info object for the given type T.
Definition TypeID.h:245
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition Types.h:74
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition Value.h:96
Type getType() const
Return the type of this value.
Definition Value.h:105
void replaceAllUsesWith(Value newValue)
Replace all uses of 'this' value with the new value, updating anything in the IR that uses 'this' to ...
Definition Value.h:149
This class represents an abstract interface.
Interface< ConcreteType, Operation *, Traits, Op< ConcreteType >, OpTrait::TraitBase > InterfaceBase
The OpAsmOpInterface, see OpAsmInterface.td for more details.
Definition CallGraph.h:229
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.
AttrTypeReplacer.
decltype(walk(nullptr, std::declval< FnT >())) walkResultType
Utility to provide the return type of a templated walk method.
Definition Visitors.h:433
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...
Definition Dialect.cpp:150
void ensureRegionTerminator(Region &region, 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.
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.
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.
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.
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 verifyTrait(Operation *op)
Verify the given trait if it provides a verifier.
detail::InFlightRemark failed(Location loc, RemarkOpts opts)
Report an optimization remark that failed.
Definition Remarks.h:853
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.
Definition Visitors.h:28
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.
Definition Value.h:496
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
Definition LLVM.h:155
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 an ancestor (anywhere up the parent chain) ...
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_iterator operand_type_begin()
Operand type access.
Operation::operand_type_range operand_type_range
unsigned getNumOperands()
Return the number of operands.
operand_iterator operand_begin()
Operand iterator access.
void setOperand(unsigned i, Value value)
Set the operand at index 'i' to 'value'.
Operation::operand_iterator operand_iterator
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 & 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_begin()
Result type access.
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.
Type getType(unsigned i)
Return the type of the i-th result.
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.
Block * getSuccessor(unsigned i)
Return the successor at index.
Support to check if an operation has the SingleBlockImplicitTerminator trait.
This represents an operation in an abstracted form, suitable for use with the builder APIs.
Traits to detect whether an Operation defined a Properties type, otherwise it'll default to EmptyProp...