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