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