xref: /llvm-project/mlir/include/mlir/Dialect/Arith/IR/ArithOps.td (revision 990837f91de329b1e045f90fadb86ffe21611d9a)
1//===- ArithOps.td - Arith op 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#ifndef ARITH_OPS
10#define ARITH_OPS
11
12include "mlir/Dialect/Arith/IR/ArithBase.td"
13include "mlir/Dialect/Arith/IR/ArithOpsInterfaces.td"
14include "mlir/Interfaces/CastInterfaces.td"
15include "mlir/Interfaces/ControlFlowInterfaces.td"
16include "mlir/Interfaces/InferIntRangeInterface.td"
17include "mlir/Interfaces/InferTypeOpInterface.td"
18include "mlir/Interfaces/SideEffectInterfaces.td"
19include "mlir/Interfaces/VectorInterfaces.td"
20include "mlir/IR/BuiltinAttributeInterfaces.td"
21include "mlir/IR/OpAsmInterface.td"
22include "mlir/IR/EnumAttr.td"
23
24// Base class for Arith dialect ops. Ops in this dialect have no memory
25// effects and can be applied element-wise to vectors and tensors.
26class Arith_Op<string mnemonic, list<Trait> traits = []> :
27    Op<Arith_Dialect, mnemonic,
28       traits #
29       [DeclareOpInterfaceMethods<VectorUnrollOpInterface>, NoMemoryEffect] #
30       ElementwiseMappable.traits>;
31
32// Base class for integer and floating point arithmetic ops. All ops have one
33// result, require operands and results to be of the same type, and can accept
34// tensors or vectors of integers or floats.
35class Arith_ArithOp<string mnemonic, list<Trait> traits = []> :
36    Arith_Op<mnemonic, traits # [SameOperandsAndResultType]>;
37
38// Base class for unary arithmetic operations.
39class Arith_UnaryOp<string mnemonic, list<Trait> traits = []> :
40    Arith_ArithOp<mnemonic, traits # [Pure]> {
41  let assemblyFormat = "$operand attr-dict `:` type($result)";
42}
43
44// Base class for binary arithmetic operations.
45class Arith_BinaryOp<string mnemonic, list<Trait> traits = []> :
46    Arith_ArithOp<mnemonic, traits> {
47  let assemblyFormat = "$lhs `,` $rhs attr-dict `:` type($result)";
48}
49
50// Base class for integer binary operations.
51class Arith_IntBinaryOp<string mnemonic, list<Trait> traits = []> :
52    Arith_BinaryOp<mnemonic, traits #
53      [DeclareOpInterfaceMethods<InferIntRangeInterface, ["inferResultRanges"]>]>,
54    Arguments<(ins SignlessIntegerOrIndexLike:$lhs, SignlessIntegerOrIndexLike:$rhs)>,
55    Results<(outs SignlessIntegerOrIndexLike:$result)>;
56
57// Base class for integer binary operations without undefined behavior.
58class Arith_TotalIntBinaryOp<string mnemonic, list<Trait> traits = []> :
59    Arith_IntBinaryOp<mnemonic, traits # [Pure]>;
60
61// Base class for floating point unary operations.
62class Arith_FloatUnaryOp<string mnemonic, list<Trait> traits = []> :
63    Arith_UnaryOp<mnemonic,
64      !listconcat([DeclareOpInterfaceMethods<ArithFastMathInterface>],
65                  traits)>,
66    Arguments<(ins FloatLike:$operand,
67      DefaultValuedAttr<
68        Arith_FastMathAttr, "::mlir::arith::FastMathFlags::none">:$fastmath)>,
69    Results<(outs FloatLike:$result)> {
70  let assemblyFormat = [{ $operand (`fastmath` `` $fastmath^)?
71                          attr-dict `:` type($result) }];
72}
73
74// Base class for floating point binary operations.
75class Arith_FloatBinaryOp<string mnemonic, list<Trait> traits = []> :
76    Arith_BinaryOp<mnemonic,
77      !listconcat([Pure, DeclareOpInterfaceMethods<ArithFastMathInterface>],
78                  traits)>,
79    Arguments<(ins FloatLike:$lhs, FloatLike:$rhs,
80      DefaultValuedAttr<
81        Arith_FastMathAttr, "::mlir::arith::FastMathFlags::none">:$fastmath)>,
82    Results<(outs FloatLike:$result)> {
83  let assemblyFormat = [{ $lhs `,` $rhs (`fastmath` `` $fastmath^)?
84                          attr-dict `:` type($result) }];
85}
86
87// Checks that tensor input and outputs have identical shapes. This is stricker
88// than the verification done in `SameOperandsAndResultShape` that allows for
89// tensor dimensions to be 'compatible' (e.g., dynamic dimensions being
90// compatible with static ones).
91def SameInputOutputTensorDims : PredOpTrait<
92    "input and output have the same tensor dimensions",
93    AllMatchSameOperatorPred<["in", "out"],
94      "(::llvm::isa<::mlir::TensorType>($_self.getType()) ?"
95      " ::llvm::cast<::mlir::TensorType>($_self.getType()).getShape() :"
96      " ::llvm::ArrayRef<int64_t>{})">>;
97
98// Base class for arithmetic cast operations. Requires a single operand and
99// result. If either is a shaped type, then the other must be of the same
100// shape.  In the case of tensor types, this also includes the corresponding
101// operand/result dimensions being equal.
102class Arith_CastOp<string mnemonic, TypeConstraint From, TypeConstraint To,
103                   list<Trait> traits = []> :
104    Arith_Op<mnemonic, traits # [Pure, SameOperandsAndResultShape,
105      SameInputOutputTensorDims, DeclareOpInterfaceMethods<CastOpInterface>]>,
106    Arguments<(ins From:$in)>,
107    Results<(outs To:$out)> {
108  let assemblyFormat = "$in attr-dict `:` type($in) `to` type($out)";
109}
110
111// Casts do not accept indices. Type constraint for signless-integer-like types
112// excluding indices: signless integers, vectors or tensors thereof.
113def SignlessFixedWidthIntegerLike : TypeConstraint<Or<[
114        AnySignlessInteger.predicate,
115        VectorOfAnyRankOf<[AnySignlessInteger]>.predicate,
116        TensorOf<[AnySignlessInteger]>.predicate]>,
117    "signless-fixed-width-integer-like">;
118
119// Cast from an integer type to another integer type.
120class Arith_IToICastOp<string mnemonic, list<Trait> traits = []> :
121    Arith_CastOp<mnemonic, SignlessFixedWidthIntegerLike,
122                           SignlessFixedWidthIntegerLike,
123                           traits #
124                           [DeclareOpInterfaceMethods<InferIntRangeInterface, ["inferResultRanges"]>]>;
125// Cast from an integer type to a floating point type.
126class Arith_IToFCastOp<string mnemonic, list<Trait> traits = []> :
127    Arith_CastOp<mnemonic, SignlessFixedWidthIntegerLike, FloatLike, traits>;
128// Cast from a floating point type to an integer type.
129class Arith_FToICastOp<string mnemonic, list<Trait> traits = []> :
130    Arith_CastOp<mnemonic, FloatLike, SignlessFixedWidthIntegerLike, traits>;
131// Cast from a floating point type to another floating point type.
132class Arith_FToFCastOp<string mnemonic, list<Trait> traits = []> :
133    Arith_CastOp<mnemonic, FloatLike, FloatLike, traits>;
134
135// Base class for compare operations. Requires two operands of the same type
136// and returns a single `BoolLike` result. If the operand type is a vector or
137// tensor, then the result will be one of `i1` of the same shape.
138class Arith_CompareOp<string mnemonic, list<Trait> traits = []> :
139    Arith_Op<mnemonic, traits # [Pure, SameTypeOperands, TypesMatchWith<
140    "result type has i1 element type and same shape as operands",
141    "lhs", "result", "::getI1SameShape($_self)">]> {
142  let results = (outs BoolLike:$result);
143
144  let assemblyFormat = "$predicate `,` $lhs `,` $rhs attr-dict `:` type($lhs)";
145}
146
147// Just like `Arith_CompareOp` but also admits 0-D vectors. Introduced
148// temporarily to allow gradual transition to 0-D vectors.
149class Arith_CompareOpOfAnyRank<string mnemonic, list<Trait> traits = []> :
150    Arith_CompareOp<mnemonic, traits> {
151  let results = (outs BoolLikeOfAnyRank:$result);
152}
153
154class Arith_IntBinaryOpWithOverflowFlags<string mnemonic, list<Trait> traits = []> :
155    Arith_BinaryOp<mnemonic, traits #
156      [Pure, DeclareOpInterfaceMethods<InferIntRangeInterface, ["inferResultRanges"]>,
157       DeclareOpInterfaceMethods<ArithIntegerOverflowFlagsInterface>]>,
158    Arguments<(ins SignlessIntegerOrIndexLike:$lhs, SignlessIntegerOrIndexLike:$rhs,
159      DefaultValuedAttr<
160        Arith_IntegerOverflowAttr,
161        "::mlir::arith::IntegerOverflowFlags::none">:$overflowFlags)>,
162    Results<(outs SignlessIntegerOrIndexLike:$result)> {
163
164  let assemblyFormat = [{ $lhs `,` $rhs (`overflow` `` $overflowFlags^)?
165                          attr-dict `:` type($result) }];
166}
167
168//===----------------------------------------------------------------------===//
169// ConstantOp
170//===----------------------------------------------------------------------===//
171
172def Arith_ConstantOp : Op<Arith_Dialect, "constant",
173    [ConstantLike, Pure,
174     DeclareOpInterfaceMethods<OpAsmOpInterface, ["getAsmResultNames"]>,
175     AllTypesMatch<["value", "result"]>,
176     DeclareOpInterfaceMethods<InferIntRangeInterface, ["inferResultRanges"]>]> {
177  let summary = "integer or floating point constant";
178  let description = [{
179    The `constant` operation produces an SSA value equal to some integer or
180    floating-point constant specified by an attribute. This is the way MLIR
181    forms simple integer and floating point constants.
182
183    Example:
184
185    ```
186    // Integer constant
187    %1 = arith.constant 42 : i32
188
189    // Equivalent generic form
190    %1 = "arith.constant"() {value = 42 : i32} : () -> i32
191    ```
192  }];
193
194  let arguments = (ins TypedAttrInterface:$value);
195  // TODO: Disallow arith.constant to return anything other than a signless
196  // integer or float like. Downstream users of Arith should only be
197  // working with signless integers, floats, or vectors/tensors thereof.
198  // However, it is necessary to allow arith.constant to return vectors/tensors
199  // of strings and signed/unsigned integers (for now) as an artefact of
200  // splitting the Standard dialect.
201  let results = (outs /*SignlessIntegerOrIndexOrFloatLike*/AnyType:$result);
202
203  let extraClassDeclaration = [{
204    /// Whether the constant op can be constructed with a particular value and
205    /// type.
206    static bool isBuildableWith(Attribute value, Type type);
207
208    /// Build the constant op with `value` and `type` if possible, otherwise
209    /// returns null.
210    static ConstantOp materialize(OpBuilder &builder, Attribute value,
211                                  Type type, Location loc);
212  }];
213
214  let hasFolder = 1;
215  let assemblyFormat = "attr-dict $value";
216  let hasVerifier = 1;
217}
218
219//===----------------------------------------------------------------------===//
220// AddIOp
221//===----------------------------------------------------------------------===//
222
223def Arith_AddIOp : Arith_IntBinaryOpWithOverflowFlags<"addi", [Commutative]> {
224  let summary = "integer addition operation";
225  let description = [{
226    Performs N-bit addition on the operands. The operands are interpreted as
227    unsigned bitvectors. The result is represented by a bitvector containing the
228    mathematical value of the addition modulo 2^n, where `n` is the bitwidth.
229    Because `arith` integers use a two's complement representation, this operation
230    is applicable on both signed and unsigned integer operands.
231
232    The `addi` operation takes two operands and returns one result, each of
233    these is required to be the same type. This type may be an integer scalar type,
234    a vector whose element type is integer, or a tensor of integers.
235
236    This op supports `nuw`/`nsw` overflow flags which stands stand for
237    "No Unsigned Wrap" and "No Signed Wrap", respectively. If the `nuw` and/or
238    `nsw` flags are present, and an unsigned/signed overflow occurs
239    (respectively), the result is poison.
240
241    Example:
242
243    ```mlir
244    // Scalar addition.
245    %a = arith.addi %b, %c : i64
246
247    // Scalar addition with overflow flags.
248    %a = arith.addi %b, %c overflow<nsw, nuw> : i64
249
250    // SIMD vector element-wise addition.
251    %f = arith.addi %g, %h : vector<4xi32>
252
253    // Tensor element-wise addition.
254    %x = arith.addi %y, %z : tensor<4x?xi8>
255    ```
256  }];
257  let hasFolder = 1;
258  let hasCanonicalizer = 1;
259}
260
261//===----------------------------------------------------------------------===//
262// AddUIExtendedOp
263//===----------------------------------------------------------------------===//
264
265def Arith_AddUIExtendedOp : Arith_Op<"addui_extended", [Pure, Commutative,
266    AllTypesMatch<["lhs", "rhs", "sum"]>]> {
267  let summary = [{
268    extended unsigned integer addition operation returning sum and overflow bit
269  }];
270
271  let description = [{
272    Performs (N+1)-bit addition on zero-extended operands. Returns two results:
273    the N-bit sum (same type as both operands), and the overflow bit
274    (boolean-like), where `1` indicates unsigned addition overflow, while `0`
275    indicates no overflow.
276
277    Example:
278
279    ```mlir
280    // Scalar addition.
281    %sum, %overflow = arith.addui_extended %b, %c : i64, i1
282
283    // Vector element-wise addition.
284    %d:2 = arith.addui_extended %e, %f : vector<4xi32>, vector<4xi1>
285
286    // Tensor element-wise addition.
287    %x:2 = arith.addui_extended %y, %z : tensor<4x?xi8>, tensor<4x?xi1>
288    ```
289  }];
290
291  let arguments = (ins SignlessIntegerOrIndexLike:$lhs, SignlessIntegerOrIndexLike:$rhs);
292  let results = (outs SignlessIntegerOrIndexLike:$sum, BoolLike:$overflow);
293  let assemblyFormat = [{
294    $lhs `,` $rhs attr-dict `:` type($sum) `,` type($overflow)
295  }];
296
297  let builders = [
298    OpBuilder<(ins "Value":$lhs, "Value":$rhs), [{
299      build($_builder, $_state, lhs.getType(), ::getI1SameShape(lhs.getType()),
300            lhs, rhs);
301    }]>
302  ];
303
304  let hasFolder = 1;
305  let hasCanonicalizer = 1;
306
307  let extraClassDeclaration = [{
308    std::optional<SmallVector<int64_t, 4>> getShapeForUnroll();
309  }];
310}
311
312//===----------------------------------------------------------------------===//
313// SubIOp
314//===----------------------------------------------------------------------===//
315
316def Arith_SubIOp : Arith_IntBinaryOpWithOverflowFlags<"subi"> {
317  let summary = [{
318    Integer subtraction operation.
319  }];
320  let description = [{
321    Performs N-bit subtraction on the operands. The operands are interpreted as unsigned
322    bitvectors. The result is represented by a bitvector containing the mathematical
323    value of the subtraction modulo 2^n, where `n` is the bitwidth. Because `arith`
324    integers use a two's complement representation, this operation is applicable on
325    both signed and unsigned integer operands.
326
327    The `subi` operation takes two operands and returns one result, each of
328    these is required to be the same type. This type may be an integer scalar type,
329    a vector whose element type is integer, or a tensor of integers.
330
331    This op supports `nuw`/`nsw` overflow flags which stands stand for
332    "No Unsigned Wrap" and "No Signed Wrap", respectively. If the `nuw` and/or
333    `nsw` flags are present, and an unsigned/signed overflow occurs
334    (respectively), the result is poison.
335
336    Example:
337
338    ```mlir
339    // Scalar subtraction.
340    %a = arith.subi %b, %c : i64
341
342    // Scalar subtraction with overflow flags.
343    %a = arith.subi %b, %c overflow<nsw, nuw> : i64
344
345    // SIMD vector element-wise subtraction.
346    %f = arith.subi %g, %h : vector<4xi32>
347
348    // Tensor element-wise subtraction.
349    %x = arith.subi %y, %z : tensor<4x?xi8>
350    ```
351  }];
352  let hasFolder = 1;
353  let hasCanonicalizer = 1;
354}
355
356//===----------------------------------------------------------------------===//
357// MulIOp
358//===----------------------------------------------------------------------===//
359
360def Arith_MulIOp : Arith_IntBinaryOpWithOverflowFlags<"muli",
361  [Commutative, DeclareOpInterfaceMethods<OpAsmOpInterface, ["getAsmResultNames"]>]
362> {
363  let summary = [{
364    Integer multiplication operation.
365  }];
366  let description = [{
367    Performs N-bit multiplication on the operands. The operands are interpreted as
368    unsigned bitvectors. The result is represented by a bitvector containing the
369    mathematical value of the multiplication modulo 2^n, where `n` is the bitwidth.
370    Because `arith` integers use a two's complement representation, this operation is
371    applicable on both signed and unsigned integer operands.
372
373    The `muli` operation takes two operands and returns one result, each of
374    these is required to be the same type. This type may be an integer scalar type,
375    a vector whose element type is integer, or a tensor of integers.
376
377    This op supports `nuw`/`nsw` overflow flags which stands stand for
378    "No Unsigned Wrap" and "No Signed Wrap", respectively. If the `nuw` and/or
379    `nsw` flags are present, and an unsigned/signed overflow occurs
380    (respectively), the result is poison.
381
382    Example:
383
384    ```mlir
385    // Scalar multiplication.
386    %a = arith.muli %b, %c : i64
387
388    // Scalar multiplication with overflow flags.
389    %a = arith.muli %b, %c overflow<nsw, nuw> : i64
390
391    // SIMD vector element-wise multiplication.
392    %f = arith.muli %g, %h : vector<4xi32>
393
394    // Tensor element-wise multiplication.
395    %x = arith.muli %y, %z : tensor<4x?xi8>
396    ```
397  }];
398  let hasFolder = 1;
399  let hasCanonicalizer = 1;
400}
401
402//===----------------------------------------------------------------------===//
403// MulSIExtendedOp
404//===----------------------------------------------------------------------===//
405
406def Arith_MulSIExtendedOp : Arith_Op<"mulsi_extended", [Pure, Commutative,
407    AllTypesMatch<["lhs", "rhs", "low", "high"]>]> {
408  let summary = [{
409    extended signed integer multiplication operation
410  }];
411
412  let description = [{
413    Performs (2*N)-bit multiplication on sign-extended operands. Returns two
414    N-bit results: the low and the high halves of the product. The low half has
415    the same value as the result of regular multiplication `arith.muli` with
416    the same operands.
417
418    Example:
419
420    ```mlir
421    // Scalar multiplication.
422    %low, %high = arith.mulsi_extended %a, %b : i32
423
424    // Vector element-wise multiplication.
425    %c:2 = arith.mulsi_extended %d, %e : vector<4xi32>
426
427    // Tensor element-wise multiplication.
428    %x:2 = arith.mulsi_extended %y, %z : tensor<4x?xi8>
429    ```
430  }];
431
432  let arguments = (ins SignlessIntegerOrIndexLike:$lhs, SignlessIntegerOrIndexLike:$rhs);
433  let results = (outs SignlessIntegerOrIndexLike:$low, SignlessIntegerOrIndexLike:$high);
434
435  let assemblyFormat = "$lhs `,` $rhs attr-dict `:` type($lhs)";
436
437  let hasFolder = 1;
438  let hasCanonicalizer = 1;
439
440  let extraClassDeclaration = [{
441    std::optional<SmallVector<int64_t, 4>> getShapeForUnroll();
442  }];
443}
444
445//===----------------------------------------------------------------------===//
446// MulUIExtendedOp
447//===----------------------------------------------------------------------===//
448
449def Arith_MulUIExtendedOp : Arith_Op<"mului_extended", [Pure, Commutative,
450    AllTypesMatch<["lhs", "rhs", "low", "high"]>]> {
451  let summary = [{
452    extended unsigned integer multiplication operation
453  }];
454
455  let description = [{
456    Performs (2*N)-bit multiplication on zero-extended operands. Returns two
457    N-bit results: the low and the high halves of the product. The low half has
458    the same value as the result of regular multiplication `arith.muli` with
459    the same operands.
460
461    Example:
462
463    ```mlir
464    // Scalar multiplication.
465    %low, %high = arith.mului_extended %a, %b : i32
466
467    // Vector element-wise multiplication.
468    %c:2 = arith.mului_extended %d, %e : vector<4xi32>
469
470    // Tensor element-wise multiplication.
471    %x:2 = arith.mului_extended %y, %z : tensor<4x?xi8>
472    ```
473  }];
474
475  let arguments = (ins SignlessIntegerOrIndexLike:$lhs, SignlessIntegerOrIndexLike:$rhs);
476  let results = (outs SignlessIntegerOrIndexLike:$low, SignlessIntegerOrIndexLike:$high);
477
478  let assemblyFormat = "$lhs `,` $rhs attr-dict `:` type($lhs)";
479
480  let hasFolder = 1;
481  let hasCanonicalizer = 1;
482
483  let extraClassDeclaration = [{
484    std::optional<SmallVector<int64_t, 4>> getShapeForUnroll();
485  }];
486}
487
488//===----------------------------------------------------------------------===//
489// DivUIOp
490//===----------------------------------------------------------------------===//
491
492def Arith_DivUIOp : Arith_IntBinaryOp<"divui", [ConditionallySpeculatable]> {
493  let summary = "unsigned integer division operation";
494  let description = [{
495    Unsigned integer division. Rounds towards zero. Treats the leading bit as
496    the most significant, i.e. for `i16` given two's complement representation,
497    `6 / -2 = 6 / (2^16 - 2) = 0`.
498
499    Division by zero is undefined behavior. When applied to `vector` and
500    `tensor` values, the behavior is undefined if _any_ elements are divided by
501    zero.
502
503    Example:
504
505    ```mlir
506    // Scalar unsigned integer division.
507    %a = arith.divui %b, %c : i64
508
509    // SIMD vector element-wise division.
510    %f = arith.divui %g, %h : vector<4xi32>
511
512    // Tensor element-wise integer division.
513    %x = arith.divui %y, %z : tensor<4x?xi8>
514    ```
515  }];
516
517  let extraClassDeclaration = [{
518    /// Interface method for ConditionallySpeculatable.
519    Speculation::Speculatability getSpeculatability();
520  }];
521
522  let hasFolder = 1;
523}
524
525//===----------------------------------------------------------------------===//
526// DivSIOp
527//===----------------------------------------------------------------------===//
528
529def Arith_DivSIOp : Arith_IntBinaryOp<"divsi", [ConditionallySpeculatable]> {
530  let summary = "signed integer division operation";
531  let description = [{
532    Signed integer division. Rounds towards zero. Treats the leading bit as
533    sign, i.e. `6 / -2 = -3`.
534
535    Divison by zero, or signed division overflow (minimum value divided by -1)
536    is undefined behavior. When applied to `vector` and `tensor` values, the
537    behavior is undefined if _any_ of its elements are divided by zero or has a
538    signed division overflow.
539
540    Example:
541
542    ```mlir
543    // Scalar signed integer division.
544    %a = arith.divsi %b, %c : i64
545
546    // SIMD vector element-wise division.
547    %f = arith.divsi %g, %h : vector<4xi32>
548
549    // Tensor element-wise integer division.
550    %x = arith.divsi %y, %z : tensor<4x?xi8>
551    ```
552  }];
553
554  let extraClassDeclaration = [{
555    /// Interface method for ConditionallySpeculatable.
556    Speculation::Speculatability getSpeculatability();
557  }];
558
559  let hasFolder = 1;
560}
561
562//===----------------------------------------------------------------------===//
563// CeilDivUIOp
564//===----------------------------------------------------------------------===//
565
566def Arith_CeilDivUIOp : Arith_IntBinaryOp<"ceildivui",
567                                          [ConditionallySpeculatable]> {
568  let summary = "unsigned ceil integer division operation";
569  let description = [{
570    Unsigned integer division. Rounds towards positive infinity. Treats the
571    leading bit as the most significant, i.e. for `i16` given two's complement
572    representation, `6 / -2 = 6 / (2^16 - 2) = 1`.
573
574    Division by zero is undefined behavior. When applied to `vector` and
575    `tensor` values, the behavior is undefined if _any_ elements are divided by
576    zero.
577
578    Example:
579
580    ```mlir
581    // Scalar unsigned integer division.
582    %a = arith.ceildivui %b, %c : i64
583    ```
584  }];
585
586  let extraClassDeclaration = [{
587    /// Interface method for ConditionallySpeculatable.
588    Speculation::Speculatability getSpeculatability();
589  }];
590
591  let hasFolder = 1;
592}
593
594//===----------------------------------------------------------------------===//
595// CeilDivSIOp
596//===----------------------------------------------------------------------===//
597
598def Arith_CeilDivSIOp : Arith_IntBinaryOp<"ceildivsi",
599                                          [ConditionallySpeculatable]> {
600  let summary = "signed ceil integer division operation";
601  let description = [{
602    Signed integer division. Rounds towards positive infinity, i.e. `7 / -2 = -3`.
603
604    Divison by zero, or signed division overflow (minimum value divided by -1)
605    is undefined behavior. When applied to `vector` and `tensor` values, the
606    behavior is undefined if _any_ of its elements are divided by zero or has a
607    signed division overflow.
608
609    Example:
610
611    ```mlir
612    // Scalar signed integer division.
613    %a = arith.ceildivsi %b, %c : i64
614    ```
615  }];
616
617  let extraClassDeclaration = [{
618    /// Interface method for ConditionallySpeculatable.
619    Speculation::Speculatability getSpeculatability();
620  }];
621
622  let hasFolder = 1;
623}
624
625//===----------------------------------------------------------------------===//
626// FloorDivSIOp
627//===----------------------------------------------------------------------===//
628
629def Arith_FloorDivSIOp : Arith_TotalIntBinaryOp<"floordivsi"> {
630  let summary = "signed floor integer division operation";
631  let description = [{
632    Signed integer division. Rounds towards negative infinity, i.e. `5 / -2 = -3`.
633
634    Divison by zero, or signed division overflow (minimum value divided by -1)
635    is undefined behavior. When applied to `vector` and `tensor` values, the
636    behavior is undefined if _any_ of its elements are divided by zero or has a
637    signed division overflow.
638
639    Example:
640
641    ```mlir
642    // Scalar signed integer division.
643    %a = arith.floordivsi %b, %c : i64
644
645    ```
646  }];
647  let hasFolder = 1;
648}
649
650//===----------------------------------------------------------------------===//
651// RemUIOp
652//===----------------------------------------------------------------------===//
653
654def Arith_RemUIOp : Arith_TotalIntBinaryOp<"remui"> {
655  let summary = "unsigned integer division remainder operation";
656  let description = [{
657    Unsigned integer division remainder. Treats the leading bit as the most
658    significant, i.e. for `i16`, `6 % -2 = 6 % (2^16 - 2) = 6`.
659
660    Division by zero is undefined behavior. When applied to `vector` and
661    `tensor` values, the behavior is undefined if _any_ elements are divided by
662    zero.
663
664    Example:
665
666    ```mlir
667    // Scalar unsigned integer division remainder.
668    %a = arith.remui %b, %c : i64
669
670    // SIMD vector element-wise division remainder.
671    %f = arith.remui %g, %h : vector<4xi32>
672
673    // Tensor element-wise integer division remainder.
674    %x = arith.remui %y, %z : tensor<4x?xi8>
675    ```
676  }];
677  let hasFolder = 1;
678}
679
680//===----------------------------------------------------------------------===//
681// RemSIOp
682//===----------------------------------------------------------------------===//
683
684def Arith_RemSIOp : Arith_TotalIntBinaryOp<"remsi"> {
685  let summary = "signed integer division remainder operation";
686  let description = [{
687    Signed integer division remainder. Treats the leading bit as sign, i.e. `6 %
688    -2 = 0`.
689
690    Division by zero is undefined behavior. When applied to `vector` and
691    `tensor` values, the behavior is undefined if _any_ elements are divided by
692    zero.
693
694    Example:
695
696    ```mlir
697    // Scalar signed integer division remainder.
698    %a = arith.remsi %b, %c : i64
699
700    // SIMD vector element-wise division remainder.
701    %f = arith.remsi %g, %h : vector<4xi32>
702
703    // Tensor element-wise integer division remainder.
704    %x = arith.remsi %y, %z : tensor<4x?xi8>
705    ```
706  }];
707  let hasFolder = 1;
708}
709
710//===----------------------------------------------------------------------===//
711// AndIOp
712//===----------------------------------------------------------------------===//
713
714def Arith_AndIOp : Arith_TotalIntBinaryOp<"andi", [Commutative, Idempotent]> {
715  let summary = "integer binary and";
716  let description = [{
717    The `andi` operation takes two operands and returns one result, each of
718    these is required to be the same type. This type may be an integer scalar
719    type, a vector whose element type is integer, or a tensor of integers. It
720    has no standard attributes.
721
722    Example:
723
724    ```mlir
725    // Scalar integer bitwise and.
726    %a = arith.andi %b, %c : i64
727
728    // SIMD vector element-wise bitwise integer and.
729    %f = arith.andi %g, %h : vector<4xi32>
730
731    // Tensor element-wise bitwise integer and.
732    %x = arith.andi %y, %z : tensor<4x?xi8>
733    ```
734  }];
735  let hasFolder = 1;
736  let hasCanonicalizer = 1;
737}
738
739//===----------------------------------------------------------------------===//
740// OrIOp
741//===----------------------------------------------------------------------===//
742
743def Arith_OrIOp : Arith_TotalIntBinaryOp<"ori", [Commutative, Idempotent]> {
744  let summary = "integer binary or";
745  let description = [{
746    The `ori` operation takes two operands and returns one result, each of these
747    is required to be the same type. This type may be an integer scalar type, a
748    vector whose element type is integer, or a tensor of integers. It has no
749    standard attributes.
750
751    Example:
752
753    ```mlir
754    // Scalar integer bitwise or.
755    %a = arith.ori %b, %c : i64
756
757    // SIMD vector element-wise bitwise integer or.
758    %f = arith.ori %g, %h : vector<4xi32>
759
760    // Tensor element-wise bitwise integer or.
761    %x = arith.ori %y, %z : tensor<4x?xi8>
762    ```
763  }];
764  let hasFolder = 1;
765  let hasCanonicalizer = 1;
766}
767
768//===----------------------------------------------------------------------===//
769// XOrIOp
770//===----------------------------------------------------------------------===//
771
772def Arith_XOrIOp : Arith_TotalIntBinaryOp<"xori", [Commutative]> {
773  let summary = "integer binary xor";
774  let description = [{
775    The `xori` operation takes two operands and returns one result, each of
776    these is required to be the same type. This type may be an integer scalar
777    type, a vector whose element type is integer, or a tensor of integers. It
778    has no standard attributes.
779
780    Example:
781
782    ```mlir
783    // Scalar integer bitwise xor.
784    %a = arith.xori %b, %c : i64
785
786    // SIMD vector element-wise bitwise integer xor.
787    %f = arith.xori %g, %h : vector<4xi32>
788
789    // Tensor element-wise bitwise integer xor.
790    %x = arith.xori %y, %z : tensor<4x?xi8>
791    ```
792  }];
793  let hasFolder = 1;
794  let hasCanonicalizer = 1;
795}
796
797//===----------------------------------------------------------------------===//
798// ShLIOp
799//===----------------------------------------------------------------------===//
800
801def Arith_ShLIOp : Arith_IntBinaryOpWithOverflowFlags<"shli"> {
802  let summary = "integer left-shift";
803  let description = [{
804    The `shli` operation shifts the integer value of the first operand to the left
805    by the integer value of the second operand. The second operand is interpreted as
806    unsigned. The low order bits are filled with zeros. If the value of the second
807    operand is greater or equal than the bitwidth of the first operand, then the
808    operation returns poison.
809
810    This op supports `nuw`/`nsw` overflow flags which stands stand for
811    "No Unsigned Wrap" and "No Signed Wrap", respectively. If the `nuw` and/or
812    `nsw` flags are present, and an unsigned/signed overflow occurs
813    (respectively), the result is poison.
814
815    Example:
816
817    ```mlir
818    %1 = arith.constant 5 : i8  // %1 is 0b00000101
819    %2 = arith.constant 3 : i8
820    %3 = arith.shli %1, %2 : i8 // %3 is 0b00101000
821    %4 = arith.shli %1, %2 overflow<nsw, nuw> : i8
822    ```
823  }];
824  let hasFolder = 1;
825}
826
827//===----------------------------------------------------------------------===//
828// ShRUIOp
829//===----------------------------------------------------------------------===//
830
831def Arith_ShRUIOp : Arith_TotalIntBinaryOp<"shrui"> {
832  let summary = "unsigned integer right-shift";
833  let description = [{
834    The `shrui` operation shifts an integer value of the first operand to the right
835    by the value of the second operand. The first operand is interpreted as unsigned,
836    and the second operand is interpreted as unsigned. The high order bits are always
837    filled with zeros. If the value of the second operand is greater or equal than the
838    bitwidth of the first operand, then the operation returns poison.
839
840    Example:
841
842    ```mlir
843    %1 = arith.constant 160 : i8               // %1 is 0b10100000
844    %2 = arith.constant 3 : i8
845    %3 = arith.shrui %1, %2 : (i8, i8) -> i8   // %3 is 0b00010100
846    ```
847  }];
848  let hasFolder = 1;
849}
850
851//===----------------------------------------------------------------------===//
852// ShRSIOp
853//===----------------------------------------------------------------------===//
854
855def Arith_ShRSIOp : Arith_TotalIntBinaryOp<"shrsi"> {
856  let summary = "signed integer right-shift";
857  let description = [{
858    The `shrsi` operation shifts an integer value of the first operand to the right
859    by the value of the second operand. The first operand is interpreted as signed,
860    and the second operand is interpreter as unsigned. The high order bits in the
861    output are filled with copies of the most-significant bit of the shifted value
862    (which means that the sign of the value is preserved). If the value of the second
863    operand is greater or equal than bitwidth of the first operand, then the operation
864    returns poison.
865
866    Example:
867
868    ```mlir
869    %1 = arith.constant 160 : i8               // %1 is 0b10100000
870    %2 = arith.constant 3 : i8
871    %3 = arith.shrsi %1, %2 : (i8, i8) -> i8   // %3 is 0b11110100
872    %4 = arith.constant 96 : i8                   // %4 is 0b01100000
873    %5 = arith.shrsi %4, %2 : (i8, i8) -> i8   // %5 is 0b00001100
874    ```
875  }];
876  let hasFolder = 1;
877}
878
879//===----------------------------------------------------------------------===//
880// NegFOp
881//===----------------------------------------------------------------------===//
882
883def Arith_NegFOp : Arith_FloatUnaryOp<"negf"> {
884  let summary = "floating point negation";
885  let description = [{
886    The `negf` operation computes the negation of a given value. It takes one
887    operand and returns one result of the same type. This type may be a float
888    scalar type, a vector whose element type is float, or a tensor of floats.
889    It has no standard attributes.
890
891    Example:
892
893    ```mlir
894    // Scalar negation value.
895    %a = arith.negf %b : f64
896
897    // SIMD vector element-wise negation value.
898    %f = arith.negf %g : vector<4xf32>
899
900    // Tensor element-wise negation value.
901    %x = arith.negf %y : tensor<4x?xf8>
902    ```
903  }];
904  let hasFolder = 1;
905}
906
907//===----------------------------------------------------------------------===//
908// AddFOp
909//===----------------------------------------------------------------------===//
910
911def Arith_AddFOp : Arith_FloatBinaryOp<"addf", [Commutative]> {
912  let summary = "floating point addition operation";
913  let description = [{
914    The `addf` operation takes two operands and returns one result, each of
915    these is required to be the same type. This type may be a floating point
916    scalar type, a vector whose element type is a floating point type, or a
917    floating point tensor.
918
919    Example:
920
921    ```mlir
922    // Scalar addition.
923    %a = arith.addf %b, %c : f64
924
925    // SIMD vector addition, e.g. for Intel SSE.
926    %f = arith.addf %g, %h : vector<4xf32>
927
928    // Tensor addition.
929    %x = arith.addf %y, %z : tensor<4x?xbf16>
930    ```
931
932    TODO: In the distant future, this will accept optional attributes for fast
933    math, contraction, rounding mode, and other controls.
934  }];
935  let hasFolder = 1;
936}
937
938//===----------------------------------------------------------------------===//
939// SubFOp
940//===----------------------------------------------------------------------===//
941
942def Arith_SubFOp : Arith_FloatBinaryOp<"subf"> {
943  let summary = "floating point subtraction operation";
944  let description = [{
945    The `subf` operation takes two operands and returns one result, each of
946    these is required to be the same type. This type may be a floating point
947    scalar type, a vector whose element type is a floating point type, or a
948    floating point tensor.
949
950    Example:
951
952    ```mlir
953    // Scalar subtraction.
954    %a = arith.subf %b, %c : f64
955
956    // SIMD vector subtraction, e.g. for Intel SSE.
957    %f = arith.subf %g, %h : vector<4xf32>
958
959    // Tensor subtraction.
960    %x = arith.subf %y, %z : tensor<4x?xbf16>
961    ```
962
963    TODO: In the distant future, this will accept optional attributes for fast
964    math, contraction, rounding mode, and other controls.
965  }];
966  let hasFolder = 1;
967}
968
969//===----------------------------------------------------------------------===//
970// MaximumFOp
971//===----------------------------------------------------------------------===//
972
973def Arith_MaximumFOp : Arith_FloatBinaryOp<"maximumf", [Commutative]> {
974  let summary = "floating-point maximum operation";
975  let description = [{
976    Returns the maximum of the two arguments, treating -0.0 as less than +0.0.
977    If one of the arguments is NaN, then the result is also NaN.
978
979    Example:
980
981    ```mlir
982    // Scalar floating-point maximum.
983    %a = arith.maximumf %b, %c : f64
984    ```
985  }];
986  let hasFolder = 1;
987}
988
989//===----------------------------------------------------------------------===//
990// MaxNumFOp
991//===----------------------------------------------------------------------===//
992
993def Arith_MaxNumFOp : Arith_FloatBinaryOp<"maxnumf", [Commutative]> {
994  let summary = "floating-point maximum operation";
995  let description = [{
996    Returns the maximum of the two arguments.
997    If the arguments are -0.0 and +0.0, then the result is either of them.
998    If one of the arguments is NaN, then the result is the other argument.
999
1000    Example:
1001
1002    ```mlir
1003    // Scalar floating-point maximum.
1004    %a = arith.maxnumf %b, %c : f64
1005    ```
1006  }];
1007  let hasFolder = 1;
1008}
1009
1010
1011//===----------------------------------------------------------------------===//
1012// MaxSIOp
1013//===----------------------------------------------------------------------===//
1014
1015def Arith_MaxSIOp : Arith_TotalIntBinaryOp<"maxsi", [Commutative]> {
1016  let summary = "signed integer maximum operation";
1017  let hasFolder = 1;
1018}
1019
1020//===----------------------------------------------------------------------===//
1021// MaxUIOp
1022//===----------------------------------------------------------------------===//
1023
1024def Arith_MaxUIOp : Arith_TotalIntBinaryOp<"maxui", [Commutative]> {
1025  let summary = "unsigned integer maximum operation";
1026  let hasFolder = 1;
1027}
1028
1029//===----------------------------------------------------------------------===//
1030// MinimumFOp
1031//===----------------------------------------------------------------------===//
1032
1033def Arith_MinimumFOp : Arith_FloatBinaryOp<"minimumf", [Commutative]> {
1034  let summary = "floating-point minimum operation";
1035  let description = [{
1036    Returns the minimum of the two arguments, treating -0.0 as less than +0.0.
1037    If one of the arguments is NaN, then the result is also NaN.
1038
1039    Example:
1040
1041    ```mlir
1042    // Scalar floating-point minimum.
1043    %a = arith.minimumf %b, %c : f64
1044    ```
1045  }];
1046  let hasFolder = 1;
1047}
1048
1049//===----------------------------------------------------------------------===//
1050// MinNumFOp
1051//===----------------------------------------------------------------------===//
1052
1053def Arith_MinNumFOp : Arith_FloatBinaryOp<"minnumf", [Commutative]> {
1054  let summary = "floating-point minimum operation";
1055  let description = [{
1056    Returns the minimum of the two arguments.
1057    If the arguments are -0.0 and +0.0, then the result is either of them.
1058    If one of the arguments is NaN, then the result is the other argument.
1059
1060    Example:
1061
1062    ```mlir
1063    // Scalar floating-point minimum.
1064    %a = arith.minnumf %b, %c : f64
1065    ```
1066  }];
1067  let hasFolder = 1;
1068}
1069
1070//===----------------------------------------------------------------------===//
1071// MinSIOp
1072//===----------------------------------------------------------------------===//
1073
1074def Arith_MinSIOp : Arith_TotalIntBinaryOp<"minsi", [Commutative]> {
1075  let summary = "signed integer minimum operation";
1076  let hasFolder = 1;
1077}
1078
1079//===----------------------------------------------------------------------===//
1080// MinUIOp
1081//===----------------------------------------------------------------------===//
1082
1083def Arith_MinUIOp : Arith_TotalIntBinaryOp<"minui", [Commutative]> {
1084  let summary = "unsigned integer minimum operation";
1085  let hasFolder = 1;
1086}
1087
1088
1089//===----------------------------------------------------------------------===//
1090// MulFOp
1091//===----------------------------------------------------------------------===//
1092
1093def Arith_MulFOp : Arith_FloatBinaryOp<"mulf", [Commutative]> {
1094  let summary = "floating point multiplication operation";
1095  let description = [{
1096    The `mulf` operation takes two operands and returns one result, each of
1097    these is required to be the same type. This type may be a floating point
1098    scalar type, a vector whose element type is a floating point type, or a
1099    floating point tensor.
1100
1101    Example:
1102
1103    ```mlir
1104    // Scalar multiplication.
1105    %a = arith.mulf %b, %c : f64
1106
1107    // SIMD pointwise vector multiplication, e.g. for Intel SSE.
1108    %f = arith.mulf %g, %h : vector<4xf32>
1109
1110    // Tensor pointwise multiplication.
1111    %x = arith.mulf %y, %z : tensor<4x?xbf16>
1112    ```
1113
1114    TODO: In the distant future, this will accept optional attributes for fast
1115    math, contraction, rounding mode, and other controls.
1116  }];
1117  let hasFolder = 1;
1118  let hasCanonicalizer = 1;
1119}
1120
1121//===----------------------------------------------------------------------===//
1122// DivFOp
1123//===----------------------------------------------------------------------===//
1124
1125def Arith_DivFOp : Arith_FloatBinaryOp<"divf"> {
1126  let summary = "floating point division operation";
1127  let hasFolder = 1;
1128  let hasCanonicalizer = 1;
1129}
1130
1131//===----------------------------------------------------------------------===//
1132// RemFOp
1133//===----------------------------------------------------------------------===//
1134
1135def Arith_RemFOp : Arith_FloatBinaryOp<"remf"> {
1136  let summary = "floating point division remainder operation";
1137  let description = [{
1138    Returns the floating point division remainder.
1139    The remainder has the same sign as the dividend (lhs operand).
1140  }];
1141  let hasFolder = 1;
1142}
1143
1144//===----------------------------------------------------------------------===//
1145// ExtUIOp
1146//===----------------------------------------------------------------------===//
1147
1148def Arith_ExtUIOp : Arith_IToICastOp<"extui"> {
1149  let summary = "integer zero extension operation";
1150  let description = [{
1151    The integer zero extension operation takes an integer input of
1152    width M and an integer destination type of width N. The destination
1153    bit-width must be larger than the input bit-width (N > M).
1154    The top-most (N - M) bits of the output are filled with zeros.
1155
1156    Example:
1157
1158    ```mlir
1159      %1 = arith.constant 5 : i3      // %1 is 0b101
1160      %2 = arith.extui %1 : i3 to i6  // %2 is 0b000101
1161      %3 = arith.constant 2 : i3      // %3 is 0b010
1162      %4 = arith.extui %3 : i3 to i6  // %4 is 0b000010
1163
1164      %5 = arith.extui %0 : vector<2 x i32> to vector<2 x i64>
1165    ```
1166  }];
1167
1168  let hasFolder = 1;
1169  let hasVerifier = 1;
1170}
1171
1172//===----------------------------------------------------------------------===//
1173// ExtSIOp
1174//===----------------------------------------------------------------------===//
1175
1176def Arith_ExtSIOp : Arith_IToICastOp<"extsi"> {
1177  let summary = "integer sign extension operation";
1178
1179  let description = [{
1180    The integer sign extension operation takes an integer input of
1181    width M and an integer destination type of width N. The destination
1182    bit-width must be larger than the input bit-width (N > M).
1183    The top-most (N - M) bits of the output are filled with copies
1184    of the most-significant bit of the input.
1185
1186    Example:
1187
1188    ```mlir
1189    %1 = arith.constant 5 : i3      // %1 is 0b101
1190    %2 = arith.extsi %1 : i3 to i6  // %2 is 0b111101
1191    %3 = arith.constant 2 : i3      // %3 is 0b010
1192    %4 = arith.extsi %3 : i3 to i6  // %4 is 0b000010
1193
1194    %5 = arith.extsi %0 : vector<2 x i32> to vector<2 x i64>
1195    ```
1196  }];
1197
1198  let hasFolder = 1;
1199  let hasCanonicalizer = 1;
1200  let hasVerifier = 1;
1201}
1202
1203//===----------------------------------------------------------------------===//
1204// ExtFOp
1205//===----------------------------------------------------------------------===//
1206
1207def Arith_ExtFOp : Arith_FToFCastOp<"extf", [DeclareOpInterfaceMethods<ArithFastMathInterface>]> {
1208  let summary = "cast from floating-point to wider floating-point";
1209  let description = [{
1210    Cast a floating-point value to a larger floating-point-typed value.
1211    The destination type must to be strictly wider than the source type.
1212    When operating on vectors, casts elementwise.
1213  }];
1214  let hasVerifier = 1;
1215  let hasFolder = 1;
1216
1217  let arguments = (ins FloatLike:$in,
1218                       OptionalAttr<Arith_FastMathAttr>:$fastmath);
1219  let results = (outs FloatLike:$out);
1220
1221  let assemblyFormat = [{ $in (`fastmath` `` $fastmath^)?
1222                          attr-dict `:` type($in) `to` type($out) }];
1223}
1224
1225//===----------------------------------------------------------------------===//
1226// TruncIOp
1227//===----------------------------------------------------------------------===//
1228
1229def Arith_TruncIOp : Arith_IToICastOp<"trunci"> {
1230  let summary = "integer truncation operation";
1231  let description = [{
1232    The integer truncation operation takes an integer input of
1233    width M and an integer destination type of width N. The destination
1234    bit-width must be smaller than the input bit-width (N < M).
1235    The top-most (N - M) bits of the input are discarded.
1236
1237    Example:
1238
1239    ```mlir
1240      %1 = arith.constant 21 : i5     // %1 is 0b10101
1241      %2 = arith.trunci %1 : i5 to i4 // %2 is 0b0101
1242      %3 = arith.trunci %1 : i5 to i3 // %3 is 0b101
1243
1244      %5 = arith.trunci %0 : vector<2 x i32> to vector<2 x i16>
1245    ```
1246  }];
1247
1248  let hasFolder = 1;
1249  let hasCanonicalizer = 1;
1250  let hasVerifier = 1;
1251}
1252
1253//===----------------------------------------------------------------------===//
1254// TruncFOp
1255//===----------------------------------------------------------------------===//
1256
1257def Arith_TruncFOp :
1258    Arith_Op<"truncf",
1259      [Pure, SameOperandsAndResultShape, SameInputOutputTensorDims,
1260       DeclareOpInterfaceMethods<ArithRoundingModeInterface>,
1261       DeclareOpInterfaceMethods<ArithFastMathInterface>,
1262       DeclareOpInterfaceMethods<CastOpInterface>]>,
1263    Arguments<(ins FloatLike:$in,
1264                   OptionalAttr<Arith_RoundingModeAttr>:$roundingmode,
1265                   OptionalAttr<Arith_FastMathAttr>:$fastmath)>,
1266    Results<(outs FloatLike:$out)> {
1267  let summary = "cast from floating-point to narrower floating-point";
1268  let description = [{
1269    Truncate a floating-point value to a smaller floating-point-typed value.
1270    The destination type must be strictly narrower than the source type.
1271    If the value cannot be exactly represented, it is rounded using the
1272    provided rounding mode or the default one if no rounding mode is provided.
1273    When operating on vectors, casts elementwise.
1274  }];
1275  let builders = [
1276    OpBuilder<(ins "Type":$out, "Value":$in), [{
1277      $_state.addOperands(in);
1278      $_state.addTypes(out);
1279    }]>
1280  ];
1281
1282  let hasFolder = 1;
1283  let hasVerifier = 1;
1284  let assemblyFormat = [{ $in ($roundingmode^)?
1285                          (`fastmath` `` $fastmath^)?
1286                          attr-dict `:` type($in) `to` type($out) }];
1287}
1288
1289//===----------------------------------------------------------------------===//
1290// UIToFPOp
1291//===----------------------------------------------------------------------===//
1292
1293def Arith_UIToFPOp : Arith_IToFCastOp<"uitofp"> {
1294  let summary = "cast from unsigned integer type to floating-point";
1295  let description = [{
1296    Cast from a value interpreted as unsigned integer to the corresponding
1297    floating-point value. If the value cannot be exactly represented, it is
1298    rounded using the default rounding mode. When operating on vectors, casts
1299    elementwise.
1300  }];
1301  let hasFolder = 1;
1302}
1303
1304//===----------------------------------------------------------------------===//
1305// SIToFPOp
1306//===----------------------------------------------------------------------===//
1307
1308def Arith_SIToFPOp : Arith_IToFCastOp<"sitofp"> {
1309  let summary = "cast from integer type to floating-point";
1310  let description = [{
1311    Cast from a value interpreted as a signed integer to the corresponding
1312    floating-point value. If the value cannot be exactly represented, it is
1313    rounded using the default rounding mode. When operating on vectors, casts
1314    elementwise.
1315  }];
1316  let hasFolder = 1;
1317}
1318
1319//===----------------------------------------------------------------------===//
1320// FPToUIOp
1321//===----------------------------------------------------------------------===//
1322
1323def Arith_FPToUIOp : Arith_FToICastOp<"fptoui"> {
1324  let summary = "cast from floating-point type to integer type";
1325  let description = [{
1326    Cast from a value interpreted as floating-point to the nearest (rounding
1327    towards zero) unsigned integer value. When operating on vectors, casts
1328    elementwise.
1329  }];
1330  let hasFolder = 1;
1331}
1332
1333//===----------------------------------------------------------------------===//
1334// FPToSIOp
1335//===----------------------------------------------------------------------===//
1336
1337def Arith_FPToSIOp : Arith_FToICastOp<"fptosi"> {
1338  let summary = "cast from floating-point type to integer type";
1339  let description = [{
1340    Cast from a value interpreted as floating-point to the nearest (rounding
1341    towards zero) signed integer value. When operating on vectors, casts
1342    elementwise.
1343  }];
1344  let hasFolder = 1;
1345}
1346
1347//===----------------------------------------------------------------------===//
1348// IndexCastOp
1349//===----------------------------------------------------------------------===//
1350
1351// Index cast can convert between memrefs of signless integers and indices too.
1352def IndexCastTypeConstraint : TypeConstraint<Or<[
1353        SignlessIntegerOrIndexLike.predicate,
1354        MemRefOf<[AnySignlessInteger, Index]>.predicate]>,
1355    "signless-integer-like or memref of signless-integer">;
1356
1357def Arith_IndexCastOp
1358  : Arith_CastOp<"index_cast", IndexCastTypeConstraint, IndexCastTypeConstraint,
1359                 [DeclareOpInterfaceMethods<InferIntRangeInterface, ["inferResultRanges"]>]> {
1360  let summary = "cast between index and integer types";
1361  let description = [{
1362    Casts between scalar or vector integers and corresponding 'index' scalar or
1363    vectors. Index is an integer of platform-specific bit width. If casting to
1364    a wider integer, the value is sign-extended. If casting to a narrower
1365    integer, the value is truncated.
1366  }];
1367
1368  let hasFolder = 1;
1369  let hasCanonicalizer = 1;
1370}
1371
1372//===----------------------------------------------------------------------===//
1373// IndexCastUIOp
1374//===----------------------------------------------------------------------===//
1375
1376def Arith_IndexCastUIOp
1377  : Arith_CastOp<"index_castui", IndexCastTypeConstraint, IndexCastTypeConstraint,
1378                 [DeclareOpInterfaceMethods<InferIntRangeInterface, ["inferResultRanges"]>]> {
1379  let summary = "unsigned cast between index and integer types";
1380  let description = [{
1381    Casts between scalar or vector integers and corresponding 'index' scalar or
1382    vectors. Index is an integer of platform-specific bit width. If casting to
1383    a wider integer, the value is zero-extended. If casting to a narrower
1384    integer, the value is truncated.
1385  }];
1386
1387  let hasFolder = 1;
1388  let hasCanonicalizer = 1;
1389}
1390
1391//===----------------------------------------------------------------------===//
1392// BitcastOp
1393//===----------------------------------------------------------------------===//
1394
1395// Bitcast can convert between memrefs of signless integers and floats.
1396def BitcastTypeConstraint : TypeConstraint<Or<[
1397        SignlessIntegerOrFloatLike.predicate,
1398        MemRefOf<[AnySignlessInteger, AnyFloat]>.predicate]>,
1399    "signless-integer-or-float-like or memref of signless-integer or float">;
1400
1401def Arith_BitcastOp : Arith_CastOp<"bitcast", BitcastTypeConstraint,
1402                                              BitcastTypeConstraint> {
1403  let summary = "bitcast between values of equal bit width";
1404  let description = [{
1405    Bitcast an integer or floating point value to an integer or floating point
1406    value of equal bit width. When operating on vectors, casts elementwise.
1407
1408    Note that this implements a logical bitcast independent of target
1409    endianness. This allows constant folding without target information and is
1410    consitent with the bitcast constant folders in LLVM (see
1411    https://github.com/llvm/llvm-project/blob/18c19414eb/llvm/lib/IR/ConstantFold.cpp#L168)
1412    For targets where the source and target type have the same endianness (which
1413    is the standard), this cast will also change no bits at runtime, but it may
1414    still require an operation, for example if the machine has different
1415    floating point and integer register files. For targets that have a different
1416    endianness for the source and target types (e.g. float is big-endian and
1417    integer is little-endian) a proper lowering would add operations to swap the
1418    order of words in addition to the bitcast.
1419  }];
1420
1421  let hasFolder = 1;
1422  let hasCanonicalizer = 1;
1423}
1424
1425//===----------------------------------------------------------------------===//
1426// CmpIOp
1427//===----------------------------------------------------------------------===//
1428
1429def Arith_CmpIOp
1430  : Arith_CompareOpOfAnyRank<"cmpi",
1431                             [DeclareOpInterfaceMethods<InferIntRangeInterface, ["inferResultRanges"]>]> {
1432  let summary = "integer comparison operation";
1433  let description = [{
1434    The `cmpi` operation is a generic comparison for integer-like types. Its two
1435    arguments can be integers, vectors or tensors thereof as long as their types
1436    match. The operation produces an i1 for the former case, a vector or a
1437    tensor of i1 with the same shape as inputs in the other cases.
1438
1439    Its first argument is an attribute that defines which type of comparison is
1440    performed. The following comparisons are supported:
1441
1442    -   equal (mnemonic: `"eq"`; integer value: `0`)
1443    -   not equal (mnemonic: `"ne"`; integer value: `1`)
1444    -   signed less than (mnemonic: `"slt"`; integer value: `2`)
1445    -   signed less than or equal (mnemonic: `"sle"`; integer value: `3`)
1446    -   signed greater than (mnemonic: `"sgt"`; integer value: `4`)
1447    -   signed greater than or equal (mnemonic: `"sge"`; integer value: `5`)
1448    -   unsigned less than (mnemonic: `"ult"`; integer value: `6`)
1449    -   unsigned less than or equal (mnemonic: `"ule"`; integer value: `7`)
1450    -   unsigned greater than (mnemonic: `"ugt"`; integer value: `8`)
1451    -   unsigned greater than or equal (mnemonic: `"uge"`; integer value: `9`)
1452
1453    The result is `1` if the comparison is true and `0` otherwise. For vector or
1454    tensor operands, the comparison is performed elementwise and the element of
1455    the result indicates whether the comparison is true for the operand elements
1456    with the same indices as those of the result.
1457
1458    Note: while the custom assembly form uses strings, the actual underlying
1459    attribute has integer type (or rather enum class in C++ code) as seen from
1460    the generic assembly form. String literals are used to improve readability
1461    of the IR by humans.
1462
1463    This operation only applies to integer-like operands, but not floats. The
1464    main reason being that comparison operations have diverging sets of
1465    attributes: integers require sign specification while floats require various
1466    floating point-related particularities, e.g., `-ffast-math` behavior,
1467    IEEE754 compliance, etc
1468    ([rationale](../Rationale/Rationale.md#splitting-floating-point-vs-integer-operations)).
1469    The type of comparison is specified as attribute to avoid introducing ten
1470    similar operations, taking into account that they are often implemented
1471    using the same operation downstream
1472    ([rationale](../Rationale/Rationale.md#specifying-comparison-kind-as-attribute)). The
1473    separation between signed and unsigned order comparisons is necessary
1474    because of integers being signless. The comparison operation must know how
1475    to interpret values with the foremost bit being set: negatives in two's
1476    complement or large positives
1477    ([rationale](../Rationale/Rationale.md#specifying-sign-in-integer-comparison-operations)).
1478
1479    Example:
1480
1481    ```mlir
1482    // Custom form of scalar "signed less than" comparison.
1483    %x = arith.cmpi slt, %lhs, %rhs : i32
1484
1485    // Generic form of the same operation.
1486    %x = "arith.cmpi"(%lhs, %rhs) {predicate = 2 : i64} : (i32, i32) -> i1
1487
1488    // Custom form of vector equality comparison.
1489    %x = arith.cmpi eq, %lhs, %rhs : vector<4xi64>
1490
1491    // Generic form of the same operation.
1492    %x = "arith.cmpi"(%lhs, %rhs) {predicate = 0 : i64}
1493        : (vector<4xi64>, vector<4xi64>) -> vector<4xi1>
1494    ```
1495  }];
1496
1497  let arguments = (ins Arith_CmpIPredicateAttr:$predicate,
1498                       SignlessIntegerOrIndexLikeOfAnyRank:$lhs,
1499                       SignlessIntegerOrIndexLikeOfAnyRank:$rhs);
1500
1501  let hasFolder = 1;
1502  let hasCanonicalizer = 1;
1503}
1504
1505//===----------------------------------------------------------------------===//
1506// CmpFOp
1507//===----------------------------------------------------------------------===//
1508
1509def Arith_CmpFOp : Arith_CompareOp<"cmpf",
1510    [DeclareOpInterfaceMethods<ArithFastMathInterface>]> {
1511  let summary = "floating-point comparison operation";
1512  let description = [{
1513    The `cmpf` operation compares its two operands according to the float
1514    comparison rules and the predicate specified by the respective attribute.
1515    The predicate defines the type of comparison: (un)orderedness, (in)equality
1516    and signed less/greater than (or equal to) as well as predicates that are
1517    always true or false.  The operands must have the same type, and this type
1518    must be a float type, or a vector or tensor thereof.  The result is an i1,
1519    or a vector/tensor thereof having the same shape as the inputs. Unlike cmpi,
1520    the operands are always treated as signed. The u prefix indicates
1521    *unordered* comparison, not unsigned comparison, so "une" means unordered or
1522    not equal. For the sake of readability by humans, custom assembly form for
1523    the operation uses a string-typed attribute for the predicate.  The value of
1524    this attribute corresponds to lower-cased name of the predicate constant,
1525    e.g., "one" means "ordered not equal".  The string representation of the
1526    attribute is merely a syntactic sugar and is converted to an integer
1527    attribute by the parser.
1528
1529    Example:
1530
1531    ```mlir
1532    %r1 = arith.cmpf oeq, %0, %1 : f32
1533    %r2 = arith.cmpf ult, %0, %1 : tensor<42x42xf64>
1534    %r3 = "arith.cmpf"(%0, %1) {predicate: 0} : (f8, f8) -> i1
1535    ```
1536  }];
1537
1538  let arguments = (ins Arith_CmpFPredicateAttr:$predicate,
1539                       FloatLike:$lhs,
1540                       FloatLike:$rhs,
1541                       DefaultValuedAttr<
1542                         Arith_FastMathAttr, "::mlir::arith::FastMathFlags::none">:$fastmath);
1543
1544  let hasFolder = 1;
1545  let hasCanonicalizer = 1;
1546  let assemblyFormat = [{ $predicate `,` $lhs `,` $rhs (`fastmath` `` $fastmath^)?
1547                          attr-dict `:` type($lhs)}];
1548}
1549
1550//===----------------------------------------------------------------------===//
1551// SelectOp
1552//===----------------------------------------------------------------------===//
1553
1554class BooleanConditionOrMatchingShape<string condition, string result> :
1555    PredOpTrait<
1556      condition # " is signless i1 or has matching shape",
1557      Or<[TypeIsPred<condition, I1>,
1558          AllShapesMatch<[condition, result]>.predicate]>>;
1559
1560def SelectOp : Arith_Op<"select", [Pure,
1561    AllTypesMatch<["true_value", "false_value", "result"]>,
1562    BooleanConditionOrMatchingShape<"condition", "result">,
1563    DeclareOpInterfaceMethods<InferIntRangeInterface, ["inferResultRangesFromOptional"]>,
1564    DeclareOpInterfaceMethods<SelectLikeOpInterface>,
1565  ] # ElementwiseMappable.traits> {
1566  let summary = "select operation";
1567  let description = [{
1568    The `arith.select` operation chooses one value based on a binary condition
1569    supplied as its first operand.
1570
1571    If the value of the first operand (the condition) is `1`, then the second
1572    operand is returned, and the third operand is ignored, even if it was poison.
1573
1574    If the value of the first operand (the condition) is `0`, then the third
1575    operand is returned, and the second operand is ignored, even if it was poison.
1576
1577    If the value of the first operand (the condition) is poison, then the
1578    operation returns poison.
1579
1580    The operation applies to vectors and tensors elementwise given the _shape_
1581    of all operands is identical. The choice is made for each element
1582    individually based on the value at the same position as the element in the
1583    condition operand. If an i1 is provided as the condition, the entire vector
1584    or tensor is chosen.
1585
1586    Example:
1587
1588    ```mlir
1589    // Custom form of scalar selection.
1590    %x = arith.select %cond, %true, %false : i32
1591
1592    // Generic form of the same operation.
1593    %x = "arith.select"(%cond, %true, %false) : (i1, i32, i32) -> i32
1594
1595    // Element-wise vector selection.
1596    %vx = arith.select %vcond, %vtrue, %vfalse : vector<42xi1>, vector<42xf32>
1597
1598    // Full vector selection.
1599    %vx = arith.select %cond, %vtrue, %vfalse : vector<42xf32>
1600    ```
1601  }];
1602
1603  let arguments = (ins BoolLike:$condition,
1604                       AnyType:$true_value,
1605                       AnyType:$false_value);
1606  let results = (outs AnyType:$result);
1607
1608  let hasCanonicalizer = 1;
1609  let hasFolder = 1;
1610  let hasVerifier = 1;
1611
1612  // FIXME: Switch this to use the declarative assembly format.
1613  let hasCustomAssemblyFormat = 1;
1614}
1615
1616#endif // ARITH_OPS
1617