[MLIR][Standard] Add log1p operation to std
[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 //===----------------------------------------------------------------------===//
1946 // Log10Op
1947 //===----------------------------------------------------------------------===//
1948
1949 def Log10Op : FloatUnaryOp<"log10"> {
1950   let summary = "base-10 logarithm of the specified value";
1951 }
1952
1953 //===----------------------------------------------------------------------===//
1954 // Log1pOp
1955 //===----------------------------------------------------------------------===//
1956
1957 def Log1pOp : FloatUnaryOp<"log1p"> {
1958   let summary = "Computes the natural logarithm of one plus the given value";
1959
1960   let description = [{
1961     Computes the base-e logarithm of one plus the given value. It takes one
1962     operand and returns one result of the same type.
1963
1964     log1p(x) := log(1 + x)
1965
1966     Example:
1967
1968     ```mlir
1969     %y = log1p %x : f64
1970     ```
1971   }];
1972 }
1973
1974 //===----------------------------------------------------------------------===//
1975 // Log2Op
1976 //===----------------------------------------------------------------------===//
1977
1978 def Log2Op : FloatUnaryOp<"log2"> {
1979   let summary = "base-2 logarithm of the specified value";
1980 }
1981
1982 //===----------------------------------------------------------------------===//
1983 // MemRefCastOp
1984 //===----------------------------------------------------------------------===//
1985
1986 def MemRefCastOp : CastOp<"memref_cast", [
1987     DeclareOpInterfaceMethods<ViewLikeOpInterface>
1988   ]> {
1989   let summary = "memref cast operation";
1990   let description = [{
1991     Syntax:
1992
1993     ```
1994     operation ::= ssa-id `=` `std.memref_cast` ssa-use `:` type `to` type
1995     ```
1996
1997     The `memref_cast` operation converts a memref from one type to an equivalent
1998     type with a compatible shape. The source and destination types are
1999     compatible if:
2000
2001     a. Both are ranked memref types with the same element type, address space,
2002     and rank and:
2003       1. Both have the same layout or both have compatible strided layouts.
2004       2. The individual sizes (resp. offset and strides in the case of strided
2005          memrefs) may convert constant dimensions to dynamic dimensions and
2006          vice-versa.
2007
2008     If the cast converts any dimensions from an unknown to a known size, then it
2009     acts as an assertion that fails at runtime if the dynamic dimensions
2010     disagree with resultant destination size.
2011
2012     Example:
2013
2014     ```mlir
2015     // Assert that the input dynamic shape matches the destination static shape.
2016     %2 = memref_cast %1 : memref<?x?xf32> to memref<4x4xf32>
2017     // Erase static shape information, replacing it with dynamic information.
2018     %3 = memref_cast %1 : memref<4xf32> to memref<?xf32>
2019
2020     // The same holds true for offsets and strides.
2021
2022     // Assert that the input dynamic shape matches the destination static stride.
2023     %4 = memref_cast %1 : memref<12x4xf32, offset:?, strides: [?, ?]> to
2024                           memref<12x4xf32, offset:5, strides: [4, 1]>
2025     // Erase static offset and stride information, replacing it with
2026     // dynamic information.
2027     %5 = memref_cast %1 : memref<12x4xf32, offset:5, strides: [4, 1]> to
2028                           memref<12x4xf32, offset:?, strides: [?, ?]>
2029     ```
2030
2031     b. Either or both memref types are unranked with the same element type, and
2032     address space.
2033
2034     Example:
2035
2036     ```mlir
2037     Cast to concrete shape.
2038         %4 = memref_cast %1 : memref<*xf32> to memref<4x?xf32>
2039
2040     Erase rank information.
2041         %5 = memref_cast %1 : memref<4x?xf32> to memref<*xf32>
2042     ```
2043   }];
2044
2045   let arguments = (ins AnyRankedOrUnrankedMemRef:$source);
2046   let results = (outs AnyRankedOrUnrankedMemRef);
2047
2048   let extraClassDeclaration = [{
2049     /// Return true if `a` and `b` are valid operand and result pairs for
2050     /// the operation.
2051     static bool areCastCompatible(Type a, Type b);
2052
2053     /// The result of a memref_cast is always a memref.
2054     Type getType() { return getResult().getType(); }
2055   }];
2056 }
2057
2058
2059 //===----------------------------------------------------------------------===//
2060 // MemRefReinterpretCastOp
2061 //===----------------------------------------------------------------------===//
2062
2063 def MemRefReinterpretCastOp:
2064     BaseOpWithOffsetSizesAndStrides<"memref_reinterpret_cast", [
2065       NoSideEffect, ViewLikeOpInterface, OffsetSizeAndStrideOpInterface
2066     ]> {
2067   let summary = "memref reinterpret cast operation";
2068   let description = [{
2069     Modify offset, sizes and strides of an unranked/ranked memref.
2070
2071     Example:
2072     ```mlir
2073     memref_reinterpret_cast %ranked to
2074       offset: [0],
2075       sizes: [%size0, 10],
2076       strides: [1, %stride1]
2077     : memref<?x?xf32> to memref<?x10xf32, offset: 0, strides: [1, ?]>
2078
2079     memref_reinterpret_cast %unranked to
2080       offset: [%offset],
2081       sizes: [%size0, %size1],
2082       strides: [%stride0, %stride1]
2083     : memref<*xf32> to memref<?x?xf32, offset: ?, strides: [?, ?]>
2084     ```
2085   }];
2086
2087   let arguments = (ins
2088     Arg<AnyRankedOrUnrankedMemRef, "", []>:$source,
2089     Variadic<Index>:$offsets,
2090     Variadic<Index>:$sizes,
2091     Variadic<Index>:$strides,
2092     I64ArrayAttr:$static_offsets,
2093     I64ArrayAttr:$static_sizes,
2094     I64ArrayAttr:$static_strides
2095   );
2096   let results = (outs AnyMemRef:$result);
2097
2098   let builders = [
2099     // Build a ReinterpretCastOp with mixed static and dynamic entries.
2100     OpBuilderDAG<(ins "MemRefType":$resultType, "Value":$source,
2101       "int64_t":$staticOffset, "ArrayRef<int64_t>":$staticSizes,
2102       "ArrayRef<int64_t>":$staticStrides, "ValueRange":$offset,
2103       "ValueRange":$sizes, "ValueRange":$strides,
2104       CArg<"ArrayRef<NamedAttribute>", "{}">:$attrs)>,
2105     // Build a ReinterpretCastOp with all dynamic entries.
2106     OpBuilderDAG<(ins "MemRefType":$resultType, "Value":$source,
2107       "Value":$offset, "ValueRange":$sizes, "ValueRange":$strides,
2108       CArg<"ArrayRef<NamedAttribute>", "{}">:$attrs)>,
2109   ];
2110
2111   let extraClassDeclaration = extraBaseClassDeclaration # [{
2112     // The result of the op is always a ranked memref.
2113     MemRefType getType() { return getResult().getType().cast<MemRefType>(); }
2114     Value getViewSource() { return source(); }
2115
2116     /// Return the rank of the source ShapedType.
2117     unsigned getResultRank() {
2118       return getResult().getType().cast<ShapedType>().getRank();
2119     }
2120
2121     /// Return the expected rank of each of the`static_offsets`, `static_sizes`
2122     /// and `static_strides` attributes.
2123     std::array<unsigned, 3> getArrayAttrRanks() {
2124       unsigned resultRank = getResult().getType().cast<ShapedType>().getRank();
2125       return {1, resultRank, resultRank};
2126     }
2127
2128     /// Return the number of leading operands before the `offsets`, `sizes` and
2129     /// and `strides` operands.
2130     static unsigned getOffsetSizeAndStrideStartOperandIndex() { return 1; }
2131   }];
2132 }
2133
2134 //===----------------------------------------------------------------------===//
2135 // MemRefReshapeOp
2136 //===----------------------------------------------------------------------===//
2137
2138 def MemRefReshapeOp: Std_Op<"memref_reshape", [
2139     ViewLikeOpInterface, NoSideEffect]>  {
2140   let summary = "memref reshape operation";
2141   let description = [{
2142     The `memref_reshape` operation converts a memref from one type to an
2143     equivalent type with a provided shape. The data is never copied or
2144     modified.  The source and destination types are compatible if both have the
2145     same element type, same number of elements, address space and identity
2146     layout map. The following combinations are possible:
2147
2148     a. Source type is ranked or unranked. Shape argument has static size.
2149     Result type is ranked.
2150
2151     ```mlir
2152     // Reshape statically-shaped memref.
2153     %dst = memref_reshape %src(%shape)
2154              : (memref<4x1xf32>, memref<1xi32>) to memref<4xf32>
2155     %dst0 = memref_reshape %src(%shape0)
2156              : (memref<4x1xf32>, memref<2xi32>) to memref<2x2xf32>
2157     // Flatten unranked memref.
2158     %dst = memref_reshape %src(%shape)
2159              : (memref<*xf32>, memref<1xi32>) to memref<?xf32>
2160     ```
2161
2162     a. Source type is ranked or unranked. Shape argument has dynamic size.
2163     Result type is unranked.
2164
2165     ```mlir
2166     // Reshape dynamically-shaped 1D memref.
2167     %dst = memref_reshape %src(%shape)
2168              : (memref<?xf32>, memref<?xi32>) to memref<*xf32>
2169     // Reshape unranked memref.
2170     %dst = memref_reshape %src(%shape)
2171              : (memref<*xf32>, memref<?xi32>) to memref<*xf32>
2172     ```
2173   }];
2174
2175   let arguments = (ins
2176     AnyRankedOrUnrankedMemRef:$source,
2177     MemRefRankOf<[AnySignlessInteger, Index], [1]>:$shape
2178   );
2179   let results = (outs AnyRankedOrUnrankedMemRef:$result);
2180
2181   let builders = [OpBuilderDAG<
2182      (ins "MemRefType":$resultType, "Value":$operand, "Value":$shape), [{
2183        $_state.addOperands(operand);
2184        $_state.addOperands(shape);
2185        $_state.addTypes(resultType);
2186      }]>];
2187
2188   let extraClassDeclaration = [{
2189     MemRefType getType() { return getResult().getType().cast<MemRefType>(); }
2190     Value getViewSource() { return source(); }
2191   }];
2192
2193   let assemblyFormat = [{
2194     $source `(` $shape `)` attr-dict `:` functional-type(operands, results)
2195   }];
2196 }
2197
2198 //===----------------------------------------------------------------------===//
2199 // MulFOp
2200 //===----------------------------------------------------------------------===//
2201
2202 def MulFOp : FloatArithmeticOp<"mulf"> {
2203   let summary = "floating point multiplication operation";
2204   let description = [{
2205     Syntax:
2206
2207     ```
2208     operation ::= ssa-id `=` `std.mulf` ssa-use `,` ssa-use `:` type
2209     ```
2210
2211     The `mulf` operation takes two operands and returns one result, each of
2212     these is required to be the same type. This type may be a floating point
2213     scalar type, a vector whose element type is a floating point type, or a
2214     floating point tensor.
2215
2216     Example:
2217
2218     ```mlir
2219     // Scalar multiplication.
2220     %a = mulf %b, %c : f64
2221
2222     // SIMD pointwise vector multiplication, e.g. for Intel SSE.
2223     %f = mulf %g, %h : vector<4xf32>
2224
2225     // Tensor pointwise multiplication.
2226     %x = mulf %y, %z : tensor<4x?xbf16>
2227     ```
2228
2229     TODO: In the distant future, this will accept optional attributes for fast
2230     math, contraction, rounding mode, and other controls.
2231   }];
2232   let hasFolder = 1;
2233 }
2234
2235 //===----------------------------------------------------------------------===//
2236 // MulIOp
2237 //===----------------------------------------------------------------------===//
2238
2239 def MulIOp : IntArithmeticOp<"muli", [Commutative]> {
2240   let summary = "integer multiplication operation";
2241   let hasFolder = 1;
2242 }
2243
2244 //===----------------------------------------------------------------------===//
2245 // NegFOp
2246 //===----------------------------------------------------------------------===//
2247
2248 def NegFOp : FloatUnaryOp<"negf"> {
2249   let summary = "floating point negation";
2250   let description = [{
2251     Syntax:
2252
2253     ```
2254     operation ::= ssa-id `=` `negf` ssa-use `:` type
2255     ```
2256
2257     The `negf` operation computes the negation of a given value. It takes one
2258     operand and returns one result of the same type. This type may be a float
2259     scalar type, a vector whose element type is float, or a tensor of floats.
2260     It has no standard attributes.
2261
2262     Example:
2263
2264     ```mlir
2265     // Scalar negation value.
2266     %a = negf %b : f64
2267
2268     // SIMD vector element-wise negation value.
2269     %f = negf %g : vector<4xf32>
2270
2271     // Tensor element-wise negation value.
2272     %x = negf %y : tensor<4x?xf8>
2273     ```
2274   }];
2275 }
2276
2277 //===----------------------------------------------------------------------===//
2278 // OrOp
2279 //===----------------------------------------------------------------------===//
2280
2281 def OrOp : IntArithmeticOp<"or", [Commutative]> {
2282   let summary = "integer binary or";
2283   let description = [{
2284     Syntax:
2285
2286     ```
2287     operation ::= ssa-id `=` `or` ssa-use `,` ssa-use `:` type
2288     ```
2289
2290     The `or` operation takes two operands and returns one result, each of these
2291     is required to be the same type. This type may be an integer scalar type, a
2292     vector whose element type is integer, or a tensor of integers. It has no
2293     standard attributes.
2294
2295     Example:
2296
2297     ```mlir
2298     // Scalar integer bitwise or.
2299     %a = or %b, %c : i64
2300
2301     // SIMD vector element-wise bitwise integer or.
2302     %f = or %g, %h : vector<4xi32>
2303
2304     // Tensor element-wise bitwise integer or.
2305     %x = or %y, %z : tensor<4x?xi8>
2306     ```
2307   }];
2308   let hasFolder = 1;
2309 }
2310
2311 //===----------------------------------------------------------------------===//
2312 // PowFOp
2313 //===----------------------------------------------------------------------===//
2314
2315 def PowFOp : FloatArithmeticOp<"powf"> {
2316   let summary = "floating point raised to the power of operation";
2317   let description = [{
2318     Syntax:
2319
2320     ```
2321     operation ::= ssa-id `=` `std.powf` ssa-use `,` ssa-use `:` type
2322     ```
2323
2324     The `powf` operation takes two operands and returns one result, each of
2325     these is required to be the same type. This type may be a floating point
2326     scalar type, a vector whose element type is a floating point type, or a
2327     floating point tensor.
2328
2329     Example:
2330
2331     ```mlir
2332     // Scalar exponentiation.
2333     %a = powf %b, %c : f64
2334
2335     // SIMD pointwise vector exponentiation
2336     %f = powf %g, %h : vector<4xf32>
2337
2338     // Tensor pointwise exponentiation.
2339     %x = powf %y, %z : tensor<4x?xbf16>
2340     ```
2341   }];
2342 }
2343
2344 //===----------------------------------------------------------------------===//
2345 // PrefetchOp
2346 //===----------------------------------------------------------------------===//
2347
2348 def PrefetchOp : Std_Op<"prefetch"> {
2349   let summary = "prefetch operation";
2350   let description = [{
2351     The "prefetch" op prefetches data from a memref location described with
2352     subscript indices similar to std.load, and with three attributes: a
2353     read/write specifier, a locality hint, and a cache type specifier as shown
2354     below:
2355
2356     ```mlir
2357     prefetch %0[%i, %j], read, locality<3>, data : memref<400x400xi32>
2358     ```
2359
2360     The read/write specifier is either 'read' or 'write', the locality hint
2361     ranges from locality<0> (no locality) to locality<3> (extremely local keep
2362     in cache). The cache type specifier is either 'data' or 'instr'
2363     and specifies whether the prefetch is performed on data cache or on
2364     instruction cache.
2365   }];
2366
2367   let arguments = (ins AnyMemRef:$memref, Variadic<Index>:$indices,
2368                    BoolAttr:$isWrite,
2369                    Confined<I32Attr, [IntMinValue<0>,
2370                      IntMaxValue<3>]>:$localityHint,
2371                    BoolAttr:$isDataCache);
2372
2373   let extraClassDeclaration = [{
2374     MemRefType getMemRefType() {
2375       return memref().getType().cast<MemRefType>();
2376     }
2377     static StringRef getLocalityHintAttrName() { return "localityHint"; }
2378     static StringRef getIsWriteAttrName() { return "isWrite"; }
2379     static StringRef getIsDataCacheAttrName() { return "isDataCache"; }
2380   }];
2381
2382   let hasFolder = 1;
2383 }
2384
2385 //===----------------------------------------------------------------------===//
2386 // RankOp
2387 //===----------------------------------------------------------------------===//
2388
2389 def RankOp : Std_Op<"rank", [NoSideEffect]> {
2390   let summary = "rank operation";
2391   let description = [{
2392     The `rank` operation takes a memref/tensor operand and returns its rank.
2393
2394     Example:
2395
2396     ```mlir
2397     %1 = rank %arg0 : tensor<*xf32>
2398     %2 = rank %arg1 : memref<*xf32>
2399     ```
2400   }];
2401
2402   let arguments = (ins AnyTypeOf<[AnyRankedOrUnrankedMemRef, AnyTensor],
2403                                  "any tensor or memref type">:$memrefOrTensor);
2404   let results = (outs Index);
2405   let verifier = ?;
2406
2407   let builders = [
2408     OpBuilderDAG<(ins "Value":$tensor), [{
2409       auto indexType = $_builder.getIndexType();
2410       build($_builder, $_state, indexType, tensor);
2411     }]>];
2412
2413   let hasFolder = 1;
2414   let assemblyFormat = "$memrefOrTensor attr-dict `:` type($memrefOrTensor)";
2415 }
2416
2417 //===----------------------------------------------------------------------===//
2418 // ReOp
2419 //===----------------------------------------------------------------------===//
2420
2421 def ReOp : Std_Op<"re",
2422     [NoSideEffect,
2423      TypesMatchWith<"complex element type matches result type",
2424                     "complex", "real",
2425                     "$_self.cast<ComplexType>().getElementType()">]> {
2426   let summary = "extracts the real part of a complex number";
2427   let description = [{
2428     The `re` operation takes a single complex number as its operand and extracts
2429     the real part as a floating-point value.
2430
2431     Example:
2432
2433     ```mlir
2434     %a = re %b : complex<f32>
2435     ```
2436   }];
2437
2438   let arguments = (ins Complex<AnyFloat>:$complex);
2439   let results = (outs AnyFloat:$real);
2440
2441   let assemblyFormat = "$complex attr-dict `:` type($complex)";
2442
2443   // `ReOp` is fully verified by its traits.
2444   let verifier = ?;
2445 }
2446
2447 //===----------------------------------------------------------------------===//
2448 // RemFOp
2449 //===----------------------------------------------------------------------===//
2450
2451 def RemFOp : FloatArithmeticOp<"remf"> {
2452   let summary = "floating point division remainder operation";
2453 }
2454
2455 //===----------------------------------------------------------------------===//
2456 // ReturnOp
2457 //===----------------------------------------------------------------------===//
2458
2459 def ReturnOp : Std_Op<"return", [NoSideEffect, HasParent<"FuncOp">,
2460                                 MemRefsNormalizable, ReturnLike, Terminator]> {
2461   let summary = "return operation";
2462   let description = [{
2463     The `return` operation represents a return operation within a function.
2464     The operation takes variable number of operands and produces no results.
2465     The operand number and types must match the signature of the function
2466     that contains the operation.
2467
2468     Example:
2469
2470     ```mlir
2471     func @foo() : (i32, f8) {
2472       ...
2473       return %0, %1 : i32, f8
2474     }
2475     ```
2476   }];
2477
2478   let arguments = (ins Variadic<AnyType>:$operands);
2479
2480   let builders = [
2481     OpBuilderDAG<(ins),
2482     [{ build($_builder, $_state, llvm::None); }]>];
2483
2484   let assemblyFormat = "attr-dict ($operands^ `:` type($operands))?";
2485 }
2486
2487 //===----------------------------------------------------------------------===//
2488 // RsqrtOp
2489 //===----------------------------------------------------------------------===//
2490
2491 def RsqrtOp : FloatUnaryOp<"rsqrt"> {
2492   let summary = "reciprocal of sqrt (1 / sqrt of the specified value)";
2493   let description = [{
2494     The `rsqrt` operation computes the reciprocal of the square root. It takes
2495     one operand and returns one result of the same type. This type may be a
2496     float scalar type, a vector whose element type is float, or a tensor of
2497     floats. It has no standard attributes.
2498   }];
2499 }
2500
2501 //===----------------------------------------------------------------------===//
2502 // SelectOp
2503 //===----------------------------------------------------------------------===//
2504
2505 def SelectOp : Std_Op<"select", [NoSideEffect,
2506      AllTypesMatch<["true_value", "false_value", "result"]>,
2507      ElementwiseMappable, DeclareOpInterfaceMethods<VectorUnrollOpInterface>]> {
2508   let summary = "select operation";
2509   let description = [{
2510     The `select` operation chooses one value based on a binary condition
2511     supplied as its first operand. If the value of the first operand is `1`,
2512     the second operand is chosen, otherwise the third operand is chosen.
2513     The second and the third operand must have the same type.
2514
2515     The operation applies to vectors and tensors elementwise given the _shape_
2516     of all operands is identical. The choice is made for each element
2517     individually based on the value at the same position as the element in the
2518     condition operand. If an i1 is provided as the condition, the entire vector
2519     or tensor is chosen.
2520
2521     The `select` operation combined with [`cmpi`](#stdcmpi-cmpiop) can be used
2522     to implement `min` and `max` with signed or unsigned comparison semantics.
2523
2524     Example:
2525
2526     ```mlir
2527     // Custom form of scalar selection.
2528     %x = select %cond, %true, %false : i32
2529
2530     // Generic form of the same operation.
2531     %x = "std.select"(%cond, %true, %false) : (i1, i32, i32) -> i32
2532
2533     // Element-wise vector selection.
2534     %vx = std.select %vcond, %vtrue, %vfalse : vector<42xi1>, vector<42xf32>
2535
2536     // Full vector selection.
2537     %vx = std.select %cond, %vtrue, %vfalse : vector<42xf32>
2538     ```
2539   }];
2540
2541   let arguments = (ins BoolLike:$condition,
2542                        AnyType:$true_value,
2543                        AnyType:$false_value);
2544   let results = (outs AnyType:$result);
2545
2546   let builders = [
2547     OpBuilderDAG<(ins "Value":$condition, "Value":$trueValue,
2548       "Value":$falseValue), [{
2549       $_state.addOperands({condition, trueValue, falseValue});
2550       $_state.addTypes(trueValue.getType());
2551     }]>];
2552
2553   let extraClassDeclaration = [{
2554       Value getCondition() { return condition(); }
2555       Value getTrueValue() { return true_value(); }
2556       Value getFalseValue() { return false_value(); }
2557   }];
2558
2559   let hasFolder = 1;
2560 }
2561
2562 //===----------------------------------------------------------------------===//
2563 // ShiftLeftOp
2564 //===----------------------------------------------------------------------===//
2565
2566 def ShiftLeftOp : IntArithmeticOp<"shift_left"> {
2567   let summary = "integer left-shift";
2568   let description = [{
2569     The shift_left operation shifts an integer value to the left by a variable
2570     amount. The low order bits are filled with zeros.
2571
2572     Example:
2573
2574     ```mlir
2575     %1 = constant 5 : i8                       // %1 is 0b00000101
2576     %2 = constant 3 : i8
2577     %3 = shift_left %1, %2 : (i8, i8) -> i8    // %3 is 0b00101000
2578     ```
2579   }];
2580 }
2581
2582 //===----------------------------------------------------------------------===//
2583 // SignedDivIOp
2584 //===----------------------------------------------------------------------===//
2585
2586 def SignedDivIOp : IntArithmeticOp<"divi_signed"> {
2587   let summary = "signed integer division operation";
2588   let description = [{
2589     Syntax:
2590
2591     ```
2592     operation ::= ssa-id `=` `divi_signed` ssa-use `,` ssa-use `:` type
2593     ```
2594
2595     Signed integer division. Rounds towards zero. Treats the leading bit as
2596     sign, i.e. `6 / -2 = -3`.
2597
2598     Note: the semantics of division by zero or signed division overflow (minimum
2599     value divided by -1) is TBD; do NOT assume any specific behavior.
2600
2601     Example:
2602
2603     ```mlir
2604     // Scalar signed integer division.
2605     %a = divis %b, %c : i64
2606
2607     // SIMD vector element-wise division.
2608     %f = divis %g, %h : vector<4xi32>
2609
2610     // Tensor element-wise integer division.
2611     %x = divis %y, %z : tensor<4x?xi8>
2612     ```
2613   }];
2614   let hasFolder = 1;
2615 }
2616
2617 //===----------------------------------------------------------------------===//
2618 // SignedFloorDivIOp
2619 //===----------------------------------------------------------------------===//
2620
2621 def SignedFloorDivIOp : IntArithmeticOp<"floordivi_signed"> {
2622   let summary = "signed floor integer division operation";
2623   let description = [{
2624     Syntax:
2625
2626     ```
2627     operation ::= ssa-id `=` `floordivi_signed` ssa-use `,` ssa-use `:` type
2628     ```
2629
2630     Signed integer division. Rounds towards negative infinity, i.e. `5 / -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 = floordivi_signed %b, %c : i64
2640
2641     ```
2642   }];
2643   let hasFolder = 1;
2644 }
2645
2646 //===----------------------------------------------------------------------===//
2647 // SignedCeilDivIOp
2648 //===----------------------------------------------------------------------===//
2649
2650 def SignedCeilDivIOp : IntArithmeticOp<"ceildivi_signed"> {
2651   let summary = "signed ceil integer division operation";
2652   let description = [{
2653     Syntax:
2654
2655     ```
2656     operation ::= ssa-id `=` `ceildivi_signed` ssa-use `,` ssa-use `:` type
2657     ```
2658
2659     Signed integer division. Rounds towards positive infinity, i.e. `7 / -2 = -3`.
2660
2661     Note: the semantics of division by zero or signed division overflow (minimum
2662     value divided by -1) is TBD; do NOT assume any specific behavior.
2663
2664     Example:
2665
2666     ```mlir
2667     // Scalar signed integer division.
2668     %a = ceildivi_signed %b, %c : i64
2669     ```
2670   }];
2671   let hasFolder = 1;
2672 }
2673
2674 //===----------------------------------------------------------------------===//
2675 // SignedRemIOp
2676 //===----------------------------------------------------------------------===//
2677
2678 def SignedRemIOp : IntArithmeticOp<"remi_signed"> {
2679   let summary = "signed integer division remainder operation";
2680   let description = [{
2681     Syntax:
2682
2683     ```
2684     operation ::= ssa-id `=` `std.remi_signed` ssa-use `,` ssa-use `:` type
2685     ```
2686
2687     Signed integer division remainder. Treats the leading bit as sign, i.e. `6 %
2688     -2 = 0`.
2689
2690     Note: the semantics of division by zero is TBD; do NOT assume any specific
2691     behavior.
2692
2693     Example:
2694
2695     ```mlir
2696     // Scalar signed integer division remainder.
2697     %a = remis %b, %c : i64
2698
2699     // SIMD vector element-wise division remainder.
2700     %f = remis %g, %h : vector<4xi32>
2701
2702     // Tensor element-wise integer division remainder.
2703     %x = remis %y, %z : tensor<4x?xi8>
2704     ```
2705   }];
2706   let hasFolder = 1;
2707 }
2708
2709 //===----------------------------------------------------------------------===//
2710 // SignedShiftRightOp
2711 //===----------------------------------------------------------------------===//
2712
2713 def SignedShiftRightOp : IntArithmeticOp<"shift_right_signed"> {
2714   let summary = "signed integer right-shift";
2715   let description = [{
2716     The shift_right_signed operation shifts an integer value to the right by
2717     a variable amount. The integer is interpreted as signed. The high order
2718     bits in the output are filled with copies of the most-significant bit
2719     of the shifted value (which means that the sign of the value is preserved).
2720
2721     Example:
2722
2723     ```mlir
2724     %1 = constant 160 : i8                             // %1 is 0b10100000
2725     %2 = constant 3 : i8
2726     %3 = shift_right_signed %1, %2 : (i8, i8) -> i8    // %3 is 0b11110100
2727     %4 = constant 96 : i8                              // %4 is 0b01100000
2728     %5 = shift_right_signed %4, %2 : (i8, i8) -> i8    // %5 is 0b00001100
2729     ```
2730   }];
2731 }
2732
2733 //===----------------------------------------------------------------------===//
2734 // SignExtendIOp
2735 //===----------------------------------------------------------------------===//
2736
2737 def SignExtendIOp : Std_Op<"sexti",
2738     [NoSideEffect, ElementwiseMappable,
2739     DeclareOpInterfaceMethods<VectorUnrollOpInterface>]> {
2740   let summary = "integer sign extension operation";
2741   let description = [{
2742     The integer sign extension operation takes an integer input of
2743     width M and an integer destination type of width N. The destination
2744     bit-width must be larger than the input bit-width (N > M).
2745     The top-most (N - M) bits of the output are filled with copies
2746     of the most-significant bit of the input.
2747
2748     Example:
2749
2750     ```mlir
2751     %1 = constant 5 : i3            // %1 is 0b101
2752     %2 = sexti %1 : i3 to i6        // %2 is 0b111101
2753     %3 = constant 2 : i3            // %3 is 0b010
2754     %4 = sexti %3 : i3 to i6        // %4 is 0b000010
2755
2756     %5 = sexti %0 : vector<2 x i32> to vector<2 x i64>
2757     ```
2758   }];
2759
2760   let arguments = (ins SignlessIntegerLike:$value);
2761   let results = (outs SignlessIntegerLike);
2762
2763   let builders = [
2764     OpBuilderDAG<(ins "Value":$value, "Type":$destType), [{
2765       $_state.addOperands(value);
2766       $_state.addTypes(destType);
2767     }]>];
2768
2769   let parser = [{
2770     return impl::parseCastOp(parser, result);
2771   }];
2772   let printer = [{
2773     return printStandardCastOp(this->getOperation(), p);
2774   }];
2775 }
2776
2777 //===----------------------------------------------------------------------===//
2778 // SIToFPOp
2779 //===----------------------------------------------------------------------===//
2780
2781 def SIToFPOp : ArithmeticCastOp<"sitofp">, Arguments<(ins AnyType:$in)> {
2782   let summary = "cast from integer type to floating-point";
2783   let description = [{
2784     Cast from a value interpreted as signed or vector of signed integers to the
2785     corresponding floating-point scalar or vector value. If the value cannot be
2786     exactly represented, it is rounded using the default rounding mode. Scalars
2787     and vector types are currently supported.
2788   }];
2789
2790   let extraClassDeclaration = [{
2791     /// Return true if `a` and `b` are valid operand and result pairs for
2792     /// the operation.
2793     static bool areCastCompatible(Type a, Type b);
2794   }];
2795
2796   let hasFolder = 0;
2797 }
2798
2799 //===----------------------------------------------------------------------===//
2800 // SplatOp
2801 //===----------------------------------------------------------------------===//
2802
2803 def SplatOp : Std_Op<"splat", [NoSideEffect,
2804      TypesMatchWith<"operand type matches element type of result",
2805                     "aggregate", "input",
2806                     "$_self.cast<ShapedType>().getElementType()">]> {
2807   let summary = "splat or broadcast operation";
2808   let description = [{
2809     Broadcast the operand to all elements of the result vector or tensor. The
2810     operand has to be of either integer or float type. When the result is a
2811     tensor, it has to be statically shaped.
2812
2813     Example:
2814
2815     ```mlir
2816     %s = load %A[%i] : memref<128xf32>
2817     %v = splat %s : vector<4xf32>
2818     %t = splat %s : tensor<8x16xi32>
2819     ```
2820
2821     TODO: This operation is easy to extend to broadcast to dynamically shaped
2822     tensors in the same way dynamically shaped memrefs are handled.
2823
2824     ```mlir
2825     // Broadcasts %s to a 2-d dynamically shaped tensor, with %m, %n binding
2826     // to the sizes of the two dynamic dimensions.
2827     %m = "foo"() : () -> (index)
2828     %n = "bar"() : () -> (index)
2829     %t = splat %s [%m, %n] : tensor<?x?xi32>
2830     ```
2831   }];
2832
2833   let arguments = (ins AnyTypeOf<[AnySignlessInteger, AnyFloat],
2834                                  "integer or float type">:$input);
2835   let results = (outs AnyTypeOf<[AnyVector, AnyStaticShapeTensor]>:$aggregate);
2836
2837   let builders = [
2838     OpBuilderDAG<(ins "Value":$element, "Type":$aggregateType),
2839     [{ build($_builder, $_state, aggregateType, element); }]>];
2840
2841   let hasFolder = 1;
2842
2843   let assemblyFormat = "$input attr-dict `:` type($aggregate)";
2844 }
2845
2846 //===----------------------------------------------------------------------===//
2847 // SqrtOp
2848 //===----------------------------------------------------------------------===//
2849
2850 def SqrtOp : FloatUnaryOp<"sqrt"> {
2851   let summary = "sqrt of the specified value";
2852   let description = [{
2853     The `sqrt` operation computes the square root. It takes one operand and
2854     returns one result of the same type. This type may be a float scalar type, a
2855     vector whose element type is float, or a tensor of floats. It has no standard
2856     attributes.
2857
2858     Example:
2859
2860     ```mlir
2861     // Scalar square root value.
2862     %a = sqrt %b : f64
2863     // SIMD vector element-wise square root value.
2864     %f = sqrt %g : vector<4xf32>
2865     // Tensor element-wise square root value.
2866     %x = sqrt %y : tensor<4x?xf32>
2867     ```
2868   }];
2869 }
2870
2871 //===----------------------------------------------------------------------===//
2872 // StoreOp
2873 //===----------------------------------------------------------------------===//
2874
2875 def StoreOp : Std_Op<"store",
2876      [TypesMatchWith<"type of 'value' matches element type of 'memref'",
2877                      "memref", "value",
2878                      "$_self.cast<MemRefType>().getElementType()">,
2879                      MemRefsNormalizable]> {
2880   let summary = "store operation";
2881   let description = [{
2882     Store a value to a memref location given by indices. The value stored should
2883     have the same type as the elemental type of the memref. The number of
2884     arguments provided within brackets need to match the rank of the memref.
2885
2886     In an affine context, the indices of a store are restricted to SSA values
2887     bound to surrounding loop induction variables,
2888     [symbols](Affine.md#restrictions-on-dimensions-and-symbols), results of a
2889     [`constant` operation](#stdconstant-constantop), or the result of an
2890     [`affine.apply`](Affine.md#affineapply-affineapplyop) operation that can in turn
2891     take as arguments all of the aforementioned SSA values or the recursively
2892     result of such an `affine.apply` operation.
2893
2894     Example:
2895
2896     ```mlir
2897     store %100, %A[%1, 1023] : memref<4x?xf32, #layout, memspace0>
2898     ```
2899
2900     **Context:** The `load` and `store` operations are specifically crafted to
2901     fully resolve a reference to an element of a memref, and (in polyhedral
2902     `affine.if` and `affine.for` operations) the compiler can follow use-def
2903     chains (e.g. through [`affine.apply`](Affine.md#affineapply-affineapplyop)
2904     operations) to precisely analyze references at compile-time using polyhedral
2905     techniques. This is possible because of the
2906     [restrictions on dimensions and symbols](Affine.md#restrictions-on-dimensions-and-symbols)
2907     in these contexts.
2908   }];
2909
2910   let arguments = (ins AnyType:$value,
2911                        Arg<AnyMemRef, "the reference to store to",
2912                            [MemWrite]>:$memref,
2913                        Variadic<Index>:$indices);
2914
2915   let builders = [
2916     OpBuilderDAG<(ins "Value":$valueToStore, "Value":$memref), [{
2917       $_state.addOperands(valueToStore);
2918       $_state.addOperands(memref);
2919     }]>];
2920
2921   let extraClassDeclaration = [{
2922       Value getValueToStore() { return getOperand(0); }
2923
2924       Value getMemRef() { return getOperand(1); }
2925       void setMemRef(Value value) { setOperand(1, value); }
2926       MemRefType getMemRefType() {
2927         return getMemRef().getType().cast<MemRefType>();
2928       }
2929
2930       operand_range getIndices() {
2931         return {operand_begin() + 2, operand_end()};
2932       }
2933   }];
2934
2935   let hasFolder = 1;
2936
2937   let assemblyFormat = [{
2938     $value `,` $memref `[` $indices `]` attr-dict `:` type($memref)
2939   }];
2940 }
2941
2942 //===----------------------------------------------------------------------===//
2943 // SubCFOp
2944 //===----------------------------------------------------------------------===//
2945
2946 def SubCFOp : ComplexFloatArithmeticOp<"subcf"> {
2947   let summary = "complex number subtraction";
2948   let description = [{
2949     The `subcf` operation takes two complex number operands and returns their
2950     difference, a single complex number.
2951     All operands and result must be of the same type, a complex number with a
2952     floating-point element type.
2953
2954     Example:
2955
2956     ```mlir
2957     %a = subcf %b, %c : complex<f32>
2958     ```
2959   }];
2960 }
2961
2962 //===----------------------------------------------------------------------===//
2963 // SubFOp
2964 //===----------------------------------------------------------------------===//
2965
2966 def SubFOp : FloatArithmeticOp<"subf"> {
2967   let summary = "floating point subtraction operation";
2968   let hasFolder = 1;
2969 }
2970
2971 //===----------------------------------------------------------------------===//
2972 // SubIOp
2973 //===----------------------------------------------------------------------===//
2974
2975 def SubIOp : IntArithmeticOp<"subi"> {
2976   let summary = "integer subtraction operation";
2977   let hasFolder = 1;
2978 }
2979
2980 //===----------------------------------------------------------------------===//
2981 // SubViewOp
2982 //===----------------------------------------------------------------------===//
2983
2984 def SubViewOp : BaseOpWithOffsetSizesAndStrides<
2985     "subview", [DeclareOpInterfaceMethods<ViewLikeOpInterface>,
2986                 OffsetSizeAndStrideOpInterface] >  {
2987   let summary = "memref subview operation";
2988   let description = [{
2989     The "subview" operation converts a memref type to another memref type
2990     which represents a reduced-size view of the original memref as specified by
2991     the operation's offsets, sizes and strides arguments.
2992
2993     The SubView operation supports the following arguments:
2994
2995     * semref: the "base" memref on which to create a "view" memref.
2996     * offsets: memref-rank number of offsets into the "base" memref at which to
2997                create the "view" memref.
2998     * sizes: memref-rank number of sizes which specify the sizes of the result
2999              "view" memref type.
3000     * strides: memref-rank number of strides that compose multiplicatively with
3001                the base memref strides in each dimension.
3002
3003     The representation based on offsets, sizes and strides support a
3004     partially-static specification via attributes specified through the
3005     `static_offsets`, `static_sizes` and `static_strides` arguments. A special
3006     sentinel value ShapedType::kDynamicSize and
3007     ShapedType::kDynamicStrideOrOffset encodes that the corresponding entry has
3008     a dynamic value.
3009
3010     A subview operation may additionally reduce the rank of the resulting view
3011     by removing dimensions that are statically known to be of size 1.
3012
3013     Example 1:
3014
3015     ```mlir
3016     %0 = alloc() : memref<64x4xf32, (d0, d1) -> (d0 * 4 + d1)>
3017
3018     // Create a sub-view of "base" memref '%0' with offset arguments '%c0',
3019     // dynamic sizes for each dimension, and stride arguments '%c1'.
3020     %1 = subview %0[%c0, %c0][%size0, %size1][%c1, %c1]
3021       : memref<64x4xf32, (d0, d1) -> (d0 * 4 + d1) > to
3022         memref<?x?xf32, (d0, d1)[s0, s1] -> (d0 * s1 + d1 + s0)>
3023     ```
3024
3025     Example 2:
3026
3027     ```mlir
3028     %0 = alloc() : memref<8x16x4xf32, (d0, d1, d1) -> (d0 * 64 + d1 * 4 + d2)>
3029
3030     // Create a sub-view of "base" memref '%0' with dynamic offsets, sizes,
3031     // and strides.
3032     // Note that dynamic offsets are represented by the linearized dynamic
3033     // offset symbol 's0' in the subview memref layout map, and that the
3034     // dynamic strides operands, after being applied to the base memref
3035     // strides in each dimension, are represented in the view memref layout
3036     // map as symbols 's1', 's2' and 's3'.
3037     %1 = subview %0[%i, %j, %k][%size0, %size1, %size2][%x, %y, %z]
3038       : memref<8x16x4xf32, (d0, d1, d2) -> (d0 * 64 + d1 * 4 + d2)> to
3039         memref<?x?x?xf32,
3040           (d0, d1, d2)[s0, s1, s2, s3] -> (d0 * s1 + d1 * s2 + d2 * s3 + s0)>
3041     ```
3042
3043     Example 3:
3044
3045     ```mlir
3046     %0 = alloc() : memref<8x16x4xf32, (d0, d1, d1) -> (d0 * 64 + d1 * 4 + d2)>
3047
3048     // Subview with constant offsets, sizes and strides.
3049     %1 = subview %0[0, 2, 0][4, 4, 4][64, 4, 1]
3050       : memref<8x16x4xf32, (d0, d1, d2) -> (d0 * 64 + d1 * 4 + d2)> to
3051         memref<4x4x4xf32, (d0, d1, d2) -> (d0 * 64 + d1 * 4 + d2 + 8)>
3052     ```
3053
3054     Example 4:
3055
3056     ```mlir
3057     %0 = alloc(%arg0, %arg1) : memref<?x?xf32>
3058
3059     // Subview with constant size, but dynamic offsets and
3060     // strides. The resulting memref has a static shape, but if the
3061     // base memref has an affine map to describe the layout, the result
3062     // memref also uses an affine map to describe the layout. The
3063     // strides of the result memref is computed as follows:
3064     //
3065     // Let #map1 represents the layout of the base memref, and #map2
3066     // represents the layout of the result memref. A #mapsubview can be
3067     // constructed to map an index from the result memref to the base
3068     // memref (note that the description below uses more convenient
3069     // naming for symbols, while in affine maps, symbols are
3070     // represented as unsigned numbers that identify that symbol in the
3071     // given affine map.
3072     //
3073     // #mapsubview = (d0, d1)[o0, o1, t0, t1] -> (d0 * t0 + o0, d1 * t1 + o1)
3074     //
3075     // where, o0, o1, ... are offsets, and t0, t1, ... are strides. Then,
3076     //
3077     // #map2 = #map1.compose(#mapsubview)
3078     //
3079     // If the layout map is represented as
3080     //
3081     // #map1 = (d0, d1)[s0, s1, s2] -> (d0 * s1 + d1 * s2 + s0)
3082     //
3083     // then,
3084     //
3085     // #map2 = (d0, d1)[s0, s1, s2, o0, o1, t0, t1] ->
3086     //              (d0 * s1 * t0 + d1 * s2 * t1 + o0 * s1 + o1 * s2 + s0)
3087     //
3088     // Representing this canonically
3089     //
3090     // #map2 = (d0, d1)[r0, r1, r2] -> (d0 * r1 + d1 * r2 + r0)
3091     //
3092     // where, r0 = o0 * s1 + o1 * s2 + s0, r1 = s1 * t0, r2 = s2 * t1.
3093     %1 = subview %0[%i, %j][4, 4][%x, %y] :
3094       : memref<?x?xf32, (d0, d1)[s0, s1, s2] -> (d0 * s1 + d1 * s2 + s0)> to
3095         memref<4x4xf32, (d0, d1)[r0, r1, r2] -> (d0 * r1 + d1 * r2 + r0)>
3096
3097     // Note that the subview op does not guarantee that the result
3098     // memref is "inbounds" w.r.t to base memref. It is upto the client
3099     // to ensure that the subview is accessed in a manner that is
3100     // in-bounds.
3101     ```
3102
3103     Example 5:
3104
3105     ```mlir
3106     // Rank-reducing subview.
3107     %1 = subview %0[0, 0, 0][1, 16, 4][1, 1, 1] :
3108       memref<8x16x4xf32> to memref<16x4xf32>
3109     %3 = subview %2[3, 4, 2][1, 6, 3][1, 1, 1] :
3110       memref<8x16x4xf32> to memref<6x3xf32, offset: 210, strides: [4, 1]>
3111     ```
3112     }
3113   }];
3114
3115   let arguments = (ins
3116     AnyMemRef:$source,
3117     Variadic<Index>:$offsets,
3118     Variadic<Index>:$sizes,
3119     Variadic<Index>:$strides,
3120     I64ArrayAttr:$static_offsets,
3121     I64ArrayAttr:$static_sizes,
3122     I64ArrayAttr:$static_strides
3123   );
3124   let results = (outs AnyMemRef:$result);
3125
3126   let builders = [
3127     // Build a SubViewOp with mixed static and dynamic entries.
3128     OpBuilderDAG<(ins "Value":$source, "ArrayRef<int64_t>":$staticOffsets,
3129       "ArrayRef<int64_t>":$staticSizes, "ArrayRef<int64_t>":$staticStrides,
3130       "ValueRange":$offsets, "ValueRange":$sizes, "ValueRange":$strides,
3131       CArg<"ArrayRef<NamedAttribute>", "{}">:$attrs)>,
3132     // Build a SubViewOp with all dynamic entries.
3133     OpBuilderDAG<(ins "Value":$source, "ValueRange":$offsets,
3134       "ValueRange":$sizes, "ValueRange":$strides,
3135       CArg<"ArrayRef<NamedAttribute>", "{}">:$attrs)>,
3136     // Build a SubViewOp with mixed static and dynamic entries
3137     // and custom result type.
3138     OpBuilderDAG<(ins "MemRefType":$resultType, "Value":$source,
3139       "ArrayRef<int64_t>":$staticOffsets, "ArrayRef<int64_t>":$staticSizes,
3140       "ArrayRef<int64_t>":$staticStrides, "ValueRange":$offsets,
3141       "ValueRange":$sizes, "ValueRange":$strides,
3142       CArg<"ArrayRef<NamedAttribute>", "{}">:$attrs)>,
3143     // Build a SubViewOp with all dynamic entries and custom result type.
3144     OpBuilderDAG<(ins "MemRefType":$resultType, "Value":$source,
3145       "ValueRange":$offsets, "ValueRange":$sizes, "ValueRange":$strides,
3146       CArg<"ArrayRef<NamedAttribute>", "{}">:$attrs)>
3147   ];
3148
3149   let extraClassDeclaration = extraBaseClassDeclaration # [{
3150     /// Returns the type of the base memref operand.
3151     MemRefType getSourceType() {
3152       return source().getType().cast<MemRefType>();
3153     }
3154
3155     /// The result of a subview is always a memref.
3156     MemRefType getType() { return getResult().getType().cast<MemRefType>(); }
3157
3158     /// A subview result type can be fully inferred from the source type and the
3159     /// static representation of offsets, sizes and strides. Special sentinels
3160     /// encode the dynamic case.
3161     static Type inferResultType(MemRefType sourceMemRefType,
3162                                 ArrayRef<int64_t> staticOffsets,
3163                                 ArrayRef<int64_t> staticSizes,
3164                                 ArrayRef<int64_t> staticStrides);
3165
3166     /// Return the expected rank of each of the`static_offsets`, `static_sizes`
3167     /// and `static_strides` attributes.
3168     std::array<unsigned, 3> getArrayAttrRanks() {
3169       unsigned rank = getSourceType().getRank();
3170       return {rank, rank, rank};
3171     }
3172
3173     /// Return the number of leading operands before the `offsets`, `sizes` and
3174     /// and `strides` operands.
3175     static unsigned getOffsetSizeAndStrideStartOperandIndex() { return 1; }
3176   }];
3177
3178   let hasCanonicalizer = 1;
3179   let hasFolder = 1;
3180 }
3181
3182 //===----------------------------------------------------------------------===//
3183 // SubTensorOp
3184 //===----------------------------------------------------------------------===//
3185
3186 def SubTensorOp : BaseOpWithOffsetSizesAndStrides<
3187     "subtensor", [OffsetSizeAndStrideOpInterface]> {
3188   let summary = "subtensor operation";
3189   let description = [{
3190     The "subtensor" operation extract a tensor from another tensor as
3191     specified by the operation's offsets, sizes and strides arguments.
3192
3193     The subtensor operation supports the following arguments:
3194
3195     * tensor: the "base" tensor from which to extract a subtensor.
3196     * offsets: tensor-rank number of offsets into the "base" tensor from which
3197                to extract the subtensor.
3198     * sizes: tensor-rank number of sizes which specify the sizes of the result
3199              tensor type.
3200     * strides: tensor-rank number of strides specifying subsampling in each
3201                dimension.
3202
3203     The representation based on offsets, sizes and strides support a
3204     partially-static specification via attributes specified through the
3205     `static_offsets`, `static_sizes` and `static_strides` arguments. A special
3206     sentinel value ShapedType::kDynamicSize and
3207     ShapedType::kDynamicStrideOrOffset encodes that the corresponding entry has
3208     a dynamic value.
3209
3210     After buffer-allocation, the "subtensor" op is expected to lower into a
3211     "subview" op.
3212
3213     A subtensor operation may additionally reduce the rank of the resulting
3214     tensor by removing dimensions that are statically known to be of size 1.
3215
3216     Example:
3217
3218     ```
3219     // Rank-reducing subtensor.
3220     %1 = subtensor %0[0, 0, 0][1, 16, 4][1, 1, 1] :
3221       tensor<8x16x4xf32> to tensor<16x4xf32>
3222     %3 = subtensor %2[3, 4, 2][1, 6, 3][1, 1, 1] :
3223       tensor<8x16x4xf32> to tensor<6x3xf32>
3224     ```
3225   }];
3226
3227   let arguments = (ins
3228     AnyRankedTensor:$source,
3229     Variadic<Index>:$offsets,
3230     Variadic<Index>:$sizes,
3231     Variadic<Index>:$strides,
3232     I64ArrayAttr:$static_offsets,
3233     I64ArrayAttr:$static_sizes,
3234     I64ArrayAttr:$static_strides
3235   );
3236   let results = (outs AnyRankedTensor:$result);
3237
3238   let builders = [
3239     // Build a SubTensorOp with mixed static and dynamic entries.
3240     OpBuilderDAG<(ins "Value":$source, "ArrayRef<int64_t>":$staticOffsets,
3241       "ArrayRef<int64_t>":$staticSizes, "ArrayRef<int64_t>":$staticStrides,
3242       "ValueRange":$offsets, "ValueRange":$sizes, "ValueRange":$strides,
3243       CArg<"ArrayRef<NamedAttribute>", "{}">:$attrs)>,
3244     // Build a SubTensorOp with all dynamic entries.
3245     OpBuilderDAG<(ins "Value":$source, "ValueRange":$offsets,
3246       "ValueRange":$sizes, "ValueRange":$strides,
3247       CArg<"ArrayRef<NamedAttribute>", "{}">:$attrs)>
3248   ];
3249
3250   let extraClassDeclaration = extraBaseClassDeclaration # [{
3251     /// Returns the type of the base tensor operand.
3252     RankedTensorType getSourceType() {
3253       return source().getType().cast<RankedTensorType>();
3254     }
3255
3256     /// The result of a subtensor is always a tensor.
3257     RankedTensorType getType() {
3258       return getResult().getType().cast<RankedTensorType>();
3259     }
3260
3261     /// A subview result type can be fully inferred from the source type and the
3262     /// static representation of offsets, sizes and strides. Special sentinels
3263     /// encode the dynamic case.
3264     static Type inferResultType(RankedTensorType sourceRankedTensorType,
3265                                 ArrayRef<int64_t> staticOffsets,
3266                                 ArrayRef<int64_t> staticSizes,
3267                                 ArrayRef<int64_t> staticStrides);
3268
3269     /// Return the expected rank of each of the`static_offsets`, `static_sizes`
3270     /// and `static_strides` attributes.
3271     std::array<unsigned, 3> getArrayAttrRanks() {
3272       unsigned rank = getSourceType().getRank();
3273       return {rank, rank, rank};
3274     }
3275
3276     /// Return the number of leading operands before the `offsets`, `sizes` and
3277     /// and `strides` operands.
3278     static unsigned getOffsetSizeAndStrideStartOperandIndex() { return 1; }
3279   }];
3280
3281   let hasCanonicalizer = 1;
3282 }
3283
3284 //===----------------------------------------------------------------------===//
3285 // SubTensorInsertOp
3286 //===----------------------------------------------------------------------===//
3287
3288 def SubTensorInsertOp : BaseOpWithOffsetSizesAndStrides<
3289     "subtensor_insert", [OffsetSizeAndStrideOpInterface]> {
3290   let summary = "subtensor_insert operation";
3291   let description = [{
3292     The "subtensor_insert" operation insert a tensor `source` into another
3293     tensor `dest` as specified by the operation's offsets, sizes and strides
3294     arguments.
3295
3296     It returns a copy of `dest` with the proper subtensor updated with the value
3297     of `source`.
3298
3299     The subtensor_insert operation has the encodes the following information:
3300
3301     * source: the tensor that is inserted.
3302     * dest: the tensor into which the source tensor is inserted.
3303     * offsets: tensor-rank number of offsets into the "base" tensor from which
3304                to extract the subtensor.
3305     * sizes: tensor-rank number of sizes which specify the sizes of the result
3306              tensor type.
3307     * strides: tensor-rank number of strides that specify subsampling in each
3308                dimension.
3309
3310     The representation based on offsets, sizes and strides support a
3311     partially-static specification via attributes specified through the
3312     `static_offsets`, `static_sizes` and `static_strides` arguments. A special
3313     sentinel value ShapedType::kDynamicSize and
3314     ShapedType::kDynamicStrideOrOffset encodes that the corresponding entry has
3315     a dynamic value.
3316
3317     After buffer-allocation, the "subtensor_insert" op is expected to become
3318     an in-place buffer update.
3319   }];
3320
3321   let arguments = (ins
3322     AnyRankedTensor:$source,
3323     AnyRankedTensor:$dest,
3324     Variadic<Index>:$offsets,
3325     Variadic<Index>:$sizes,
3326     Variadic<Index>:$strides,
3327     I64ArrayAttr:$static_offsets,
3328     I64ArrayAttr:$static_sizes,
3329     I64ArrayAttr:$static_strides
3330   );
3331   let results = (outs AnyRankedTensor:$result);
3332
3333   let builders = [
3334     // Build a SubTensorInsertOp with mixed static and dynamic entries.
3335     OpBuilderDAG<(ins "Value":$source, "Value":$dest,
3336       "ArrayRef<int64_t>":$staticOffsets, "ArrayRef<int64_t>":$staticSizes,
3337       "ArrayRef<int64_t>":$staticStrides, "ValueRange":$offsets,
3338       "ValueRange":$sizes, "ValueRange":$strides,
3339       CArg<"ArrayRef<NamedAttribute>", "{}">:$attrs)>,
3340     // Build a SubTensorInsertOp with all dynamic entries.
3341     OpBuilderDAG<(ins "Value":$source, "Value":$dest, "ValueRange":$offsets,
3342       "ValueRange":$sizes, "ValueRange":$strides,
3343       CArg<"ArrayRef<NamedAttribute>", "{}">:$attrs)>
3344   ];
3345
3346   let extraClassDeclaration = extraBaseClassDeclaration # [{
3347     /// Returns the type of the base tensor operand.
3348     RankedTensorType getSourceType() {
3349       return source().getType().cast<RankedTensorType>();
3350     }
3351
3352     /// The result of a subtensor is always a tensor.
3353     RankedTensorType getType() {
3354       return getResult().getType().cast<RankedTensorType>();
3355     }
3356
3357     /// Return the expected rank of each of the`static_offsets`, `static_sizes`
3358     /// and `static_strides` attributes.
3359     std::array<unsigned, 3> getArrayAttrRanks() {
3360       unsigned rank = getSourceType().getRank();
3361       return {rank, rank, rank};
3362     }
3363
3364     /// Return the number of leading operands before the `offsets`, `sizes` and
3365     /// and `strides` operands.
3366     static unsigned getOffsetSizeAndStrideStartOperandIndex() { return 2; }
3367   }];
3368 }
3369
3370 //===----------------------------------------------------------------------===//
3371 // TanhOp
3372 //===----------------------------------------------------------------------===//
3373
3374 def TanhOp : FloatUnaryOp<"tanh"> {
3375   let summary = "hyperbolic tangent of the specified value";
3376   let description = [{
3377     Syntax:
3378
3379     ```
3380     operation ::= ssa-id `=` `std.tanh` ssa-use `:` type
3381     ```
3382
3383     The `tanh` operation computes the hyperbolic tangent. It takes one operand
3384     and returns one result of the same type. This type may be a float scalar
3385     type, a vector whose element type is float, or a tensor of floats. It has
3386     no standard attributes.
3387
3388     Example:
3389
3390     ```mlir
3391     // Scalar hyperbolic tangent value.
3392     %a = tanh %b : f64
3393
3394     // SIMD vector element-wise hyperbolic tangent value.
3395     %f = tanh %g : vector<4xf32>
3396
3397     // Tensor element-wise hyperbolic tangent value.
3398     %x = tanh %y : tensor<4x?xf8>
3399     ```
3400   }];
3401 }
3402
3403 //===----------------------------------------------------------------------===//
3404 // TensorLoadOp
3405 //===----------------------------------------------------------------------===//
3406
3407 def TensorLoadOp : Std_Op<"tensor_load",
3408     [SameOperandsAndResultShape, SameOperandsAndResultElementType,
3409      TypesMatchWith<"result type matches tensor equivalent of 'memref'",
3410                     "memref", "result",
3411                     "getTensorTypeFromMemRefType($_self)">]> {
3412   let summary = "tensor load operation";
3413   let description = [{
3414     Create a tensor from a memref, making an independent copy of the element
3415     data. The result value is a tensor whose shape and element type match the
3416     memref operand.
3417
3418     The opposite of this op is tensor_to_memref. Together, these two ops are
3419     useful for source/target materializations when doing type conversions
3420     involving tensors and memrefs.
3421
3422     Example:
3423
3424     ```mlir
3425     // Produces a value of tensor<4x?xf32> type.
3426     %12 = tensor_load %10 : memref<4x?xf32, #layout, memspace0>
3427     ```
3428   }];
3429
3430   let arguments = (ins Arg<AnyRankedOrUnrankedMemRef,
3431                        "the reference to load from", [MemRead]>:$memref);
3432   let results = (outs AnyTensor:$result);
3433   // TensorLoadOp is fully verified by traits.
3434   let verifier = ?;
3435
3436   let builders = [
3437     OpBuilderDAG<(ins "Value":$memref), [{
3438       $_state.addOperands(memref);
3439       $_state.addTypes(getTensorTypeFromMemRefType(memref.getType()));
3440     }]>];
3441
3442   let extraClassDeclaration = [{
3443     /// The result of a tensor_load is always a tensor.
3444     TensorType getType() {
3445       Type resultType = getResult().getType();
3446       if (resultType.isa<TensorType>())
3447         return resultType.cast<TensorType>();
3448       return {};
3449     }
3450   }];
3451
3452   let assemblyFormat = "$memref attr-dict `:` type($memref)";
3453
3454   let hasFolder = 1;
3455 }
3456
3457 //===----------------------------------------------------------------------===//
3458 // TensorStoreOp
3459 //===----------------------------------------------------------------------===//
3460
3461 def TensorStoreOp : Std_Op<"tensor_store",
3462     [SameOperandsShape, SameOperandsElementType,
3463      TypesMatchWith<"type of 'value' matches tensor equivalent of 'memref'",
3464                     "memref", "tensor",
3465                     "getTensorTypeFromMemRefType($_self)">]> {
3466   let summary = "tensor store operation";
3467   let description = [{
3468     Stores the contents of a tensor into a memref. The first operand is a value
3469     of tensor type, the second operand is a value of memref type. The shapes and
3470     element types of these must match, and are specified by the memref type.
3471
3472     Example:
3473
3474     ```mlir
3475     %9 = dim %8, 1 : tensor<4x?xf32>
3476     %10 = alloc(%9) : memref<4x?xf32, #layout, memspace0>
3477     tensor_store %8, %10 : memref<4x?xf32, #layout, memspace0>
3478     ```
3479   }];
3480
3481   let arguments = (ins AnyTensor:$tensor, Arg<AnyRankedOrUnrankedMemRef,
3482                        "the reference to store to", [MemWrite]>:$memref);
3483   // TensorStoreOp is fully verified by traits.
3484   let verifier = ?;
3485
3486   let assemblyFormat = "$tensor `,` $memref attr-dict `:` type($memref)";
3487 }
3488
3489 //===----------------------------------------------------------------------===//
3490 // TensorToMemrefOp
3491 //===--------