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 trait marks operations that are allowed to produce builtin token
782/// values.
783template <typename ConcreteType>
784class TokenProducerTrait : public TraitBase<ConcreteType, TokenProducerTrait> {
785};
786
787/// This trait marks operations that are allowed to consume builtin token
788/// values.
789template <typename ConcreteType>
790class TokenConsumerTrait : public TraitBase<ConcreteType, TokenConsumerTrait> {
791};
792
793/// This class provides verification for ops that are known to have zero
794/// successors.
795template <typename ConcreteType>
796class ZeroSuccessors : public TraitBase<ConcreteType, ZeroSuccessors> {
797public:
798 static LogicalResult verifyTrait(Operation *op) {
800 }
801};
802
803namespace detail {
804/// Utility trait base that provides accessors for derived traits that have
805/// multiple successors.
806template <typename ConcreteType, template <typename> class TraitType>
807struct MultiSuccessorTraitBase : public TraitBase<ConcreteType, TraitType> {
810
811 /// Return the number of successors.
812 unsigned getNumSuccessors() {
813 return this->getOperation()->getNumSuccessors();
814 }
815
816 /// Return the successor at `index`.
817 Block *getSuccessor(unsigned i) {
818 return this->getOperation()->getSuccessor(i);
819 }
820
821 /// Set the successor at `index`.
822 void setSuccessor(Block *block, unsigned i) {
823 return this->getOperation()->setSuccessor(block, i);
824 }
825
826 /// Successor iterator access.
827 succ_iterator succ_begin() { return this->getOperation()->succ_begin(); }
828 succ_iterator succ_end() { return this->getOperation()->succ_end(); }
830};
831} // namespace detail
832
833/// This class provides APIs for ops that are known to have a single successor.
834template <typename ConcreteType>
835class OneSuccessor : public TraitBase<ConcreteType, OneSuccessor> {
836public:
837 Block *getSuccessor() { return this->getOperation()->getSuccessor(0); }
838 void setSuccessor(Block *succ) {
839 this->getOperation()->setSuccessor(succ, 0);
840 }
841
842 static LogicalResult verifyTrait(Operation *op) {
843 return impl::verifyOneSuccessor(op);
844 }
845};
846
847/// This class provides the API for ops that are known to have a specified
848/// number of successors.
849template <unsigned N>
851public:
852 static_assert(N > 1, "use ZeroSuccessors/OneSuccessor for N < 2");
853
854 template <typename ConcreteType>
855 class Impl : public detail::MultiSuccessorTraitBase<ConcreteType,
856 NSuccessors<N>::Impl> {
857 public:
858 static LogicalResult verifyTrait(Operation *op) {
859 return impl::verifyNSuccessors(op, N);
860 }
861 };
862};
863
864/// This class provides APIs for ops that are known to have at least a specified
865/// number of successors.
866template <unsigned N>
868public:
869 template <typename ConcreteType>
870 class Impl
871 : public detail::MultiSuccessorTraitBase<ConcreteType,
872 AtLeastNSuccessors<N>::Impl> {
873 public:
874 static LogicalResult verifyTrait(Operation *op) {
875 return impl::verifyAtLeastNSuccessors(op, N);
876 }
877 };
878};
879
880/// This class provides the API for ops which have an unknown number of
881/// successors.
882template <typename ConcreteType>
884 : public detail::MultiSuccessorTraitBase<ConcreteType, VariadicSuccessors> {
885};
886
887//===----------------------------------------------------------------------===//
888// SingleBlock
889//===----------------------------------------------------------------------===//
890
891/// This class provides APIs and verifiers for ops with regions having a single
892/// block.
893template <typename ConcreteType>
894struct SingleBlock : public TraitBase<ConcreteType, SingleBlock> {
895public:
896 static LogicalResult verifyTrait(Operation *op) {
897 for (unsigned i = 0, e = op->getNumRegions(); i < e; ++i) {
898 Region &region = op->getRegion(i);
899
900 // Empty regions are fine.
901 if (region.empty())
902 continue;
903
904 // Non-empty regions must contain a single basic block.
905 if (!region.hasOneBlock())
906 return op->emitOpError("expects region #")
907 << i << " to have 0 or 1 blocks";
908
909 if (!ConcreteType::template hasTrait<NoTerminator>()) {
910 Block &block = region.front();
911 if (block.empty())
912 return op->emitOpError() << "expects a non-empty block";
913 }
914 }
915 return success();
916 }
917
918 Block *getBody(unsigned idx = 0) {
919 Region &region = this->getOperation()->getRegion(idx);
920 assert(!region.empty() && "unexpected empty region");
921 return &region.front();
922 }
923 Region &getBodyRegion(unsigned idx = 0) {
924 return this->getOperation()->getRegion(idx);
925 }
926
927 //===------------------------------------------------------------------===//
928 // Single Region Utilities
929 //===------------------------------------------------------------------===//
930
931 /// The following are a set of methods only enabled when the parent
932 /// operation has a single region. Each of these methods take an additional
933 /// template parameter that represents the concrete operation so that we
934 /// can use SFINAE to disable the methods for non-single region operations.
935 template <typename OpT, typename T = void>
937 std::enable_if_t<OpT::template hasTrait<OneRegion>(), T>;
938
939 template <typename OpT = ConcreteType>
943 template <typename OpT = ConcreteType>
947 template <typename OpT = ConcreteType>
951
952 /// Insert the operation into the back of the body.
953 template <typename OpT = ConcreteType>
957
958 /// Insert the operation at the given insertion point.
959 template <typename OpT = ConcreteType>
963 template <typename OpT = ConcreteType>
965 getBody()->getOperations().insert(insertPt, op);
966 }
967};
968
969//===----------------------------------------------------------------------===//
970// SingleBlockImplicitTerminator
971//===----------------------------------------------------------------------===//
972
973/// This class provides APIs and verifiers for ops with regions having a single
974/// block that must terminate with `TerminatorOpType`.
975template <typename TerminatorOpType>
977 template <typename ConcreteType>
978 class Impl : public TraitBase<ConcreteType, SingleBlockImplicitTerminator<
979 TerminatorOpType>::Impl> {
980 private:
981 /// Builds a terminator operation without relying on OpBuilder APIs to avoid
982 /// cyclic header inclusion.
983 static Operation *buildTerminator(OpBuilder &builder, Location loc) {
984 OperationState state(loc, TerminatorOpType::getOperationName());
985 TerminatorOpType::build(builder, state);
986 return Operation::create(state);
987 }
988
989 public:
990 /// The type of the operation used as the implicit terminator type.
991 using ImplicitTerminatorOpT = TerminatorOpType;
992
993 static LogicalResult verifyRegionTrait(Operation *op) {
994 for (unsigned i = 0, e = op->getNumRegions(); i < e; ++i) {
995 Region &region = op->getRegion(i);
996 // Empty regions are fine.
997 if (region.empty())
998 continue;
999 Operation &terminator = region.front().back();
1000 if (isa<TerminatorOpType>(terminator))
1001 continue;
1002
1003 return op->emitOpError("expects regions to end with '" +
1004 TerminatorOpType::getOperationName() +
1005 "', found '" +
1006 terminator.getName().getStringRef() + "'")
1007 .attachNote()
1008 << "in custom textual format, the absence of terminator implies "
1009 "'"
1010 << TerminatorOpType::getOperationName() << '\'';
1011 }
1012
1013 return success();
1014 }
1015
1016 /// Ensure that the given region has the terminator required by this trait.
1017 /// If OpBuilder is provided, use it to build the terminator and notify the
1018 /// OpBuilder listeners accordingly. If only a Builder is provided, locally
1019 /// construct an OpBuilder with no listeners; this should only be used if no
1020 /// OpBuilder is available at the call site, e.g., in the parser.
1021 static void ensureTerminator(Region &region, Builder &builder,
1022 Location loc) {
1023 ::mlir::impl::ensureRegionTerminator(region, builder, loc,
1024 buildTerminator);
1025 }
1026 static void ensureTerminator(Region &region, OpBuilder &builder,
1027 Location loc) {
1028 ::mlir::impl::ensureRegionTerminator(region, builder, loc,
1029 buildTerminator);
1030 }
1031 };
1032};
1033
1034/// Check is an op defines the `ImplicitTerminatorOpT` member. This is intended
1035/// to be used with `llvm::is_detected`.
1036template <class T>
1037using has_implicit_terminator_t = typename T::ImplicitTerminatorOpT;
1038
1039/// Support to check if an operation has the SingleBlockImplicitTerminator
1040/// trait. We can't just use `hasTrait` because this class is templated on a
1041/// specific terminator op.
1042template <class Op, bool hasTerminator =
1043 llvm::is_detected<has_implicit_terminator_t, Op>::value>
1045 static constexpr bool value = std::is_base_of<
1047 typename Op::ImplicitTerminatorOpT>::template Impl<Op>,
1048 Op>::value;
1049};
1050template <class Op>
1052 static constexpr bool value = false;
1053};
1054
1055//===----------------------------------------------------------------------===//
1056// Misc Traits
1057//===----------------------------------------------------------------------===//
1058
1059/// This class provides verification for ops that are known to have the same
1060/// operand shape: all operands are scalars, vectors/tensors of the same
1061/// shape.
1062template <typename ConcreteType>
1063class SameOperandsShape : public TraitBase<ConcreteType, SameOperandsShape> {
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 and result shape: both are scalars, vectors/tensors of the same
1072/// shape.
1073template <typename ConcreteType>
1075 : public TraitBase<ConcreteType, SameOperandsAndResultShape> {
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 element type (or the type itself if it is scalar).
1084///
1085template <typename ConcreteType>
1087 : public TraitBase<ConcreteType, SameOperandsElementType> {
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 element type (or the type itself if it is scalar).
1096///
1097template <typename ConcreteType>
1099 : public TraitBase<ConcreteType, SameOperandsAndResultElementType> {
1100public:
1101 static LogicalResult verifyTrait(Operation *op) {
1103 }
1104};
1105
1106/// This class provides verification for ops that are known to have the same
1107/// operand and result type.
1108///
1109/// Note: this trait subsumes the SameOperandsAndResultShape and
1110/// SameOperandsAndResultElementType traits.
1111template <typename ConcreteType>
1113 : public TraitBase<ConcreteType, SameOperandsAndResultType> {
1114public:
1115 static LogicalResult verifyTrait(Operation *op) {
1117 }
1118};
1119
1120/// This class verifies that op has same ranks for all
1121/// operands and results types, if known.
1122template <typename ConcreteType>
1124 : public TraitBase<ConcreteType, SameOperandsAndResultRank> {
1125public:
1126 static LogicalResult verifyTrait(Operation *op) {
1128 }
1129};
1130
1131/// This class verifies that any results of the specified op have a boolean
1132/// type, a vector thereof, or a tensor thereof.
1133template <typename ConcreteType>
1134class ResultsAreBoolLike : public TraitBase<ConcreteType, ResultsAreBoolLike> {
1135public:
1136 static LogicalResult verifyTrait(Operation *op) {
1138 }
1139};
1140
1141/// This class verifies that any results of the specified op have a floating
1142/// point type, a vector thereof, or a tensor thereof.
1143template <typename ConcreteType>
1145 : public TraitBase<ConcreteType, ResultsAreFloatLike> {
1146public:
1147 static LogicalResult verifyTrait(Operation *op) {
1149 }
1150};
1151
1152/// This class verifies that any results of the specified op have a signless
1153/// integer or index type, a vector thereof, or a tensor thereof.
1154template <typename ConcreteType>
1156 : public TraitBase<ConcreteType, ResultsAreSignlessIntegerLike> {
1157public:
1158 static LogicalResult verifyTrait(Operation *op) {
1160 }
1161};
1162
1163/// This class adds property that the operation is commutative.
1164template <typename ConcreteType>
1165class IsCommutative : public TraitBase<ConcreteType, IsCommutative> {
1166public:
1167 static LogicalResult foldTrait(Operation *op, ArrayRef<Attribute> operands,
1169 return impl::foldCommutative(op, operands, results);
1170 }
1171};
1172
1173/// This class adds property that the operation is an involution.
1174/// This means a unary to unary operation "f" that satisfies f(f(x)) = x
1175template <typename ConcreteType>
1176class IsInvolution : public TraitBase<ConcreteType, IsInvolution> {
1177public:
1178 static LogicalResult verifyTrait(Operation *op) {
1179 static_assert(ConcreteType::template hasTrait<OneResult>(),
1180 "expected operation to produce one result");
1181 static_assert(ConcreteType::template hasTrait<OneOperand>(),
1182 "expected operation to take one operand");
1183 static_assert(ConcreteType::template hasTrait<SameOperandsAndResultType>(),
1184 "expected operation to preserve type");
1185 // Involution requires the operation to be side effect free as well
1186 // but currently this check is under a FIXME and is not actually done.
1187 return impl::verifyIsInvolution(op);
1188 }
1189
1191 return impl::foldInvolution(op);
1192 }
1193};
1194
1195/// This class adds property that the operation is idempotent.
1196/// This means a unary to unary operation "f" that satisfies f(f(x)) = f(x),
1197/// or a binary operation "g" that satisfies g(x, x) = x.
1198template <typename ConcreteType>
1199class IsIdempotent : public TraitBase<ConcreteType, IsIdempotent> {
1200public:
1201 static LogicalResult verifyTrait(Operation *op) {
1202 static_assert(ConcreteType::template hasTrait<OneResult>(),
1203 "expected operation to produce one result");
1204 static_assert(ConcreteType::template hasTrait<OneOperand>() ||
1205 ConcreteType::template hasTrait<NOperands<2>::Impl>(),
1206 "expected operation to take one or two operands");
1207 static_assert(ConcreteType::template hasTrait<SameOperandsAndResultType>(),
1208 "expected operation to preserve type");
1209 // Idempotent requires the operation to be side effect free as well
1210 // but currently this check is under a FIXME and is not actually done.
1211 return impl::verifyIsIdempotent(op);
1212 }
1213
1215 return impl::foldIdempotent(op);
1216 }
1217};
1218
1219/// This class verifies that all operands of the specified op have a float type,
1220/// a vector thereof, or a tensor thereof.
1221template <typename ConcreteType>
1223 : public TraitBase<ConcreteType, OperandsAreFloatLike> {
1224public:
1225 static LogicalResult verifyTrait(Operation *op) {
1227 }
1228};
1229
1230/// This class verifies that all operands of the specified op have a signless
1231/// integer or index type, a vector thereof, or a tensor thereof.
1232template <typename ConcreteType>
1234 : public TraitBase<ConcreteType, OperandsAreSignlessIntegerLike> {
1235public:
1236 static LogicalResult verifyTrait(Operation *op) {
1238 }
1239};
1240
1241/// This class verifies that all operands of the specified op have the same
1242/// type.
1243template <typename ConcreteType>
1244class SameTypeOperands : public TraitBase<ConcreteType, SameTypeOperands> {
1245public:
1246 static LogicalResult verifyTrait(Operation *op) {
1248 }
1249};
1250
1251/// This class provides the API for a sub-set of ops that are known to be
1252/// constant-like. These are non-side effecting operations with one result and
1253/// zero operands that can always be folded to a specific attribute value.
1254template <typename ConcreteType>
1255class ConstantLike : public TraitBase<ConcreteType, ConstantLike> {
1256public:
1257 static LogicalResult verifyTrait(Operation *op) {
1258 static_assert(ConcreteType::template hasTrait<OneResult>(),
1259 "expected operation to produce one result");
1260 static_assert(ConcreteType::template hasTrait<ZeroOperands>(),
1261 "expected operation to take zero operands");
1262 // TODO: We should verify that the operation can always be folded, but this
1263 // requires that the attributes of the op already be verified. We should add
1264 // support for verifying traits "after" the operation to enable this use
1265 // case.
1266 return success();
1267 }
1268};
1269
1270/// This class provides the API for ops that are known to be isolated from
1271/// above.
1272template <typename ConcreteType>
1274 : public TraitBase<ConcreteType, IsIsolatedFromAbove> {
1275public:
1276 static LogicalResult verifyRegionTrait(Operation *op) {
1278 }
1279};
1280
1281/// A trait of region holding operations that defines a new scope for polyhedral
1282/// optimization purposes. Any SSA values of 'index' type that either dominate
1283/// such an operation or are used at the top-level of such an operation
1284/// automatically become valid symbols for the polyhedral scope defined by that
1285/// operation. For more details, see `Traits.md#AffineScope`.
1286template <typename ConcreteType>
1287class AffineScope : public TraitBase<ConcreteType, AffineScope> {
1288public:
1289 static LogicalResult verifyTrait(Operation *op) {
1290 static_assert(!ConcreteType::template hasTrait<ZeroRegions>(),
1291 "expected operation to have one or more regions");
1292 return success();
1293 }
1294};
1295
1296/// A trait of region holding operations that define a new scope for automatic
1297/// allocations, i.e., allocations that are freed when control is transferred
1298/// back from the operation's region. Any operations performing such allocations
1299/// (for eg. memref.alloca) will have their allocations automatically freed at
1300/// their closest enclosing operation with this trait.
1301template <typename ConcreteType>
1303 : public TraitBase<ConcreteType, AutomaticAllocationScope> {
1304public:
1305 static LogicalResult verifyTrait(Operation *op) {
1306 static_assert(!ConcreteType::template hasTrait<ZeroRegions>(),
1307 "expected operation to have one or more regions");
1308 return success();
1309 }
1310};
1311
1312/// This class provides a verifier for ops that are expecting their parent
1313/// to be one of the given parent ops
1314template <typename... ParentOpTypes>
1316 template <typename ConcreteType>
1317 class Impl : public TraitBase<ConcreteType, Impl> {
1318 public:
1319 static LogicalResult verifyTrait(Operation *op) {
1320 if (llvm::isa_and_nonnull<ParentOpTypes...>(op->getParentOp()))
1321 return success();
1322
1323 return op->emitOpError()
1324 << "expects parent op "
1325 << (sizeof...(ParentOpTypes) != 1 ? "to be one of '" : "'")
1326 << llvm::ArrayRef({ParentOpTypes::getOperationName()...}) << "'";
1327 }
1328
1329 template <typename ParentOpType =
1330 std::tuple_element_t<0, std::tuple<ParentOpTypes...>>>
1331 std::enable_if_t<sizeof...(ParentOpTypes) == 1, ParentOpType>
1333 Operation *parent = this->getOperation()->getParentOp();
1334 return llvm::cast<ParentOpType>(parent);
1335 }
1336 };
1337};
1338
1339/// This class provides a verifier for ops that are expecting an ancestor
1340/// (anywhere up the parent chain) to be one of the given op types.
1341template <typename... AncestorOpTypes>
1343 template <typename ConcreteType>
1344 class Impl : public TraitBase<ConcreteType, Impl> {
1345 public:
1346 static LogicalResult verifyTrait(Operation *op) {
1347 if (op->getParentOfType<AncestorOpTypes...>())
1348 return success();
1349
1350 return op->emitOpError()
1351 << "expects ancestor op "
1352 << (sizeof...(AncestorOpTypes) != 1 ? "to be one of '" : "'")
1353 << llvm::ArrayRef({AncestorOpTypes::getOperationName()...}) << "'";
1354 }
1355
1356 template <typename AncestorOpType =
1357 std::tuple_element_t<0, std::tuple<AncestorOpTypes...>>>
1358 std::enable_if_t<sizeof...(AncestorOpTypes) == 1, AncestorOpType>
1360 return this->getOperation()->template getParentOfType<AncestorOpType>();
1361 }
1362 };
1363};
1364
1365/// A trait for operations that have an attribute specifying operand segments.
1366///
1367/// Certain operations can have multiple variadic operands and their size
1368/// relationship is not always known statically. For such cases, we need
1369/// a per-op-instance specification to divide the operands into logical groups
1370/// or segments. This can be modeled by attributes. The attribute will be named
1371/// as `operandSegmentSizes`.
1372///
1373/// This trait verifies the attribute for specifying operand segments has
1374/// the correct type (1D vector) and values (non-negative), etc.
1375template <typename ConcreteType>
1378public:
1379 static StringRef getOperandSegmentSizeAttr() { return "operandSegmentSizes"; }
1380
1381 static LogicalResult verifyTrait(Operation *op) {
1382 return ::mlir::OpTrait::impl::verifyOperandSizeAttr(
1384 }
1385};
1386
1387/// Similar to AttrSizedOperandSegments but used for results.
1388template <typename ConcreteType>
1391public:
1392 static StringRef getResultSegmentSizeAttr() { return "resultSegmentSizes"; }
1393
1394 static LogicalResult verifyTrait(Operation *op) {
1395 return ::mlir::OpTrait::impl::verifyResultSizeAttr(
1397 }
1398};
1399
1400/// This trait provides a verifier for ops that are expecting their regions to
1401/// not have any arguments
1402template <typename ConcrentType>
1404 static LogicalResult verifyTrait(Operation *op) {
1405 return ::mlir::OpTrait::impl::verifyNoRegionArguments(op);
1406 }
1407};
1408
1409// This trait is used to flag operations that consume or produce
1410// values of `MemRef` type where those references can be 'normalized'.
1411// TODO: Right now, the operands of an operation are either all normalizable,
1412// or not. In the future, we may want to allow some of the operands to be
1413// normalizable.
1414template <typename ConcrentType>
1417
1418/// This trait tags element-wise ops on vectors or tensors.
1419///
1420/// NOTE: Not all ops that are "elementwise" in some abstract sense satisfy this
1421/// trait. In particular, broadcasting behavior is not allowed.
1422///
1423/// An `Elementwise` op must satisfy the following properties:
1424///
1425/// 1. If any result is a vector/tensor then at least one operand must also be a
1426/// vector/tensor.
1427/// 2. If any operand is a vector/tensor then there must be at least one result
1428/// and all results must be vectors/tensors.
1429/// 3. All operand and result vector/tensor types must be of the same shape. The
1430/// shape may be dynamic in which case the op's behaviour is undefined for
1431/// non-matching shapes.
1432/// 4. The operation must be elementwise on its vector/tensor operands and
1433/// results. When applied to single-element vectors/tensors, the result must
1434/// be the same per elememnt.
1435///
1436/// TODO: Avoid hardcoding vector/tensor, and generalize this trait to a new
1437/// interface `ElementwiseTypeInterface` that describes the container types for
1438/// which the operation is elementwise.
1439///
1440/// Rationale:
1441/// - 1. and 2. guarantee a well-defined iteration space and exclude the cases
1442/// of 0 non-scalar operands or 0 non-scalar results, which complicate a
1443/// generic definition of the iteration space.
1444/// - 3. guarantees that folding can be done across scalars/vectors/tensors with
1445/// the same pattern, as otherwise lots of special handling for type
1446/// mismatches would be needed.
1447/// - 4. guarantees that no error handling is needed. Higher-level dialects
1448/// should reify any needed guards or error handling code before lowering to
1449/// an `Elementwise` op.
1450template <typename ConcreteType>
1452 static LogicalResult verifyTrait(Operation *op) {
1453 return ::mlir::OpTrait::impl::verifyElementwise(op);
1454 }
1455};
1456
1457/// This trait tags `Elementwise` operatons that can be systematically
1458/// scalarized. All vector/tensor operands and results are then replaced by
1459/// scalars of the respective element type. Semantically, this is the operation
1460/// on a single element of the vector/tensor.
1461///
1462/// Rationale:
1463/// Allow to define the vector/tensor semantics of elementwise operations based
1464/// on the same op's behavior on scalars. This provides a constructive procedure
1465/// for IR transformations to, e.g., create scalar loop bodies from tensor ops.
1466///
1467/// Example:
1468/// ```
1469/// %tensor_select = "arith.select"(%pred_tensor, %true_val, %false_val)
1470/// : (tensor<?xi1>, tensor<?xf32>, tensor<?xf32>)
1471/// -> tensor<?xf32>
1472/// ```
1473/// can be scalarized to
1474///
1475/// ```
1476/// %scalar_select = "arith.select"(%pred, %true_val_scalar, %false_val_scalar)
1477/// : (i1, f32, f32) -> f32
1478/// ```
1479template <typename ConcreteType>
1481 static LogicalResult verifyTrait(Operation *op) {
1482 static_assert(
1483 ConcreteType::template hasTrait<Elementwise>(),
1484 "`Scalarizable` trait is only applicable to `Elementwise` ops.");
1485 return success();
1486 }
1487};
1488
1489/// This trait tags `Elementwise` operatons that can be systematically
1490/// vectorized. All scalar operands and results are then replaced by vectors
1491/// with the respective element type. Semantically, this is the operation on
1492/// multiple elements simultaneously. See also `Tensorizable`.
1493///
1494/// Rationale:
1495/// Provide the reverse to `Scalarizable` which, when chained together, allows
1496/// reasoning about the relationship between the tensor and vector case.
1497/// Additionally, it permits reasoning about promoting scalars to vectors via
1498/// broadcasting in cases like `%select_scalar_pred` below.
1499template <typename ConcreteType>
1501 static LogicalResult verifyTrait(Operation *op) {
1502 static_assert(
1503 ConcreteType::template hasTrait<Elementwise>(),
1504 "`Vectorizable` trait is only applicable to `Elementwise` ops.");
1505 return success();
1506 }
1507};
1508
1509/// This trait tags `Elementwise` operatons that can be systematically
1510/// tensorized. All scalar operands and results are then replaced by tensors
1511/// with the respective element type. Semantically, this is the operation on
1512/// multiple elements simultaneously. See also `Vectorizable`.
1513///
1514/// Rationale:
1515/// Provide the reverse to `Scalarizable` which, when chained together, allows
1516/// reasoning about the relationship between the tensor and vector case.
1517/// Additionally, it permits reasoning about promoting scalars to tensors via
1518/// broadcasting in cases like `%select_scalar_pred` below.
1519///
1520/// Examples:
1521/// ```
1522/// %scalar = "arith.addf"(%a, %b) : (f32, f32) -> f32
1523/// ```
1524/// can be tensorized to
1525/// ```
1526/// %tensor = "arith.addf"(%a, %b) : (tensor<?xf32>, tensor<?xf32>)
1527/// -> tensor<?xf32>
1528/// ```
1529///
1530/// ```
1531/// %scalar_pred = "arith.select"(%pred, %true_val, %false_val)
1532/// : (i1, tensor<?xf32>, tensor<?xf32>) -> tensor<?xf32>
1533/// ```
1534/// can be tensorized to
1535/// ```
1536/// %tensor_pred = "arith.select"(%pred, %true_val, %false_val)
1537/// : (tensor<?xi1>, tensor<?xf32>, tensor<?xf32>)
1538/// -> tensor<?xf32>
1539/// ```
1540template <typename ConcreteType>
1542 static LogicalResult verifyTrait(Operation *op) {
1543 static_assert(
1544 ConcreteType::template hasTrait<Elementwise>(),
1545 "`Tensorizable` trait is only applicable to `Elementwise` ops.");
1546 return success();
1547 }
1548};
1549
1550/// Together, `Elementwise`, `Scalarizable`, `Vectorizable`, and `Tensorizable`
1551/// provide an easy way for scalar operations to conveniently generalize their
1552/// behavior to vectors/tensors, and systematize conversion between these forms.
1554
1555} // namespace OpTrait
1556
1557//===----------------------------------------------------------------------===//
1558// Internal Trait Utilities
1559//===----------------------------------------------------------------------===//
1560
1562//===----------------------------------------------------------------------===//
1563// Trait Existence
1564//===----------------------------------------------------------------------===//
1565
1566/// Returns true if this given Trait ID matches the IDs of any of the provided
1567/// trait types `Traits`.
1568template <template <typename T> class... Traits>
1569inline bool hasTrait(TypeID traitID) {
1570 TypeID traitIDs[] = {TypeID::get<Traits>()...};
1571 for (unsigned i = 0, e = sizeof...(Traits); i != e; ++i)
1572 if (traitIDs[i] == traitID)
1573 return true;
1574 return false;
1575}
1576template <>
1577inline bool hasTrait<>(TypeID traitID) {
1578 return false;
1579}
1580
1581//===----------------------------------------------------------------------===//
1582// Trait Folding
1583//===----------------------------------------------------------------------===//
1584
1585/// Trait to check if T provides a 'foldTrait' method for single result
1586/// operations.
1587template <typename T, typename... Args>
1588using has_single_result_fold_trait = decltype(T::foldTrait(
1589 std::declval<Operation *>(), std::declval<ArrayRef<Attribute>>()));
1590template <typename T>
1592 llvm::is_detected<has_single_result_fold_trait, T>;
1593/// Trait to check if T provides a general 'foldTrait' method.
1594template <typename T, typename... Args>
1596 decltype(T::foldTrait(std::declval<Operation *>(),
1597 std::declval<ArrayRef<Attribute>>(),
1598 std::declval<SmallVectorImpl<OpFoldResult> &>()));
1599template <typename T>
1600using detect_has_fold_trait = llvm::is_detected<has_fold_trait, T>;
1601/// Trait to check if T provides any `foldTrait` method.
1602template <typename T>
1604 std::disjunction<detect_has_fold_trait<T>,
1606
1607/// Returns the result of folding a trait that implements a `foldTrait` function
1608/// that is specialized for operations that have a single result.
1609template <typename Trait>
1610static std::enable_if_t<detect_has_single_result_fold_trait<Trait>::value,
1611 LogicalResult>
1614 assert(op->hasTrait<OpTrait::OneResult>() &&
1615 "expected trait on non single-result operation to implement the "
1616 "general `foldTrait` method");
1617 // If a previous trait has already been folded and replaced this operation, we
1618 // fail to fold this trait.
1619 if (!results.empty())
1620 return failure();
1621
1622 if (OpFoldResult result = Trait::foldTrait(op, operands)) {
1623 if (llvm::dyn_cast_if_present<Value>(result) != op->getResult(0))
1624 results.push_back(result);
1625 return success();
1626 }
1627 return failure();
1628}
1629/// Returns the result of folding a trait that implements a generalized
1630/// `foldTrait` function that is supports any operation type.
1631template <typename Trait>
1632static std::enable_if_t<detect_has_fold_trait<Trait>::value, LogicalResult>
1635 // If a previous trait has already been folded and replaced this operation, we
1636 // fail to fold this trait.
1637 return results.empty() ? Trait::foldTrait(op, operands, results) : failure();
1638}
1639template <typename Trait>
1640static inline std::enable_if_t<!detect_has_any_fold_trait<Trait>::value,
1641 LogicalResult>
1645
1646/// Given a tuple type containing a set of traits, return the result of folding
1647/// the given operation.
1648template <typename... Ts>
1649static LogicalResult foldTraits(Operation *op, ArrayRef<Attribute> operands,
1651 return success((succeeded(foldTrait<Ts>(op, operands, results)) || ...));
1652}
1653
1654//===----------------------------------------------------------------------===//
1655// Trait Verification
1656//===----------------------------------------------------------------------===//
1657
1658/// Trait to check if T provides a `verifyTrait` method.
1659template <typename T, typename... Args>
1660using has_verify_trait = decltype(T::verifyTrait(std::declval<Operation *>()));
1661template <typename T>
1662using detect_has_verify_trait = llvm::is_detected<has_verify_trait, T>;
1663
1664/// Trait to check if T provides a `verifyTrait` method.
1665template <typename T, typename... Args>
1667 decltype(T::verifyRegionTrait(std::declval<Operation *>()));
1668template <typename T>
1670 llvm::is_detected<has_verify_region_trait, T>;
1671
1672/// Verify the given trait if it provides a verifier.
1673template <typename T>
1674LogicalResult verifyTrait(Operation *op) {
1676 return T::verifyTrait(op);
1677 else
1678 return success();
1679}
1680
1681/// Given a set of traits, return the result of verifying the given operation.
1682template <typename... Ts>
1683LogicalResult verifyTraits(Operation *op) {
1684 return success((succeeded(verifyTrait<Ts>(op)) && ...));
1685}
1686
1687/// Verify the given trait if it provides a region verifier.
1688template <typename T>
1689LogicalResult verifyRegionTrait(Operation *op) {
1691 return T::verifyRegionTrait(op);
1692 else
1693 return success();
1694}
1695
1696/// Given a set of traits, return the result of verifying the regions of the
1697/// given operation.
1698template <typename... Ts>
1699LogicalResult verifyRegionTraits(Operation *op) {
1700 return success((succeeded(verifyRegionTrait<Ts>(op)) && ...));
1701}
1702} // namespace op_definition_impl
1703
1704//===----------------------------------------------------------------------===//
1705// Operation Definition classes
1706//===----------------------------------------------------------------------===//
1707
1708/// This provides public APIs that all operations should have. The template
1709/// argument 'ConcreteType' should be the concrete type by CRTP and the others
1710/// are base classes by the policy pattern.
1711template <typename ConcreteType, template <typename T> class... Traits>
1712class Op : public OpState, public Traits<ConcreteType>... {
1713public:
1714 /// Inherit getOperation from `OpState`.
1716 using OpState::verify;
1718
1719 /// Return if this operation contains the provided trait.
1720 template <template <typename T> class Trait>
1721 static constexpr bool hasTrait() {
1722 return llvm::is_one_of<Trait<ConcreteType>, Traits<ConcreteType>...>::value;
1723 }
1724
1725 /// Create a deep copy of this operation.
1726 ConcreteType clone() { return cast<ConcreteType>(getOperation()->clone()); }
1727
1728 /// Create a partial copy of this operation without traversing into attached
1729 /// regions. The new operation will have the same number of regions as the
1730 /// original one, but they will be left empty.
1731 ConcreteType cloneWithoutRegions() {
1732 return cast<ConcreteType>(getOperation()->cloneWithoutRegions());
1733 }
1734
1735 /// Return true if this "op class" can match against the specified operation.
1736 static bool classof(Operation *op) {
1737 if (auto info = op->getRegisteredInfo())
1738 return TypeID::get<ConcreteType>() == info->getTypeID();
1739#ifndef NDEBUG
1740 if (op->getName().getStringRef() == ConcreteType::getOperationName())
1741 llvm::report_fatal_error(
1742 "classof on '" + ConcreteType::getOperationName() +
1743 "' failed due to the operation not being registered");
1744#endif
1745 return false;
1746 }
1747 /// Provide `classof` support for other OpBase derived classes, such as
1748 /// Interfaces.
1749 template <typename T>
1750 static std::enable_if_t<std::is_base_of<OpState, T>::value, bool>
1751 classof(const T *op) {
1752 return classof(const_cast<T *>(op)->getOperation());
1753 }
1754
1755 /// Expose the type we are instantiated on to template machinery that may want
1756 /// to introspect traits on this operation.
1757 using ConcreteOpType = ConcreteType;
1758
1759 /// This is a public constructor. Any op can be initialized to null.
1760 explicit Op() : OpState(nullptr) {}
1761 Op(std::nullptr_t) : OpState(nullptr) {}
1762
1763 /// This is a public constructor to enable access via the llvm::cast family of
1764 /// methods. This should not be used directly.
1765 explicit Op(Operation *state) : OpState(state) {}
1766
1767 /// Methods for supporting PointerLikeTypeTraits.
1768 const void *getAsOpaquePointer() const {
1769 return static_cast<const void *>((Operation *)*this);
1770 }
1771 static ConcreteOpType getFromOpaquePointer(const void *pointer) {
1772 return ConcreteOpType(
1773 reinterpret_cast<Operation *>(const_cast<void *>(pointer)));
1774 }
1775
1776 /// Attach the given models as implementations of the corresponding
1777 /// interfaces for the concrete operation.
1778 template <typename... Models>
1779 static void attachInterface(MLIRContext &context) {
1780 std::optional<RegisteredOperationName> info =
1782 if (!info)
1783 llvm::report_fatal_error(
1784 "Attempting to attach an interface to an unregistered operation " +
1785 ConcreteType::getOperationName() + ".");
1786 (checkInterfaceTarget<Models>(), ...);
1787 info->attachInterface<Models...>();
1788 }
1789 /// Convert the provided attribute to a property and assigned it to the
1790 /// provided properties. This default implementation forwards to a free
1791 /// function `setPropertiesFromAttribute` that can be looked up with ADL in
1792 /// the namespace where the properties are defined. It can also be overridden
1793 /// in the derived ConcreteOp.
1794 template <typename PropertiesTy>
1795 static LogicalResult
1796 setPropertiesFromAttr(PropertiesTy &prop, Attribute attr,
1798 return setPropertiesFromAttribute(prop, attr, emitError);
1799 }
1800 /// Convert the provided properties to an attribute. This default
1801 /// implementation forwards to a free function `getPropertiesAsAttribute` that
1802 /// can be looked up with ADL in the namespace where the properties are
1803 /// defined. It can also be overridden in the derived ConcreteOp.
1804 template <typename PropertiesTy>
1806 const PropertiesTy &prop) {
1807 return getPropertiesAsAttribute(ctx, prop);
1808 }
1809 /// Hash the provided properties. This default implementation forwards to a
1810 /// free function `computeHash` that can be looked up with ADL in the
1811 /// namespace where the properties are defined. It can also be overridden in
1812 /// the derived ConcreteOp.
1813 template <typename PropertiesTy>
1814 static llvm::hash_code computePropertiesHash(const PropertiesTy &prop) {
1815 return computeHash(prop);
1816 }
1817
1818private:
1819 /// Trait to check if T provides a 'fold' method for a single result op.
1820 template <typename T, typename... Args>
1821 using has_single_result_fold_t =
1822 decltype(std::declval<T>().fold(std::declval<ArrayRef<Attribute>>()));
1823 template <typename T>
1824 constexpr static bool has_single_result_fold_v =
1825 llvm::is_detected<has_single_result_fold_t, T>::value;
1826 /// Trait to check if T provides a general 'fold' method.
1827 template <typename T, typename... Args>
1828 using has_fold_t = decltype(std::declval<T>().fold(
1829 std::declval<ArrayRef<Attribute>>(),
1830 std::declval<SmallVectorImpl<OpFoldResult> &>()));
1831 template <typename T>
1832 constexpr static bool has_fold_v = llvm::is_detected<has_fold_t, T>::value;
1833 /// Trait to check if T provides a 'fold' method with a FoldAdaptor for a
1834 /// single result op.
1835 template <typename T, typename... Args>
1836 using has_fold_adaptor_single_result_fold_t =
1837 decltype(std::declval<T>().fold(std::declval<typename T::FoldAdaptor>()));
1838 template <class T>
1839 constexpr static bool has_fold_adaptor_single_result_v =
1840 llvm::is_detected<has_fold_adaptor_single_result_fold_t, T>::value;
1841 /// Trait to check if T provides a general 'fold' method with a FoldAdaptor.
1842 template <typename T, typename... Args>
1843 using has_fold_adaptor_fold_t = decltype(std::declval<T>().fold(
1844 std::declval<typename T::FoldAdaptor>(),
1845 std::declval<SmallVectorImpl<OpFoldResult> &>()));
1846 template <class T>
1847 constexpr static bool has_fold_adaptor_v =
1848 llvm::is_detected<has_fold_adaptor_fold_t, T>::value;
1849
1850 /// Trait to check if T provides a 'print' method.
1851 template <typename T, typename... Args>
1852 using has_print =
1853 decltype(std::declval<T>().print(std::declval<OpAsmPrinter &>()));
1854 template <typename T>
1855 using detect_has_print = llvm::is_detected<has_print, T>;
1856
1857 /// Trait to check if printProperties(OpAsmPrinter, T, ArrayRef<StringRef>)
1858 /// exist
1859 template <typename T, typename... Args>
1860 using has_print_properties =
1861 decltype(printProperties(std::declval<OpAsmPrinter &>(),
1862 std::declval<T>(),
1863 std::declval<ArrayRef<StringRef>>()));
1864 template <typename T>
1865 using detect_has_print_properties =
1866 llvm::is_detected<has_print_properties, T>;
1867
1868 /// Trait to check if parseProperties(OpAsmParser, T) exist
1869 template <typename T, typename... Args>
1870 using has_parse_properties = decltype(parseProperties(
1871 std::declval<OpAsmParser &>(), std::declval<T &>()));
1872 template <typename T>
1873 using detect_has_parse_properties =
1874 llvm::is_detected<has_parse_properties, T>;
1875
1876 /// Trait to check if T provides a 'ConcreteEntity' type alias.
1877 template <typename T>
1878 using has_concrete_entity_t = typename T::ConcreteEntity;
1879
1880public:
1881 /// Returns true if this operation defines a `Properties` inner type.
1882 static constexpr bool hasProperties() {
1883 return !std::is_same_v<
1884 typename ConcreteType::template InferredProperties<ConcreteType>,
1886 }
1887
1888private:
1889 /// A struct-wrapped type alias to T::ConcreteEntity if provided and to
1890 /// ConcreteType otherwise. This is akin to std::conditional but doesn't fail
1891 /// on the missing typedef. Useful for checking if the interface is targeting
1892 /// the right class.
1893 template <typename T,
1894 bool = llvm::is_detected<has_concrete_entity_t, T>::value>
1895 struct InterfaceTargetOrOpT {
1896 using type = typename T::ConcreteEntity;
1897 };
1898 template <typename T>
1899 struct InterfaceTargetOrOpT<T, false> {
1900 using type = ConcreteType;
1901 };
1902
1903 /// A hook for static assertion that the external interface model T is
1904 /// targeting the concrete type of this op. The model can also be a fallback
1905 /// model that works for every op.
1906 template <typename T>
1907 static void checkInterfaceTarget() {
1908 static_assert(std::is_same<typename InterfaceTargetOrOpT<T>::type,
1909 ConcreteType>::value,
1910 "attaching an interface to the wrong op kind");
1911 }
1912
1913 /// Returns an interface map containing the interfaces registered to this
1914 /// operation.
1915 static detail::InterfaceMap getInterfaceMap() {
1916 return detail::InterfaceMap::template get<Traits<ConcreteType>...>();
1917 }
1918
1919 /// Return the internal implementations of each of the OperationName
1920 /// hooks.
1921 /// Implementation of `FoldHookFn` OperationName hook.
1922 static OperationName::FoldHookFn getFoldHookFn() {
1923 // If the operation is single result and defines a `fold` method.
1924 if constexpr (llvm::is_one_of<OpTrait::OneResult<ConcreteType>,
1925 Traits<ConcreteType>...>::value &&
1926 (has_single_result_fold_v<ConcreteType> ||
1927 has_fold_adaptor_single_result_v<ConcreteType>))
1928 return [](Operation *op, ArrayRef<Attribute> operands,
1929 SmallVectorImpl<OpFoldResult> &results) {
1930 return foldSingleResultHook<ConcreteType>(op, operands, results);
1931 };
1932 // The operation is not single result and defines a `fold` method.
1933 if constexpr (has_fold_v<ConcreteType> || has_fold_adaptor_v<ConcreteType>)
1934 return [](Operation *op, ArrayRef<Attribute> operands,
1935 SmallVectorImpl<OpFoldResult> &results) {
1936 return foldHook<ConcreteType>(op, operands, results);
1937 };
1938 // The operation does not define a `fold` method.
1939 return [](Operation *op, ArrayRef<Attribute> operands,
1940 SmallVectorImpl<OpFoldResult> &results) {
1941 // In this case, we only need to fold the traits of the operation.
1943 op, operands, results);
1944 };
1945 }
1946 /// Return the result of folding a single result operation that defines a
1947 /// `fold` method.
1948 template <typename ConcreteOpT>
1949 static LogicalResult
1950 foldSingleResultHook(Operation *op, ArrayRef<Attribute> operands,
1951 SmallVectorImpl<OpFoldResult> &results) {
1952 OpFoldResult result;
1953 if constexpr (has_fold_adaptor_single_result_v<ConcreteOpT>) {
1954 result = cast<ConcreteOpT>(op).fold(
1955 typename ConcreteOpT::FoldAdaptor(operands, cast<ConcreteOpT>(op)));
1956 } else {
1957 result = cast<ConcreteOpT>(op).fold(operands);
1958 }
1959
1960 // If the fold failed or was in-place, try to fold the traits of the
1961 // operation.
1962 if (!result ||
1963 llvm::dyn_cast_if_present<Value>(result) == op->getResult(0)) {
1964 if (succeeded(op_definition_impl::foldTraits<Traits<ConcreteType>...>(
1965 op, operands, results)))
1966 return success();
1967 return success(static_cast<bool>(result));
1968 }
1969 results.push_back(result);
1970 return success();
1971 }
1972 /// Return the result of folding an operation that defines a `fold` method.
1973 template <typename ConcreteOpT>
1974 static LogicalResult foldHook(Operation *op, ArrayRef<Attribute> operands,
1975 SmallVectorImpl<OpFoldResult> &results) {
1976 auto result = LogicalResult::failure();
1977 if constexpr (has_fold_adaptor_v<ConcreteOpT>) {
1978 result = cast<ConcreteOpT>(op).fold(
1979 typename ConcreteOpT::FoldAdaptor(operands, cast<ConcreteOpT>(op)),
1980 results);
1981 } else {
1982 result = cast<ConcreteOpT>(op).fold(operands, results);
1983 }
1984
1985 // If the fold failed or was in-place, try to fold the traits of the
1986 // operation.
1987 if (failed(result) || results.empty()) {
1988 if (succeeded(op_definition_impl::foldTraits<Traits<ConcreteType>...>(
1989 op, operands, results)))
1990 return success();
1991 }
1992 return result;
1993 }
1994
1995 /// Implementation of `GetHasTraitFn`
1996 static OperationName::HasTraitFn getHasTraitFn() {
1997 return
1998 [](TypeID id) { return op_definition_impl::hasTrait<Traits...>(id); };
1999 }
2000 /// Implementation of `PrintAssemblyFn` OperationName hook.
2001 static OperationName::PrintAssemblyFn getPrintAssemblyFn() {
2002 if constexpr (detect_has_print<ConcreteType>::value)
2003 return [](Operation *op, OpAsmPrinter &p, StringRef defaultDialect) {
2004 OpState::printOpName(op, p, defaultDialect);
2005 return cast<ConcreteType>(op).print(p);
2006 };
2007 return [](Operation *op, OpAsmPrinter &printer, StringRef defaultDialect) {
2008 return OpState::print(op, printer, defaultDialect);
2009 };
2010 }
2011
2012public:
2013 template <typename T>
2015 template <typename T = ConcreteType>
2017 if constexpr (!hasProperties())
2018 return getEmptyProperties();
2019 return *getOperation()
2021 .template as<InferredProperties<T> *>();
2022 }
2023
2024 /// This hook populates any unset default attrs when mapped to properties.
2025 template <typename T = ConcreteType>
2027 InferredProperties<T> &properties) {}
2028
2029 /// Print the operation properties with names not included within
2030 /// 'elidedProps'. Unless overridden, this method will try to dispatch to a
2031 /// `printProperties` free-function if it exists, and otherwise by converting
2032 /// the properties to an Attribute.
2033 template <typename T>
2035 const T &properties,
2036 ArrayRef<StringRef> elidedProps = {}) {
2037 if constexpr (detect_has_print_properties<T>::value)
2038 return printProperties(p, properties, elidedProps);
2040 p, ConcreteType::getPropertiesAsAttr(ctx, properties), elidedProps);
2041 }
2042
2043 /// Parses 'prop-dict' for the operation. Unless overridden, the method will
2044 /// parse the properties using the generic property dictionary using the
2045 /// '<{ ... }>' syntax. The resulting properties are stored within the
2046 /// property structure of 'result', accessible via 'getOrAddProperties'.
2047 template <typename T = ConcreteType>
2048 static ParseResult parseProperties(OpAsmParser &parser,
2050 if constexpr (detect_has_parse_properties<InferredProperties<T>>::value) {
2051 return parseProperties(
2052 parser, result.getOrAddProperties<InferredProperties<T>>());
2053 }
2054
2055 Attribute propertyDictionary;
2056 if (genericParseProperties(parser, propertyDictionary))
2057 return failure();
2058
2059 // The generated 'setPropertiesFromParsedAttr', like
2060 // 'setPropertiesFromAttr', expects a 'DictionaryAttr' that is not null.
2061 // Use an empty dictionary in the case that the whole dictionary is
2062 // optional.
2063 if (!propertyDictionary)
2064 propertyDictionary = DictionaryAttr::get(result.getContext());
2065
2066 auto emitError = [&]() {
2067 return mlir::emitError(result.location, "invalid properties ")
2068 << propertyDictionary << " for op " << result.name.getStringRef()
2069 << ": ";
2070 };
2071
2072 // Copy the data from the dictionary attribute into the property struct of
2073 // the operation. This method is generated by ODS by default if there are
2074 // any occurrences of 'prop-dict' in the assembly format and should set
2075 // any properties that aren't parsed elsewhere.
2076 return ConcreteOpType::setPropertiesFromParsedAttr(
2077 result.getOrAddProperties<InferredProperties<T>>(), propertyDictionary,
2078 emitError);
2079 }
2080
2081private:
2082 /// Implementation of `PopulateDefaultAttrsFn` OperationName hook.
2083 static OperationName::PopulateDefaultAttrsFn getPopulateDefaultAttrsFn() {
2084 return ConcreteType::populateDefaultAttrs;
2085 }
2086 /// Implementation of `VerifyInvariantsFn` OperationName hook.
2087 static LogicalResult verifyInvariants(Operation *op) {
2088 static_assert(hasNoDataMembers(),
2089 "Op class shouldn't define new data members");
2090 return failure(
2091 failed(op_definition_impl::verifyTraits<Traits<ConcreteType>...>(op)) ||
2092 failed(cast<ConcreteType>(op).verify()));
2093 }
2094 static OperationName::VerifyInvariantsFn getVerifyInvariantsFn() {
2095 return static_cast<LogicalResult (*)(Operation *)>(&verifyInvariants);
2096 }
2097 /// Implementation of `VerifyRegionInvariantsFn` OperationName hook.
2098 static LogicalResult verifyRegionInvariants(Operation *op) {
2099 static_assert(hasNoDataMembers(),
2100 "Op class shouldn't define new data members");
2101 return failure(
2102 failed(op_definition_impl::verifyRegionTraits<Traits<ConcreteType>...>(
2103 op)) ||
2104 failed(cast<ConcreteType>(op).verifyRegions()));
2105 }
2106 static OperationName::VerifyRegionInvariantsFn getVerifyRegionInvariantsFn() {
2107 return static_cast<LogicalResult (*)(Operation *)>(&verifyRegionInvariants);
2108 }
2109
2110 static constexpr bool hasNoDataMembers() {
2111 // Checking that the derived class does not define any member by comparing
2112 // its size to an ad-hoc EmptyOp.
2113 class EmptyOp : public Op<EmptyOp, Traits...> {};
2114 return sizeof(ConcreteType) == sizeof(EmptyOp);
2115 }
2116
2117 /// Allow access to internal implementation methods.
2118 friend RegisteredOperationName;
2119};
2120
2121/// This class represents the base of an operation interface. See the definition
2122/// of `detail::Interface` for requirements on the `Traits` type.
2123template <typename ConcreteType, typename Traits>
2125 : public detail::Interface<ConcreteType, Operation *, Traits,
2126 Op<ConcreteType>, OpTrait::TraitBase> {
2127public:
2129 using InterfaceBase = detail::Interface<ConcreteType, Operation *, Traits,
2131
2132 /// Inherit the base class constructor.
2134
2135protected:
2136 /// Returns the impl interface instance for the given operation.
2138 OperationName name = op->getName();
2139
2140#ifndef NDEBUG
2141 // Check that the current interface isn't an unresolved promise for the
2142 // given operation.
2143 if (Dialect *dialect = name.getDialect()) {
2145 *dialect, name.getTypeID(), ConcreteType::getInterfaceID(),
2146 llvm::getTypeName<ConcreteType>());
2147 }
2148#endif
2149
2150 // Access the raw interface from the operation info.
2151 if (std::optional<RegisteredOperationName> rInfo =
2152 name.getRegisteredInfo()) {
2153 if (auto *opIface = rInfo->getInterface<ConcreteType>())
2154 return opIface;
2155 // Fallback to the dialect to provide it with a chance to implement this
2156 // interface for this operation.
2157 return rInfo->getDialect().getRegisteredInterfaceForOp<ConcreteType>(
2158 op->getName());
2159 }
2160 // Fallback to the dialect to provide it with a chance to implement this
2161 // interface for this operation.
2162 if (Dialect *dialect = name.getDialect())
2163 return dialect->getRegisteredInterfaceForOp<ConcreteType>(name);
2164 return nullptr;
2165 }
2166
2167 /// Allow access to `getInterfaceFor`.
2169};
2170
2171} // namespace mlir
2172
2173namespace llvm {
2174
2175template <typename T>
2177 std::enable_if_t<std::is_base_of<mlir::OpState, T>::value &&
2178 !mlir::detail::IsInterface<T>::value>> {
2179 static unsigned getHashValue(T val) {
2180 return hash_value(val.getAsOpaquePointer());
2181 }
2182 static bool isEqual(T lhs, T rhs) { return lhs == rhs; }
2183};
2184} // namespace llvm
2185
2187
2188#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.
This trait marks operations that are allowed to consume builtin token values.
This trait marks operations that are allowed to produce builtin token values.
Helper class for implementing traits.
Operation * getOperation()
Return the ultimate Operation being worked on.
This class provides the API for ops which have an unknown number of SSA operands.
This class provides the API for ops which have an unknown number of regions.
This class provides the API for ops which have an unknown number of results.
This class provides the API for ops which have an unknown number of successors.
This class provides the API for ops that are known to have no SSA operand.
static LogicalResult verifyTrait(Operation *op)
This class provides verification for ops that are known to have zero regions.
static LogicalResult verifyTrait(Operation *op)
This class provides return value APIs for ops that are known to have zero results.
static LogicalResult verifyTrait(Operation *op)
This class provides verification for ops that are known to have zero successors.
static LogicalResult verifyTrait(Operation *op)
This provides public APIs that all operations should have.
Operation * getOperation()
Inherit getOperation from OpState.
static bool classof(Operation *op)
Return true if this "op class" can match against the specified operation.
static LogicalResult setPropertiesFromAttr(PropertiesTy &prop, Attribute attr, function_ref< InFlightDiagnostic()> emitError)
Convert the provided attribute to a property and assigned it to the provided properties.
Op(std::nullptr_t)
static ConcreteOpType getFromOpaquePointer(const void *pointer)
LogicalResult verify()
If the concrete type didn't implement a custom verifier hook, just fall back to this one which accept...
InferredProperties< T > & getProperties()
Op(Operation *state)
This is a public constructor to enable access via the llvm::cast family of methods.
ConcreteType ConcreteOpType
Expose the type we are instantiated on to template machinery that may want to introspect traits on th...
static Attribute getPropertiesAsAttr(MLIRContext *ctx, const PropertiesTy &prop)
Convert the provided properties to an attribute.
LogicalResult verifyRegions()
static void printProperties(MLIRContext *ctx, OpAsmPrinter &p, const T &properties, ArrayRef< StringRef > elidedProps={})
Print the operation properties with names not included within 'elidedProps'.
ConcreteType clone()
Create a deep copy of this operation.
const void * getAsOpaquePointer() const
Methods for supporting PointerLikeTypeTraits.
static constexpr bool hasTrait()
Return if this operation contains the provided trait.
static llvm::hash_code computePropertiesHash(const PropertiesTy &prop)
Hash the provided properties.
static constexpr bool hasProperties()
Returns true if this operation defines a Properties inner type.
Op()
This is a public constructor. Any op can be initialized to null.
static ParseResult parseProperties(OpAsmParser &parser, OperationState &result)
Parses 'prop-dict' for the operation.
static void attachInterface(MLIRContext &context)
Attach the given models as implementations of the corresponding interfaces for the concrete operation...
static std::enable_if_t< std::is_base_of< OpState, T >::value, bool > classof(const T *op)
Provide classof support for other OpBase derived classes, such as Interfaces.
typename PropertiesSelector< T >::type InferredProperties
ConcreteType cloneWithoutRegions()
Create a partial copy of this operation without traversing into attached regions.
static void populateDefaultProperties(OperationName opName, InferredProperties< T > &properties)
This hook populates any unset default attrs when mapped to properties.
StringRef getStringRef() const
Return the name of this operation. This always succeeds.
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:87
PropertyRef getPropertiesStorage()
Return a generic (but typed) reference to the property type storage.
Definition Operation.h:926
ResultRange result_range
Support result iteration.
Definition Operation.h:435
Region & getRegion(unsigned index)
Returns the region held by this operation at position 'index'.
Definition Operation.h:711
Value getOperand(unsigned idx)
Definition Operation.h:375
bool hasTrait()
Returns true if the operation was registered with a particular trait, e.g.
Definition Operation.h:774
operand_range::type_range operand_type_range
Definition Operation.h:419
void setOperand(unsigned idx, Value value)
Definition Operation.h:376
unsigned getNumSuccessors()
Definition Operation.h:731
result_iterator result_begin()
Definition Operation.h:438
result_range::iterator result_iterator
Definition Operation.h:436
operand_iterator operand_begin()
Definition Operation.h:399
OpResult getResult(unsigned idx)
Get the 'idx'th result of this operation.
Definition Operation.h:432
operand_range::type_iterator operand_type_iterator
Definition Operation.h:418
operand_type_iterator operand_type_end()
Definition Operation.h:421
result_range::type_range result_type_range
Definition Operation.h:450
unsigned getNumRegions()
Returns the number of regions held by this operation.
Definition Operation.h:699
Operation * getParentOp()
Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...
Definition Operation.h:251
std::optional< RegisteredOperationName > getRegisteredInfo()
If this operation has a registered operation description, return it.
Definition Operation.h:119
unsigned getNumOperands()
Definition Operation.h:371
result_type_iterator result_type_end()
Definition Operation.h:452
OperandRange operand_range
Definition Operation.h:396
OpTy getParentOfType()
Return the closest surrounding parent operation that is of type 'OpTy'.
Definition Operation.h:255
result_range::type_iterator result_type_iterator
Support result type iteration.
Definition Operation.h:449
operand_iterator operand_end()
Definition Operation.h:400
result_type_iterator result_type_begin()
Definition Operation.h:451
OperationName getName()
The name of an operation is the key identifier for it.
Definition Operation.h:115
void print(raw_ostream &os, const OpPrintingFlags &flags={})
operand_type_range getOperandTypes()
Definition Operation.h:422
MutableArrayRef< Region > getRegions()
Returns the regions held by this operation.
Definition Operation.h:702
result_iterator result_end()
Definition Operation.h:439
static Operation * create(Location location, OperationName name, TypeRange resultTypes, ValueRange operands, NamedAttrList &&attributes, PropertyRef properties, BlockRange successors, unsigned numRegions)
Create a new Operation with the specific fields.
Definition Operation.cpp:65
result_type_range getResultTypes()
Definition Operation.h:453
operand_range getOperands()
Returns an iterator on the underlying Value's.
Definition Operation.h:403
void setSuccessor(Block *block, unsigned index)
void replaceAllUsesWith(ValuesT &&values)
Replace all uses of results of this operation with the provided 'values'.
Definition Operation.h:297
Block * getSuccessor(unsigned index)
Definition Operation.h:733
SuccessorRange getSuccessors()
Definition Operation.h:728
result_range getResults()
Definition Operation.h:440
SuccessorRange::iterator succ_iterator
Definition Operation.h:725
MLIRContext * getContext()
Return the context this operation is associated with.
Definition Operation.h:233
operand_range::iterator operand_iterator
Definition Operation.h:397
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:429
operand_type_iterator operand_type_begin()
Definition Operation.h:420
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:227
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...