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