1//===-- SPIRVArithmeticOps.td - MLIR SPIR-V Arithmetic Ops -*- 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// This file contains arithmetic ops for the SPIR-V dialect. It corresponds 10// to "3.32.13. Arithmetic Instructions" of the SPIR-V specification. 11// 12//===----------------------------------------------------------------------===// 13 14#ifndef MLIR_DIALECT_SPIRV_IR_ARITHMETIC_OPS 15#define MLIR_DIALECT_SPIRV_IR_ARITHMETIC_OPS 16 17include "mlir/Dialect/SPIRV/IR/SPIRVBase.td" 18include "mlir/Interfaces/InferTypeOpInterface.td" 19include "mlir/Interfaces/SideEffectInterfaces.td" 20 21class SPIRV_ArithmeticBinaryOp<string mnemonic, Type type, 22 list<Trait> traits = []> : 23 // Operands type same as result type. 24 SPIRV_BinaryOp<mnemonic, type, type, 25 !listconcat(traits, 26 [Pure, SameOperandsAndResultType])> { 27 // In addition to normal types arithmetic instructions can support cooperative 28 // matrix. 29 let arguments = (ins 30 SPIRV_ScalarOrVectorOrCoopMatrixOf<type>:$operand1, 31 SPIRV_ScalarOrVectorOrCoopMatrixOf<type>:$operand2 32 ); 33 34 let results = (outs 35 SPIRV_ScalarOrVectorOrCoopMatrixOf<type>:$result 36 ); 37 let assemblyFormat = "operands attr-dict `:` type($result)"; 38} 39 40class SPIRV_ArithmeticUnaryOp<string mnemonic, Type type, 41 list<Trait> traits = []> : 42 // Operand type same as result type. 43 SPIRV_UnaryOp<mnemonic, type, type, 44 !listconcat(traits, 45 [Pure, SameOperandsAndResultType])> { 46 // In addition to normal types arithmetic instructions can support cooperative 47 // matrix. 48 let arguments = (ins 49 SPIRV_ScalarOrVectorOrCoopMatrixOf<type>:$operand 50 ); 51 52 let results = (outs 53 SPIRV_ScalarOrVectorOrCoopMatrixOf<type>:$result 54 ); 55 let assemblyFormat = "operands attr-dict `:` type($result)"; 56} 57 58class SPIRV_ArithmeticExtendedBinaryOp<string mnemonic, 59 list<Trait> traits = []> : 60 // Result type is a struct with two operand-typed elements. 61 SPIRV_BinaryOp<mnemonic, SPIRV_AnyStruct, SPIRV_Integer, traits> { 62 let arguments = (ins 63 SPIRV_ScalarOrVectorOf<SPIRV_Integer>:$operand1, 64 SPIRV_ScalarOrVectorOf<SPIRV_Integer>:$operand2 65 ); 66 67 let results = (outs 68 SPIRV_AnyStruct:$result 69 ); 70 71 let builders = [ 72 OpBuilder<(ins "Value":$operand1, "Value":$operand2), [{ 73 build($_builder, $_state, 74 ::mlir::spirv::StructType::get({operand1.getType(), operand1.getType()}), 75 operand1, operand2); 76 }]> 77 ]; 78 79 // These ops require a custom verifier. 80 let hasVerifier = 1; 81} 82 83// ----- 84 85def SPIRV_FAddOp : SPIRV_ArithmeticBinaryOp<"FAdd", SPIRV_Float, [Commutative]> { 86 let summary = "Floating-point addition of Operand 1 and Operand 2."; 87 88 let description = [{ 89 Result Type must be a scalar or vector of floating-point type. 90 91 The types of Operand 1 and Operand 2 both must be the same as Result 92 Type. 93 94 Results are computed per component. 95 96 #### Example: 97 98 ```mlir 99 %4 = spirv.FAdd %0, %1 : f32 100 %5 = spirv.FAdd %2, %3 : vector<4xf32> 101 ``` 102 }]; 103} 104 105// ----- 106 107def SPIRV_FDivOp : SPIRV_ArithmeticBinaryOp<"FDiv", SPIRV_Float, []> { 108 let summary = "Floating-point division of Operand 1 divided by Operand 2."; 109 110 let description = [{ 111 Result Type must be a scalar or vector of floating-point type. 112 113 The types of Operand 1 and Operand 2 both must be the same as Result 114 Type. 115 116 Results are computed per component. The resulting value is undefined 117 if Operand 2 is 0. 118 119 #### Example: 120 121 ```mlir 122 %4 = spirv.FDiv %0, %1 : f32 123 %5 = spirv.FDiv %2, %3 : vector<4xf32> 124 ``` 125 }]; 126} 127 128// ----- 129 130def SPIRV_FModOp : SPIRV_ArithmeticBinaryOp<"FMod", SPIRV_Float, []> { 131 let summary = [{ 132 The floating-point remainder whose sign matches the sign of Operand 2. 133 }]; 134 135 let description = [{ 136 Result Type must be a scalar or vector of floating-point type. 137 138 The types of Operand 1 and Operand 2 both must be the same as Result 139 Type. 140 141 Results are computed per component. The resulting value is undefined 142 if Operand 2 is 0. Otherwise, the result is the remainder r of Operand 143 1 divided by Operand 2 where if r ≠ 0, the sign of r is the same as the 144 sign of Operand 2. 145 146 #### Example: 147 148 ```mlir 149 %4 = spirv.FMod %0, %1 : f32 150 %5 = spirv.FMod %2, %3 : vector<4xf32> 151 ``` 152 }]; 153} 154 155// ----- 156 157def SPIRV_FMulOp : SPIRV_ArithmeticBinaryOp<"FMul", SPIRV_Float, [Commutative]> { 158 let summary = "Floating-point multiplication of Operand 1 and Operand 2."; 159 160 let description = [{ 161 Result Type must be a scalar or vector of floating-point type. 162 163 The types of Operand 1 and Operand 2 both must be the same as Result 164 Type. 165 166 Results are computed per component. 167 168 #### Example: 169 170 ```mlir 171 %4 = spirv.FMul %0, %1 : f32 172 %5 = spirv.FMul %2, %3 : vector<4xf32> 173 ``` 174 }]; 175} 176 177// ----- 178 179def SPIRV_FNegateOp : SPIRV_ArithmeticUnaryOp<"FNegate", SPIRV_Float, []> { 180 let summary = [{ 181 Inverts the sign bit of Operand. (Note, however, that OpFNegate is still 182 considered a floating-point instruction, and so is subject to the 183 general floating-point rules regarding, for example, subnormals and NaN 184 propagation). 185 }]; 186 187 let description = [{ 188 Result Type must be a scalar or vector of floating-point type. 189 190 The type of Operand must be the same as Result Type. 191 192 Results are computed per component. 193 194 #### Example: 195 196 ```mlir 197 %1 = spirv.FNegate %0 : f32 198 %3 = spirv.FNegate %2 : vector<4xf32> 199 ``` 200 }]; 201} 202 203// ----- 204 205def SPIRV_FRemOp : SPIRV_ArithmeticBinaryOp<"FRem", SPIRV_Float, []> { 206 let summary = [{ 207 The floating-point remainder whose sign matches the sign of Operand 1. 208 }]; 209 210 let description = [{ 211 Result Type must be a scalar or vector of floating-point type. 212 213 The types of Operand 1 and Operand 2 both must be the same as Result 214 Type. 215 216 Results are computed per component. The resulting value is undefined 217 if Operand 2 is 0. Otherwise, the result is the remainder r of Operand 218 1 divided by Operand 2 where if r ≠ 0, the sign of r is the same as the 219 sign of Operand 1. 220 221 #### Example: 222 223 ```mlir 224 %4 = spirv.FRemOp %0, %1 : f32 225 %5 = spirv.FRemOp %2, %3 : vector<4xf32> 226 ``` 227 }]; 228} 229 230// ----- 231 232def SPIRV_FSubOp : SPIRV_ArithmeticBinaryOp<"FSub", SPIRV_Float, []> { 233 let summary = "Floating-point subtraction of Operand 2 from Operand 1."; 234 235 let description = [{ 236 Result Type must be a scalar or vector of floating-point type. 237 238 The types of Operand 1 and Operand 2 both must be the same as Result 239 Type. 240 241 Results are computed per component. 242 243 #### Example: 244 245 ```mlir 246 %4 = spirv.FRemOp %0, %1 : f32 247 %5 = spirv.FRemOp %2, %3 : vector<4xf32> 248 ``` 249 }]; 250} 251 252// ----- 253 254def SPIRV_IAddOp : SPIRV_ArithmeticBinaryOp<"IAdd", 255 SPIRV_Integer, 256 [Commutative, UsableInSpecConstantOp]> { 257 let summary = "Integer addition of Operand 1 and Operand 2."; 258 259 let description = [{ 260 Result Type must be a scalar or vector of integer type. 261 262 The type of Operand 1 and Operand 2 must be a scalar or vector of 263 integer type. They must have the same number of components as Result 264 Type. They must have the same component width as Result Type. 265 266 The resulting value will equal the low-order N bits of the correct 267 result R, where N is the component width and R is computed with enough 268 precision to avoid overflow and underflow. 269 270 Results are computed per component. 271 272 #### Example: 273 274 ```mlir 275 %4 = spirv.IAdd %0, %1 : i32 276 %5 = spirv.IAdd %2, %3 : vector<4xi32> 277 278 ``` 279 }]; 280 281 let hasFolder = 1; 282} 283 284// ----- 285 286def SPIRV_IAddCarryOp : SPIRV_ArithmeticExtendedBinaryOp<"IAddCarry", 287 [Commutative, Pure]> { 288 let summary = [{ 289 Integer addition of Operand 1 and Operand 2, including the carry. 290 }]; 291 292 let description = [{ 293 Result Type must be from OpTypeStruct. The struct must have two 294 members, and the two members must be the same type. The member type 295 must be a scalar or vector of integer type, whose Signedness operand is 296 0. 297 298 Operand 1 and Operand 2 must have the same type as the members of Result 299 Type. These are consumed as unsigned integers. 300 301 Results are computed per component. 302 303 Member 0 of the result gets the low-order bits (full component width) of 304 the addition. 305 306 Member 1 of the result gets the high-order (carry) bit of the result of 307 the addition. That is, it gets the value 1 if the addition overflowed 308 the component width, and 0 otherwise. 309 310 <!-- End of AutoGen section --> 311 312 #### Example: 313 314 ```mlir 315 %2 = spirv.IAddCarry %0, %1 : !spirv.struct<(i32, i32)> 316 %2 = spirv.IAddCarry %0, %1 : !spirv.struct<(vector<2xi32>, vector<2xi32>)> 317 ``` 318 }]; 319 320 let hasCanonicalizer = 1; 321} 322 323// ----- 324 325def SPIRV_IMulOp : SPIRV_ArithmeticBinaryOp<"IMul", 326 SPIRV_Integer, 327 [Commutative, UsableInSpecConstantOp]> { 328 let summary = "Integer multiplication of Operand 1 and Operand 2."; 329 330 let description = [{ 331 Result Type must be a scalar or vector of integer type. 332 333 The type of Operand 1 and Operand 2 must be a scalar or vector of 334 integer type. They must have the same number of components as Result 335 Type. They must have the same component width as Result Type. 336 337 The resulting value will equal the low-order N bits of the correct 338 result R, where N is the component width and R is computed with enough 339 precision to avoid overflow and underflow. 340 341 Results are computed per component. 342 343 #### Example: 344 345 ```mlir 346 %4 = spirv.IMul %0, %1 : i32 347 %5 = spirv.IMul %2, %3 : vector<4xi32> 348 349 ``` 350 }]; 351 352 let hasFolder = 1; 353} 354 355// ----- 356 357def SPIRV_ISubOp : SPIRV_ArithmeticBinaryOp<"ISub", 358 SPIRV_Integer, 359 [UsableInSpecConstantOp]> { 360 let summary = "Integer subtraction of Operand 2 from Operand 1."; 361 362 let description = [{ 363 Result Type must be a scalar or vector of integer type. 364 365 The type of Operand 1 and Operand 2 must be a scalar or vector of 366 integer type. They must have the same number of components as Result 367 Type. They must have the same component width as Result Type. 368 369 The resulting value will equal the low-order N bits of the correct 370 result R, where N is the component width and R is computed with enough 371 precision to avoid overflow and underflow. 372 373 Results are computed per component. 374 375 #### Example: 376 377 ```mlir 378 %4 = spirv.ISub %0, %1 : i32 379 %5 = spirv.ISub %2, %3 : vector<4xi32> 380 381 ``` 382 }]; 383 384 let hasFolder = 1; 385} 386 387// ----- 388 389def SPIRV_ISubBorrowOp : SPIRV_ArithmeticExtendedBinaryOp<"ISubBorrow", 390 [Pure]> { 391 let summary = [{ 392 Result is the unsigned integer subtraction of Operand 2 from Operand 1, 393 and what it needed to borrow. 394 }]; 395 396 let description = [{ 397 Result Type must be from OpTypeStruct. The struct must have two 398 members, and the two members must be the same type. The member type 399 must be a scalar or vector of integer type, whose Signedness operand is 400 0. 401 402 Operand 1 and Operand 2 must have the same type as the members of Result 403 Type. These are consumed as unsigned integers. 404 405 Results are computed per component. 406 407 Member 0 of the result gets the low-order bits (full component width) of 408 the subtraction. That is, if Operand 1 is larger than Operand 2, member 409 0 gets the full value of the subtraction; if Operand 2 is larger than 410 Operand 1, member 0 gets 2w + Operand 1 - Operand 2, where w is the 411 component width. 412 413 Member 1 of the result gets 0 if Operand 1 ≥ Operand 2, and gets 1 414 otherwise. 415 416 <!-- End of AutoGen section --> 417 418 #### Example: 419 420 ```mlir 421 %2 = spirv.ISubBorrow %0, %1 : !spirv.struct<(i32, i32)> 422 %2 = spirv.ISubBorrow %0, %1 : !spirv.struct<(vector<2xi32>, vector<2xi32>)> 423 ``` 424 }]; 425} 426 427// ----- 428 429def SPIRV_DotOp : SPIRV_Op<"Dot", 430 [Pure, AllTypesMatch<["vector1", "vector2"]>, 431 AllElementTypesMatch<["vector1", "result"]>]> { 432 let summary = "Dot product of Vector 1 and Vector 2"; 433 434 let description = [{ 435 Result Type must be a floating point scalar. 436 437 Vector 1 and Vector 2 must be vectors of the same type, and their component 438 type must be Result Type. 439 440 #### Example: 441 442 ```mlir 443 %0 = spirv.Dot %v1, %v2 : vector<4xf32> -> f32 444 ``` 445 }]; 446 447 let arguments = (ins 448 SPIRV_VectorOf<SPIRV_Float>:$vector1, 449 SPIRV_VectorOf<SPIRV_Float>:$vector2 450 ); 451 452 let results = (outs 453 SPIRV_Float:$result 454 ); 455 456 let assemblyFormat = "operands attr-dict `:` type($vector1) `->` type($result)"; 457 458 let hasVerifier = 0; 459} 460 461// ----- 462 463def SPIRV_SDivOp : SPIRV_ArithmeticBinaryOp<"SDiv", 464 SPIRV_Integer, 465 [UsableInSpecConstantOp]> { 466 let summary = "Signed-integer division of Operand 1 divided by Operand 2."; 467 468 let description = [{ 469 Result Type must be a scalar or vector of integer type. 470 471 The type of Operand 1 and Operand 2 must be a scalar or vector of 472 integer type. They must have the same number of components as Result 473 Type. They must have the same component width as Result Type. 474 475 Results are computed per component. The resulting value is undefined 476 if Operand 2 is 0. 477 478 #### Example: 479 480 ```mlir 481 %4 = spirv.SDiv %0, %1 : i32 482 %5 = spirv.SDiv %2, %3 : vector<4xi32> 483 484 ``` 485 }]; 486 487 let hasFolder = 1; 488} 489 490// ----- 491 492def SPIRV_SModOp : SPIRV_ArithmeticBinaryOp<"SMod", 493 SPIRV_Integer, 494 [UsableInSpecConstantOp]> { 495 let summary = [{ 496 Signed remainder operation for the remainder whose sign matches the sign 497 of Operand 2. 498 }]; 499 500 let description = [{ 501 Result Type must be a scalar or vector of integer type. 502 503 The type of Operand 1 and Operand 2 must be a scalar or vector of 504 integer type. They must have the same number of components as Result 505 Type. They must have the same component width as Result Type. 506 507 Results are computed per component. The resulting value is undefined 508 if Operand 2 is 0. Otherwise, the result is the remainder r of Operand 509 1 divided by Operand 2 where if r ≠ 0, the sign of r is the same as the 510 sign of Operand 2. 511 512 #### Example: 513 514 ```mlir 515 %4 = spirv.SMod %0, %1 : i32 516 %5 = spirv.SMod %2, %3 : vector<4xi32> 517 518 ``` 519 }]; 520 521 let hasFolder = 1; 522} 523 524// ----- 525 526def SPIRV_SMulExtendedOp : SPIRV_ArithmeticExtendedBinaryOp<"SMulExtended", 527 [Pure, Commutative]> { 528 let summary = [{ 529 Result is the full value of the signed integer multiplication of Operand 530 1 and Operand 2. 531 }]; 532 533 let description = [{ 534 Result Type must be from OpTypeStruct. The struct must have two 535 members, and the two members must be the same type. The member type 536 must be a scalar or vector of integer type. 537 538 Operand 1 and Operand 2 must have the same type as the members of Result 539 Type. These are consumed as signed integers. 540 541 Results are computed per component. 542 543 Member 0 of the result gets the low-order bits of the multiplication. 544 545 Member 1 of the result gets the high-order bits of the multiplication. 546 547 <!-- End of AutoGen section --> 548 549 #### Example: 550 551 ```mlir 552 %2 = spirv.SMulExtended %0, %1 : !spirv.struct<(i32, i32)> 553 %2 = spirv.SMulExtended %0, %1 : !spirv.struct<(vector<2xi32>, vector<2xi32>)> 554 ``` 555 }]; 556 557 let hasCanonicalizer = 1; 558} 559 560// ----- 561 562def SPIRV_SNegateOp : SPIRV_ArithmeticUnaryOp<"SNegate", 563 SPIRV_Integer, 564 [UsableInSpecConstantOp]> { 565 let summary = "Signed-integer subtract of Operand from zero."; 566 567 let description = [{ 568 Result Type must be a scalar or vector of integer type. 569 570 Operand's type must be a scalar or vector of integer type. It must 571 have the same number of components as Result Type. The component width 572 must equal the component width in Result Type. 573 574 Results are computed per component. 575 576 <!-- End of AutoGen section --> 577 578 #### Example: 579 580 ```mlir 581 %1 = spirv.SNegate %0 : i32 582 %3 = spirv.SNegate %2 : vector<4xi32> 583 ``` 584 }]; 585 586 let hasFolder = 1; 587} 588 589// ----- 590 591def SPIRV_SRemOp : SPIRV_ArithmeticBinaryOp<"SRem", 592 SPIRV_Integer, 593 [UsableInSpecConstantOp]> { 594 let summary = [{ 595 Signed remainder operation for the remainder whose sign matches the sign 596 of Operand 1. 597 }]; 598 599 let description = [{ 600 Result Type must be a scalar or vector of integer type. 601 602 The type of Operand 1 and Operand 2 must be a scalar or vector of 603 integer type. They must have the same number of components as Result 604 Type. They must have the same component width as Result Type. 605 606 Results are computed per component. The resulting value is undefined 607 if Operand 2 is 0. Otherwise, the result is the remainder r of Operand 608 1 divided by Operand 2 where if r ≠ 0, the sign of r is the same as the 609 sign of Operand 1. 610 611 #### Example: 612 613 ```mlir 614 %4 = spirv.SRem %0, %1 : i32 615 %5 = spirv.SRem %2, %3 : vector<4xi32> 616 617 ``` 618 }]; 619 620 let hasFolder = 1; 621} 622 623// ----- 624 625def SPIRV_UDivOp : SPIRV_ArithmeticBinaryOp<"UDiv", 626 SPIRV_Integer, 627 [UnsignedOp, UsableInSpecConstantOp]> { 628 let summary = "Unsigned-integer division of Operand 1 divided by Operand 2."; 629 630 let description = [{ 631 Result Type must be a scalar or vector of integer type, whose Signedness 632 operand is 0. 633 634 The types of Operand 1 and Operand 2 both must be the same as Result 635 Type. 636 637 Results are computed per component. The resulting value is undefined 638 if Operand 2 is 0. 639 640 #### Example: 641 642 ```mlir 643 %4 = spirv.UDiv %0, %1 : i32 644 %5 = spirv.UDiv %2, %3 : vector<4xi32> 645 ``` 646 }]; 647 648 let hasFolder = 1; 649} 650 651// ----- 652 653def SPIRV_UMulExtendedOp : SPIRV_ArithmeticExtendedBinaryOp<"UMulExtended", 654 [Pure, Commutative]> { 655 let summary = [{ 656 Result is the full value of the unsigned integer multiplication of 657 Operand 1 and Operand 2. 658 }]; 659 660 let description = [{ 661 Result Type must be from OpTypeStruct. The struct must have two 662 members, and the two members must be the same type. The member type 663 must be a scalar or vector of integer type, whose Signedness operand is 664 0. 665 666 Operand 1 and Operand 2 must have the same type as the members of Result 667 Type. These are consumed as unsigned integers. 668 669 Results are computed per component. 670 671 Member 0 of the result gets the low-order bits of the multiplication. 672 673 Member 1 of the result gets the high-order bits of the multiplication. 674 675 <!-- End of AutoGen section --> 676 677 #### Example: 678 679 ```mlir 680 %2 = spirv.UMulExtended %0, %1 : !spirv.struct<(i32, i32)> 681 %2 = spirv.UMulExtended %0, %1 : !spirv.struct<(vector<2xi32>, vector<2xi32>)> 682 ``` 683 }]; 684 685 let hasCanonicalizer = 1; 686} 687 688// ----- 689 690def SPIRV_VectorTimesScalarOp : SPIRV_Op<"VectorTimesScalar", [Pure]> { 691 let summary = "Scale a floating-point vector."; 692 693 let description = [{ 694 Result Type must be a vector of floating-point type. 695 696 The type of Vector must be the same as Result Type. Each component of 697 Vector is multiplied by Scalar. 698 699 Scalar must have the same type as the Component Type in Result Type. 700 701 <!-- End of AutoGen section --> 702 703 #### Example: 704 705 ```mlir 706 %0 = spirv.VectorTimesScalar %vector, %scalar : vector<4xf32> 707 ``` 708 }]; 709 710 let arguments = (ins 711 VectorOfLengthAndType<[2, 3, 4], [SPIRV_Float]>:$vector, 712 SPIRV_Float:$scalar 713 ); 714 715 let results = (outs 716 VectorOfLengthAndType<[2, 3, 4], [SPIRV_Float]>:$result 717 ); 718 719 let assemblyFormat = "operands attr-dict `:` `(` type(operands) `)` `->` type($result)"; 720} 721 722// ----- 723 724def SPIRV_UModOp : SPIRV_ArithmeticBinaryOp<"UMod", 725 SPIRV_Integer, 726 [UnsignedOp, UsableInSpecConstantOp]> { 727 let summary = "Unsigned modulo operation of Operand 1 modulo Operand 2."; 728 729 let description = [{ 730 Result Type must be a scalar or vector of integer type, whose Signedness 731 operand is 0. 732 733 The types of Operand 1 and Operand 2 both must be the same as Result 734 Type. 735 736 Results are computed per component. The resulting value is undefined 737 if Operand 2 is 0. 738 739 #### Example: 740 741 ```mlir 742 %4 = spirv.UMod %0, %1 : i32 743 %5 = spirv.UMod %2, %3 : vector<4xi32> 744 ``` 745 }]; 746 747 let hasFolder = 1; 748 let hasCanonicalizer = 1; 749} 750 751#endif // MLIR_DIALECT_SPIRV_IR_ARITHMETIC_OPS 752