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