1//===- ArithmeticOps.td - Arithmetic 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 ARITHMETIC_OPS
10#define ARITHMETIC_OPS
11
12include "mlir/Dialect/Arithmetic/IR/ArithmeticBase.td"
13include "mlir/Interfaces/CastInterfaces.td"
14include "mlir/Interfaces/InferIntRangeInterface.td"
15include "mlir/Interfaces/InferTypeOpInterface.td"
16include "mlir/Interfaces/SideEffectInterfaces.td"
17include "mlir/Interfaces/VectorInterfaces.td"
18include "mlir/IR/OpAsmInterface.td"
19
20// Base class for Arithmetic dialect ops. Ops in this dialect have no side
21// effects and can be applied element-wise to vectors and tensors.
22class Arith_Op<string mnemonic, list<Trait> traits = []> :
23    Op<Arithmetic_Dialect, mnemonic, traits # [NoSideEffect,
24    DeclareOpInterfaceMethods<VectorUnrollOpInterface>] #
25    ElementwiseMappable.traits>;
26
27// Base class for integer and floating point arithmetic ops. All ops have one
28// result, require operands and results to be of the same type, and can accept
29// tensors or vectors of integers or floats.
30class Arith_ArithmeticOp<string mnemonic, list<Trait> traits = []> :
31    Arith_Op<mnemonic, traits # [SameOperandsAndResultType]>;
32
33// Base class for unary arithmetic operations.
34class Arith_UnaryOp<string mnemonic, list<Trait> traits = []> :
35    Arith_ArithmeticOp<mnemonic, traits> {
36  let assemblyFormat = "$operand attr-dict `:` type($result)";
37}
38
39// Base class for binary arithmetic operations.
40class Arith_BinaryOp<string mnemonic, list<Trait> traits = []> :
41    Arith_ArithmeticOp<mnemonic, traits> {
42  let assemblyFormat = "$lhs `,` $rhs attr-dict `:` type($result)";
43}
44
45// Base class for ternary arithmetic operations.
46class Arith_TernaryOp<string mnemonic, list<Trait> traits = []> :
47    Arith_ArithmeticOp<mnemonic, traits> {
48  let assemblyFormat = "$a `,` $b `,` $c attr-dict `:` type($result)";
49}
50
51// Base class for integer binary operations.
52class Arith_IntBinaryOp<string mnemonic, list<Trait> traits = []> :
53    Arith_BinaryOp<mnemonic, traits #
54      [DeclareOpInterfaceMethods<InferIntRangeInterface>]>,
55    Arguments<(ins SignlessIntegerLike:$lhs, SignlessIntegerLike:$rhs)>,
56    Results<(outs SignlessIntegerLike:$result)>;
57
58// Base class for floating point unary operations.
59class Arith_FloatUnaryOp<string mnemonic, list<Trait> traits = []> :
60    Arith_UnaryOp<mnemonic, traits>,
61    Arguments<(ins FloatLike:$operand)>,
62    Results<(outs FloatLike:$result)>;
63
64// Base class for floating point binary operations.
65class Arith_FloatBinaryOp<string mnemonic, list<Trait> traits = []> :
66    Arith_BinaryOp<mnemonic, traits>,
67    Arguments<(ins FloatLike:$lhs, FloatLike:$rhs)>,
68    Results<(outs FloatLike:$result)>;
69
70// Base class for arithmetic cast operations. Requires a single operand and
71// result. If either is a shaped type, then the other must be of the same shape.
72class Arith_CastOp<string mnemonic, TypeConstraint From, TypeConstraint To,
73                   list<Trait> traits = []> :
74    Arith_Op<mnemonic, traits # [SameOperandsAndResultShape,
75      DeclareOpInterfaceMethods<CastOpInterface>]>,
76    Arguments<(ins From:$in)>,
77    Results<(outs To:$out)> {
78  let assemblyFormat = "$in attr-dict `:` type($in) `to` type($out)";
79}
80
81// Casts do not accept indices. Type constraint for signless-integer-like types
82// excluding indices: signless integers, vectors or tensors thereof.
83def SignlessFixedWidthIntegerLike : TypeConstraint<Or<[
84        AnySignlessInteger.predicate,
85        VectorOf<[AnySignlessInteger]>.predicate,
86        TensorOf<[AnySignlessInteger]>.predicate]>,
87    "signless-fixed-width-integer-like">;
88
89// Cast from an integer type to another integer type.
90class Arith_IToICastOp<string mnemonic, list<Trait> traits = []> :
91    Arith_CastOp<mnemonic, SignlessFixedWidthIntegerLike,
92                           SignlessFixedWidthIntegerLike,
93                           traits #
94                           [DeclareOpInterfaceMethods<InferIntRangeInterface>]>;
95// Cast from an integer type to a floating point type.
96class Arith_IToFCastOp<string mnemonic, list<Trait> traits = []> :
97    Arith_CastOp<mnemonic, SignlessFixedWidthIntegerLike, FloatLike, traits>;
98// Cast from a floating point type to an integer type.
99class Arith_FToICastOp<string mnemonic, list<Trait> traits = []> :
100    Arith_CastOp<mnemonic, FloatLike, SignlessFixedWidthIntegerLike, traits>;
101// Cast from a floating point type to another floating point type.
102class Arith_FToFCastOp<string mnemonic, list<Trait> traits = []> :
103    Arith_CastOp<mnemonic, FloatLike, FloatLike, traits>;
104
105// Base class for compare operations. Requires two operands of the same type
106// and returns a single `BoolLike` result. If the operand type is a vector or
107// tensor, then the result will be one of `i1` of the same shape.
108class Arith_CompareOp<string mnemonic, list<Trait> traits = []> :
109    Arith_Op<mnemonic, traits # [SameTypeOperands, TypesMatchWith<
110    "result type has i1 element type and same shape as operands",
111    "lhs", "result", "::getI1SameShape($_self)">]> {
112  let results = (outs BoolLike:$result);
113
114  let assemblyFormat = "$predicate `,` $lhs `,` $rhs attr-dict `:` type($lhs)";
115}
116
117// Just like `Arith_CompareOp` but also admits 0-D vectors. Introduced
118// temporarily to allow gradual transition to 0-D vectors.
119class Arith_CompareOpOfAnyRank<string mnemonic, list<Trait> traits = []> :
120    Arith_CompareOp<mnemonic, traits> {
121  let results = (outs BoolLikeOfAnyRank:$result);
122}
123
124//===----------------------------------------------------------------------===//
125// ConstantOp
126//===----------------------------------------------------------------------===//
127
128def Arith_ConstantOp : Op<Arithmetic_Dialect, "constant",
129    [ConstantLike, NoSideEffect,
130     DeclareOpInterfaceMethods<OpAsmOpInterface, ["getAsmResultNames"]>,
131     AllTypesMatch<["value", "result"]>,
132     DeclareOpInterfaceMethods<InferIntRangeInterface>]> {
133  let summary = "integer or floating point constant";
134  let description = [{
135    The `constant` operation produces an SSA value equal to some integer or
136    floating-point constant specified by an attribute. This is the way MLIR
137    forms simple integer and floating point constants.
138
139    Example:
140
141    ```
142    // Integer constant
143    %1 = arith.constant 42 : i32
144
145    // Equivalent generic form
146    %1 = "arith.constant"() {value = 42 : i32} : () -> i32
147    ```
148  }];
149
150  let arguments = (ins AnyAttr:$value);
151  // TODO: Disallow arith.constant to return anything other than a signless
152  // integer or float like. Downstream users of Arithmetic should only be
153  // working with signless integers, floats, or vectors/tensors thereof.
154  // However, it is necessary to allow arith.constant to return vectors/tensors
155  // of strings and signed/unsigned integers (for now) as an artefact of
156  // splitting the Standard dialect.
157  let results = (outs /*SignlessIntegerOrFloatLike*/AnyType:$result);
158
159  let builders = [
160    OpBuilder<(ins "Attribute":$value, "Type":$type),
161    [{ build($_builder, $_state, type, value); }]>,
162  ];
163
164  let extraClassDeclaration = [{
165    /// Whether the constant op can be constructed with a particular value and
166    /// type.
167    static bool isBuildableWith(Attribute value, Type type);
168  }];
169
170  let hasFolder = 1;
171  let assemblyFormat = "attr-dict $value";
172  let hasVerifier = 1;
173}
174
175//===----------------------------------------------------------------------===//
176// AddIOp
177//===----------------------------------------------------------------------===//
178
179def Arith_AddIOp : Arith_IntBinaryOp<"addi", [Commutative]> {
180  let summary = "integer addition operation";
181  let description = [{
182    The `addi` operation takes two operands and returns one result, each of
183    these is required to be the same type. This type may be an integer scalar
184    type, a vector whose element type is integer, or a tensor of integers. It
185    has no standard attributes.
186
187    Example:
188
189    ```mlir
190    // Scalar addition.
191    %a = arith.addi %b, %c : i64
192
193    // SIMD vector element-wise addition, e.g. for Intel SSE.
194    %f = arith.addi %g, %h : vector<4xi32>
195
196    // Tensor element-wise addition.
197    %x = arith.addi %y, %z : tensor<4x?xi8>
198    ```
199  }];
200  let hasFolder = 1;
201  let hasCanonicalizer = 1;
202}
203
204//===----------------------------------------------------------------------===//
205// SubIOp
206//===----------------------------------------------------------------------===//
207
208def Arith_SubIOp : Arith_IntBinaryOp<"subi"> {
209  let summary = "integer subtraction operation";
210  let hasFolder = 1;
211  let hasCanonicalizer = 1;
212}
213
214//===----------------------------------------------------------------------===//
215// MulIOp
216//===----------------------------------------------------------------------===//
217
218def Arith_MulIOp : Arith_IntBinaryOp<"muli", [Commutative]> {
219  let summary = "integer multiplication operation";
220  let hasFolder = 1;
221}
222
223//===----------------------------------------------------------------------===//
224// DivUIOp
225//===----------------------------------------------------------------------===//
226
227def Arith_DivUIOp : Arith_IntBinaryOp<"divui"> {
228  let summary = "unsigned integer division operation";
229  let description = [{
230    Unsigned integer division. Rounds towards zero. Treats the leading bit as
231    the most significant, i.e. for `i16` given two's complement representation,
232    `6 / -2 = 6 / (2^16 - 2) = 0`.
233
234    Note: the semantics of division by zero is TBD; do NOT assume any specific
235    behavior.
236
237    Example:
238
239    ```mlir
240    // Scalar unsigned integer division.
241    %a = arith.divui %b, %c : i64
242
243    // SIMD vector element-wise division.
244    %f = arith.divui %g, %h : vector<4xi32>
245
246    // Tensor element-wise integer division.
247    %x = arith.divui %y, %z : tensor<4x?xi8>
248    ```
249  }];
250  let hasFolder = 1;
251}
252
253//===----------------------------------------------------------------------===//
254// DivSIOp
255//===----------------------------------------------------------------------===//
256
257def Arith_DivSIOp : Arith_IntBinaryOp<"divsi"> {
258  let summary = "signed integer division operation";
259  let description = [{
260    Signed integer division. Rounds towards zero. Treats the leading bit as
261    sign, i.e. `6 / -2 = -3`.
262
263    Note: the semantics of division by zero or signed division overflow (minimum
264    value divided by -1) is TBD; do NOT assume any specific behavior.
265
266    Example:
267
268    ```mlir
269    // Scalar signed integer division.
270    %a = arith.divsi %b, %c : i64
271
272    // SIMD vector element-wise division.
273    %f = arith.divsi %g, %h : vector<4xi32>
274
275    // Tensor element-wise integer division.
276    %x = arith.divsi %y, %z : tensor<4x?xi8>
277    ```
278  }];
279  let hasFolder = 1;
280}
281
282//===----------------------------------------------------------------------===//
283// CeilDivUIOp
284//===----------------------------------------------------------------------===//
285
286def Arith_CeilDivUIOp : Arith_IntBinaryOp<"ceildivui"> {
287  let summary = "unsigned ceil integer division operation";
288  let description = [{
289    Unsigned integer division. Rounds towards positive infinity. Treats the
290    leading bit as the most significant, i.e. for `i16` given two's complement
291    representation, `6 / -2 = 6 / (2^16 - 2) = 1`.
292
293    Note: the semantics of division by zero is TBD; do NOT assume any specific
294    behavior.
295
296    Example:
297
298    ```mlir
299    // Scalar unsigned integer division.
300    %a = arith.ceildivui %b, %c : i64
301    ```
302  }];
303  let hasFolder = 1;
304}
305
306//===----------------------------------------------------------------------===//
307// CeilDivSIOp
308//===----------------------------------------------------------------------===//
309
310def Arith_CeilDivSIOp : Arith_IntBinaryOp<"ceildivsi"> {
311  let summary = "signed ceil integer division operation";
312  let description = [{
313    Signed integer division. Rounds towards positive infinity, i.e. `7 / -2 = -3`.
314
315    Note: the semantics of division by zero or signed division overflow (minimum
316    value divided by -1) is TBD; do NOT assume any specific behavior.
317
318    Example:
319
320    ```mlir
321    // Scalar signed integer division.
322    %a = arith.ceildivsi %b, %c : i64
323    ```
324  }];
325  let hasFolder = 1;
326}
327
328//===----------------------------------------------------------------------===//
329// FloorDivSIOp
330//===----------------------------------------------------------------------===//
331
332def Arith_FloorDivSIOp : Arith_IntBinaryOp<"floordivsi"> {
333  let summary = "signed floor integer division operation";
334  let description = [{
335    Signed integer division. Rounds towards negative infinity, i.e. `5 / -2 = -3`.
336
337    Note: the semantics of division by zero or signed division overflow (minimum
338    value divided by -1) is TBD; do NOT assume any specific behavior.
339
340    Example:
341
342    ```mlir
343    // Scalar signed integer division.
344    %a = arith.floordivsi %b, %c : i64
345
346    ```
347  }];
348  let hasFolder = 1;
349}
350
351//===----------------------------------------------------------------------===//
352// RemUIOp
353//===----------------------------------------------------------------------===//
354
355def Arith_RemUIOp : Arith_IntBinaryOp<"remui"> {
356  let summary = "unsigned integer division remainder operation";
357  let description = [{
358    Unsigned integer division remainder. Treats the leading bit as the most
359    significant, i.e. for `i16`, `6 % -2 = 6 % (2^16 - 2) = 6`.
360
361    Note: the semantics of division by zero is TBD; do NOT assume any specific
362    behavior.
363
364    Example:
365
366    ```mlir
367    // Scalar unsigned integer division remainder.
368    %a = arith.remui %b, %c : i64
369
370    // SIMD vector element-wise division remainder.
371    %f = arith.remui %g, %h : vector<4xi32>
372
373    // Tensor element-wise integer division remainder.
374    %x = arith.remui %y, %z : tensor<4x?xi8>
375    ```
376  }];
377  let hasFolder = 1;
378}
379
380//===----------------------------------------------------------------------===//
381// RemSIOp
382//===----------------------------------------------------------------------===//
383
384def Arith_RemSIOp : Arith_IntBinaryOp<"remsi"> {
385  let summary = "signed integer division remainder operation";
386  let description = [{
387    Signed integer division remainder. Treats the leading bit as sign, i.e. `6 %
388    -2 = 0`.
389
390    Note: the semantics of division by zero is TBD; do NOT assume any specific
391    behavior.
392
393    Example:
394
395    ```mlir
396    // Scalar signed integer division remainder.
397    %a = arith.remsi %b, %c : i64
398
399    // SIMD vector element-wise division remainder.
400    %f = arith.remsi %g, %h : vector<4xi32>
401
402    // Tensor element-wise integer division remainder.
403    %x = arith.remsi %y, %z : tensor<4x?xi8>
404    ```
405  }];
406  let hasFolder = 1;
407}
408
409//===----------------------------------------------------------------------===//
410// AndIOp
411//===----------------------------------------------------------------------===//
412
413def Arith_AndIOp : Arith_IntBinaryOp<"andi", [Commutative, Idempotent]> {
414  let summary = "integer binary and";
415  let description = [{
416    The `andi` operation takes two operands and returns one result, each of
417    these is required to be the same type. This type may be an integer scalar
418    type, a vector whose element type is integer, or a tensor of integers. It
419    has no standard attributes.
420
421    Example:
422
423    ```mlir
424    // Scalar integer bitwise and.
425    %a = arith.andi %b, %c : i64
426
427    // SIMD vector element-wise bitwise integer and.
428    %f = arith.andi %g, %h : vector<4xi32>
429
430    // Tensor element-wise bitwise integer and.
431    %x = arith.andi %y, %z : tensor<4x?xi8>
432    ```
433  }];
434  let hasFolder = 1;
435  let hasCanonicalizer = 1;
436}
437
438//===----------------------------------------------------------------------===//
439// OrIOp
440//===----------------------------------------------------------------------===//
441
442def Arith_OrIOp : Arith_IntBinaryOp<"ori", [Commutative, Idempotent]> {
443  let summary = "integer binary or";
444  let description = [{
445    The `ori` operation takes two operands and returns one result, each of these
446    is required to be the same type. This type may be an integer scalar type, a
447    vector whose element type is integer, or a tensor of integers. It has no
448    standard attributes.
449
450    Example:
451
452    ```mlir
453    // Scalar integer bitwise or.
454    %a = arith.ori %b, %c : i64
455
456    // SIMD vector element-wise bitwise integer or.
457    %f = arith.ori %g, %h : vector<4xi32>
458
459    // Tensor element-wise bitwise integer or.
460    %x = arith.ori %y, %z : tensor<4x?xi8>
461    ```
462  }];
463  let hasFolder = 1;
464  let hasCanonicalizer = 1;
465}
466
467//===----------------------------------------------------------------------===//
468// XOrIOp
469//===----------------------------------------------------------------------===//
470
471def Arith_XOrIOp : Arith_IntBinaryOp<"xori", [Commutative]> {
472  let summary = "integer binary xor";
473  let description = [{
474    The `xori` operation takes two operands and returns one result, each of
475    these is required to be the same type. This type may be an integer scalar
476    type, a vector whose element type is integer, or a tensor of integers. It
477    has no standard attributes.
478
479    Example:
480
481    ```mlir
482    // Scalar integer bitwise xor.
483    %a = arith.xori %b, %c : i64
484
485    // SIMD vector element-wise bitwise integer xor.
486    %f = arith.xori %g, %h : vector<4xi32>
487
488    // Tensor element-wise bitwise integer xor.
489    %x = arith.xori %y, %z : tensor<4x?xi8>
490    ```
491  }];
492  let hasFolder = 1;
493  let hasCanonicalizer = 1;
494}
495
496//===----------------------------------------------------------------------===//
497// ShLIOp
498//===----------------------------------------------------------------------===//
499
500def Arith_ShLIOp : Arith_IntBinaryOp<"shli"> {
501  let summary = "integer left-shift";
502  let description = [{
503    The `shli` operation shifts an integer value to the left by a variable
504    amount. The low order bits are filled with zeros.
505
506    Example:
507
508    ```mlir
509    %1 = arith.constant 5 : i8                 // %1 is 0b00000101
510    %2 = arith.constant 3 : i8
511    %3 = arith.shli %1, %2 : (i8, i8) -> i8    // %3 is 0b00101000
512    ```
513  }];
514  let hasFolder = 1;
515}
516
517//===----------------------------------------------------------------------===//
518// ShRUIOp
519//===----------------------------------------------------------------------===//
520
521def Arith_ShRUIOp : Arith_IntBinaryOp<"shrui"> {
522  let summary = "unsigned integer right-shift";
523  let description = [{
524    The `shrui` operation shifts an integer value to the right by a variable
525    amount. The integer is interpreted as unsigned. The high order bits are
526    always filled with zeros.
527
528    Example:
529
530    ```mlir
531    %1 = arith.constant 160 : i8               // %1 is 0b10100000
532    %2 = arith.constant 3 : i8
533    %3 = arith.shrui %1, %2 : (i8, i8) -> i8   // %3 is 0b00010100
534    ```
535  }];
536  let hasFolder = 1;
537}
538
539//===----------------------------------------------------------------------===//
540// ShRSIOp
541//===----------------------------------------------------------------------===//
542
543def Arith_ShRSIOp : Arith_IntBinaryOp<"shrsi"> {
544  let summary = "signed integer right-shift";
545  let description = [{
546    The `shrsi` operation shifts an integer value to the right by a variable
547    amount. The integer is interpreted as signed. The high order bits in the
548    output are filled with copies of the most-significant bit of the shifted
549    value (which means that the sign of the value is preserved).
550
551    Example:
552
553    ```mlir
554    %1 = arith.constant 160 : i8               // %1 is 0b10100000
555    %2 = arith.constant 3 : i8
556    %3 = arith.shrsi %1, %2 : (i8, i8) -> i8   // %3 is 0b11110100
557    %4 = arith.constant 96 : i8                   // %4 is 0b01100000
558    %5 = arith.shrsi %4, %2 : (i8, i8) -> i8   // %5 is 0b00001100
559    ```
560  }];
561  let hasFolder = 1;
562}
563
564//===----------------------------------------------------------------------===//
565// NegFOp
566//===----------------------------------------------------------------------===//
567
568def Arith_NegFOp : Arith_FloatUnaryOp<"negf"> {
569  let summary = "floating point negation";
570  let description = [{
571    The `negf` operation computes the negation of a given value. It takes one
572    operand and returns one result of the same type. This type may be a float
573    scalar type, a vector whose element type is float, or a tensor of floats.
574    It has no standard attributes.
575
576    Example:
577
578    ```mlir
579    // Scalar negation value.
580    %a = arith.negf %b : f64
581
582    // SIMD vector element-wise negation value.
583    %f = arith.negf %g : vector<4xf32>
584
585    // Tensor element-wise negation value.
586    %x = arith.negf %y : tensor<4x?xf8>
587    ```
588  }];
589  let hasFolder = 1;
590}
591
592//===----------------------------------------------------------------------===//
593// AddFOp
594//===----------------------------------------------------------------------===//
595
596def Arith_AddFOp : Arith_FloatBinaryOp<"addf", [Commutative]> {
597  let summary = "floating point addition operation";
598  let description = [{
599    The `addf` operation takes two operands and returns one result, each of
600    these is required to be the same type. This type may be a floating point
601    scalar type, a vector whose element type is a floating point type, or a
602    floating point tensor.
603
604    Example:
605
606    ```mlir
607    // Scalar addition.
608    %a = arith.addf %b, %c : f64
609
610    // SIMD vector addition, e.g. for Intel SSE.
611    %f = arith.addf %g, %h : vector<4xf32>
612
613    // Tensor addition.
614    %x = arith.addf %y, %z : tensor<4x?xbf16>
615    ```
616
617    TODO: In the distant future, this will accept optional attributes for fast
618    math, contraction, rounding mode, and other controls.
619  }];
620  let hasFolder = 1;
621}
622
623//===----------------------------------------------------------------------===//
624// SubFOp
625//===----------------------------------------------------------------------===//
626
627def Arith_SubFOp : Arith_FloatBinaryOp<"subf"> {
628  let summary = "floating point subtraction operation";
629  let description = [{
630    The `subf` operation takes two operands and returns one result, each of
631    these is required to be the same type. This type may be a floating point
632    scalar type, a vector whose element type is a floating point type, or a
633    floating point tensor.
634
635    Example:
636
637    ```mlir
638    // Scalar subtraction.
639    %a = arith.subf %b, %c : f64
640
641    // SIMD vector subtraction, e.g. for Intel SSE.
642    %f = arith.subf %g, %h : vector<4xf32>
643
644    // Tensor subtraction.
645    %x = arith.subf %y, %z : tensor<4x?xbf16>
646    ```
647
648    TODO: In the distant future, this will accept optional attributes for fast
649    math, contraction, rounding mode, and other controls.
650  }];
651  let hasFolder = 1;
652}
653
654//===----------------------------------------------------------------------===//
655// MaxFOp
656//===----------------------------------------------------------------------===//
657
658def Arith_MaxFOp : Arith_FloatBinaryOp<"maxf", [Commutative]> {
659  let summary = "floating-point maximum operation";
660  let description = [{
661    Syntax:
662
663    ```
664    operation ::= ssa-id `=` `arith.maxf` ssa-use `,` ssa-use `:` type
665    ```
666
667    Returns the maximum of the two arguments, treating -0.0 as less than +0.0.
668    If one of the arguments is NaN, then the result is also NaN.
669
670    Example:
671
672    ```mlir
673    // Scalar floating-point maximum.
674    %a = arith.maxf %b, %c : f64
675    ```
676  }];
677  let hasFolder = 1;
678}
679
680//===----------------------------------------------------------------------===//
681// MaxSIOp
682//===----------------------------------------------------------------------===//
683
684def Arith_MaxSIOp : Arith_IntBinaryOp<"maxsi", [Commutative]> {
685  let summary = "signed integer maximum operation";
686  let hasFolder = 1;
687}
688
689//===----------------------------------------------------------------------===//
690// MaxUIOp
691//===----------------------------------------------------------------------===//
692
693def Arith_MaxUIOp : Arith_IntBinaryOp<"maxui", [Commutative]> {
694  let summary = "unsigned integer maximum operation";
695  let hasFolder = 1;
696}
697
698//===----------------------------------------------------------------------===//
699// MinFOp
700//===----------------------------------------------------------------------===//
701
702def Arith_MinFOp : Arith_FloatBinaryOp<"minf", [Commutative]> {
703  let summary = "floating-point minimum operation";
704  let description = [{
705    Syntax:
706
707    ```
708    operation ::= ssa-id `=` `arith.minf` ssa-use `,` ssa-use `:` type
709    ```
710
711    Returns the minimum of the two arguments, treating -0.0 as less than +0.0.
712    If one of the arguments is NaN, then the result is also NaN.
713
714    Example:
715
716    ```mlir
717    // Scalar floating-point minimum.
718    %a = arith.minf %b, %c : f64
719    ```
720  }];
721  let hasFolder = 1;
722}
723
724//===----------------------------------------------------------------------===//
725// MinSIOp
726//===----------------------------------------------------------------------===//
727
728def Arith_MinSIOp : Arith_IntBinaryOp<"minsi", [Commutative]> {
729  let summary = "signed integer minimum operation";
730  let hasFolder = 1;
731}
732
733//===----------------------------------------------------------------------===//
734// MinUIOp
735//===----------------------------------------------------------------------===//
736
737def Arith_MinUIOp : Arith_IntBinaryOp<"minui", [Commutative]> {
738  let summary = "unsigned integer minimum operation";
739  let hasFolder = 1;
740}
741
742
743//===----------------------------------------------------------------------===//
744// MulFOp
745//===----------------------------------------------------------------------===//
746
747def Arith_MulFOp : Arith_FloatBinaryOp<"mulf", [Commutative]> {
748  let summary = "floating point multiplication operation";
749  let description = [{
750    The `mulf` operation takes two operands and returns one result, each of
751    these is required to be the same type. This type may be a floating point
752    scalar type, a vector whose element type is a floating point type, or a
753    floating point tensor.
754
755    Example:
756
757    ```mlir
758    // Scalar multiplication.
759    %a = arith.mulf %b, %c : f64
760
761    // SIMD pointwise vector multiplication, e.g. for Intel SSE.
762    %f = arith.mulf %g, %h : vector<4xf32>
763
764    // Tensor pointwise multiplication.
765    %x = arith.mulf %y, %z : tensor<4x?xbf16>
766    ```
767
768    TODO: In the distant future, this will accept optional attributes for fast
769    math, contraction, rounding mode, and other controls.
770  }];
771  let hasFolder = 1;
772  let hasCanonicalizer = 1;
773}
774
775//===----------------------------------------------------------------------===//
776// DivFOp
777//===----------------------------------------------------------------------===//
778
779def Arith_DivFOp : Arith_FloatBinaryOp<"divf"> {
780  let summary = "floating point division operation";
781  let hasFolder = 1;
782  let hasCanonicalizer = 1;
783}
784
785//===----------------------------------------------------------------------===//
786// RemFOp
787//===----------------------------------------------------------------------===//
788
789def Arith_RemFOp : Arith_FloatBinaryOp<"remf"> {
790  let summary = "floating point division remainder operation";
791  let hasFolder = 1;
792}
793
794//===----------------------------------------------------------------------===//
795// ExtUIOp
796//===----------------------------------------------------------------------===//
797
798def Arith_ExtUIOp : Arith_IToICastOp<"extui"> {
799  let summary = "integer zero extension operation";
800  let description = [{
801    The integer zero extension operation takes an integer input of
802    width M and an integer destination type of width N. The destination
803    bit-width must be larger than the input bit-width (N > M).
804    The top-most (N - M) bits of the output are filled with zeros.
805
806    Example:
807
808    ```mlir
809      %1 = arith.constant 5 : i3      // %1 is 0b101
810      %2 = arith.extui %1 : i3 to i6  // %2 is 0b000101
811      %3 = arith.constant 2 : i3      // %3 is 0b010
812      %4 = arith.extui %3 : i3 to i6  // %4 is 0b000010
813
814      %5 = arith.extui %0 : vector<2 x i32> to vector<2 x i64>
815    ```
816  }];
817
818  let hasFolder = 1;
819  let hasVerifier = 1;
820}
821
822//===----------------------------------------------------------------------===//
823// ExtSIOp
824//===----------------------------------------------------------------------===//
825
826def Arith_ExtSIOp : Arith_IToICastOp<"extsi"> {
827  let summary = "integer sign extension operation";
828
829  let description = [{
830    The integer sign extension operation takes an integer input of
831    width M and an integer destination type of width N. The destination
832    bit-width must be larger than the input bit-width (N > M).
833    The top-most (N - M) bits of the output are filled with copies
834    of the most-significant bit of the input.
835
836    Example:
837
838    ```mlir
839    %1 = arith.constant 5 : i3      // %1 is 0b101
840    %2 = arith.extsi %1 : i3 to i6  // %2 is 0b111101
841    %3 = arith.constant 2 : i3      // %3 is 0b010
842    %4 = arith.extsi %3 : i3 to i6  // %4 is 0b000010
843
844    %5 = arith.extsi %0 : vector<2 x i32> to vector<2 x i64>
845    ```
846  }];
847
848  let hasFolder = 1;
849  let hasCanonicalizer = 1;
850  let hasVerifier = 1;
851}
852
853//===----------------------------------------------------------------------===//
854// ExtFOp
855//===----------------------------------------------------------------------===//
856
857def Arith_ExtFOp : Arith_FToFCastOp<"extf"> {
858  let summary = "cast from floating-point to wider floating-point";
859  let description = [{
860    Cast a floating-point value to a larger floating-point-typed value.
861    The destination type must to be strictly wider than the source type.
862    When operating on vectors, casts elementwise.
863  }];
864  let hasVerifier = 1;
865}
866
867//===----------------------------------------------------------------------===//
868// TruncIOp
869//===----------------------------------------------------------------------===//
870
871def Arith_TruncIOp : Arith_IToICastOp<"trunci"> {
872  let summary = "integer truncation operation";
873  let description = [{
874    The integer truncation operation takes an integer input of
875    width M and an integer destination type of width N. The destination
876    bit-width must be smaller than the input bit-width (N < M).
877    The top-most (N - M) bits of the input are discarded.
878
879    Example:
880
881    ```mlir
882      %1 = arith.constant 21 : i5     // %1 is 0b10101
883      %2 = arith.trunci %1 : i5 to i4 // %2 is 0b0101
884      %3 = arith.trunci %1 : i5 to i3 // %3 is 0b101
885
886      %5 = arith.trunci %0 : vector<2 x i32> to vector<2 x i16>
887    ```
888  }];
889
890  let hasFolder = 1;
891  let hasVerifier = 1;
892}
893
894//===----------------------------------------------------------------------===//
895// TruncFOp
896//===----------------------------------------------------------------------===//
897
898def Arith_TruncFOp : Arith_FToFCastOp<"truncf"> {
899  let summary = "cast from floating-point to narrower floating-point";
900  let description = [{
901    Truncate a floating-point value to a smaller floating-point-typed value.
902    The destination type must be strictly narrower than the source type.
903    If the value cannot be exactly represented, it is rounded using the default
904    rounding mode. When operating on vectors, casts elementwise.
905  }];
906
907  let hasFolder = 1;
908  let hasVerifier = 1;
909}
910
911//===----------------------------------------------------------------------===//
912// UIToFPOp
913//===----------------------------------------------------------------------===//
914
915def Arith_UIToFPOp : Arith_IToFCastOp<"uitofp"> {
916  let summary = "cast from unsigned integer type to floating-point";
917  let description = [{
918    Cast from a value interpreted as unsigned integer to the corresponding
919    floating-point value. If the value cannot be exactly represented, it is
920    rounded using the default rounding mode. When operating on vectors, casts
921    elementwise.
922  }];
923  let hasFolder = 1;
924}
925
926//===----------------------------------------------------------------------===//
927// SIToFPOp
928//===----------------------------------------------------------------------===//
929
930def Arith_SIToFPOp : Arith_IToFCastOp<"sitofp"> {
931  let summary = "cast from integer type to floating-point";
932  let description = [{
933    Cast from a value interpreted as a signed integer to the corresponding
934    floating-point value. If the value cannot be exactly represented, it is
935    rounded using the default rounding mode. When operating on vectors, casts
936    elementwise.
937  }];
938  let hasFolder = 1;
939}
940
941//===----------------------------------------------------------------------===//
942// FPToUIOp
943//===----------------------------------------------------------------------===//
944
945def Arith_FPToUIOp : Arith_FToICastOp<"fptoui"> {
946  let summary = "cast from floating-point type to integer type";
947  let description = [{
948    Cast from a value interpreted as floating-point to the nearest (rounding
949    towards zero) unsigned integer value. When operating on vectors, casts
950    elementwise.
951  }];
952  let hasFolder = 1;
953}
954
955//===----------------------------------------------------------------------===//
956// FPToSIOp
957//===----------------------------------------------------------------------===//
958
959def Arith_FPToSIOp : Arith_FToICastOp<"fptosi"> {
960  let summary = "cast from floating-point type to integer type";
961  let description = [{
962    Cast from a value interpreted as floating-point to the nearest (rounding
963    towards zero) signed integer value. When operating on vectors, casts
964    elementwise.
965  }];
966  let hasFolder = 1;
967}
968
969//===----------------------------------------------------------------------===//
970// IndexCastOp
971//===----------------------------------------------------------------------===//
972
973// Index cast can convert between memrefs of signless integers and indices too.
974def IndexCastTypeConstraint : TypeConstraint<Or<[
975        SignlessIntegerLike.predicate,
976        MemRefOf<[AnySignlessInteger, Index]>.predicate]>,
977    "signless-integer-like or memref of signless-integer">;
978
979def Arith_IndexCastOp
980  : Arith_CastOp<"index_cast", IndexCastTypeConstraint, IndexCastTypeConstraint,
981                 [DeclareOpInterfaceMethods<InferIntRangeInterface>]> {
982  let summary = "cast between index and integer types";
983  let description = [{
984    Casts between scalar or vector integers and corresponding 'index' scalar or
985    vectors. Index is an integer of platform-specific bit width. If casting to
986    a wider integer, the value is sign-extended. If casting to a narrower
987    integer, the value is truncated.
988  }];
989
990  let hasFolder = 1;
991  let hasCanonicalizer = 1;
992}
993
994//===----------------------------------------------------------------------===//
995// BitcastOp
996//===----------------------------------------------------------------------===//
997
998// Bitcast can convert between memrefs of signless integers, indices, and
999// floats too.
1000def BitcastTypeConstraint : TypeConstraint<Or<[
1001        SignlessIntegerOrFloatLike.predicate,
1002        MemRefOf<[AnySignlessInteger, Index, AnyFloat]>.predicate]>,
1003    "signless-integer-or-float-like or memref of signless-integer or float">;
1004
1005def Arith_BitcastOp : Arith_CastOp<"bitcast", BitcastTypeConstraint,
1006                                              BitcastTypeConstraint> {
1007  let summary = "bitcast between values of equal bit width";
1008  let description = [{
1009    Bitcast an integer or floating point value to an integer or floating point
1010    value of equal bit width. When operating on vectors, casts elementwise.
1011
1012    Note that this implements a logical bitcast independent of target
1013    endianness. This allows constant folding without target information and is
1014    consitent with the bitcast constant folders in LLVM (see
1015    https://github.com/llvm/llvm-project/blob/18c19414eb/llvm/lib/IR/ConstantFold.cpp#L168)
1016    For targets where the source and target type have the same endianness (which
1017    is the standard), this cast will also change no bits at runtime, but it may
1018    still require an operation, for example if the machine has different
1019    floating point and integer register files. For targets that have a different
1020    endianness for the source and target types (e.g. float is big-endian and
1021    integer is little-endian) a proper lowering would add operations to swap the
1022    order of words in addition to the bitcast.
1023  }];
1024
1025  let hasFolder = 1;
1026  let hasCanonicalizer = 1;
1027}
1028
1029//===----------------------------------------------------------------------===//
1030// CmpIOp
1031//===----------------------------------------------------------------------===//
1032
1033def Arith_CmpIOp
1034  : Arith_CompareOpOfAnyRank<"cmpi",
1035                             [DeclareOpInterfaceMethods<InferIntRangeInterface>]> {
1036  let summary = "integer comparison operation";
1037  let description = [{
1038    The `cmpi` operation is a generic comparison for integer-like types. Its two
1039    arguments can be integers, vectors or tensors thereof as long as their types
1040    match. The operation produces an i1 for the former case, a vector or a
1041    tensor of i1 with the same shape as inputs in the other cases.
1042
1043    Its first argument is an attribute that defines which type of comparison is
1044    performed. The following comparisons are supported:
1045
1046    -   equal (mnemonic: `"eq"`; integer value: `0`)
1047    -   not equal (mnemonic: `"ne"`; integer value: `1`)
1048    -   signed less than (mnemonic: `"slt"`; integer value: `2`)
1049    -   signed less than or equal (mnemonic: `"sle"`; integer value: `3`)
1050    -   signed greater than (mnemonic: `"sgt"`; integer value: `4`)
1051    -   signed greater than or equal (mnemonic: `"sge"`; integer value: `5`)
1052    -   unsigned less than (mnemonic: `"ult"`; integer value: `6`)
1053    -   unsigned less than or equal (mnemonic: `"ule"`; integer value: `7`)
1054    -   unsigned greater than (mnemonic: `"ugt"`; integer value: `8`)
1055    -   unsigned greater than or equal (mnemonic: `"uge"`; integer value: `9`)
1056
1057    The result is `1` if the comparison is true and `0` otherwise. For vector or
1058    tensor operands, the comparison is performed elementwise and the element of
1059    the result indicates whether the comparison is true for the operand elements
1060    with the same indices as those of the result.
1061
1062    Note: while the custom assembly form uses strings, the actual underlying
1063    attribute has integer type (or rather enum class in C++ code) as seen from
1064    the generic assembly form. String literals are used to improve readability
1065    of the IR by humans.
1066
1067    This operation only applies to integer-like operands, but not floats. The
1068    main reason being that comparison operations have diverging sets of
1069    attributes: integers require sign specification while floats require various
1070    floating point-related particularities, e.g., `-ffast-math` behavior,
1071    IEEE754 compliance, etc
1072    ([rationale](../Rationale/Rationale.md#splitting-floating-point-vs-integer-operations)).
1073    The type of comparison is specified as attribute to avoid introducing ten
1074    similar operations, taking into account that they are often implemented
1075    using the same operation downstream
1076    ([rationale](../Rationale/Rationale.md#specifying-comparison-kind-as-attribute)). The
1077    separation between signed and unsigned order comparisons is necessary
1078    because of integers being signless. The comparison operation must know how
1079    to interpret values with the foremost bit being set: negatives in two's
1080    complement or large positives
1081    ([rationale](../Rationale/Rationale.md#specifying-sign-in-integer-comparison-operations)).
1082
1083    Example:
1084
1085    ```mlir
1086    // Custom form of scalar "signed less than" comparison.
1087    %x = arith.cmpi "slt", %lhs, %rhs : i32
1088
1089    // Generic form of the same operation.
1090    %x = "arith.cmpi"(%lhs, %rhs) {predicate = 2 : i64} : (i32, i32) -> i1
1091
1092    // Custom form of vector equality comparison.
1093    %x = arith.cmpi "eq", %lhs, %rhs : vector<4xi64>
1094
1095    // Generic form of the same operation.
1096    %x = "arith.cmpi"(%lhs, %rhs) {predicate = 0 : i64}
1097        : (vector<4xi64>, vector<4xi64>) -> vector<4xi1>
1098    ```
1099  }];
1100
1101  let arguments = (ins Arith_CmpIPredicateAttr:$predicate,
1102                       SignlessIntegerLikeOfAnyRank:$lhs,
1103                       SignlessIntegerLikeOfAnyRank:$rhs);
1104
1105  let builders = [
1106    OpBuilder<(ins "CmpIPredicate":$predicate, "Value":$lhs, "Value":$rhs), [{
1107      build($_builder, $_state, ::getI1SameShape(lhs.getType()),
1108            predicate, lhs, rhs);
1109    }]>
1110  ];
1111
1112  let extraClassDeclaration = [{
1113    static arith::CmpIPredicate getPredicateByName(StringRef name);
1114  }];
1115
1116  let hasFolder = 1;
1117  let hasCanonicalizer = 1;
1118}
1119
1120//===----------------------------------------------------------------------===//
1121// CmpFOp
1122//===----------------------------------------------------------------------===//
1123
1124def Arith_CmpFOp : Arith_CompareOp<"cmpf"> {
1125  let summary = "floating-point comparison operation";
1126  let description = [{
1127    The `cmpf` operation compares its two operands according to the float
1128    comparison rules and the predicate specified by the respective attribute.
1129    The predicate defines the type of comparison: (un)orderedness, (in)equality
1130    and signed less/greater than (or equal to) as well as predicates that are
1131    always true or false.  The operands must have the same type, and this type
1132    must be a float type, or a vector or tensor thereof.  The result is an i1,
1133    or a vector/tensor thereof having the same shape as the inputs. Unlike cmpi,
1134    the operands are always treated as signed. The u prefix indicates
1135    *unordered* comparison, not unsigned comparison, so "une" means unordered or
1136    not equal. For the sake of readability by humans, custom assembly form for
1137    the operation uses a string-typed attribute for the predicate.  The value of
1138    this attribute corresponds to lower-cased name of the predicate constant,
1139    e.g., "one" means "ordered not equal".  The string representation of the
1140    attribute is merely a syntactic sugar and is converted to an integer
1141    attribute by the parser.
1142
1143    Example:
1144
1145    ```mlir
1146    %r1 = arith.cmpf "oeq" %0, %1 : f32
1147    %r2 = arith.cmpf "ult" %0, %1 : tensor<42x42xf64>
1148    %r3 = "arith.cmpf"(%0, %1) {predicate: 0} : (f8, f8) -> i1
1149    ```
1150  }];
1151
1152  let arguments = (ins Arith_CmpFPredicateAttr:$predicate,
1153                       FloatLike:$lhs,
1154                       FloatLike:$rhs);
1155
1156  let builders = [
1157    OpBuilder<(ins "CmpFPredicate":$predicate, "Value":$lhs, "Value":$rhs), [{
1158      build($_builder, $_state, ::getI1SameShape(lhs.getType()),
1159            predicate, lhs, rhs);
1160    }]>
1161  ];
1162
1163  let extraClassDeclaration = [{
1164    static arith::CmpFPredicate getPredicateByName(StringRef name);
1165  }];
1166
1167  let hasFolder = 1;
1168  let hasCanonicalizer = 1;
1169}
1170
1171//===----------------------------------------------------------------------===//
1172// SelectOp
1173//===----------------------------------------------------------------------===//
1174
1175def SelectOp : Arith_Op<"select", [
1176    AllTypesMatch<["true_value", "false_value", "result"]>,
1177    DeclareOpInterfaceMethods<InferIntRangeInterface>,
1178  ] # ElementwiseMappable.traits> {
1179  let summary = "select operation";
1180  let description = [{
1181    The `arith.select` operation chooses one value based on a binary condition
1182    supplied as its first operand. If the value of the first operand is `1`,
1183    the second operand is chosen, otherwise the third operand is chosen.
1184    The second and the third operand must have the same type.
1185
1186    The operation applies to vectors and tensors elementwise given the _shape_
1187    of all operands is identical. The choice is made for each element
1188    individually based on the value at the same position as the element in the
1189    condition operand. If an i1 is provided as the condition, the entire vector
1190    or tensor is chosen.
1191
1192    Example:
1193
1194    ```mlir
1195    // Custom form of scalar selection.
1196    %x = arith.select %cond, %true, %false : i32
1197
1198    // Generic form of the same operation.
1199    %x = "arith.select"(%cond, %true, %false) : (i1, i32, i32) -> i32
1200
1201    // Element-wise vector selection.
1202    %vx = arith.select %vcond, %vtrue, %vfalse : vector<42xi1>, vector<42xf32>
1203
1204    // Full vector selection.
1205    %vx = arith.select %cond, %vtrue, %vfalse : vector<42xf32>
1206    ```
1207  }];
1208
1209  let arguments = (ins BoolLike:$condition,
1210                       AnyType:$true_value,
1211                       AnyType:$false_value);
1212  let results = (outs AnyType:$result);
1213
1214  let hasCanonicalizer = 1;
1215  let hasFolder = 1;
1216  let hasVerifier = 1;
1217
1218  // FIXME: Switch this to use the declarative assembly format.
1219  let hasCustomAssemblyFormat = 1;
1220}
1221
1222#endif // ARITHMETIC_OPS
1223