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