8db6129dbb88421ad645247c3eebc2b4e46748c1
[lldb.git] / mlir / include / mlir / Dialect / StandardOps / IR / Ops.td
1 //===- Ops.td - Standard operation definitions -------------*- tablegen -*-===//
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 // Defines some MLIR standard operations.
10 //
11 //===----------------------------------------------------------------------===//
12
13 #ifndef STANDARD_OPS
14 #define STANDARD_OPS
15
16 include "mlir/Dialect/StandardOps/IR/StandardOpsBase.td"
17 include "mlir/IR/OpAsmInterface.td"
18 include "mlir/IR/SymbolInterfaces.td"
19 include "mlir/Interfaces/CallInterfaces.td"
20 include "mlir/Interfaces/ControlFlowInterfaces.td"
21 include "mlir/Interfaces/SideEffectInterfaces.td"
22 include "mlir/Interfaces/VectorInterfaces.td"
23 include "mlir/Interfaces/ViewLikeInterface.td"
24
25 def StandardOps_Dialect : Dialect {
26   let name = "std";
27   let cppNamespace = "";
28   let hasConstantMaterializer = 1;
29 }
30
31 // Base class for Standard dialect ops.
32 class Std_Op<string mnemonic, list<OpTrait> traits = []> :
33     Op<StandardOps_Dialect, mnemonic, traits> {
34   // For every standard op, there needs to be a:
35   //   * void print(OpAsmPrinter &p, ${C++ class of Op} op)
36   //   * LogicalResult verify(${C++ class of Op} op)
37   //   * ParseResult parse${C++ class of Op}(OpAsmParser &parser,
38   //                                         OperationState &result)
39   // functions.
40   let printer = [{ return ::print(p, *this); }];
41   let verifier = [{ return ::verify(*this); }];
42   let parser = [{ return ::parse$cppClass(parser, result); }];
43 }
44
45 // Base class for standard cast operations. Requires single operand and result,
46 // but does not constrain them to specific types.
47 class CastOp<string mnemonic, list<OpTrait> traits = []> :
48     Std_Op<mnemonic,
49            !listconcat(traits, [NoSideEffect, SameOperandsAndResultShape])> {
50
51   let results = (outs AnyType);
52
53   let builders = [
54     OpBuilderDAG<(ins "Value":$source, "Type":$destType), [{
55        impl::buildCastOp($_builder, $_state, source, destType);
56     }]>
57   ];
58
59   let parser = [{
60     return impl::parseCastOp(parser, result);
61   }];
62   let printer = [{
63     return printStandardCastOp(this->getOperation(), p);
64   }];
65   let verifier = [{ return impl::verifyCastOp(*this, areCastCompatible); }];
66
67   let hasFolder = 1;
68 }
69
70 // Base class for arithmetic cast operations.
71 class ArithmeticCastOp<string mnemonic, list<OpTrait> traits = []> :
72     CastOp<mnemonic,
73     !listconcat(traits, [ElementwiseMappable,
74                          DeclareOpInterfaceMethods<VectorUnrollOpInterface>])> {
75 }
76
77 // Base class for unary ops. Requires single operand and result. Individual
78 // classes will have `operand` accessor.
79 class UnaryOp<string mnemonic, list<OpTrait> traits = []> :
80     Op<StandardOps_Dialect, mnemonic, !listconcat(traits, [NoSideEffect])> {
81   let results = (outs AnyType);
82   let printer = [{
83     return printStandardUnaryOp(this->getOperation(), p);
84   }];
85 }
86
87 class UnaryOpSameOperandAndResultType<string mnemonic,
88                                       list<OpTrait> traits = []> :
89     UnaryOp<mnemonic, !listconcat(traits, [SameOperandsAndResultType])> {
90   let parser = [{
91     return impl::parseOneResultSameOperandTypeOp(parser, result);
92   }];
93 }
94
95 class FloatUnaryOp<string mnemonic, list<OpTrait> traits = []> :
96     UnaryOpSameOperandAndResultType<mnemonic,
97       !listconcat(traits,
98                   [DeclareOpInterfaceMethods<VectorUnrollOpInterface>,
99                    ElementwiseMappable])>,
100     Arguments<(ins FloatLike:$operand)>;
101
102 // Base class for standard arithmetic operations.  Requires operands and
103 // results to be of the same type, but does not constrain them to specific
104 // types.  Individual classes will have `lhs` and `rhs` accessor to operands.
105 class ArithmeticOp<string mnemonic, list<OpTrait> traits = []> :
106     Op<StandardOps_Dialect, mnemonic,
107        !listconcat(traits, [NoSideEffect,
108                             SameOperandsAndResultType,
109                             DeclareOpInterfaceMethods<VectorUnrollOpInterface>,
110                             ElementwiseMappable])> {
111
112   let results = (outs AnyType:$result);
113
114   let parser = [{
115     return impl::parseOneResultSameOperandTypeOp(parser, result);
116   }];
117
118   let printer = [{
119     return printStandardBinaryOp(this->getOperation(), p);
120   }];
121 }
122
123 // Base class for standard arithmetic operations on integers, vectors and
124 // tensors thereof.  This operation takes two operands and returns one result,
125 // each of these is required to be of the same type.  This type may be an
126 // integer scalar type, a vector whose element type is an integer type, or an
127 // integer tensor.  The custom assembly form of the operation is as follows
128 //
129 //     <op>i %0, %1 : i32
130 //
131 class IntArithmeticOp<string mnemonic, list<OpTrait> traits = []> :
132     ArithmeticOp<mnemonic,
133       !listconcat(traits,
134                   [DeclareOpInterfaceMethods<VectorUnrollOpInterface>])>,
135     Arguments<(ins SignlessIntegerLike:$lhs, SignlessIntegerLike:$rhs)>;
136
137 // Base class for standard arithmetic binary operations on floats, vectors and
138 // tensors thereof.  This operation has two operands and returns one result,
139 // each of these is required to be of the same type.  This type may be a
140 // floating point scalar type, a vector whose element type is a floating point
141 // type, or a floating point tensor.  The custom assembly form of the operation
142 // is as follows
143 //
144 //     <op>f %0, %1 : f32
145 //
146 class FloatArithmeticOp<string mnemonic, list<OpTrait> traits = []> :
147     ArithmeticOp<mnemonic,
148       !listconcat(traits,
149                   [DeclareOpInterfaceMethods<VectorUnrollOpInterface>])>,
150     Arguments<(ins FloatLike:$lhs, FloatLike:$rhs)>;
151
152 // Base class for standard arithmetic operations on complex numbers with a
153 // floating-point element type.
154 // These operations take two operands and return one result, all of which must
155 // be complex numbers of the same type.
156 // The assembly format is as follows
157 //
158 //     <op>cf %0, %1 : complex<f32>
159 //
160 class ComplexFloatArithmeticOp<string mnemonic, list<OpTrait> traits = []> :
161     ArithmeticOp<mnemonic, traits>,
162     Arguments<(ins Complex<AnyFloat>:$lhs, Complex<AnyFloat>:$rhs)>;
163
164 // Base class for memref allocating ops: alloca and alloc.
165 //
166 //   %0 = alloclike(%m)[%s] : memref<8x?xf32, (d0, d1)[s0] -> ((d0 + s0), d1)>
167 //
168 class AllocLikeOp<string mnemonic,
169                   Resource resource,
170                   list<OpTrait> traits = []> :
171     Std_Op<mnemonic,
172     !listconcat([
173       AttrSizedOperandSegments
174     ], traits)> {
175
176   let arguments = (ins Variadic<Index>:$dynamicSizes,
177                    // The symbolic operands (the ones in square brackets) bind
178                    // to the symbols of the memref's layout map.
179                    Variadic<Index>:$symbolOperands,
180                    Confined<OptionalAttr<I64Attr>, [IntMinValue<0>]>:$alignment);
181   let results = (outs Res<AnyMemRef, "", [MemAlloc<resource>]>:$memref);
182
183   let builders = [
184     OpBuilderDAG<(ins "MemRefType":$memrefType,
185                   CArg<"IntegerAttr", "IntegerAttr()">:$alignment), [{
186       return build($_builder, $_state, memrefType, {}, alignment);
187     }]>,
188     OpBuilderDAG<(ins "MemRefType":$memrefType, "ValueRange":$dynamicSizes,
189                   CArg<"IntegerAttr", "IntegerAttr()">:$alignment), [{
190       return build($_builder, $_state, memrefType, dynamicSizes, {}, alignment);
191     }]>,
192     OpBuilderDAG<(ins "MemRefType":$memrefType, "ValueRange":$dynamicSizes,
193                   "ValueRange":$symbolOperands,
194                   CArg<"IntegerAttr", "{}">:$alignment), [{
195       $_state.types.push_back(memrefType);
196       $_state.addOperands(dynamicSizes);
197       $_state.addOperands(symbolOperands);
198       $_state.addAttribute(getOperandSegmentSizeAttr(),
199           $_builder.getI32VectorAttr({
200               static_cast<int32_t>(dynamicSizes.size()),
201               static_cast<int32_t>(symbolOperands.size())}));
202       if (alignment)
203         $_state.addAttribute(getAlignmentAttrName(), alignment);
204     }]>];
205
206   let extraClassDeclaration = [{
207     static StringRef getAlignmentAttrName() { return "alignment"; }
208
209     MemRefType getType() { return getResult().getType().cast<MemRefType>(); }
210
211     /// Returns the dynamic sizes for this alloc operation if specified.
212     operand_range getDynamicSizes() { return dynamicSizes(); }
213   }];
214
215   let assemblyFormat = [{
216     `(`$dynamicSizes`)` (`` `[` $symbolOperands^ `]`)? attr-dict `:` type($memref)
217   }];
218
219   let hasCanonicalizer = 1;
220 }
221
222 // Base class for ops with static/dynamic offset, sizes and strides
223 // attributes/arguments.
224 class BaseOpWithOffsetSizesAndStrides<string mnemonic, list<OpTrait> traits = []> :
225     Std_Op<mnemonic,
226            !listconcat(traits, [NoSideEffect, AttrSizedOperandSegments])> {
227   code extraBaseClassDeclaration = [{
228     /// Returns the dynamic sizes for this subview operation if specified.
229     operand_range getDynamicSizes() { return sizes(); }
230
231     /// Return the list of Range (i.e. offset, size, stride). Each
232     /// Range entry contains either the dynamic value or a ConstantIndexOp
233     /// constructed with `b` at location `loc`.
234     SmallVector<Range, 8> getOrCreateRanges(OpBuilder &b, Location loc) {
235       return mlir::getOrCreateRanges(*this, b, loc);
236     }
237   }];
238 }
239
240 //===----------------------------------------------------------------------===//
241 // AbsFOp
242 //===----------------------------------------------------------------------===//
243
244 def AbsFOp : FloatUnaryOp<"absf"> {
245   let summary = "floating point absolute-value operation";
246   let description = [{
247     The `absf` operation computes the absolute value. It takes one operand and
248     returns one result of the same type. This type may be a float scalar type,
249     a vector whose element type is float, or a tensor of floats.
250
251     Example:
252
253     ```mlir
254     // Scalar absolute value.
255     %a = absf %b : f64
256
257     // SIMD vector element-wise absolute value.
258     %f = absf %g : vector<4xf32>
259
260     // Tensor element-wise absolute value.
261     %x = absf %y : tensor<4x?xf8>
262     ```
263   }];
264 }
265
266 //===----------------------------------------------------------------------===//
267 // AddCFOp
268 //===----------------------------------------------------------------------===//
269
270 def AddCFOp : ComplexFloatArithmeticOp<"addcf"> {
271   let summary = "complex number addition";
272   let description = [{
273     The `addcf` operation takes two complex number operands and returns their
274     sum, a single complex number.
275     All operands and result must be of the same type, a complex number with a
276     floating-point element type.
277
278     Example:
279
280     ```mlir
281     %a = addcf %b, %c : complex<f32>
282     ```
283   }];
284 }
285
286 //===----------------------------------------------------------------------===//
287 // AddFOp
288 //===----------------------------------------------------------------------===//
289
290 def AddFOp : FloatArithmeticOp<"addf"> {
291   let summary = "floating point addition operation";
292   let description = [{
293     Syntax:
294
295     ```
296     operation ::= ssa-id `=` `std.addf` ssa-use `,` ssa-use `:` type
297     ```
298
299     The `addf` operation takes two operands and returns one result, each of
300     these is required to be the same type. This type may be a floating point
301     scalar type, a vector whose element type is a floating point type, or a
302     floating point tensor.
303
304     Example:
305
306     ```mlir
307     // Scalar addition.
308     %a = addf %b, %c : f64
309
310     // SIMD vector addition, e.g. for Intel SSE.
311     %f = addf %g, %h : vector<4xf32>
312
313     // Tensor addition.
314     %x = addf %y, %z : tensor<4x?xbf16>
315     ```
316
317     TODO: In the distant future, this will accept optional attributes for fast
318     math, contraction, rounding mode, and other controls.
319   }];
320   let hasFolder = 1;
321 }
322
323 //===----------------------------------------------------------------------===//
324 // AddIOp
325 //===----------------------------------------------------------------------===//
326
327 def AddIOp : IntArithmeticOp<"addi", [Commutative]> {
328   let summary = "integer addition operation";
329   let description = [{
330     Syntax:
331
332     ```
333     operation ::= ssa-id `=` `std.addi` ssa-use `,` ssa-use `:` type
334     ```
335
336     The `addi` operation takes two operands and returns one result, each of
337     these is required to be the same type. This type may be an integer scalar
338     type, a vector whose element type is integer, or a tensor of integers. It
339     has no standard attributes.
340
341     Example:
342
343     ```mlir
344     // Scalar addition.
345     %a = addi %b, %c : i64
346
347     // SIMD vector element-wise addition, e.g. for Intel SSE.
348     %f = addi %g, %h : vector<4xi32>
349
350     // Tensor element-wise addition.
351     %x = addi %y, %z : tensor<4x?xi8>
352     ```
353   }];
354   let hasFolder = 1;
355 }
356
357 //===----------------------------------------------------------------------===//
358 // AllocOp
359 //===----------------------------------------------------------------------===//
360
361 def AllocOp : AllocLikeOp<"alloc", DefaultResource> {
362   let summary = "memory allocation operation";
363   let description = [{
364     The `alloc` operation allocates a region of memory, as specified by its
365     memref type.
366
367     Example:
368
369     ```mlir
370     %0 = alloc() : memref<8x64xf32, 1>
371     ```
372
373     The optional list of dimension operands are bound to the dynamic dimensions
374     specified in its memref type. In the example below, the ssa value '%d' is
375     bound to the second dimension of the memref (which is dynamic).
376
377     ```mlir
378     %0 = alloc(%d) : memref<8x?xf32, 1>
379     ```
380
381     The optional list of symbol operands are bound to the symbols of the
382     memrefs affine map. In the example below, the ssa value '%s' is bound to
383     the symbol 's0' in the affine map specified in the allocs memref type.
384
385     ```mlir
386     %0 = alloc()[%s] : memref<8x64xf32,
387                               affine_map<(d0, d1)[s0] -> ((d0 + s0), d1)>, 1>
388     ```
389
390     This operation returns a single ssa value of memref type, which can be used
391     by subsequent load and store operations.
392
393     The optional `alignment` attribute may be specified to ensure that the
394     region of memory that will be indexed is aligned at the specified byte
395     boundary.
396
397     ```mlir
398     %0 = alloc()[%s] {alignment = 8} :
399       memref<8x64xf32, affine_map<(d0, d1)[s0] -> ((d0 + s0), d1)>, 1>
400     ```
401   }];
402 }
403
404 //===----------------------------------------------------------------------===//
405 // AllocaOp
406 //===----------------------------------------------------------------------===//
407
408 def AllocaOp : AllocLikeOp<"alloca", AutomaticAllocationScopeResource> {
409   let summary = "stack memory allocation operation";
410   let description = [{
411     The `alloca` operation allocates memory on the stack, to be automatically
412     released when control transfers back from the region of its closest
413     surrounding operation with an
414     [`AutomaticAllocationScope`](../Traits.md#automaticallocationscope) trait.
415     The amount of memory allocated is specified by its memref and additional
416     operands. For example:
417
418     ```mlir
419     %0 = alloca() : memref<8x64xf32>
420     ```
421
422     The optional list of dimension operands are bound to the dynamic dimensions
423     specified in its memref type. In the example below, the SSA value '%d' is
424     bound to the second dimension of the memref (which is dynamic).
425
426     ```mlir
427     %0 = alloca(%d) : memref<8x?xf32>
428     ```
429
430     The optional list of symbol operands are bound to the symbols of the
431     memref's affine map. In the example below, the SSA value '%s' is bound to
432     the symbol 's0' in the affine map specified in the allocs memref type.
433
434     ```mlir
435     %0 = alloca()[%s] : memref<8x64xf32,
436                                affine_map<(d0, d1)[s0] -> ((d0 + s0), d1)>>
437     ```
438
439     This operation returns a single SSA value of memref type, which can be used
440     by subsequent load and store operations. An optional alignment attribute, if
441     specified, guarantees alignment at least to that boundary. If not specified,
442     an alignment on any convenient boundary compatible with the type will be
443     chosen.
444   }];
445 }
446
447 //===----------------------------------------------------------------------===//
448 // AndOp
449 //===----------------------------------------------------------------------===//
450
451 def AndOp : IntArithmeticOp<"and", [Commutative]> {
452   let summary = "integer binary and";
453   let description = [{
454     Syntax:
455
456     ```
457     operation ::= ssa-id `=` `std.and` ssa-use `,` ssa-use `:` type
458     ```
459
460     The `and` operation takes two operands and returns one result, each of these
461     is required to be the same type. This type may be an integer scalar type, a
462     vector whose element type is integer, or a tensor of integers. It has no
463     standard attributes.
464
465     Example:
466
467     ```mlir
468     // Scalar integer bitwise and.
469     %a = and %b, %c : i64
470
471     // SIMD vector element-wise bitwise integer and.
472     %f = and %g, %h : vector<4xi32>
473
474     // Tensor element-wise bitwise integer and.
475     %x = and %y, %z : tensor<4x?xi8>
476     ```
477   }];
478   let hasFolder = 1;
479 }
480
481 //===----------------------------------------------------------------------===//
482 // AssertOp
483 //===----------------------------------------------------------------------===//
484
485 def AssertOp : Std_Op<"assert"> {
486   let summary = "Assert operation with message attribute";
487   let description = [{
488     Assert operation with single boolean operand and an error message attribute.
489     If the argument is `true` this operation has no effect. Otherwise, the
490     program execution will abort. The provided error message may be used by a
491     runtime to propagate the error to the user.
492
493     Example:
494
495     ```mlir
496     assert %b, "Expected ... to be true"
497     ```
498   }];
499
500   let arguments = (ins I1:$arg, StrAttr:$msg);
501
502   let assemblyFormat = "$arg `,` $msg attr-dict";
503
504   // AssertOp is fully verified by its traits.
505   let verifier = ?;
506
507   let hasCanonicalizer = 1;
508 }
509
510 //===----------------------------------------------------------------------===//
511 // AssumeAlignmentOp
512 //===----------------------------------------------------------------------===//
513
514 def AssumeAlignmentOp : Std_Op<"assume_alignment"> {
515   let summary =
516       "assertion that gives alignment information to the input memref";
517   let description = [{
518     The `assume_alignment` operation takes a memref and an integer of alignment
519     value, and internally annotates the buffer with the given alignment. If
520     the buffer isn't aligned to the given alignment, the behavior is undefined.
521
522     This operation doesn't affect the semantics of a correct program. It's for
523     optimization only, and the optimization is best-effort.
524   }];
525   let arguments = (ins AnyMemRef:$memref,
526                        Confined<I32Attr, [IntPositive]>:$alignment);
527   let results = (outs);
528
529   let assemblyFormat = "$memref `,` $alignment attr-dict `:` type($memref)";
530 }
531
532 //===----------------------------------------------------------------------===//
533 // AtanOp
534 //===----------------------------------------------------------------------===//
535
536 def AtanOp : FloatUnaryOp<"atan", []>{
537   let summary = "arcus tangent of the given value";
538   let description = [{
539     Syntax:
540
541     ```
542     operation ::= ssa-id `=` `std.atan` ssa-use `:` type
543     ```
544
545     The `atan` operation computes the arcus tangent of a given value.  It takes
546     one operand and returns one result of the same type.  This type may be a
547     float scalar type, a vector whose element type is float, or a tensor of
548     floats.  It has no standard attributes.
549
550     Example:
551
552     ```mlir
553     // Arcus tangent of scalar value.
554     %a = atan %b : f64
555
556     // SIMD vector element-wise arcus tangent.
557     %f = atan %g : vector<4xf32>
558
559     // Tensor element-wise arcus tangent.
560     %x = atan %y : tensor<4x?xf8>
561     ```
562   }];
563 }
564
565 //===----------------------------------------------------------------------===//
566 // Atan2Op
567 //===----------------------------------------------------------------------===//
568
569 def Atan2Op : FloatArithmeticOp<"atan2">{
570   let summary = "2-argument arcus tangent of the given values";
571   let description = [{
572     Syntax:
573
574     ```
575     operation ::= ssa-id `=` `std.atan2` ssa-use `,` ssa-use `:` type
576     ```
577
578     The `atan2` operation takes two operands and returns one result, all of
579     which must be of the same type.  This type may be a floating point scalar
580     type, a vector whose element type is a floating point type, or a floating
581     point tensor.
582
583     The 2-argument arcus tangent `atan2(y, x)` returns the angle in the
584     Euclidian plane between the positive x-axis and the ray through the point
585     (x, y).  It is a generalization of the 1-argument arcus tangent which
586     returns the angle on the basis of the ratio y/x.
587
588     See also https://en.wikipedia.org/wiki/Atan2
589
590     Example:
591
592     ```mlir
593     // Scalar variant.
594     %a = atan2 %b, %c : f32
595
596     // SIMD vector variant.
597     %f = atan2 %g, %h : vector<4xf32>
598
599     // Tensor variant.
600     %x = atan2 %y, %z : tensor<4x?xf32>
601     ```
602   }];
603 }
604
605 //===----------------------------------------------------------------------===//
606 // AtomicRMWOp
607 //===----------------------------------------------------------------------===//
608
609 def AtomicRMWOp : Std_Op<"atomic_rmw", [
610       AllTypesMatch<["value", "result"]>,
611       TypesMatchWith<"value type matches element type of memref",
612                      "memref", "value",
613                      "$_self.cast<MemRefType>().getElementType()">
614     ]> {
615   let summary = "atomic read-modify-write operation";
616   let description = [{
617     The `atomic_rmw` operation provides a way to perform a read-modify-write
618     sequence that is free from data races. The kind enumeration specifies the
619     modification to perform. The value operand represents the new value to be
620     applied during the modification. The memref operand represents the buffer
621     that the read and write will be performed against, as accessed by the
622     specified indices. The arity of the indices is the rank of the memref. The
623     result represents the latest value that was stored.
624
625     Example:
626
627     ```mlir
628     %x = atomic_rmw "addf" %value, %I[%i] : (f32, memref<10xf32>) -> f32
629     ```
630   }];
631
632   let arguments = (ins
633       AtomicRMWKindAttr:$kind,
634       AnyTypeOf<[AnySignlessInteger, AnyFloat]>:$value,
635       MemRefOf<[AnySignlessInteger, AnyFloat]>:$memref,
636       Variadic<Index>:$indices);
637   let results = (outs AnyTypeOf<[AnySignlessInteger, AnyFloat]>:$result);
638
639   let assemblyFormat = [{
640     $kind $value `,` $memref `[` $indices `]` attr-dict `:` `(` type($value) `,`
641     type($memref) `)` `->` type($result)
642   }];
643
644   let extraClassDeclaration = [{
645     MemRefType getMemRefType() {
646       return memref().getType().cast<MemRefType>();
647     }
648   }];
649 }
650
651 def GenericAtomicRMWOp : Std_Op<"generic_atomic_rmw", [
652       SingleBlockImplicitTerminator<"AtomicYieldOp">,
653       TypesMatchWith<"result type matches element type of memref",
654                      "memref", "result",
655                      "$_self.cast<MemRefType>().getElementType()">
656     ]> {
657   let summary = "atomic read-modify-write operation with a region";
658   let description = [{
659     The `generic_atomic_rmw` operation provides a way to perform a read-modify-write
660     sequence that is free from data races. The memref operand represents the
661     buffer that the read and write will be performed against, as accessed by
662     the specified indices. The arity of the indices is the rank of the memref.
663     The result represents the latest value that was stored. The region contains
664     the code for the modification itself. The entry block has a single argument
665     that represents the value stored in `memref[indices]` before the write is
666     performed. No side-effecting ops are allowed in the body of
667     `GenericAtomicRMWOp`.
668
669     Example:
670
671     ```mlir
672     %x = generic_atomic_rmw %I[%i] : memref<10xf32> {
673       ^bb0(%current_value : f32):
674         %c1 = constant 1.0 : f32
675         %inc = addf %c1, %current_value : f32
676         atomic_yield %inc : f32
677     }
678     ```
679   }];
680
681   let arguments = (ins
682       MemRefOf<[AnySignlessInteger, AnyFloat]>:$memref,
683       Variadic<Index>:$indices);
684
685   let results = (outs
686       AnyTypeOf<[AnySignlessInteger, AnyFloat]>:$result);
687
688   let regions = (region AnyRegion:$body);
689
690   let skipDefaultBuilders = 1;
691   let builders = [OpBuilderDAG<(ins "Value":$memref, "ValueRange":$ivs)>];
692
693   let extraClassDeclaration = [{
694     // The value stored in memref[ivs].
695     Value getCurrentValue() {
696       return body().getArgument(0);
697     }
698     MemRefType getMemRefType() {
699       return memref().getType().cast<MemRefType>();
700     }
701   }];
702 }
703
704 def AtomicYieldOp : Std_Op<"atomic_yield", [
705       HasParent<"GenericAtomicRMWOp">,
706       NoSideEffect,
707       Terminator
708     ]> {
709   let summary = "yield operation for GenericAtomicRMWOp";
710   let description = [{
711     "atomic_yield" yields an SSA value from a GenericAtomicRMWOp region.
712   }];
713
714   let arguments = (ins AnyType:$result);
715   let assemblyFormat = "$result attr-dict `:` type($result)";
716 }
717
718 //===----------------------------------------------------------------------===//
719 // BranchOp
720 //===----------------------------------------------------------------------===//
721
722 def BranchOp : Std_Op<"br",
723     [DeclareOpInterfaceMethods<BranchOpInterface, ["getSuccessorForOperands"]>,
724      NoSideEffect, Terminator]> {
725   let summary = "branch operation";
726   let description = [{
727     The `br` operation represents a branch operation in a function.
728     The operation takes variable number of operands and produces no results.
729     The operand number and types for each successor must match the arguments of
730     the block successor.
731
732     Example:
733
734     ```mlir
735     ^bb2:
736       %2 = call @someFn()
737       br ^bb3(%2 : tensor<*xf32>)
738     ^bb3(%3: tensor<*xf32>):
739     ```
740   }];
741
742   let arguments = (ins Variadic<AnyType>:$destOperands);
743   let successors = (successor AnySuccessor:$dest);
744
745   let builders = [
746     OpBuilderDAG<(ins "Block *":$dest,
747                   CArg<"ValueRange", "{}">:$destOperands), [{
748       $_state.addSuccessors(dest);
749       $_state.addOperands(destOperands);
750     }]>];
751
752   // BranchOp is fully verified by traits.
753   let verifier = ?;
754
755   let extraClassDeclaration = [{
756     Block *getDest();
757     void setDest(Block *block);
758
759     /// Erase the operand at 'index' from the operand list.
760     void eraseOperand(unsigned index);
761   }];
762
763   let hasCanonicalizer = 1;
764   let assemblyFormat = [{
765     $dest (`(` $destOperands^ `:` type($destOperands) `)`)? attr-dict
766   }];
767 }
768
769 //===----------------------------------------------------------------------===//
770 // CallOp
771 //===----------------------------------------------------------------------===//
772
773 def CallOp : Std_Op<"call",
774     [CallOpInterface, MemRefsNormalizable,
775      DeclareOpInterfaceMethods<SymbolUserOpInterface>]> {
776   let summary = "call operation";
777   let description = [{
778     The `call` operation represents a direct call to a function that is within
779     the same symbol scope as the call. The operands and result types of the
780     call must match the specified function type. The callee is encoded as a
781     symbol reference attribute named "callee".
782
783     Example:
784
785     ```mlir
786     %2 = call @my_add(%0, %1) : (f32, f32) -> f32
787     ```
788   }];
789
790   let arguments = (ins FlatSymbolRefAttr:$callee, Variadic<AnyType>:$operands);
791   let results = (outs Variadic<AnyType>);
792
793   let builders = [
794     OpBuilderDAG<(ins "FuncOp":$callee, CArg<"ValueRange", "{}">:$operands), [{
795       $_state.addOperands(operands);
796       $_state.addAttribute("callee",$_builder.getSymbolRefAttr(callee));
797       $_state.addTypes(callee.getType().getResults());
798     }]>,
799     OpBuilderDAG<(ins "SymbolRefAttr":$callee, "TypeRange":$results,
800       CArg<"ValueRange", "{}">:$operands), [{
801       $_state.addOperands(operands);
802       $_state.addAttribute("callee", callee);
803       $_state.addTypes(results);
804     }]>,
805     OpBuilderDAG<(ins "StringRef":$callee, "TypeRange":$results,
806       CArg<"ValueRange", "{}">:$operands), [{
807       build($_builder, $_state, $_builder.getSymbolRefAttr(callee), results,
808             operands);
809     }]>];
810
811   let extraClassDeclaration = [{
812     StringRef getCallee() { return callee(); }
813     FunctionType getCalleeType();
814
815     /// Get the argument operands to the called function.
816     operand_range getArgOperands() {
817       return {arg_operand_begin(), arg_operand_end()};
818     }
819
820     operand_iterator arg_operand_begin() { return operand_begin(); }
821     operand_iterator arg_operand_end() { return operand_end(); }
822
823     /// Return the callee of this operation.
824     CallInterfaceCallable getCallableForCallee() {
825       return (*this)->getAttrOfType<SymbolRefAttr>("callee");
826     }
827   }];
828
829   let assemblyFormat = [{
830     $callee `(` $operands `)` attr-dict `:` functional-type($operands, results)
831   }];
832   let verifier = ?;
833 }
834
835 //===----------------------------------------------------------------------===//
836 // CallIndirectOp
837 //===----------------------------------------------------------------------===//
838
839 def CallIndirectOp : Std_Op<"call_indirect", [
840       CallOpInterface,
841       TypesMatchWith<"callee input types match argument types",
842                      "callee", "operands",
843                      "$_self.cast<FunctionType>().getInputs()">,
844       TypesMatchWith<"callee result types match result types",
845                      "callee", "results",
846                      "$_self.cast<FunctionType>().getResults()">
847     ]> {
848   let summary = "indirect call operation";
849   let description = [{
850     The `call_indirect` operation represents an indirect call to a value of
851     function type. Functions are first class types in MLIR, and may be passed as
852     arguments and merged together with block arguments. The operands and result
853     types of the call must match the specified function type.
854
855     Function values can be created with the
856     [`constant` operation](#stdconstant-constantop).
857
858     Example:
859
860     ```mlir
861     %31 = call_indirect %15(%0, %1)
862             : (tensor<16xf32>, tensor<16xf32>) -> tensor<16xf32>
863     ```
864   }];
865
866   let arguments = (ins FunctionType:$callee, Variadic<AnyType>:$operands);
867   let results = (outs Variadic<AnyType>:$results);
868
869   let builders = [
870     OpBuilderDAG<(ins "Value":$callee, CArg<"ValueRange", "{}">:$operands), [{
871       $_state.operands.push_back(callee);
872       $_state.addOperands(operands);
873       $_state.addTypes(callee.getType().cast<FunctionType>().getResults());
874     }]>];
875
876   let extraClassDeclaration = [{
877     Value getCallee() { return getOperand(0); }
878
879     /// Get the argument operands to the called function.
880     operand_range getArgOperands() {
881       return {arg_operand_begin(), arg_operand_end()};
882     }
883
884     operand_iterator arg_operand_begin() { return ++operand_begin(); }
885     operand_iterator arg_operand_end() { return operand_end(); }
886
887     /// Return the callee of this operation.
888     CallInterfaceCallable getCallableForCallee() { return getCallee(); }
889   }];
890
891   let verifier = ?;
892   let hasCanonicalizer = 1;
893
894   let assemblyFormat = "$callee `(` $operands `)` attr-dict `:` type($callee)";
895 }
896
897 //===----------------------------------------------------------------------===//
898 // CeilFOp
899 //===----------------------------------------------------------------------===//
900
901 def CeilFOp : FloatUnaryOp<"ceilf"> {
902   let summary = "ceiling of the specified value";
903   let description = [{
904     Syntax:
905
906     ```
907     operation ::= ssa-id `=` `std.ceilf` ssa-use `:` type
908     ```
909
910     The `ceilf` operation computes the ceiling of a given value. It takes one
911     operand and returns one result of the same type. This type may be a float
912     scalar type, a vector whose element type is float, or a tensor of floats.
913     It has no standard attributes.
914
915     Example:
916
917     ```mlir
918     // Scalar ceiling value.
919     %a = ceilf %b : f64
920
921     // SIMD vector element-wise ceiling value.
922     %f = ceilf %g : vector<4xf32>
923
924     // Tensor element-wise ceiling value.
925     %x = ceilf %y : tensor<4x?xf8>
926     ```
927   }];
928 }
929
930 //===----------------------------------------------------------------------===//
931 // FloorFOp
932 //===----------------------------------------------------------------------===//
933
934 def FloorFOp : FloatUnaryOp<"floorf"> {
935   let summary = "floor of the specified value";
936   let description = [{
937     Syntax:
938
939     ```
940     operation ::= ssa-id `=` `std.floorf` ssa-use `:` type
941     ```
942
943     The `floorf` operation computes the floor of a given value. It takes one
944     operand and returns one result of the same type. This type may be a float
945     scalar type, a vector whose element type is float, or a tensor of floats.
946     It has no standard attributes.
947
948     Example:
949
950     ```mlir
951     // Scalar floor value.
952     %a = floorf %b : f64
953
954     // SIMD vector element-wise floor value.
955     %f = floorf %g : vector<4xf32>
956
957     // Tensor element-wise floor value.
958     %x = floorf %y : tensor<4x?xf8>
959     ```
960   }];
961 }
962
963 //===----------------------------------------------------------------------===//
964 // CmpFOp
965 //===----------------------------------------------------------------------===//
966
967 // The predicate indicates the type of the comparison to perform:
968 // (un)orderedness, (in)equality and less/greater than (or equal to) as
969 // well as predicates that are always true or false.
970 def CMPF_P_FALSE   : I64EnumAttrCase<"AlwaysFalse", 0, "false">;
971 def CMPF_P_OEQ     : I64EnumAttrCase<"OEQ", 1, "oeq">;
972 def CMPF_P_OGT     : I64EnumAttrCase<"OGT", 2, "ogt">;
973 def CMPF_P_OGE     : I64EnumAttrCase<"OGE", 3, "oge">;
974 def CMPF_P_OLT     : I64EnumAttrCase<"OLT", 4, "olt">;
975 def CMPF_P_OLE     : I64EnumAttrCase<"OLE", 5, "ole">;
976 def CMPF_P_ONE     : I64EnumAttrCase<"ONE", 6, "one">;
977 def CMPF_P_ORD     : I64EnumAttrCase<"ORD", 7, "ord">;
978 def CMPF_P_UEQ     : I64EnumAttrCase<"UEQ", 8, "ueq">;
979 def CMPF_P_UGT     : I64EnumAttrCase<"UGT", 9, "ugt">;
980 def CMPF_P_UGE     : I64EnumAttrCase<"UGE", 10, "uge">;
981 def CMPF_P_ULT     : I64EnumAttrCase<"ULT", 11, "ult">;
982 def CMPF_P_ULE     : I64EnumAttrCase<"ULE", 12, "ule">;
983 def CMPF_P_UNE     : I64EnumAttrCase<"UNE", 13, "une">;
984 def CMPF_P_UNO     : I64EnumAttrCase<"UNO", 14, "uno">;
985 def CMPF_P_TRUE    : I64EnumAttrCase<"AlwaysTrue", 15, "true">;
986
987 def CmpFPredicateAttr : I64EnumAttr<
988     "CmpFPredicate", "",
989     [CMPF_P_FALSE, CMPF_P_OEQ, CMPF_P_OGT, CMPF_P_OGE, CMPF_P_OLT, CMPF_P_OLE,
990      CMPF_P_ONE, CMPF_P_ORD, CMPF_P_UEQ, CMPF_P_UGT, CMPF_P_UGE, CMPF_P_ULT,
991      CMPF_P_ULE, CMPF_P_UNE, CMPF_P_UNO, CMPF_P_TRUE]> {
992   let cppNamespace = "::mlir";
993 }
994
995 def CmpFOp : Std_Op<"cmpf",
996     [NoSideEffect, SameTypeOperands, ElementwiseMappable,
997      DeclareOpInterfaceMethods<VectorUnrollOpInterface>,
998      TypesMatchWith<
999        "result type has i1 element type and same shape as operands",
1000        "lhs", "result", "getI1SameShape($_self)">]> {
1001   let summary = "floating-point comparison operation";
1002   let description = [{
1003     The `cmpf` operation compares its two operands according to the float
1004     comparison rules and the predicate specified by the respective attribute.
1005     The predicate defines the type of comparison: (un)orderedness, (in)equality
1006     and signed less/greater than (or equal to) as well as predicates that are
1007     always true or false.  The operands must have the same type, and this type
1008     must be a float type, or a vector or tensor thereof.  The result is an i1,
1009     or a vector/tensor thereof having the same shape as the inputs. Unlike cmpi,
1010     the operands are always treated as signed. The u prefix indicates
1011     *unordered* comparison, not unsigned comparison, so "une" means unordered or
1012     not equal. For the sake of readability by humans, custom assembly form for
1013     the operation uses a string-typed attribute for the predicate.  The value of
1014     this attribute corresponds to lower-cased name of the predicate constant,
1015     e.g., "one" means "ordered not equal".  The string representation of the
1016     attribute is merely a syntactic sugar and is converted to an integer
1017     attribute by the parser.
1018
1019     Example:
1020
1021     ```mlir
1022     %r1 = cmpf "oeq" %0, %1 : f32
1023     %r2 = cmpf "ult" %0, %1 : tensor<42x42xf64>
1024     %r3 = "std.cmpf"(%0, %1) {predicate: 0} : (f8, f8) -> i1
1025     ```
1026   }];
1027
1028   let arguments = (ins
1029     CmpFPredicateAttr:$predicate,
1030     FloatLike:$lhs,
1031     FloatLike:$rhs
1032   );
1033   let results = (outs BoolLike:$result);
1034
1035   let builders = [
1036     OpBuilderDAG<(ins "CmpFPredicate":$predicate, "Value":$lhs,
1037                   "Value":$rhs), [{
1038       ::buildCmpFOp($_builder, $_state, predicate, lhs, rhs);
1039     }]>];
1040
1041   let extraClassDeclaration = [{
1042     static StringRef getPredicateAttrName() { return "predicate"; }
1043     static CmpFPredicate getPredicateByName(StringRef name);
1044
1045     CmpFPredicate getPredicate() {
1046       return (CmpFPredicate)(*this)->getAttrOfType<IntegerAttr>(
1047           getPredicateAttrName()).getInt();
1048     }
1049   }];
1050
1051   let verifier = [{ return success(); }];
1052
1053   let hasFolder = 1;
1054
1055   let assemblyFormat = "$predicate `,` $lhs `,` $rhs attr-dict `:` type($lhs)";
1056 }
1057
1058 //===----------------------------------------------------------------------===//
1059 // CmpIOp
1060 //===----------------------------------------------------------------------===//
1061
1062 def CMPI_P_EQ  : I64EnumAttrCase<"eq", 0>;
1063 def CMPI_P_NE  : I64EnumAttrCase<"ne", 1>;
1064 def CMPI_P_SLT : I64EnumAttrCase<"slt", 2>;
1065 def CMPI_P_SLE : I64EnumAttrCase<"sle", 3>;
1066 def CMPI_P_SGT : I64EnumAttrCase<"sgt", 4>;
1067 def CMPI_P_SGE : I64EnumAttrCase<"sge", 5>;
1068 def CMPI_P_ULT : I64EnumAttrCase<"ult", 6>;
1069 def CMPI_P_ULE : I64EnumAttrCase<"ule", 7>;
1070 def CMPI_P_UGT : I64EnumAttrCase<"ugt", 8>;
1071 def CMPI_P_UGE : I64EnumAttrCase<"uge", 9>;
1072
1073 def CmpIPredicateAttr : I64EnumAttr<
1074     "CmpIPredicate", "",
1075     [CMPI_P_EQ, CMPI_P_NE, CMPI_P_SLT, CMPI_P_SLE, CMPI_P_SGT,
1076      CMPI_P_SGE, CMPI_P_ULT, CMPI_P_ULE, CMPI_P_UGT, CMPI_P_UGE]> {
1077   let cppNamespace = "::mlir";
1078 }
1079
1080 def CmpIOp : Std_Op<"cmpi",
1081     [NoSideEffect, SameTypeOperands, ElementwiseMappable,
1082      DeclareOpInterfaceMethods<VectorUnrollOpInterface>,
1083      TypesMatchWith<
1084        "result type has i1 element type and same shape as operands",
1085        "lhs", "result", "getI1SameShape($_self)">]> {
1086   let summary = "integer comparison operation";
1087   let description = [{
1088     The `cmpi` operation is a generic comparison for integer-like types. Its two
1089     arguments can be integers, vectors or tensors thereof as long as their types
1090     match. The operation produces an i1 for the former case, a vector or a
1091     tensor of i1 with the same shape as inputs in the other cases.
1092
1093     Its first argument is an attribute that defines which type of comparison is
1094     performed. The following comparisons are supported:
1095
1096     -   equal (mnemonic: `"eq"`; integer value: `0`)
1097     -   not equal (mnemonic: `"ne"`; integer value: `1`)
1098     -   signed less than (mnemonic: `"slt"`; integer value: `2`)
1099     -   signed less than or equal (mnemonic: `"sle"`; integer value: `3`)
1100     -   signed greater than (mnemonic: `"sgt"`; integer value: `4`)
1101     -   signed greater than or equal (mnemonic: `"sge"`; integer value: `5`)
1102     -   unsigned less than (mnemonic: `"ult"`; integer value: `6`)
1103     -   unsigned less than or equal (mnemonic: `"ule"`; integer value: `7`)
1104     -   unsigned greater than (mnemonic: `"ugt"`; integer value: `8`)
1105     -   unsigned greater than or equal (mnemonic: `"uge"`; integer value: `9`)
1106
1107     The result is `1` if the comparison is true and `0` otherwise. For vector or
1108     tensor operands, the comparison is performed elementwise and the element of
1109     the result indicates whether the comparison is true for the operand elements
1110     with the same indices as those of the result.
1111
1112     Note: while the custom assembly form uses strings, the actual underlying
1113     attribute has integer type (or rather enum class in C++ code) as seen from
1114     the generic assembly form. String literals are used to improve readability
1115     of the IR by humans.
1116
1117     This operation only applies to integer-like operands, but not floats. The
1118     main reason being that comparison operations have diverging sets of
1119     attributes: integers require sign specification while floats require various
1120     floating point-related particularities, e.g., `-ffast-math` behavior,
1121     IEEE754 compliance, etc
1122     ([rationale](../Rationale/Rationale.md#splitting-floating-point-vs-integer-operations)).
1123     The type of comparison is specified as attribute to avoid introducing ten
1124     similar operations, taking into account that they are often implemented
1125     using the same operation downstream
1126     ([rationale](../Rationale/Rationale.md#specifying-comparison-kind-as-attribute)). The
1127     separation between signed and unsigned order comparisons is necessary
1128     because of integers being signless. The comparison operation must know how
1129     to interpret values with the foremost bit being set: negatives in two's
1130     complement or large positives
1131     ([rationale](../Rationale/Rationale.md#specifying-sign-in-integer-comparison-operations)).
1132
1133     Example:
1134
1135     ```mlir
1136     // Custom form of scalar "signed less than" comparison.
1137     %x = cmpi "slt", %lhs, %rhs : i32
1138
1139     // Generic form of the same operation.
1140     %x = "std.cmpi"(%lhs, %rhs) {predicate = 2 : i64} : (i32, i32) -> i1
1141
1142     // Custom form of vector equality comparison.
1143     %x = cmpi "eq", %lhs, %rhs : vector<4xi64>
1144
1145     // Generic form of the same operation.
1146     %x = "std.cmpi"(%lhs, %rhs) {predicate = 0 : i64}
1147         : (vector<4xi64>, vector<4xi64>) -> vector<4xi1>
1148     ```
1149   }];
1150
1151   let arguments = (ins
1152       CmpIPredicateAttr:$predicate,
1153       SignlessIntegerLike:$lhs,
1154       SignlessIntegerLike:$rhs
1155   );
1156   let results = (outs BoolLike:$result);
1157
1158   let builders = [
1159     OpBuilderDAG<(ins "CmpIPredicate":$predicate, "Value":$lhs,
1160                  "Value":$rhs), [{
1161       ::buildCmpIOp($_builder, $_state, predicate, lhs, rhs);
1162     }]>];
1163
1164   let extraClassDeclaration = [{
1165     static StringRef getPredicateAttrName() { return "predicate"; }
1166     static CmpIPredicate getPredicateByName(StringRef name);
1167
1168     CmpIPredicate getPredicate() {
1169       return (CmpIPredicate)(*this)->getAttrOfType<IntegerAttr>(
1170           getPredicateAttrName()).getInt();
1171     }
1172   }];
1173
1174   let verifier = [{ return success(); }];
1175
1176   let hasFolder = 1;
1177
1178   let assemblyFormat = "$predicate `,` $lhs `,` $rhs attr-dict `:` type($lhs)";
1179 }
1180
1181 //===----------------------------------------------------------------------===//
1182 // CreateComplexOp
1183 //===----------------------------------------------------------------------===//
1184
1185 def CreateComplexOp : Std_Op<"create_complex",
1186     [NoSideEffect,
1187      AllTypesMatch<["real", "imaginary"]>,
1188      TypesMatchWith<"complex element type matches real operand type",
1189                     "complex", "real",
1190                     "$_self.cast<ComplexType>().getElementType()">,
1191      TypesMatchWith<"complex element type matches imaginary operand type",
1192                     "complex", "imaginary",
1193                     "$_self.cast<ComplexType>().getElementType()">]> {
1194   let summary = "creates a complex number";
1195   let description = [{
1196     The `create_complex` operation creates a complex number from two
1197     floating-point operands, the real and the imaginary part.
1198
1199     Example:
1200
1201     ```mlir
1202     %a = create_complex %b, %c : complex<f32>
1203     ```
1204   }];
1205
1206   let arguments = (ins AnyFloat:$real, AnyFloat:$imaginary);
1207   let results = (outs Complex<AnyFloat>:$complex);
1208
1209   let assemblyFormat = "$real `,` $imaginary attr-dict `:` type($complex)";
1210
1211   // `CreateComplexOp` is fully verified by its traits.
1212   let verifier = ?;
1213 }
1214
1215 //===----------------------------------------------------------------------===//
1216 // CondBranchOp
1217 //===----------------------------------------------------------------------===//
1218
1219 def CondBranchOp : Std_Op<"cond_br",
1220     [AttrSizedOperandSegments,
1221      DeclareOpInterfaceMethods<BranchOpInterface, ["getSuccessorForOperands"]>,
1222      NoSideEffect, Terminator]> {
1223   let summary = "conditional branch operation";
1224   let description = [{
1225     The `cond_br` terminator operation represents a conditional branch on a
1226     boolean (1-bit integer) value. If the bit is set, then the first destination
1227     is jumped to; if it is false, the second destination is chosen. The count
1228     and types of operands must align with the arguments in the corresponding
1229     target blocks.
1230
1231     The MLIR conditional branch operation is not allowed to target the entry
1232     block for a region. The two destinations of the conditional branch operation
1233     are allowed to be the same.
1234
1235     The following example illustrates a function with a conditional branch
1236     operation that targets the same block.
1237
1238     Example:
1239
1240     ```mlir
1241     func @select(%a: i32, %b: i32, %flag: i1) -> i32 {
1242       // Both targets are the same, operands differ
1243       cond_br %flag, ^bb1(%a : i32), ^bb1(%b : i32)
1244
1245     ^bb1(%x : i32) :
1246       return %x : i32
1247     }
1248     ```
1249   }];
1250
1251   let arguments = (ins I1:$condition,
1252                        Variadic<AnyType>:$trueDestOperands,
1253                        Variadic<AnyType>:$falseDestOperands);
1254   let successors = (successor AnySuccessor:$trueDest, AnySuccessor:$falseDest);
1255
1256   let builders = [
1257     OpBuilderDAG<(ins "Value":$condition, "Block *":$trueDest,
1258       "ValueRange":$trueOperands, "Block *":$falseDest,
1259       "ValueRange":$falseOperands), [{
1260       build($_builder, $_state, condition, trueOperands, falseOperands, trueDest,
1261             falseDest);
1262     }]>,
1263     OpBuilderDAG<(ins "Value":$condition, "Block *":$trueDest,
1264       "Block *":$falseDest, CArg<"ValueRange", "{}">:$falseOperands), [{
1265       build($_builder, $_state, condition, trueDest, ValueRange(), falseDest,
1266             falseOperands);
1267     }]>];
1268
1269   // CondBranchOp is fully verified by traits.
1270   let verifier = ?;
1271
1272   let extraClassDeclaration = [{
1273     // These are the indices into the dests list.
1274     enum { trueIndex = 0, falseIndex = 1 };
1275
1276     // The condition operand is the first operand in the list.
1277     Value getCondition() { return getOperand(0); }
1278
1279     /// Return the destination if the condition is true.
1280     Block *getTrueDest() {
1281       return getSuccessor(trueIndex);
1282     }
1283
1284     /// Return the destination if the condition is false.
1285     Block *getFalseDest() {
1286       return getSuccessor(falseIndex);
1287     }
1288
1289     // Accessors for operands to the 'true' destination.
1290     Value getTrueOperand(unsigned idx) {
1291       assert(idx < getNumTrueOperands());
1292       return getOperand(getTrueDestOperandIndex() + idx);
1293     }
1294
1295     void setTrueOperand(unsigned idx, Value value) {
1296       assert(idx < getNumTrueOperands());
1297       setOperand(getTrueDestOperandIndex() + idx, value);
1298     }
1299
1300     operand_range getTrueOperands() { return trueDestOperands(); }
1301
1302     unsigned getNumTrueOperands()  { return getTrueOperands().size(); }
1303
1304     /// Erase the operand at 'index' from the true operand list.
1305     void eraseTrueOperand(unsigned index)  {
1306       trueDestOperandsMutable().erase(index);
1307     }
1308
1309     // Accessors for operands to the 'false' destination.
1310     Value getFalseOperand(unsigned idx) {
1311       assert(idx < getNumFalseOperands());
1312       return getOperand(getFalseDestOperandIndex() + idx);
1313     }
1314     void setFalseOperand(unsigned idx, Value value) {
1315       assert(idx < getNumFalseOperands());
1316       setOperand(getFalseDestOperandIndex() + idx, value);
1317     }
1318
1319     operand_range getFalseOperands() { return falseDestOperands(); }
1320
1321     unsigned getNumFalseOperands() { return getFalseOperands().size(); }
1322
1323     /// Erase the operand at 'index' from the false operand list.
1324     void eraseFalseOperand(unsigned index) {
1325       falseDestOperandsMutable().erase(index);
1326     }
1327
1328   private:
1329     /// Get the index of the first true destination operand.
1330     unsigned getTrueDestOperandIndex() { return 1; }
1331
1332     /// Get the index of the first false destination operand.
1333     unsigned getFalseDestOperandIndex() {
1334       return getTrueDestOperandIndex() + getNumTrueOperands();
1335     }
1336   }];
1337
1338   let hasCanonicalizer = 1;
1339   let assemblyFormat = [{
1340     $condition `,`
1341     $trueDest (`(` $trueDestOperands^ `:` type($trueDestOperands) `)`)? `,`
1342     $falseDest (`(` $falseDestOperands^ `:` type($falseDestOperands) `)`)?
1343     attr-dict
1344   }];
1345 }
1346
1347 //===----------------------------------------------------------------------===//
1348 // ConstantOp
1349 //===----------------------------------------------------------------------===//
1350
1351 def ConstantOp : Std_Op<"constant",
1352     [ConstantLike, NoSideEffect, DeclareOpInterfaceMethods<OpAsmOpInterface>]> {
1353   let summary = "constant";
1354   let description = [{
1355     Syntax:
1356
1357     ```
1358     operation ::= ssa-id `=` `std.constant` attribute-value `:` type
1359     ```
1360
1361     The `constant` operation produces an SSA value equal to some constant
1362     specified by an attribute. This is the way that MLIR uses to form simple
1363     integer and floating point constants, as well as more exotic things like
1364     references to functions and tensor/vector constants.
1365
1366     Example:
1367
1368     ```mlir
1369     // Integer constant
1370     %1 = constant 42 : i32
1371
1372     // Reference to function @myfn.
1373     %3 = constant @myfn : (tensor<16xf32>, f32) -> tensor<16xf32>
1374
1375     // Equivalent generic forms
1376     %1 = "std.constant"() {value = 42 : i32} : () -> i32
1377     %3 = "std.constant"() {value = @myfn}
1378        : () -> ((tensor<16xf32>, f32) -> tensor<16xf32>)
1379     ```
1380
1381     MLIR does not allow direct references to functions in SSA operands because
1382     the compiler is multithreaded, and disallowing SSA values to directly
1383     reference a function simplifies this
1384     ([rationale](../Rationale/Rationale.md#multithreading-the-compiler)).
1385   }];
1386
1387   let arguments = (ins AnyAttr:$value);
1388   let results = (outs AnyType);
1389
1390   let builders = [
1391     OpBuilderDAG<(ins "Attribute":$value),
1392     [{ build($_builder, $_state, value.getType(), value); }]>];
1393
1394   let extraClassDeclaration = [{
1395     Attribute getValue() { return (*this)->getAttr("value"); }
1396
1397     /// Returns true if a constant operation can be built with the given value
1398     /// and result type.
1399     static bool isBuildableWith(Attribute value, Type type);
1400   }];
1401
1402   let hasFolder = 1;
1403 }
1404
1405 //===----------------------------------------------------------------------===//
1406 // CopySignOp
1407 //===----------------------------------------------------------------------===//
1408
1409 def CopySignOp : FloatArithmeticOp<"copysign"> {
1410   let summary = "A copysign operation";
1411   let description = [{
1412     Syntax:
1413
1414     ```
1415     operation ::= ssa-id `=` `std.copysign` ssa-use `:` type
1416     ```
1417
1418     The `copysign` returns a value with the magnitude of the first operand and
1419     the sign of the second operand. It takes two operands and returns one
1420     result of the same type. This type may be a float scalar type, a vector
1421     whose element type is float, or a tensor of floats. It has no standard
1422     attributes.
1423
1424     Example:
1425
1426     ```mlir
1427     // Scalar copysign value.
1428     %a = copysign %b %c : f64
1429
1430     // SIMD vector element-wise copysign value.
1431     %f = copysign %g %h : vector<4xf32>
1432
1433     // Tensor element-wise copysign value.
1434     %x = copysign %y %z : tensor<4x?xf8>
1435     ```
1436   }];
1437 }
1438
1439 //===----------------------------------------------------------------------===//
1440 // CosOp
1441 //===----------------------------------------------------------------------===//
1442
1443 def CosOp : FloatUnaryOp<"cos"> {
1444   let summary = "cosine of the specified value";
1445   let description = [{
1446     Syntax:
1447
1448     ```
1449     operation ::= ssa-id `=` `std.cos` ssa-use `:` type
1450     ```
1451
1452     The `cos` operation computes the cosine of a given value. It takes one
1453     operand and returns one result of the same type. This type may be a float
1454     scalar type, a vector whose element type is float, or a tensor of floats.
1455     It has no standard attributes.
1456
1457     Example:
1458
1459     ```mlir
1460     // Scalar cosine value.
1461     %a = cos %b : f64
1462
1463     // SIMD vector element-wise cosine value.
1464     %f = cos %g : vector<4xf32>
1465
1466     // Tensor element-wise cosine value.
1467     %x = cos %y : tensor<4x?xf8>
1468     ```
1469   }];
1470 }
1471
1472 //===----------------------------------------------------------------------===//
1473 // SinOp
1474 //===----------------------------------------------------------------------===//
1475
1476 def SinOp : FloatUnaryOp<"sin"> {
1477   let summary = "sine of the specified value";
1478   let description = [{
1479     Syntax:
1480
1481     ```
1482     operation ::= ssa-id `=` `std.sin` ssa-use `:` type
1483     ```
1484
1485     The `sin` operation computes the sine of a given value. It takes one
1486     operand and returns one result of the same type. This type may be a float
1487     scalar type, a vector whose element type is float, or a tensor of floats.
1488     It has no standard attributes.
1489
1490     Example:
1491
1492     ```mlir
1493     // Scalar sine value.
1494     %a = sin %b : f64
1495
1496     // SIMD vector element-wise sine value.
1497     %f = sin %g : vector<4xf32>
1498
1499     // Tensor element-wise sine value.
1500     %x = sin %y : tensor<4x?xf8>
1501     ```
1502   }];
1503 }
1504
1505 //===----------------------------------------------------------------------===//
1506 // DeallocOp
1507 //===----------------------------------------------------------------------===//
1508
1509 def DeallocOp : Std_Op<"dealloc", [MemRefsNormalizable]> {
1510   let summary = "memory deallocation operation";
1511   let description = [{
1512     The `dealloc` operation frees the region of memory referenced by a memref
1513     which was originally created by the `alloc` operation.
1514     The `dealloc` operation should not be called on memrefs which alias an
1515     alloc'd memref (e.g. memrefs returned by `view` operations).
1516
1517     Example:
1518
1519     ```mlir
1520     %0 = alloc() : memref<8x64xf32, (d0, d1) -> (d0, d1), 1>
1521     dealloc %0 : memref<8x64xf32, (d0, d1) -> (d0, d1), 1>
1522     ```
1523   }];
1524
1525   let arguments = (ins Arg<AnyMemRef, "", [MemFree]>:$memref);
1526
1527   let hasCanonicalizer = 1;
1528   let hasFolder = 1;
1529   let assemblyFormat = "$memref attr-dict `:` type($memref)";
1530 }
1531
1532 //===----------------------------------------------------------------------===//
1533 // DimOp
1534 //===----------------------------------------------------------------------===//
1535
1536 def DimOp : Std_Op<"dim", [NoSideEffect]> {
1537   let summary = "dimension index operation";
1538   let description = [{
1539     The `dim` operation takes a memref/tensor and a dimension operand of type
1540     `index`.
1541     It returns the size of the requested dimension of the given memref/tensor.
1542     If the dimension index is out of bounds the behavior is undefined.
1543
1544     The specified memref or tensor type is that of the first operand.
1545
1546     Example:
1547
1548     ```mlir
1549     // Always returns 4, can be constant folded:
1550     %c0 = constant 0 : index
1551     %x = = dim %A, %c0 : tensor<4 x ? x f32>
1552
1553     // Returns the dynamic dimension of %A.
1554     %c1 = constant 1 : index
1555     %y = dim %A, %c1 : tensor<4 x ? x f32>
1556
1557     // Equivalent generic form:
1558     %x = "std.dim"(%A, %c0) : (tensor<4 x ? x f32>, index) -> index
1559     %y = "std.dim"(%A, %c1) : (tensor<4 x ? x f32>, index) -> index
1560     ```
1561   }];
1562
1563   let arguments = (ins AnyTypeOf<[AnyRankedOrUnrankedMemRef, AnyTensor],
1564                                  "any tensor or memref type">:$memrefOrTensor,
1565                        Index:$index);
1566   let results = (outs Index:$result);
1567
1568   let assemblyFormat = [{
1569     attr-dict $memrefOrTensor `,` $index `:` type($memrefOrTensor)
1570   }];
1571
1572   let builders = [
1573     OpBuilderDAG<(ins "Value":$memrefOrTensor, "int64_t":$index)>,
1574     OpBuilderDAG<(ins "Value":$memrefOrTensor, "Value":$index)>
1575   ];
1576
1577   let extraClassDeclaration = [{
1578     /// Helper function to get the index as a simple integer if it is constant.
1579     Optional<int64_t> getConstantIndex();
1580   }];
1581
1582   let hasCanonicalizer = 1;
1583   let hasFolder = 1;
1584 }
1585
1586 //===----------------------------------------------------------------------===//
1587 // DivFOp
1588 //===----------------------------------------------------------------------===//
1589
1590 def DivFOp : FloatArithmeticOp<"divf"> {
1591   let summary = "floating point division operation";
1592   let hasFolder = 1;
1593 }
1594
1595 //===----------------------------------------------------------------------===//
1596 // ExpOp
1597 //===----------------------------------------------------------------------===//
1598
1599 def ExpOp : FloatUnaryOp<"exp"> {
1600   let summary = "base-e exponential of the specified value";
1601   let description = [{
1602     Syntax:
1603
1604     ```
1605     operation ::= ssa-id `=` `std.exp` ssa-use `:` type
1606     ```
1607
1608     The `exp` operation takes one operand and returns one result of the same
1609     type. This type may be a float scalar type, a vector whose element type is
1610     float, or a tensor of floats. It has no standard attributes.
1611
1612     Example:
1613
1614     ```mlir
1615     // Scalar natural exponential.
1616     %a = exp %b : f64
1617
1618     // SIMD vector element-wise natural exponential.
1619     %f = exp %g : vector<4xf32>
1620
1621     // Tensor element-wise natural exponential.
1622     %x = exp %y : tensor<4x?xf8>
1623     ```
1624   }];
1625 }
1626
1627 //===----------------------------------------------------------------------===//
1628 // ExpOp
1629 //===----------------------------------------------------------------------===//
1630
1631 def Exp2Op : FloatUnaryOp<"exp2"> {
1632   let summary = "base-2 exponential of the specified value";
1633 }
1634
1635 //===----------------------------------------------------------------------===//
1636 // FPExtOp
1637 //===----------------------------------------------------------------------===//
1638
1639 def FPExtOp : ArithmeticCastOp<"fpext">, Arguments<(ins AnyType:$in)> {
1640   let summary = "cast from floating-point to wider floating-point";
1641   let description = [{
1642     Cast a floating-point value to a larger floating-point-typed value.
1643     The destination type must to be strictly wider than the source type.
1644     Only scalars are currently supported.
1645   }];
1646
1647   let extraClassDeclaration = [{
1648     /// Return true if `a` and `b` are valid operand and result pairs for
1649     /// the operation.
1650     static bool areCastCompatible(Type a, Type b);
1651   }];
1652
1653   let hasFolder = 0;
1654 }
1655
1656 //===----------------------------------------------------------------------===//
1657 // FPToSIOp
1658 //===----------------------------------------------------------------------===//
1659
1660 def FPToSIOp : ArithmeticCastOp<"fptosi">, Arguments<(ins AnyType:$in)> {
1661   let summary = "cast from floating-point type to integer type";
1662   let description = [{
1663     Cast from a value interpreted as floating-point to the nearest (rounding
1664     towards zero) signed integer value.
1665   }];
1666
1667   let extraClassDeclaration = [{
1668     /// Return true if `a` and `b` are valid operand and result pairs for
1669     /// the operation.
1670     static bool areCastCompatible(Type a, Type b);
1671   }];
1672
1673   let hasFolder = 0;
1674 }
1675
1676 //===----------------------------------------------------------------------===//
1677 // FPToUIOp
1678 //===----------------------------------------------------------------------===//
1679
1680 def FPToUIOp : ArithmeticCastOp<"fptoui">, Arguments<(ins AnyType:$in)> {
1681   let summary = "cast from floating-point type to integer type";
1682   let description = [{
1683     Cast from a value interpreted as floating-point to the nearest (rounding
1684     towards zero) unsigned integer value.
1685   }];
1686
1687   let extraClassDeclaration = [{
1688     /// Return true if `a` and `b` are valid operand and result pairs for
1689     /// the operation.
1690     static bool areCastCompatible(Type a, Type b);
1691   }];
1692
1693   let hasFolder = 0;
1694 }
1695
1696 //===----------------------------------------------------------------------===//
1697 // FPTruncOp
1698 //===----------------------------------------------------------------------===//
1699
1700 def FPTruncOp : ArithmeticCastOp<"fptrunc">, Arguments<(ins AnyType:$in)> {
1701   let summary = "cast from floating-point to narrower floating-point";
1702   let description = [{
1703     Truncate a floating-point value to a smaller floating-point-typed value.
1704     The destination type must be strictly narrower than the source type.
1705     If the value cannot be exactly represented, it is rounded using the default
1706     rounding mode. Only scalars are currently supported.
1707   }];
1708
1709   let extraClassDeclaration = [{
1710     /// Return true if `a` and `b` are valid operand and result pairs for
1711     /// the operation.
1712     static bool areCastCompatible(Type a, Type b);
1713   }];
1714
1715   let hasFolder = 0;
1716 }
1717
1718 //===----------------------------------------------------------------------===//
1719 // GlobalMemrefOp
1720 //===----------------------------------------------------------------------===//
1721
1722 def GlobalMemrefOp : Std_Op<"global_memref", [Symbol]> {
1723   let summary = "declare or define a global memref variable";
1724   let description = [{
1725     The `global_memref` operation declares or defines a named global variable.
1726     The backing memory for the variable is allocated statically and is described
1727     by the type of the variable (which should be a statically shaped memref
1728     type). The operation is a declaration if no `inital_value` is specified,
1729     else it is a definition. The `initial_value` can either be a unit attribute
1730     to represent a definition of an uninitialized global variable, or an
1731     elements attribute to represent the definition of a global variable with an
1732     initial value. The global variable can also be marked constant using the
1733     `constant` unit attribute. Writing to such constant global variables is
1734     undefined.
1735
1736     The global variable can be accessed by using the `get_global_memref` to
1737     retrieve the memref for the global variable. Note that the memref
1738     for such global variable itself is immutable (i.e., get_global_memref for a
1739     given global variable will always return the same memref descriptor).
1740
1741     Example:
1742
1743     ```mlir
1744     // Private variable with an initial value.
1745     global_memref "private" @x : memref<2xf32> = dense<0.0,2.0>
1746
1747     // Declaration of an external variable.
1748     global_memref "private" @y : memref<4xi32>
1749
1750     // Uninitialized externally visible variable.
1751     global_memref @z : memref<3xf16> = uninitialized
1752
1753     // Externally visible constant variable.
1754     global_memref constant @c : memref<2xi32> = dense<1, 4>
1755     ```
1756   }];
1757
1758   let arguments = (ins
1759       SymbolNameAttr:$sym_name,
1760       OptionalAttr<StrAttr>:$sym_visibility,
1761       TypeAttr:$type,
1762       OptionalAttr<AnyAttr>:$initial_value,
1763       UnitAttr:$constant
1764   );
1765
1766   let assemblyFormat = [{
1767        ($sym_visibility^)?
1768        (`constant` $constant^)?
1769        $sym_name `:`
1770        custom<GlobalMemrefOpTypeAndInitialValue>($type, $initial_value)
1771        attr-dict
1772   }];
1773
1774   let extraClassDeclaration = [{
1775      bool isExternal() { return !initial_value(); }
1776      bool isUninitialized() {
1777        return !isExternal() && initial_value().getValue().isa<UnitAttr>();
1778      }
1779   }];
1780 }
1781
1782 //===----------------------------------------------------------------------===//
1783 // GetGlobalMemrefOp
1784 //===----------------------------------------------------------------------===//
1785
1786 def GetGlobalMemrefOp : Std_Op<"get_global_memref",
1787     [NoSideEffect, DeclareOpInterfaceMethods<SymbolUserOpInterface>]> {
1788   let summary = "get the memref pointing to a global variable";
1789   let description = [{
1790      The `get_global_memref` operation retrieves the memref pointing to a
1791      named global variable. If the global variable is marked constant, writing
1792      to the result memref (such as through a `std.store` operation) is
1793      undefined.
1794
1795      Example:
1796
1797      ```mlir
1798      %x = get_global_memref @foo : memref<2xf32>
1799      ```
1800   }];
1801
1802   let arguments = (ins FlatSymbolRefAttr:$name);
1803   let results = (outs AnyStaticShapeMemRef:$result);
1804   let assemblyFormat = "$name `:` type($result) attr-dict";
1805
1806   // `GetGlobalMemrefOp` is fully verified by its traits.
1807   let verifier = ?;
1808 }
1809
1810 //===----------------------------------------------------------------------===//
1811 // ImOp
1812 //===----------------------------------------------------------------------===//
1813
1814 def ImOp : Std_Op<"im",
1815     [NoSideEffect,
1816      TypesMatchWith<"complex element type matches result type",
1817                     "complex", "imaginary",
1818                     "$_self.cast<ComplexType>().getElementType()">]> {
1819   let summary = "extracts the imaginary part of a complex number";
1820   let description = [{
1821     The `im` operation takes a single complex number as its operand and extracts
1822     the imaginary part as a floating-point value.
1823
1824     Example:
1825
1826     ```mlir
1827     %a = im %b : complex<f32>
1828     ```
1829   }];
1830
1831   let arguments = (ins Complex<AnyFloat>:$complex);
1832   let results = (outs AnyFloat:$imaginary);
1833
1834   let assemblyFormat = "$complex attr-dict `:` type($complex)";
1835
1836   // `ImOp` is fully verified by its traits.
1837   let verifier = ?;
1838 }
1839
1840 //===----------------------------------------------------------------------===//
1841 // IndexCastOp
1842 //===----------------------------------------------------------------------===//
1843
1844 def IndexCastOp : ArithmeticCastOp<"index_cast">, Arguments<(ins AnyType:$in)> {
1845   let summary = "cast between index and integer types";
1846   let description = [{
1847     Casts between integer scalars and 'index' scalars. Index is an integer of
1848     platform-specific bit width. If casting to a wider integer, the value is
1849     sign-extended. If casting to a narrower integer, the value is truncated.
1850   }];
1851
1852   let extraClassDeclaration = [{
1853     /// Return true if `a` and `b` are valid operand and result pairs for
1854     /// the operation.
1855     static bool areCastCompatible(Type a, Type b);
1856   }];
1857
1858   let hasFolder = 1;
1859 }
1860
1861 //===----------------------------------------------------------------------===//
1862 // LoadOp
1863 //===----------------------------------------------------------------------===//
1864
1865 def LoadOp : Std_Op<"load",
1866      [TypesMatchWith<"result type matches element type of 'memref'",
1867                      "memref", "result",
1868                      "$_self.cast<MemRefType>().getElementType()">,
1869                      MemRefsNormalizable]> {
1870   let summary = "load operation";
1871   let description = [{
1872     The `load` op reads an element from a memref specified by an index list. The
1873     output of load is a new value with the same type as the elements of the
1874     memref. The arity of indices is the rank of the memref (i.e., if the memref
1875     loaded from is of rank 3, then 3 indices are required for the load following
1876     the memref identifier).
1877
1878     In an `affine.if` or `affine.for` body, the indices of a load are restricted
1879     to SSA values bound to surrounding loop induction variables,
1880     [symbols](Affine.md#dimensions-and-symbols), results of a
1881     [`constant` operation](#stdconstant-constantop), or the result of an
1882     `affine.apply` operation that can in turn take as arguments all of the
1883     aforementioned SSA values or the recursively result of such an
1884     `affine.apply` operation.
1885
1886     Example:
1887
1888     ```mlir
1889     %1 = affine.apply affine_map<(d0, d1) -> (3*d0)> (%i, %j)
1890     %2 = affine.apply affine_map<(d0, d1) -> (d1+1)> (%i, %j)
1891     %12 = load %A[%1, %2] : memref<8x?xi32, #layout, memspace0>
1892
1893     // Example of an indirect load (treated as non-affine)
1894     %3 = affine.apply affine_map<(d0) -> (2*d0 + 1)>(%12)
1895     %13 = load %A[%3, %2] : memref<4x?xi32, #layout, memspace0>
1896     ```
1897
1898     **Context:** The `load` and `store` operations are specifically crafted to
1899     fully resolve a reference to an element of a memref, and (in affine
1900     `affine.if` and `affine.for` operations) the compiler can follow use-def
1901     chains (e.g. through [`affine.apply`](Affine.md#affineapply-affineapplyop)
1902     operations) to precisely analyze references at compile-time using polyhedral
1903     techniques. This is possible because of the
1904     [restrictions on dimensions and symbols](Affine.md#restrictions-on-dimensions-and-symbols)
1905     in these contexts.
1906   }];
1907
1908   let arguments = (ins Arg<AnyMemRef, "the reference to load from",
1909                            [MemRead]>:$memref,
1910                        Variadic<Index>:$indices);
1911   let results = (outs AnyType:$result);
1912
1913   let builders = [
1914     OpBuilderDAG<(ins "Value":$memref, CArg<"ValueRange", "{}">:$indices), [{
1915       auto memrefType = memref.getType().cast<MemRefType>();
1916       $_state.addOperands(memref);
1917       $_state.addOperands(indices);
1918       $_state.types.push_back(memrefType.getElementType());
1919     }]>];
1920
1921   let extraClassDeclaration = [{
1922     Value getMemRef() { return getOperand(0); }
1923     void setMemRef(Value value) { setOperand(0, value); }
1924     MemRefType getMemRefType() {
1925       return getMemRef().getType().cast<MemRefType>();
1926     }
1927
1928     operand_range getIndices() { return {operand_begin() + 1, operand_end()}; }
1929   }];
1930
1931   let hasCanonicalizer = 1;
1932   let hasFolder = 1;
1933
1934   let assemblyFormat = "$memref `[` $indices `]` attr-dict `:` type($memref)";
1935 }
1936
1937 //===----------------------------------------------------------------------===//
1938 // LogOp
1939 //===----------------------------------------------------------------------===//
1940
1941 def LogOp : FloatUnaryOp<"log"> {
1942   let summary = "base-e logarithm of the specified value";
1943 }
1944
1945 def Log10Op : FloatUnaryOp<"log10"> {
1946   let summary = "base-10 logarithm of the specified value";
1947 }
1948
1949 def Log2Op : FloatUnaryOp<"log2"> {
1950   let summary = "base-2 logarithm of the specified value";
1951 }
1952
1953 //===----------------------------------------------------------------------===//
1954 // MemRefCastOp
1955 //===----------------------------------------------------------------------===//
1956
1957 def MemRefCastOp : CastOp<"memref_cast", [
1958     DeclareOpInterfaceMethods<ViewLikeOpInterface>
1959   ]> {
1960   let summary = "memref cast operation";
1961   let description = [{
1962     Syntax:
1963
1964     ```
1965     operation ::= ssa-id `=` `std.memref_cast` ssa-use `:` type `to` type
1966     ```
1967
1968     The `memref_cast` operation converts a memref from one type to an equivalent
1969     type with a compatible shape. The source and destination types are
1970     compatible if:
1971
1972     a. Both are ranked memref types with the same element type, address space,
1973     and rank and:
1974       1. Both have the same layout or both have compatible strided layouts.
1975       2. The individual sizes (resp. offset and strides in the case of strided
1976          memrefs) may convert constant dimensions to dynamic dimensions and
1977          vice-versa.
1978
1979     If the cast converts any dimensions from an unknown to a known size, then it
1980     acts as an assertion that fails at runtime if the dynamic dimensions
1981     disagree with resultant destination size.
1982
1983     Example:
1984
1985     ```mlir
1986     // Assert that the input dynamic shape matches the destination static shape.
1987     %2 = memref_cast %1 : memref<?x?xf32> to memref<4x4xf32>
1988     // Erase static shape information, replacing it with dynamic information.
1989     %3 = memref_cast %1 : memref<4xf32> to memref<?xf32>
1990
1991     // The same holds true for offsets and strides.
1992
1993     // Assert that the input dynamic shape matches the destination static stride.
1994     %4 = memref_cast %1 : memref<12x4xf32, offset:?, strides: [?, ?]> to
1995                           memref<12x4xf32, offset:5, strides: [4, 1]>
1996     // Erase static offset and stride information, replacing it with
1997     // dynamic information.
1998     %5 = memref_cast %1 : memref<12x4xf32, offset:5, strides: [4, 1]> to
1999                           memref<12x4xf32, offset:?, strides: [?, ?]>
2000     ```
2001
2002     b. Either or both memref types are unranked with the same element type, and
2003     address space.
2004
2005     Example:
2006
2007     ```mlir
2008     Cast to concrete shape.
2009         %4 = memref_cast %1 : memref<*xf32> to memref<4x?xf32>
2010
2011     Erase rank information.
2012         %5 = memref_cast %1 : memref<4x?xf32> to memref<*xf32>
2013     ```
2014   }];
2015
2016   let arguments = (ins AnyRankedOrUnrankedMemRef:$source);
2017   let results = (outs AnyRankedOrUnrankedMemRef);
2018
2019   let extraClassDeclaration = [{
2020     /// Return true if `a` and `b` are valid operand and result pairs for
2021     /// the operation.
2022     static bool areCastCompatible(Type a, Type b);
2023
2024     /// The result of a memref_cast is always a memref.
2025     Type getType() { return getResult().getType(); }
2026   }];
2027 }
2028
2029
2030 //===----------------------------------------------------------------------===//
2031 // MemRefReinterpretCastOp
2032 //===----------------------------------------------------------------------===//
2033
2034 def MemRefReinterpretCastOp:
2035     BaseOpWithOffsetSizesAndStrides<"memref_reinterpret_cast", [
2036       NoSideEffect, ViewLikeOpInterface, OffsetSizeAndStrideOpInterface
2037     ]> {
2038   let summary = "memref reinterpret cast operation";
2039   let description = [{
2040     Modify offset, sizes and strides of an unranked/ranked memref.
2041
2042     Example:
2043     ```mlir
2044     memref_reinterpret_cast %ranked to
2045       offset: [0],
2046       sizes: [%size0, 10],
2047       strides: [1, %stride1]
2048     : memref<?x?xf32> to memref<?x10xf32, offset: 0, strides: [1, ?]>
2049
2050     memref_reinterpret_cast %unranked to
2051       offset: [%offset],
2052       sizes: [%size0, %size1],
2053       strides: [%stride0, %stride1]
2054     : memref<*xf32> to memref<?x?xf32, offset: ?, strides: [?, ?]>
2055     ```
2056   }];
2057
2058   let arguments = (ins
2059     Arg<AnyRankedOrUnrankedMemRef, "", []>:$source,
2060     Variadic<Index>:$offsets,
2061     Variadic<Index>:$sizes,
2062     Variadic<Index>:$strides,
2063     I64ArrayAttr:$static_offsets,
2064     I64ArrayAttr:$static_sizes,
2065     I64ArrayAttr:$static_strides
2066   );
2067   let results = (outs AnyMemRef:$result);
2068
2069   let builders = [
2070     // Build a ReinterpretCastOp with mixed static and dynamic entries.
2071     OpBuilderDAG<(ins "MemRefType":$resultType, "Value":$source,
2072       "int64_t":$staticOffset, "ArrayRef<int64_t>":$staticSizes,
2073       "ArrayRef<int64_t>":$staticStrides, "ValueRange":$offset,
2074       "ValueRange":$sizes, "ValueRange":$strides,
2075       CArg<"ArrayRef<NamedAttribute>", "{}">:$attrs)>,
2076     // Build a ReinterpretCastOp with all dynamic entries.
2077     OpBuilderDAG<(ins "MemRefType":$resultType, "Value":$source,
2078       "Value":$offset, "ValueRange":$sizes, "ValueRange":$strides,
2079       CArg<"ArrayRef<NamedAttribute>", "{}">:$attrs)>,
2080   ];
2081
2082   let extraClassDeclaration = extraBaseClassDeclaration # [{
2083     // The result of the op is always a ranked memref.
2084     MemRefType getType() { return getResult().getType().cast<MemRefType>(); }
2085     Value getViewSource() { return source(); }
2086
2087     /// Return the rank of the source ShapedType.
2088     unsigned getResultRank() {
2089       return getResult().getType().cast<ShapedType>().getRank();
2090     }
2091
2092     /// Return the expected rank of each of the`static_offsets`, `static_sizes`
2093     /// and `static_strides` attributes.
2094     std::array<unsigned, 3> getArrayAttrRanks() {
2095       unsigned resultRank = getResult().getType().cast<ShapedType>().getRank();
2096       return {1, resultRank, resultRank};
2097     }
2098
2099     /// Return the number of leading operands before the `offsets`, `sizes` and
2100     /// and `strides` operands.
2101     static unsigned getOffsetSizeAndStrideStartOperandIndex() { return 1; }
2102   }];
2103 }
2104
2105 //===----------------------------------------------------------------------===//
2106 // MemRefReshapeOp
2107 //===----------------------------------------------------------------------===//
2108
2109 def MemRefReshapeOp: Std_Op<"memref_reshape", [
2110     ViewLikeOpInterface, NoSideEffect]>  {
2111   let summary = "memref reshape operation";
2112   let description = [{
2113     The `memref_reshape` operation converts a memref from one type to an
2114     equivalent type with a provided shape. The data is never copied or
2115     modified.  The source and destination types are compatible if both have the
2116     same element type, same number of elements, address space and identity
2117     layout map. The following combinations are possible:
2118
2119     a. Source type is ranked or unranked. Shape argument has static size.
2120     Result type is ranked.
2121
2122     ```mlir
2123     // Reshape statically-shaped memref.
2124     %dst = memref_reshape %src(%shape)
2125              : (memref<4x1xf32>, memref<1xi32>) to memref<4xf32>
2126     %dst0 = memref_reshape %src(%shape0)
2127              : (memref<4x1xf32>, memref<2xi32>) to memref<2x2xf32>
2128     // Flatten unranked memref.
2129     %dst = memref_reshape %src(%shape)
2130              : (memref<*xf32>, memref<1xi32>) to memref<?xf32>
2131     ```
2132
2133     a. Source type is ranked or unranked. Shape argument has dynamic size.
2134     Result type is unranked.
2135
2136     ```mlir
2137     // Reshape dynamically-shaped 1D memref.
2138     %dst = memref_reshape %src(%shape)
2139              : (memref<?xf32>, memref<?xi32>) to memref<*xf32>
2140     // Reshape unranked memref.
2141     %dst = memref_reshape %src(%shape)
2142              : (memref<*xf32>, memref<?xi32>) to memref<*xf32>
2143     ```
2144   }];
2145
2146   let arguments = (ins
2147     AnyRankedOrUnrankedMemRef:$source,
2148     MemRefRankOf<[AnySignlessInteger, Index], [1]>:$shape
2149   );
2150   let results = (outs AnyRankedOrUnrankedMemRef:$result);
2151
2152   let builders = [OpBuilderDAG<
2153      (ins "MemRefType":$resultType, "Value":$operand, "Value":$shape), [{
2154        $_state.addOperands(operand);
2155        $_state.addOperands(shape);
2156        $_state.addTypes(resultType);
2157      }]>];
2158
2159   let extraClassDeclaration = [{
2160     MemRefType getType() { return getResult().getType().cast<MemRefType>(); }
2161     Value getViewSource() { return source(); }
2162   }];
2163
2164   let assemblyFormat = [{
2165     $source `(` $shape `)` attr-dict `:` functional-type(operands, results)
2166   }];
2167 }
2168
2169 //===----------------------------------------------------------------------===//
2170 // MulFOp
2171 //===----------------------------------------------------------------------===//
2172
2173 def MulFOp : FloatArithmeticOp<"mulf"> {
2174   let summary = "floating point multiplication operation";
2175   let description = [{
2176     Syntax:
2177
2178     ```
2179     operation ::= ssa-id `=` `std.mulf` ssa-use `,` ssa-use `:` type
2180     ```
2181
2182     The `mulf` operation takes two operands and returns one result, each of
2183     these is required to be the same type. This type may be a floating point
2184     scalar type, a vector whose element type is a floating point type, or a
2185     floating point tensor.
2186
2187     Example:
2188
2189     ```mlir
2190     // Scalar multiplication.
2191     %a = mulf %b, %c : f64
2192
2193     // SIMD pointwise vector multiplication, e.g. for Intel SSE.
2194     %f = mulf %g, %h : vector<4xf32>
2195
2196     // Tensor pointwise multiplication.
2197     %x = mulf %y, %z : tensor<4x?xbf16>
2198     ```
2199
2200     TODO: In the distant future, this will accept optional attributes for fast
2201     math, contraction, rounding mode, and other controls.
2202   }];
2203   let hasFolder = 1;
2204 }
2205
2206 //===----------------------------------------------------------------------===//
2207 // MulIOp
2208 //===----------------------------------------------------------------------===//
2209
2210 def MulIOp : IntArithmeticOp<"muli", [Commutative]> {
2211   let summary = "integer multiplication operation";
2212   let hasFolder = 1;
2213 }
2214
2215 //===----------------------------------------------------------------------===//
2216 // NegFOp
2217 //===----------------------------------------------------------------------===//
2218
2219 def NegFOp : FloatUnaryOp<"negf"> {
2220   let summary = "floating point negation";
2221   let description = [{
2222     Syntax:
2223
2224     ```
2225     operation ::= ssa-id `=` `negf` ssa-use `:` type
2226     ```
2227
2228     The `negf` operation computes the negation of a given value. It takes one
2229     operand and returns one result of the same type. This type may be a float
2230     scalar type, a vector whose element type is float, or a tensor of floats.
2231     It has no standard attributes.
2232
2233     Example:
2234
2235     ```mlir
2236     // Scalar negation value.
2237     %a = negf %b : f64
2238
2239     // SIMD vector element-wise negation value.
2240     %f = negf %g : vector<4xf32>
2241
2242     // Tensor element-wise negation value.
2243     %x = negf %y : tensor<4x?xf8>
2244     ```
2245   }];
2246 }
2247
2248 //===----------------------------------------------------------------------===//
2249 // OrOp
2250 //===----------------------------------------------------------------------===//
2251
2252 def OrOp : IntArithmeticOp<"or", [Commutative]> {
2253   let summary = "integer binary or";
2254   let description = [{
2255     Syntax:
2256
2257     ```
2258     operation ::= ssa-id `=` `or` ssa-use `,` ssa-use `:` type
2259     ```
2260
2261     The `or` operation takes two operands and returns one result, each of these
2262     is required to be the same type. This type may be an integer scalar type, a
2263     vector whose element type is integer, or a tensor of integers. It has no
2264     standard attributes.
2265
2266     Example:
2267
2268     ```mlir
2269     // Scalar integer bitwise or.
2270     %a = or %b, %c : i64
2271
2272     // SIMD vector element-wise bitwise integer or.
2273     %f = or %g, %h : vector<4xi32>
2274
2275     // Tensor element-wise bitwise integer or.
2276     %x = or %y, %z : tensor<4x?xi8>
2277     ```
2278   }];
2279   let hasFolder = 1;
2280 }
2281
2282 //===----------------------------------------------------------------------===//
2283 // PowFOp
2284 //===----------------------------------------------------------------------===//
2285
2286 def PowFOp : FloatArithmeticOp<"powf"> {
2287   let summary = "floating point raised to the power of operation";
2288   let description = [{
2289     Syntax:
2290
2291     ```
2292     operation ::= ssa-id `=` `std.powf` ssa-use `,` ssa-use `:` type
2293     ```
2294
2295     The `powf` operation takes two operands and returns one result, each of
2296     these is required to be the same type. This type may be a floating point
2297     scalar type, a vector whose element type is a floating point type, or a
2298     floating point tensor.
2299
2300     Example:
2301
2302     ```mlir
2303     // Scalar exponentiation.
2304     %a = powf %b, %c : f64
2305
2306     // SIMD pointwise vector exponentiation
2307     %f = powf %g, %h : vector<4xf32>
2308
2309     // Tensor pointwise exponentiation.
2310     %x = powf %y, %z : tensor<4x?xbf16>
2311     ```
2312   }];
2313 }
2314
2315 //===----------------------------------------------------------------------===//
2316 // PrefetchOp
2317 //===----------------------------------------------------------------------===//
2318
2319 def PrefetchOp : Std_Op<"prefetch"> {
2320   let summary = "prefetch operation";
2321   let description = [{
2322     The "prefetch" op prefetches data from a memref location described with
2323     subscript indices similar to std.load, and with three attributes: a
2324     read/write specifier, a locality hint, and a cache type specifier as shown
2325     below:
2326
2327     ```mlir
2328     prefetch %0[%i, %j], read, locality<3>, data : memref<400x400xi32>
2329     ```
2330
2331     The read/write specifier is either 'read' or 'write', the locality hint
2332     ranges from locality<0> (no locality) to locality<3> (extremely local keep
2333     in cache). The cache type specifier is either 'data' or 'instr'
2334     and specifies whether the prefetch is performed on data cache or on
2335     instruction cache.
2336   }];
2337
2338   let arguments = (ins AnyMemRef:$memref, Variadic<Index>:$indices,
2339                    BoolAttr:$isWrite,
2340                    Confined<I32Attr, [IntMinValue<0>,
2341                      IntMaxValue<3>]>:$localityHint,
2342                    BoolAttr:$isDataCache);
2343
2344   let extraClassDeclaration = [{
2345     MemRefType getMemRefType() {
2346       return memref().getType().cast<MemRefType>();
2347     }
2348     static StringRef getLocalityHintAttrName() { return "localityHint"; }
2349     static StringRef getIsWriteAttrName() { return "isWrite"; }
2350     static StringRef getIsDataCacheAttrName() { return "isDataCache"; }
2351   }];
2352
2353   let hasFolder = 1;
2354 }
2355
2356 //===----------------------------------------------------------------------===//
2357 // RankOp
2358 //===----------------------------------------------------------------------===//
2359
2360 def RankOp : Std_Op<"rank", [NoSideEffect]> {
2361   let summary = "rank operation";
2362   let description = [{
2363     The `rank` operation takes a memref/tensor operand and returns its rank.
2364
2365     Example:
2366
2367     ```mlir
2368     %1 = rank %arg0 : tensor<*xf32>
2369     %2 = rank %arg1 : memref<*xf32>
2370     ```
2371   }];
2372
2373   let arguments = (ins AnyTypeOf<[AnyRankedOrUnrankedMemRef, AnyTensor],
2374                                  "any tensor or memref type">:$memrefOrTensor);
2375   let results = (outs Index);
2376   let verifier = ?;
2377
2378   let builders = [
2379     OpBuilderDAG<(ins "Value":$tensor), [{
2380       auto indexType = $_builder.getIndexType();
2381       build($_builder, $_state, indexType, tensor);
2382     }]>];
2383
2384   let hasFolder = 1;
2385   let assemblyFormat = "$memrefOrTensor attr-dict `:` type($memrefOrTensor)";
2386 }
2387
2388 //===----------------------------------------------------------------------===//
2389 // ReOp
2390 //===----------------------------------------------------------------------===//
2391
2392 def ReOp : Std_Op<"re",
2393     [NoSideEffect,
2394      TypesMatchWith<"complex element type matches result type",
2395                     "complex", "real",
2396                     "$_self.cast<ComplexType>().getElementType()">]> {
2397   let summary = "extracts the real part of a complex number";
2398   let description = [{
2399     The `re` operation takes a single complex number as its operand and extracts
2400     the real part as a floating-point value.
2401
2402     Example:
2403
2404     ```mlir
2405     %a = re %b : complex<f32>
2406     ```
2407   }];
2408
2409   let arguments = (ins Complex<AnyFloat>:$complex);
2410   let results = (outs AnyFloat:$real);
2411
2412   let assemblyFormat = "$complex attr-dict `:` type($complex)";
2413
2414   // `ReOp` is fully verified by its traits.
2415   let verifier = ?;
2416 }
2417
2418 //===----------------------------------------------------------------------===//
2419 // RemFOp
2420 //===----------------------------------------------------------------------===//
2421
2422 def RemFOp : FloatArithmeticOp<"remf"> {
2423   let summary = "floating point division remainder operation";
2424 }
2425
2426 //===----------------------------------------------------------------------===//
2427 // ReturnOp
2428 //===----------------------------------------------------------------------===//
2429
2430 def ReturnOp : Std_Op<"return", [NoSideEffect, HasParent<"FuncOp">,
2431                                 MemRefsNormalizable, ReturnLike, Terminator]> {
2432   let summary = "return operation";
2433   let description = [{
2434     The `return` operation represents a return operation within a function.
2435     The operation takes variable number of operands and produces no results.
2436     The operand number and types must match the signature of the function
2437     that contains the operation.
2438
2439     Example:
2440
2441     ```mlir
2442     func @foo() : (i32, f8) {
2443       ...
2444       return %0, %1 : i32, f8
2445     }
2446     ```
2447   }];
2448
2449   let arguments = (ins Variadic<AnyType>:$operands);
2450
2451   let builders = [
2452     OpBuilderDAG<(ins),
2453     [{ build($_builder, $_state, llvm::None); }]>];
2454
2455   let assemblyFormat = "attr-dict ($operands^ `:` type($operands))?";
2456 }
2457
2458 //===----------------------------------------------------------------------===//
2459 // RsqrtOp
2460 //===----------------------------------------------------------------------===//
2461
2462 def RsqrtOp : FloatUnaryOp<"rsqrt"> {
2463   let summary = "reciprocal of sqrt (1 / sqrt of the specified value)";
2464   let description = [{
2465     The `rsqrt` operation computes the reciprocal of the square root. It takes
2466     one operand and returns one result of the same type. This type may be a
2467     float scalar type, a vector whose element type is float, or a tensor of
2468     floats. It has no standard attributes.
2469   }];
2470 }
2471
2472 //===----------------------------------------------------------------------===//
2473 // SelectOp
2474 //===----------------------------------------------------------------------===//
2475
2476 def SelectOp : Std_Op<"select", [NoSideEffect,
2477      AllTypesMatch<["true_value", "false_value", "result"]>,
2478      ElementwiseMappable, DeclareOpInterfaceMethods<VectorUnrollOpInterface>]> {
2479   let summary = "select operation";
2480   let description = [{
2481     The `select` operation chooses one value based on a binary condition
2482     supplied as its first operand. If the value of the first operand is `1`,
2483     the second operand is chosen, otherwise the third operand is chosen.
2484     The second and the third operand must have the same type.
2485
2486     The operation applies to vectors and tensors elementwise given the _shape_
2487     of all operands is identical. The choice is made for each element
2488     individually based on the value at the same position as the element in the
2489     condition operand. If an i1 is provided as the condition, the entire vector
2490     or tensor is chosen.
2491
2492     The `select` operation combined with [`cmpi`](#stdcmpi-cmpiop) can be used
2493     to implement `min` and `max` with signed or unsigned comparison semantics.
2494
2495     Example:
2496
2497     ```mlir
2498     // Custom form of scalar selection.
2499     %x = select %cond, %true, %false : i32
2500
2501     // Generic form of the same operation.
2502     %x = "std.select"(%cond, %true, %false) : (i1, i32, i32) -> i32
2503
2504     // Element-wise vector selection.
2505     %vx = std.select %vcond, %vtrue, %vfalse : vector<42xi1>, vector<42xf32>
2506
2507     // Full vector selection.
2508     %vx = std.select %cond, %vtrue, %vfalse : vector<42xf32>
2509     ```
2510   }];
2511
2512   let arguments = (ins BoolLike:$condition,
2513                        AnyType:$true_value,
2514                        AnyType:$false_value);
2515   let results = (outs AnyType:$result);
2516
2517   let builders = [
2518     OpBuilderDAG<(ins "Value":$condition, "Value":$trueValue,
2519       "Value":$falseValue), [{
2520       $_state.addOperands({condition, trueValue, falseValue});
2521       $_state.addTypes(trueValue.getType());
2522     }]>];
2523
2524   let extraClassDeclaration = [{
2525       Value getCondition() { return condition(); }
2526       Value getTrueValue() { return true_value(); }
2527       Value getFalseValue() { return false_value(); }
2528   }];
2529
2530   let hasFolder = 1;
2531 }
2532
2533 //===----------------------------------------------------------------------===//
2534 // ShiftLeftOp
2535 //===----------------------------------------------------------------------===//
2536
2537 def ShiftLeftOp : IntArithmeticOp<"shift_left"> {
2538   let summary = "integer left-shift";
2539   let description = [{
2540     The shift_left operation shifts an integer value to the left by a variable
2541     amount. The low order bits are filled with zeros.
2542
2543     Example:
2544
2545     ```mlir
2546     %1 = constant 5 : i8                       // %1 is 0b00000101
2547     %2 = constant 3 : i8
2548     %3 = shift_left %1, %2 : (i8, i8) -> i8    // %3 is 0b00101000
2549     ```
2550   }];
2551 }
2552
2553 //===----------------------------------------------------------------------===//
2554 // SignedDivIOp
2555 //===----------------------------------------------------------------------===//
2556
2557 def SignedDivIOp : IntArithmeticOp<"divi_signed"> {
2558   let summary = "signed integer division operation";
2559   let description = [{
2560     Syntax:
2561
2562     ```
2563     operation ::= ssa-id `=` `divi_signed` ssa-use `,` ssa-use `:` type
2564     ```
2565
2566     Signed integer division. Rounds towards zero. Treats the leading bit as
2567     sign, i.e. `6 / -2 = -3`.
2568
2569     Note: the semantics of division by zero or signed division overflow (minimum
2570     value divided by -1) is TBD; do NOT assume any specific behavior.
2571
2572     Example:
2573
2574     ```mlir
2575     // Scalar signed integer division.
2576     %a = divis %b, %c : i64
2577
2578     // SIMD vector element-wise division.
2579     %f = divis %g, %h : vector<4xi32>
2580
2581     // Tensor element-wise integer division.
2582     %x = divis %y, %z : tensor<4x?xi8>
2583     ```
2584   }];
2585   let hasFolder = 1;
2586 }
2587
2588 //===----------------------------------------------------------------------===//
2589 // SignedFloorDivIOp
2590 //===----------------------------------------------------------------------===//
2591
2592 def SignedFloorDivIOp : IntArithmeticOp<"floordivi_signed"> {
2593   let summary = "signed floor integer division operation";
2594   let description = [{
2595     Syntax:
2596
2597     ```
2598     operation ::= ssa-id `=` `floordivi_signed` ssa-use `,` ssa-use `:` type
2599     ```
2600
2601     Signed integer division. Rounds towards negative infinity, i.e. `5 / -2 = -3`.
2602
2603     Note: the semantics of division by zero or signed division overflow (minimum
2604     value divided by -1) is TBD; do NOT assume any specific behavior.
2605
2606     Example:
2607
2608     ```mlir
2609     // Scalar signed integer division.
2610     %a = floordivi_signed %b, %c : i64
2611
2612     ```
2613   }];
2614   let hasFolder = 1;
2615 }
2616
2617 //===----------------------------------------------------------------------===//
2618 // SignedCeilDivIOp
2619 //===----------------------------------------------------------------------===//
2620
2621 def SignedCeilDivIOp : IntArithmeticOp<"ceildivi_signed"> {
2622   let summary = "signed ceil integer division operation";
2623   let description = [{
2624     Syntax:
2625
2626     ```
2627     operation ::= ssa-id `=` `ceildivi_signed` ssa-use `,` ssa-use `:` type
2628     ```
2629
2630     Signed integer division. Rounds towards positive infinity, i.e. `7 / -2 = -3`.
2631
2632     Note: the semantics of division by zero or signed division overflow (minimum
2633     value divided by -1) is TBD; do NOT assume any specific behavior.
2634
2635     Example:
2636
2637     ```mlir
2638     // Scalar signed integer division.
2639     %a = ceildivi_signed %b, %c : i64
2640     ```
2641   }];
2642   let hasFolder = 1;
2643 }
2644
2645 //===----------------------------------------------------------------------===//
2646 // SignedRemIOp
2647 //===----------------------------------------------------------------------===//
2648
2649 def SignedRemIOp : IntArithmeticOp<"remi_signed"> {
2650   let summary = "signed integer division remainder operation";
2651   let description = [{
2652     Syntax:
2653
2654     ```
2655     operation ::= ssa-id `=` `std.remi_signed` ssa-use `,` ssa-use `:` type
2656     ```
2657
2658     Signed integer division remainder. Treats the leading bit as sign, i.e. `6 %
2659     -2 = 0`.
2660
2661     Note: the semantics of division by zero is TBD; do NOT assume any specific
2662     behavior.
2663
2664     Example:
2665
2666     ```mlir
2667     // Scalar signed integer division remainder.
2668     %a = remis %b, %c : i64
2669
2670     // SIMD vector element-wise division remainder.
2671     %f = remis %g, %h : vector<4xi32>
2672
2673     // Tensor element-wise integer division remainder.
2674     %x = remis %y, %z : tensor<4x?xi8>
2675     ```
2676   }];
2677   let hasFolder = 1;
2678 }
2679
2680 //===----------------------------------------------------------------------===//
2681 // SignedShiftRightOp
2682 //===----------------------------------------------------------------------===//
2683
2684 def SignedShiftRightOp : IntArithmeticOp<"shift_right_signed"> {
2685   let summary = "signed integer right-shift";
2686   let description = [{
2687     The shift_right_signed operation shifts an integer value to the right by
2688     a variable amount. The integer is interpreted as signed. The high order
2689     bits in the output are filled with copies of the most-significant bit
2690     of the shifted value (which means that the sign of the value is preserved).
2691
2692     Example:
2693
2694     ```mlir
2695     %1 = constant 160 : i8                             // %1 is 0b10100000
2696     %2 = constant 3 : i8
2697     %3 = shift_right_signed %1, %2 : (i8, i8) -> i8    // %3 is 0b11110100
2698     %4 = constant 96 : i8                              // %4 is 0b01100000
2699     %5 = shift_right_signed %4, %2 : (i8, i8) -> i8    // %5 is 0b00001100
2700     ```
2701   }];
2702 }
2703
2704 //===----------------------------------------------------------------------===//
2705 // SignExtendIOp
2706 //===----------------------------------------------------------------------===//
2707
2708 def SignExtendIOp : Std_Op<"sexti",
2709     [NoSideEffect, ElementwiseMappable,
2710     DeclareOpInterfaceMethods<VectorUnrollOpInterface>]> {
2711   let summary = "integer sign extension operation";
2712   let description = [{
2713     The integer sign extension operation takes an integer input of
2714     width M and an integer destination type of width N. The destination
2715     bit-width must be larger than the input bit-width (N > M).
2716     The top-most (N - M) bits of the output are filled with copies
2717     of the most-significant bit of the input.
2718
2719     Example:
2720
2721     ```mlir
2722     %1 = constant 5 : i3            // %1 is 0b101
2723     %2 = sexti %1 : i3 to i6        // %2 is 0b111101
2724     %3 = constant 2 : i3            // %3 is 0b010
2725     %4 = sexti %3 : i3 to i6        // %4 is 0b000010
2726
2727     %5 = sexti %0 : vector<2 x i32> to vector<2 x i64>
2728     ```
2729   }];
2730
2731   let arguments = (ins SignlessIntegerLike:$value);
2732   let results = (outs SignlessIntegerLike);
2733
2734   let builders = [
2735     OpBuilderDAG<(ins "Value":$value, "Type":$destType), [{
2736       $_state.addOperands(value);
2737       $_state.addTypes(destType);
2738     }]>];
2739
2740   let parser = [{
2741     return impl::parseCastOp(parser, result);
2742   }];
2743   let printer = [{
2744     return printStandardCastOp(this->getOperation(), p);
2745   }];
2746 }
2747
2748 //===----------------------------------------------------------------------===//
2749 // SIToFPOp
2750 //===----------------------------------------------------------------------===//
2751
2752 def SIToFPOp : ArithmeticCastOp<"sitofp">, Arguments<(ins AnyType:$in)> {
2753   let summary = "cast from integer type to floating-point";
2754   let description = [{
2755     Cast from a value interpreted as signed or vector of signed integers to the
2756     corresponding floating-point scalar or vector value. If the value cannot be
2757     exactly represented, it is rounded using the default rounding mode. Scalars
2758     and vector types are currently supported.
2759   }];
2760
2761   let extraClassDeclaration = [{
2762     /// Return true if `a` and `b` are valid operand and result pairs for
2763     /// the operation.
2764     static bool areCastCompatible(Type a, Type b);
2765   }];
2766
2767   let hasFolder = 0;
2768 }
2769
2770 //===----------------------------------------------------------------------===//
2771 // SplatOp
2772 //===----------------------------------------------------------------------===//
2773
2774 def SplatOp : Std_Op<"splat", [NoSideEffect,
2775      TypesMatchWith<"operand type matches element type of result",
2776                     "aggregate", "input",
2777                     "$_self.cast<ShapedType>().getElementType()">]> {
2778   let summary = "splat or broadcast operation";
2779   let description = [{
2780     Broadcast the operand to all elements of the result vector or tensor. The
2781     operand has to be of either integer or float type. When the result is a
2782     tensor, it has to be statically shaped.
2783
2784     Example:
2785
2786     ```mlir
2787     %s = load %A[%i] : memref<128xf32>
2788     %v = splat %s : vector<4xf32>
2789     %t = splat %s : tensor<8x16xi32>
2790     ```
2791
2792     TODO: This operation is easy to extend to broadcast to dynamically shaped
2793     tensors in the same way dynamically shaped memrefs are handled.
2794
2795     ```mlir
2796     // Broadcasts %s to a 2-d dynamically shaped tensor, with %m, %n binding
2797     // to the sizes of the two dynamic dimensions.
2798     %m = "foo"() : () -> (index)
2799     %n = "bar"() : () -> (index)
2800     %t = splat %s [%m, %n] : tensor<?x?xi32>
2801     ```
2802   }];
2803
2804   let arguments = (ins AnyTypeOf<[AnySignlessInteger, AnyFloat],
2805                                  "integer or float type">:$input);
2806   let results = (outs AnyTypeOf<[AnyVector, AnyStaticShapeTensor]>:$aggregate);
2807
2808   let builders = [
2809     OpBuilderDAG<(ins "Value":$element, "Type":$aggregateType),
2810     [{ build($_builder, $_state, aggregateType, element); }]>];
2811
2812   let hasFolder = 1;
2813
2814   let assemblyFormat = "$input attr-dict `:` type($aggregate)";
2815 }
2816
2817 //===----------------------------------------------------------------------===//
2818 // SqrtOp
2819 //===----------------------------------------------------------------------===//
2820
2821 def SqrtOp : FloatUnaryOp<"sqrt"> {
2822   let summary = "sqrt of the specified value";
2823   let description = [{
2824     The `sqrt` operation computes the square root. It takes one operand and
2825     returns one result of the same type. This type may be a float scalar type, a
2826     vector whose element type is float, or a tensor of floats. It has no standard
2827     attributes.
2828
2829     Example:
2830
2831     ```mlir
2832     // Scalar square root value.
2833     %a = sqrt %b : f64
2834     // SIMD vector element-wise square root value.
2835     %f = sqrt %g : vector<4xf32>
2836     // Tensor element-wise square root value.
2837     %x = sqrt %y : tensor<4x?xf32>
2838     ```
2839   }];
2840 }
2841
2842 //===----------------------------------------------------------------------===//
2843 // StoreOp
2844 //===----------------------------------------------------------------------===//
2845
2846 def StoreOp : Std_Op<"store",
2847      [TypesMatchWith<"type of 'value' matches element type of 'memref'",
2848                      "memref", "value",
2849                      "$_self.cast<MemRefType>().getElementType()">,
2850                      MemRefsNormalizable]> {
2851   let summary = "store operation";
2852   let description = [{
2853     Store a value to a memref location given by indices. The value stored should
2854     have the same type as the elemental type of the memref. The number of
2855     arguments provided within brackets need to match the rank of the memref.
2856
2857     In an affine context, the indices of a store are restricted to SSA values
2858     bound to surrounding loop induction variables,
2859     [symbols](Affine.md#restrictions-on-dimensions-and-symbols), results of a
2860     [`constant` operation](#stdconstant-constantop), or the result of an
2861     [`affine.apply`](Affine.md#affineapply-affineapplyop) operation that can in turn
2862     take as arguments all of the aforementioned SSA values or the recursively
2863     result of such an `affine.apply` operation.
2864
2865     Example:
2866
2867     ```mlir
2868     store %100, %A[%1, 1023] : memref<4x?xf32, #layout, memspace0>
2869     ```
2870
2871     **Context:** The `load` and `store` operations are specifically crafted to
2872     fully resolve a reference to an element of a memref, and (in polyhedral
2873     `affine.if` and `affine.for` operations) the compiler can follow use-def
2874     chains (e.g. through [`affine.apply`](Affine.md#affineapply-affineapplyop)
2875     operations) to precisely analyze references at compile-time using polyhedral
2876     techniques. This is possible because of the
2877     [restrictions on dimensions and symbols](Affine.md#restrictions-on-dimensions-and-symbols)
2878     in these contexts.
2879   }];
2880
2881   let arguments = (ins AnyType:$value,
2882                        Arg<AnyMemRef, "the reference to store to",
2883                            [MemWrite]>:$memref,
2884                        Variadic<Index>:$indices);
2885
2886   let builders = [
2887     OpBuilderDAG<(ins "Value":$valueToStore, "Value":$memref), [{
2888       $_state.addOperands(valueToStore);
2889       $_state.addOperands(memref);
2890     }]>];
2891
2892   let extraClassDeclaration = [{
2893       Value getValueToStore() { return getOperand(0); }
2894
2895       Value getMemRef() { return getOperand(1); }
2896       void setMemRef(Value value) { setOperand(1, value); }
2897       MemRefType getMemRefType() {
2898         return getMemRef().getType().cast<MemRefType>();
2899       }
2900
2901       operand_range getIndices() {
2902         return {operand_begin() + 2, operand_end()};
2903       }
2904   }];
2905
2906   let hasFolder = 1;
2907
2908   let assemblyFormat = [{
2909     $value `,` $memref `[` $indices `]` attr-dict `:` type($memref)
2910   }];
2911 }
2912
2913 //===----------------------------------------------------------------------===//
2914 // SubCFOp
2915 //===----------------------------------------------------------------------===//
2916
2917 def SubCFOp : ComplexFloatArithmeticOp<"subcf"> {
2918   let summary = "complex number subtraction";
2919   let description = [{
2920     The `subcf` operation takes two complex number operands and returns their
2921     difference, a single complex number.
2922     All operands and result must be of the same type, a complex number with a
2923     floating-point element type.
2924
2925     Example:
2926
2927     ```mlir
2928     %a = subcf %b, %c : complex<f32>
2929     ```
2930   }];
2931 }
2932
2933 //===----------------------------------------------------------------------===//
2934 // SubFOp
2935 //===----------------------------------------------------------------------===//
2936
2937 def SubFOp : FloatArithmeticOp<"subf"> {
2938   let summary = "floating point subtraction operation";
2939   let hasFolder = 1;
2940 }
2941
2942 //===----------------------------------------------------------------------===//
2943 // SubIOp
2944 //===----------------------------------------------------------------------===//
2945
2946 def SubIOp : IntArithmeticOp<"subi"> {
2947   let summary = "integer subtraction operation";
2948   let hasFolder = 1;
2949 }
2950
2951 //===----------------------------------------------------------------------===//
2952 // SubViewOp
2953 //===----------------------------------------------------------------------===//
2954
2955 def SubViewOp : BaseOpWithOffsetSizesAndStrides<
2956     "subview", [DeclareOpInterfaceMethods<ViewLikeOpInterface>,
2957                 OffsetSizeAndStrideOpInterface] >  {
2958   let summary = "memref subview operation";
2959   let description = [{
2960     The "subview" operation converts a memref type to another memref type
2961     which represents a reduced-size view of the original memref as specified by
2962     the operation's offsets, sizes and strides arguments.
2963
2964     The SubView operation supports the following arguments:
2965
2966     * semref: the "base" memref on which to create a "view" memref.
2967     * offsets: memref-rank number of offsets into the "base" memref at which to
2968                create the "view" memref.
2969     * sizes: memref-rank number of sizes which specify the sizes of the result
2970              "view" memref type.
2971     * strides: memref-rank number of strides that compose multiplicatively with
2972                the base memref strides in each dimension.
2973
2974     The representation based on offsets, sizes and strides support a
2975     partially-static specification via attributes specified through the
2976     `static_offsets`, `static_sizes` and `static_strides` arguments. A special
2977     sentinel value ShapedType::kDynamicSize and
2978     ShapedType::kDynamicStrideOrOffset encodes that the corresponding entry has
2979     a dynamic value.
2980
2981     A subview operation may additionally reduce the rank of the resulting view
2982     by removing dimensions that are statically known to be of size 1.
2983
2984     Example 1:
2985
2986     ```mlir
2987     %0 = alloc() : memref<64x4xf32, (d0, d1) -> (d0 * 4 + d1)>
2988
2989     // Create a sub-view of "base" memref '%0' with offset arguments '%c0',
2990     // dynamic sizes for each dimension, and stride arguments '%c1'.
2991     %1 = subview %0[%c0, %c0][%size0, %size1][%c1, %c1]
2992       : memref<64x4xf32, (d0, d1) -> (d0 * 4 + d1) > to
2993         memref<?x?xf32, (d0, d1)[s0, s1] -> (d0 * s1 + d1 + s0)>
2994     ```
2995
2996     Example 2:
2997
2998     ```mlir
2999     %0 = alloc() : memref<8x16x4xf32, (d0, d1, d1) -> (d0 * 64 + d1 * 4 + d2)>
3000
3001     // Create a sub-view of "base" memref '%0' with dynamic offsets, sizes,
3002     // and strides.
3003     // Note that dynamic offsets are represented by the linearized dynamic
3004     // offset symbol 's0' in the subview memref layout map, and that the
3005     // dynamic strides operands, after being applied to the base memref
3006     // strides in each dimension, are represented in the view memref layout
3007     // map as symbols 's1', 's2' and 's3'.
3008     %1 = subview %0[%i, %j, %k][%size0, %size1, %size2][%x, %y, %z]
3009       : memref<8x16x4xf32, (d0, d1, d2) -> (d0 * 64 + d1 * 4 + d2)> to
3010         memref<?x?x?xf32,
3011           (d0, d1, d2)[s0, s1, s2, s3] -> (d0 * s1 + d1 * s2 + d2 * s3 + s0)>
3012     ```
3013
3014     Example 3:
3015
3016     ```mlir
3017     %0 = alloc() : memref<8x16x4xf32, (d0, d1, d1) -> (d0 * 64 + d1 * 4 + d2)>
3018
3019     // Subview with constant offsets, sizes and strides.
3020     %1 = subview %0[0, 2, 0][4, 4, 4][64, 4, 1]
3021       : memref<8x16x4xf32, (d0, d1, d2) -> (d0 * 64 + d1 * 4 + d2)> to
3022         memref<4x4x4xf32, (d0, d1, d2) -> (d0 * 64 + d1 * 4 + d2 + 8)>
3023     ```
3024
3025     Example 4:
3026
3027     ```mlir
3028     %0 = alloc(%arg0, %arg1) : memref<?x?xf32>
3029
3030     // Subview with constant size, but dynamic offsets and
3031     // strides. The resulting memref has a static shape, but if the
3032     // base memref has an affine map to describe the layout, the result
3033     // memref also uses an affine map to describe the layout. The
3034     // strides of the result memref is computed as follows:
3035     //
3036     // Let #map1 represents the layout of the base memref, and #map2
3037     // represents the layout of the result memref. A #mapsubview can be
3038     // constructed to map an index from the result memref to the base
3039     // memref (note that the description below uses more convenient
3040     // naming for symbols, while in affine maps, symbols are
3041     // represented as unsigned numbers that identify that symbol in the
3042     // given affine map.
3043     //
3044     // #mapsubview = (d0, d1)[o0, o1, t0, t1] -> (d0 * t0 + o0, d1 * t1 + o1)
3045     //
3046     // where, o0, o1, ... are offsets, and t0, t1, ... are strides. Then,
3047     //
3048     // #map2 = #map1.compose(#mapsubview)
3049     //
3050     // If the layout map is represented as
3051     //
3052     // #map1 = (d0, d1)[s0, s1, s2] -> (d0 * s1 + d1 * s2 + s0)
3053     //
3054     // then,
3055     //
3056     // #map2 = (d0, d1)[s0, s1, s2, o0, o1, t0, t1] ->
3057     //              (d0 * s1 * t0 + d1 * s2 * t1 + o0 * s1 + o1 * s2 + s0)
3058     //
3059     // Representing this canonically
3060     //
3061     // #map2 = (d0, d1)[r0, r1, r2] -> (d0 * r1 + d1 * r2 + r0)
3062     //
3063     // where, r0 = o0 * s1 + o1 * s2 + s0, r1 = s1 * t0, r2 = s2 * t1.
3064     %1 = subview %0[%i, %j][4, 4][%x, %y] :
3065       : memref<?x?xf32, (d0, d1)[s0, s1, s2] -> (d0 * s1 + d1 * s2 + s0)> to
3066         memref<4x4xf32, (d0, d1)[r0, r1, r2] -> (d0 * r1 + d1 * r2 + r0)>
3067
3068     // Note that the subview op does not guarantee that the result
3069     // memref is "inbounds" w.r.t to base memref. It is upto the client
3070     // to ensure that the subview is accessed in a manner that is
3071     // in-bounds.
3072     ```
3073
3074     Example 5:
3075
3076     ```mlir
3077     // Rank-reducing subview.
3078     %1 = subview %0[0, 0, 0][1, 16, 4][1, 1, 1] :
3079       memref<8x16x4xf32> to memref<16x4xf32>
3080     %3 = subview %2[3, 4, 2][1, 6, 3][1, 1, 1] :
3081       memref<8x16x4xf32> to memref<6x3xf32, offset: 210, strides: [4, 1]>
3082     ```
3083     }
3084   }];
3085
3086   let arguments = (ins
3087     AnyMemRef:$source,
3088     Variadic<Index>:$offsets,
3089     Variadic<Index>:$sizes,
3090     Variadic<Index>:$strides,
3091     I64ArrayAttr:$static_offsets,
3092     I64ArrayAttr:$static_sizes,
3093     I64ArrayAttr:$static_strides
3094   );
3095   let results = (outs AnyMemRef:$result);
3096
3097   let builders = [
3098     // Build a SubViewOp with mixed static and dynamic entries.
3099     OpBuilderDAG<(ins "Value":$source, "ArrayRef<int64_t>":$staticOffsets,
3100       "ArrayRef<int64_t>":$staticSizes, "ArrayRef<int64_t>":$staticStrides,
3101       "ValueRange":$offsets, "ValueRange":$sizes, "ValueRange":$strides,
3102       CArg<"ArrayRef<NamedAttribute>", "{}">:$attrs)>,
3103     // Build a SubViewOp with all dynamic entries.
3104     OpBuilderDAG<(ins "Value":$source, "ValueRange":$offsets,
3105       "ValueRange":$sizes, "ValueRange":$strides,
3106       CArg<"ArrayRef<NamedAttribute>", "{}">:$attrs)>,
3107     // Build a SubViewOp with mixed static and dynamic entries
3108     // and custom result type.
3109     OpBuilderDAG<(ins "MemRefType":$resultType, "Value":$source,
3110       "ArrayRef<int64_t>":$staticOffsets, "ArrayRef<int64_t>":$staticSizes,
3111       "ArrayRef<int64_t>":$staticStrides, "ValueRange":$offsets,
3112       "ValueRange":$sizes, "ValueRange":$strides,
3113       CArg<"ArrayRef<NamedAttribute>", "{}">:$attrs)>,
3114     // Build a SubViewOp with all dynamic entries and custom result type.
3115     OpBuilderDAG<(ins "MemRefType":$resultType, "Value":$source,
3116       "ValueRange":$offsets, "ValueRange":$sizes, "ValueRange":$strides,
3117       CArg<"ArrayRef<NamedAttribute>", "{}">:$attrs)>
3118   ];
3119
3120   let extraClassDeclaration = extraBaseClassDeclaration # [{
3121     /// Returns the type of the base memref operand.
3122     MemRefType getSourceType() {
3123       return source().getType().cast<MemRefType>();
3124     }
3125
3126     /// The result of a subview is always a memref.
3127     MemRefType getType() { return getResult().getType().cast<MemRefType>(); }
3128
3129     /// A subview result type can be fully inferred from the source type and the
3130     /// static representation of offsets, sizes and strides. Special sentinels
3131     /// encode the dynamic case.
3132     static Type inferResultType(MemRefType sourceMemRefType,
3133                                 ArrayRef<int64_t> staticOffsets,
3134                                 ArrayRef<int64_t> staticSizes,
3135                                 ArrayRef<int64_t> staticStrides);
3136
3137     /// Return the expected rank of each of the`static_offsets`, `static_sizes`
3138     /// and `static_strides` attributes.
3139     std::array<unsigned, 3> getArrayAttrRanks() {
3140       unsigned rank = getSourceType().getRank();
3141       return {rank, rank, rank};
3142     }
3143
3144     /// Return the number of leading operands before the `offsets`, `sizes` and
3145     /// and `strides` operands.
3146     static unsigned getOffsetSizeAndStrideStartOperandIndex() { return 1; }
3147   }];
3148
3149   let hasCanonicalizer = 1;
3150   let hasFolder = 1;
3151 }
3152
3153 //===----------------------------------------------------------------------===//
3154 // SubTensorOp
3155 //===----------------------------------------------------------------------===//
3156
3157 def SubTensorOp : BaseOpWithOffsetSizesAndStrides<
3158     "subtensor", [OffsetSizeAndStrideOpInterface]> {
3159   let summary = "subtensor operation";
3160   let description = [{
3161     The "subtensor" operation extract a tensor from another tensor as
3162     specified by the operation's offsets, sizes and strides arguments.
3163
3164     The subtensor operation supports the following arguments:
3165
3166     * tensor: the "base" tensor from which to extract a subtensor.
3167     * offsets: tensor-rank number of offsets into the "base" tensor from which
3168                to extract the subtensor.
3169     * sizes: tensor-rank number of sizes which specify the sizes of the result
3170              tensor type.
3171     * strides: tensor-rank number of strides specifying subsampling in each
3172                dimension.
3173
3174     The representation based on offsets, sizes and strides support a
3175     partially-static specification via attributes specified through the
3176     `static_offsets`, `static_sizes` and `static_strides` arguments. A special
3177     sentinel value ShapedType::kDynamicSize and
3178     ShapedType::kDynamicStrideOrOffset encodes that the corresponding entry has
3179     a dynamic value.
3180
3181     After buffer-allocation, the "subtensor" op is expected to lower into a
3182     "subview" op.
3183
3184     A subtensor operation may additionally reduce the rank of the resulting
3185     tensor by removing dimensions that are statically known to be of size 1.
3186
3187     Example:
3188
3189     ```
3190     // Rank-reducing subtensor.
3191     %1 = subtensor %0[0, 0, 0][1, 16, 4][1, 1, 1] :
3192       tensor<8x16x4xf32> to tensor<16x4xf32>
3193     %3 = subtensor %2[3, 4, 2][1, 6, 3][1, 1, 1] :
3194       tensor<8x16x4xf32> to tensor<6x3xf32>
3195     ```
3196   }];
3197
3198   let arguments = (ins
3199     AnyRankedTensor:$source,
3200     Variadic<Index>:$offsets,
3201     Variadic<Index>:$sizes,
3202     Variadic<Index>:$strides,
3203     I64ArrayAttr:$static_offsets,
3204     I64ArrayAttr:$static_sizes,
3205     I64ArrayAttr:$static_strides
3206   );
3207   let results = (outs AnyRankedTensor:$result);
3208
3209   let builders = [
3210     // Build a SubTensorOp with mixed static and dynamic entries.
3211     OpBuilderDAG<(ins "Value":$source, "ArrayRef<int64_t>":$staticOffsets,
3212       "ArrayRef<int64_t>":$staticSizes, "ArrayRef<int64_t>":$staticStrides,
3213       "ValueRange":$offsets, "ValueRange":$sizes, "ValueRange":$strides,
3214       CArg<"ArrayRef<NamedAttribute>", "{}">:$attrs)>,
3215     // Build a SubTensorOp with all dynamic entries.
3216     OpBuilderDAG<(ins "Value":$source, "ValueRange":$offsets,
3217       "ValueRange":$sizes, "ValueRange":$strides,
3218       CArg<"ArrayRef<NamedAttribute>", "{}">:$attrs)>
3219   ];
3220
3221   let extraClassDeclaration = extraBaseClassDeclaration # [{
3222     /// Returns the type of the base tensor operand.
3223     RankedTensorType getSourceType() {
3224       return source().getType().cast<RankedTensorType>();
3225     }
3226
3227     /// The result of a subtensor is always a tensor.
3228     RankedTensorType getType() {
3229       return getResult().getType().cast<RankedTensorType>();
3230     }
3231
3232     /// A subview result type can be fully inferred from the source type and the
3233     /// static representation of offsets, sizes and strides. Special sentinels
3234     /// encode the dynamic case.
3235     static Type inferResultType(RankedTensorType sourceRankedTensorType,
3236                                 ArrayRef<int64_t> staticOffsets,
3237                                 ArrayRef<int64_t> staticSizes,
3238                                 ArrayRef<int64_t> staticStrides);
3239
3240     /// Return the expected rank of each of the`static_offsets`, `static_sizes`
3241     /// and `static_strides` attributes.
3242     std::array<unsigned, 3> getArrayAttrRanks() {
3243       unsigned rank = getSourceType().getRank();
3244       return {rank, rank, rank};
3245     }
3246
3247     /// Return the number of leading operands before the `offsets`, `sizes` and
3248     /// and `strides` operands.
3249     static unsigned getOffsetSizeAndStrideStartOperandIndex() { return 1; }
3250   }];
3251
3252   let hasCanonicalizer = 1;
3253 }
3254
3255 //===----------------------------------------------------------------------===//
3256 // SubTensorInsertOp
3257 //===----------------------------------------------------------------------===//
3258
3259 def SubTensorInsertOp : BaseOpWithOffsetSizesAndStrides<
3260     "subtensor_insert", [OffsetSizeAndStrideOpInterface]> {
3261   let summary = "subtensor_insert operation";
3262   let description = [{
3263     The "subtensor_insert" operation insert a tensor `source` into another
3264     tensor `dest` as specified by the operation's offsets, sizes and strides
3265     arguments.
3266
3267     It returns a copy of `dest` with the proper subtensor updated with the value
3268     of `source`.
3269
3270     The subtensor_insert operation has the encodes the following information:
3271
3272     * source: the tensor that is inserted.
3273     * dest: the tensor into which the source tensor is inserted.
3274     * offsets: tensor-rank number of offsets into the "base" tensor from which
3275                to extract the subtensor.
3276     * sizes: tensor-rank number of sizes which specify the sizes of the result
3277              tensor type.
3278     * strides: tensor-rank number of strides that specify subsampling in each
3279                dimension.
3280
3281     The representation based on offsets, sizes and strides support a
3282     partially-static specification via attributes specified through the
3283     `static_offsets`, `static_sizes` and `static_strides` arguments. A special
3284     sentinel value ShapedType::kDynamicSize and
3285     ShapedType::kDynamicStrideOrOffset encodes that the corresponding entry has
3286     a dynamic value.
3287
3288     After buffer-allocation, the "subtensor_insert" op is expected to become
3289     an in-place buffer update.
3290   }];
3291
3292   let arguments = (ins
3293     AnyRankedTensor:$source,
3294     AnyRankedTensor:$dest,
3295     Variadic<Index>:$offsets,
3296     Variadic<Index>:$sizes,
3297     Variadic<Index>:$strides,
3298     I64ArrayAttr:$static_offsets,
3299     I64ArrayAttr:$static_sizes,
3300     I64ArrayAttr:$static_strides
3301   );
3302   let results = (outs AnyRankedTensor:$result);
3303
3304   let builders = [
3305     // Build a SubTensorInsertOp with mixed static and dynamic entries.
3306     OpBuilderDAG<(ins "Value":$source, "Value":$dest,
3307       "ArrayRef<int64_t>":$staticOffsets, "ArrayRef<int64_t>":$staticSizes,
3308       "ArrayRef<int64_t>":$staticStrides, "ValueRange":$offsets,
3309       "ValueRange":$sizes, "ValueRange":$strides,
3310       CArg<"ArrayRef<NamedAttribute>", "{}">:$attrs)>,
3311     // Build a SubTensorInsertOp with all dynamic entries.
3312     OpBuilderDAG<(ins "Value":$source, "Value":$dest, "ValueRange":$offsets,
3313       "ValueRange":$sizes, "ValueRange":$strides,
3314       CArg<"ArrayRef<NamedAttribute>", "{}">:$attrs)>
3315   ];
3316
3317   let extraClassDeclaration = extraBaseClassDeclaration # [{
3318     /// Returns the type of the base tensor operand.
3319     RankedTensorType getSourceType() {
3320       return source().getType().cast<RankedTensorType>();
3321     }
3322
3323     /// The result of a subtensor is always a tensor.
3324     RankedTensorType getType() {
3325       return getResult().getType().cast<RankedTensorType>();
3326     }
3327
3328     /// Return the expected rank of each of the`static_offsets`, `static_sizes`
3329     /// and `static_strides` attributes.
3330     std::array<unsigned, 3> getArrayAttrRanks() {
3331       unsigned rank = getSourceType().getRank();
3332       return {rank, rank, rank};
3333     }
3334
3335     /// Return the number of leading operands before the `offsets`, `sizes` and
3336     /// and `strides` operands.
3337     static unsigned getOffsetSizeAndStrideStartOperandIndex() { return 2; }
3338   }];
3339 }
3340
3341 //===----------------------------------------------------------------------===//
3342 // TanhOp
3343 //===----------------------------------------------------------------------===//
3344
3345 def TanhOp : FloatUnaryOp<"tanh"> {
3346   let summary = "hyperbolic tangent of the specified value";
3347   let description = [{
3348     Syntax:
3349
3350     ```
3351     operation ::= ssa-id `=` `std.tanh` ssa-use `:` type
3352     ```
3353
3354     The `tanh` operation computes the hyperbolic tangent. It takes one operand
3355     and returns one result of the same type. This type may be a float scalar
3356     type, a vector whose element type is float, or a tensor of floats. It has
3357     no standard attributes.
3358
3359     Example:
3360
3361     ```mlir
3362     // Scalar hyperbolic tangent value.
3363     %a = tanh %b : f64
3364
3365     // SIMD vector element-wise hyperbolic tangent value.
3366     %f = tanh %g : vector<4xf32>
3367
3368     // Tensor element-wise hyperbolic tangent value.
3369     %x = tanh %y : tensor<4x?xf8>
3370     ```
3371   }];
3372 }
3373
3374 //===----------------------------------------------------------------------===//
3375 // TensorLoadOp
3376 //===----------------------------------------------------------------------===//
3377
3378 def TensorLoadOp : Std_Op<"tensor_load",
3379     [SameOperandsAndResultShape, SameOperandsAndResultElementType,
3380      TypesMatchWith<"result type matches tensor equivalent of 'memref'",
3381                     "memref", "result",
3382                     "getTensorTypeFromMemRefType($_self)">]> {
3383   let summary = "tensor load operation";
3384   let description = [{
3385     Create a tensor from a memref, making an independent copy of the element
3386     data. The result value is a tensor whose shape and element type match the
3387     memref operand.
3388
3389     The opposite of this op is tensor_to_memref. Together, these two ops are
3390     useful for source/target materializations when doing type conversions
3391     involving tensors and memrefs.
3392
3393     Example:
3394
3395     ```mlir
3396     // Produces a value of tensor<4x?xf32> type.
3397     %12 = tensor_load %10 : memref<4x?xf32, #layout, memspace0>
3398     ```
3399   }];
3400
3401   let arguments = (ins Arg<AnyRankedOrUnrankedMemRef,
3402                        "the reference to load from", [MemRead]>:$memref);
3403   let results = (outs AnyTensor:$result);
3404   // TensorLoadOp is fully verified by traits.
3405   let verifier = ?;
3406
3407   let builders = [
3408     OpBuilderDAG<(ins "Value":$memref), [{
3409       $_state.addOperands(memref);
3410       $_state.addTypes(getTensorTypeFromMemRefType(memref.getType()));
3411     }]>];
3412
3413   let extraClassDeclaration = [{
3414     /// The result of a tensor_load is always a tensor.
3415     TensorType getType() {
3416       Type resultType = getResult().getType();
3417       if (resultType.isa<TensorType>())
3418         return resultType.cast<TensorType>();
3419       return {};
3420     }
3421   }];
3422
3423   let assemblyFormat = "$memref attr-dict `:` type($memref)";
3424
3425   let hasFolder = 1;
3426 }
3427
3428 //===----------------------------------------------------------------------===//
3429 // TensorStoreOp
3430 //===----------------------------------------------------------------------===//
3431
3432 def TensorStoreOp : Std_Op<"tensor_store",
3433     [SameOperandsShape, SameOperandsElementType,
3434      TypesMatchWith<"type of 'value' matches tensor equivalent of 'memref'",
3435                     "memref", "tensor",
3436                     "getTensorTypeFromMemRefType($_self)">]> {
3437   let summary = "tensor store operation";
3438   let description = [{
3439     Stores the contents of a tensor into a memref. The first operand is a value
3440     of tensor type, the second operand is a value of memref type. The shapes and
3441     element types of these must match, and are specified by the memref type.
3442
3443     Example:
3444
3445     ```mlir
3446     %9 = dim %8, 1 : tensor<4x?xf32>
3447     %10 = alloc(%9) : memref<4x?xf32, #layout, memspace0>
3448     tensor_store %8, %10 : memref<4x?xf32, #layout, memspace0>
3449     ```
3450   }];
3451
3452   let arguments = (ins AnyTensor:$tensor, Arg<AnyRankedOrUnrankedMemRef,
3453                        "the reference to store to", [MemWrite]>:$memref);
3454   // TensorStoreOp is fully verified by traits.
3455   let verifier = ?;
3456
3457   let assemblyFormat = "$tensor `,` $memref attr-dict `:` type($memref)";
3458 }
3459
3460 //===----------------------------------------------------------------------===//
3461 // TensorToMemrefOp
3462 //===----------------------------------------------------------------------===//
3463
3464 def TensorToMemrefOp : Std_Op<"tensor_to_memref",
3465     [SameOperandsAndResultShape, SameOperandsAndResultElementType,
3466      TypesMatchWith<"type of 'tensor' is the tensor equivalent of 'memref'",
3467                     "memref", "tensor",
3468                     "getTensorTypeFromMemRefType($_self)">]> {
3469   let summary = "tensor to memref operation";
3470   let description = [{
3471     Create a memref from a tensor. This is a transient op created as a
3472     materialization during type conversions between tensors and memrefs.
3473
3474     The opposite of this op is tensor_load. Together, these two ops are useful
3475     for source/target materializations when doing type conversions involving
3476     tensors and memrefs.
3477
3478     This op is defined by the fold
3479     `tensor_to_memref(tensor_load(%memref)) -> %memref`, which is the property
3480     that makes it a valid materialization in the type conversion framework.
3481     This implies that one cannot assume that this op allocates a new memref for
3482     its result.
3483
3484     Note: This op takes the memref type in its pretty form because the tensor
3485     type can always be inferred from the memref type, but the reverse is not
3486     true. For example, the memref might have a layout map or memory space which
3487     cannot be inferred from the tensor type.
3488
3489     ```mlir
3490     // Result type is tensor<4x?xf32>
3491     %12 = tensor_to_memref %10 : memref<4x?xf32, #map0, 42>
3492     ```
3493   }];
3494
3495   let arguments = (ins AnyTensor:$tensor);
3496   let results = (outs AnyRankedOrUnrankedMemRef:$memref);
3497   // This op is fully verified by traits.
3498   let verifier = ?;
3499
3500   let assemblyFormat = "$tensor attr-dict `:` type($memref)";
3501
3502   let hasFolder = 1;
3503 }
3504
3505 //===----------------------------------------------------------------------===//
3506 // TransposeOp
3507 //===----------------------------------------------------------------------===//
3508
3509 def TransposeOp : Std_Op<"transpose", [NoSideEffect]>,
3510     Arguments<(ins AnyStridedMemRef:$in, AffineMapAttr:$permutation)>,
3511     Results<(outs AnyStridedMemRef)> {
3512   let summary = "`transpose` produces a new strided memref (metadata-only)";
3513   let description = [{
3514     The `transpose` op produces a strided memref whose sizes and strides
3515     are a permutation of the original `in` memref. This is purely a metadata
3516     transformation.
3517
3518     Example:
3519
3520     ```mlir
3521     %1 = transpose %0 (i, j) -> (j, i) : memref<?x?xf32> to memref<?x?xf32, affine_map<(d0, d1)[s0] -> (d1 * s0 + d0)>>
3522     ```
3523   }];
3524
3525   let builders = [
3526     OpBuilderDAG<(ins "Value":$in, "AffineMapAttr":$permutation,
3527       CArg<"ArrayRef<NamedAttribute>", "{}">:$attrs)>];
3528
3529   let extraClassDeclaration = [{
3530     static StringRef getPermutationAttrName() { return "permutation"; }
3531     ShapedType getShapedType() { return in().getType().cast<ShapedType>(); }
3532   }];
3533
3534   let hasFolder = 1;
3535 }
3536
3537 //===----------------------------------------------------------------------===//
3538 // TruncateIOp
3539 //===----------------------------------------------------------------------===//
3540
3541 def TruncateIOp : Std_Op<"trunci",
3542   [NoSideEffect, ElementwiseMappable,
3543    DeclareOpInterfaceMethods<VectorUnrollOpInterface>,]> {
3544   let summary = "integer truncation operation";
3545   let description = [{
3546     The integer truncation operation takes an integer input of
3547     width M and an integer destination type of width N. The destination
3548     bit-width must be smaller than the input bit-width (N < M).
3549     The top-most (N - M) bits of the input are discarded.
3550
3551     Example:
3552
3553     ```mlir
3554       %1 = constant 21 : i5           // %1 is 0b10101
3555       %2 = trunci %1 : i5 to i4       // %2 is 0b0101
3556       %3 = trunci %1 : i5 to i3       // %3 is 0b101
3557
3558       %5 = trunci %0 : vector<2 x i32> to vector<2 x i16>
3559     ```
3560   }];
3561
3562   let arguments = (ins SignlessIntegerLike:$value);
3563   let results = (outs SignlessIntegerLike);
3564
3565   let builders = [
3566     OpBuilderDAG<(ins "Value":$value, "Type":$destType), [{
3567       $_state.addOperands(value);
3568       $_state.addTypes(destType);
3569     }]>];
3570
3571   let parser = [{
3572     return impl::parseCastOp(parser, result);
3573   }];
3574   let printer = [{
3575     return printStandardCastOp(this->getOperation(), p);
3576   }];
3577 }
3578
3579 //===----------------------------------------------------------------------===//
3580 // UIToFPOp
3581 //===----------------------------------------------------------------------===//
3582
3583 def UIToFPOp : ArithmeticCastOp<"uitofp">, Arguments<(ins AnyType:$in)> {
3584   let summary = "cast from unsigned integer type to floating-point";
3585   let description = [{
3586     Cast from a value interpreted as unsigned integer or vector of unsigned
3587     integers to the corresponding scalar or vector floating-point value. If the
3588     value cannot be exactly represented, it is rounded using the default
3589     rounding mode. Scalars and vector types are currently supported.
3590   }];
3591
3592   let extraClassDeclaration = [{
3593     /// Return true if `a` and `b` are valid operand and result pairs for
3594     /// the operation.
3595     static bool areCastCompatible(Type a, Type b);
3596   }];
3597
3598   let hasFolder = 0;
3599 }
3600
3601 //===----------------------------------------------------------------------===//
3602 // UnsignedDivIOp
3603 //===----------------------------------------------------------------------===//
3604
3605 def UnsignedDivIOp : IntArithmeticOp<"divi_unsigned"> {
3606   let summary = "unsigned integer division operation";
3607   let description = [{
3608     Syntax:
3609     ```
3610     operation ::= ssa-id `=` `std.divi_unsigned` ssa-use `,` ssa-use `:` type
3611     ```
3612
3613     Unsigned integer division. Rounds towards zero. Treats the leading bit as
3614     the most significant, i.e. for `i16` given two's complement representation,
3615     `6 / -2 = 6 / (2^16 - 2) = 0`.
3616
3617     Note: the semantics of division by zero is TBD; do NOT assume any specific
3618     behavior.
3619
3620     Example:
3621
3622     ```mlir
3623     // Scalar unsigned integer division.
3624     %a = diviu %b, %c : i64
3625
3626     // SIMD vector element-wise division.
3627     %f = diviu %g, %h : vector<4xi32>
3628
3629     // Tensor element-wise integer division.
3630     %x = diviu %y, %z : tensor<4x?xi8>
3631     ```
3632   }];
3633   let hasFolder = 1;
3634 }
3635
3636 //===----------------------------------------------------------------------===//
3637 // UnsignedRemIOp
3638 //===----------------------------------------------------------------------===//
3639
3640 def UnsignedRemIOp : IntArithmeticOp<"remi_unsigned"> {
3641   let summary = "unsigned integer division remainder operation";
3642   let description = [{
3643     Syntax:
3644
3645     ```
3646     operation ::= ssa-id `=` `std.remi_unsigned` ssa-use `,` ssa-use `:` type
3647     ```
3648
3649     Unsigned integer division remainder. Treats the leading bit as the most
3650     significant, i.e. for `i16`, `6 % -2 = 6 % (2^16 - 2) = 6`.
3651
3652     Note: the semantics of division by zero is TBD; do NOT assume any specific
3653     behavior.
3654
3655     Example:
3656
3657     ```mlir
3658     // Scalar unsigned integer division remainder.
3659     %a = remiu %b, %c : i64
3660
3661     // SIMD vector element-wise division remainder.
3662     %f = remiu %g, %h : vector<4xi32>
3663
3664     // Tensor element-wise integer division remainder.
3665     %x = remiu %y, %z : tensor<4x?xi8>
3666     ```
3667   }];
3668   let hasFolder = 1;
3669 }
3670
3671 //===----------------------------------------------------------------------===//
3672 // UnsignedShiftRightOp
3673 //===----------------------------------------------------------------------===//
3674
3675 def UnsignedShiftRightOp : IntArithmeticOp<"shift_right_unsigned"> {
3676   let summary = "unsigned integer right-shift";
3677   let description = [{
3678     The shift_right_unsigned operation shifts an integer value to the right by
3679     a variable amount. The integer is interpreted as unsigned. The high order
3680     bits are always filled with zeros.
3681
3682     Example:
3683
3684     ```mlir
3685     %1 = constant 160 : i8                               // %1 is 0b10100000
3686     %2 = constant 3 : i8
3687     %3 = shift_right_unsigned %1, %2 : (i8, i8) -> i8    // %3 is 0b00010100
3688     ```
3689   }];
3690 }
3691
3692 //===----------------------------------------------------------------------===//
3693 // ViewOp
3694 //===----------------------------------------------------------------------===//
3695
3696 def ViewOp : Std_Op<"view", [
3697     DeclareOpInterfaceMethods<ViewLikeOpInterface>, NoSideEffect]> {
3698   let summary = "memref view operation";
3699   let description = [{
3700     The "view" operation extracts an N-D contiguous memref with empty layout map
3701     with arbitrary element type from a 1-D contiguous memref with empty layout
3702     map of i8 element  type. The ViewOp supports the following arguments:
3703
3704     * A single dynamic byte-shift operand must be specified which represents a
3705       a shift of the base 1-D memref pointer from which to create the resulting
3706       contiguous memref view with identity layout.
3707     * A dynamic size operand that must be specified for each dynamic dimension
3708       in the resulting view memref type.
3709
3710     The "view" operation gives a structured indexing form to a flat 1-D buffer.
3711     Unlike "subview" it can perform a type change. The type change behavior
3712     requires the op to have special semantics because, e.g. a byte shift of 3
3713     cannot be represented as an offset on f64.
3714     For now, a "view" op:
3715
3716     1. Only takes a contiguous source memref with 0 offset and empty layout.
3717     2. Must specify a byte_shift operand (in the future, a special integer
3718        attribute may be added to support the folded case).
3719     3. Returns a contiguous memref with 0 offset and empty layout.
3720
3721     Example:
3722
3723     ```mlir
3724     // Allocate a flat 1D/i8 memref.
3725     %0 = alloc() : memref<2048xi8>
3726
3727     // ViewOp with dynamic offset and static sizes.
3728     %1 = view %0[%offset_1024][] : memref<2048xi8> to memref<64x4xf32>
3729
3730     // ViewOp with dynamic offset and two dynamic size.
3731     %2 = view %0[%offset_1024][%size0, %size1] :
3732       memref<2048xi8> to memref<?x4x?xf32>
3733     ```
3734   }];
3735
3736   let arguments = (ins MemRefRankOf<[I8], [1]>:$source,
3737                    Index:$byte_shift,
3738                    Variadic<Index>:$sizes);
3739   let results = (outs AnyMemRef);
3740
3741   let extraClassDeclaration = [{
3742     /// The result of a view is always a memref.
3743     MemRefType getType() { return getResult().getType().cast<MemRefType>(); }
3744
3745     /// Returns the dynamic sizes for this view operation. This is redundant
3746     /// with `sizes` but needed in template implementations. More specifically:
3747     /// ```
3748     /// template <typename AnyMemRefDefOp>
3749     /// bool isMemRefSizeValidSymbol(AnyMemRefDefOp memrefDefOp, unsigned index,
3750     ///                              Region *region)
3751     /// ```
3752     operand_range getDynamicSizes() {
3753       return {sizes().begin(), sizes().end()};
3754     }
3755   }];
3756
3757   let hasCanonicalizer = 1;
3758 }
3759
3760 //===----------------------------------------------------------------------===//
3761 // XOrOp
3762 //===----------------------------------------------------------------------===//
3763
3764 def XOrOp : IntArithmeticOp<"xor", [Commutative]> {
3765   let summary = "integer binary xor";
3766   let description = [{
3767     The `xor` operation takes two operands and returns one result, each of these
3768     is required to be the same type. This type may be an integer scalar type, a
3769     vector whose element type is integer, or a tensor of integers. It has no
3770     standard attributes.
3771
3772     Example:
3773
3774     ```mlir
3775     // Scalar integer bitwise xor.
3776     %a = xor %b, %c : i64
3777
3778     // SIMD vector element-wise bitwise integer xor.
3779     %f = xor %g, %h : vector<4xi32>
3780
3781     // Tensor element-wise bitwise integer xor.
3782     %x = xor %y, %z : tensor<4x?xi8>
3783     ```
3784   }];
3785   let hasFolder = 1;
3786 }
3787
3788 //===----------------------------------------------------------------------===//
3789 // ZeroExtendIOp
3790 //===----------------------------------------------------------------------===//
3791
3792 def ZeroExtendIOp : Std_Op<"zexti",
3793   [NoSideEffect, ElementwiseMappable,
3794    DeclareOpInterfaceMethods<VectorUnrollOpInterface>,]> {
3795   let summary = "integer zero extension operation";
3796   let description = [{
3797     The integer zero extension operation takes an integer input of
3798     width M and an integer destination type of width N. The destination
3799     bit-width must be larger than the input bit-width (N > M).
3800     The top-most (N - M) bits of the output are filled with zeros.
3801
3802     Example:
3803
3804     ```mlir
3805       %1 = constant 5 : i3            // %1 is 0b101
3806       %2 = zexti %1 : i3 to i6        // %2 is 0b000101
3807       %3 = constant 2 : i3            // %3 is 0b010
3808       %4 = zexti %3 : i3 to i6        // %4 is 0b000010
3809
3810       %5 = zexti %0 : vector<2 x i32> to vector<2 x i64>
3811     ```
3812   }];
3813
3814   let arguments = (ins SignlessIntegerLike:$value);
3815   let results = (outs SignlessIntegerLike);
3816
3817   let builders = [
3818     OpBuilderDAG<(ins "Value":$value, "Type":$destType), [{
3819       $_state.addOperands(value);
3820       $_state.addTypes(destType);
3821     }]>];
3822
3823   let parser = [{
3824     return impl::parseCastOp(parser, result);
3825   }];
3826   let printer = [{
3827     return printStandardCastOp(this->getOperation(), p);
3828   }];
3829 }
3830
3831 #endif // STANDARD_OPS