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