1//===- ArithPatterns.td - Arith dialect patterns -*- 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_PATTERNS 10#define ARITH_PATTERNS 11 12include "mlir/IR/PatternBase.td" 13include "mlir/Dialect/Arith/IR/ArithOps.td" 14 15// Create zero attribute of type matching the argument's type. 16def GetZeroAttr : NativeCodeCall<"$_builder.getZeroAttr($0.getType())">; 17 18// Add two integer attributes and create a new one with the result. 19def AddIntAttrs : NativeCodeCall<"addIntegerAttrs($_builder, $0, $1, $2)">; 20 21// Subtract two integer attributes and create a new one with the result. 22def SubIntAttrs : NativeCodeCall<"subIntegerAttrs($_builder, $0, $1, $2)">; 23 24// Multiply two integer attributes and create a new one with the result. 25def MulIntAttrs : NativeCodeCall<"mulIntegerAttrs($_builder, $0, $1, $2)">; 26 27// Merge overflow flags from 2 ops, selecting the most conservative combination. 28def MergeOverflow : NativeCodeCall<"mergeOverflowFlags($0, $1)">; 29 30// Default overflow flag (all wraparounds allowed). 31defvar DefOverflow = ConstantEnumCase<Arith_IntegerOverflowAttr, "none">; 32 33class cast<string type> : NativeCodeCall<"::mlir::cast<" # type # ">($0)">; 34 35//===----------------------------------------------------------------------===// 36// AddIOp 37//===----------------------------------------------------------------------===// 38 39// addi is commutative and will be canonicalized to have its constants appear 40// as the second operand. 41 42// addi(addi(x, c0), c1) -> addi(x, c0 + c1) 43def AddIAddConstant : 44 Pat<(Arith_AddIOp:$res 45 (Arith_AddIOp $x, (ConstantLikeMatcher APIntAttr:$c0), $ovf1), 46 (ConstantLikeMatcher APIntAttr:$c1), $ovf2), 47 (Arith_AddIOp $x, (Arith_ConstantOp (AddIntAttrs $res, $c0, $c1)), 48 (MergeOverflow $ovf1, $ovf2))>; 49 50// addi(subi(x, c0), c1) -> addi(x, c1 - c0) 51def AddISubConstantRHS : 52 Pat<(Arith_AddIOp:$res 53 (Arith_SubIOp $x, (ConstantLikeMatcher APIntAttr:$c0), $ovf1), 54 (ConstantLikeMatcher APIntAttr:$c1), $ovf2), 55 (Arith_AddIOp $x, (Arith_ConstantOp (SubIntAttrs $res, $c1, $c0)), 56 (MergeOverflow $ovf1, $ovf2))>; 57 58// addi(subi(c0, x), c1) -> subi(c0 + c1, x) 59def AddISubConstantLHS : 60 Pat<(Arith_AddIOp:$res 61 (Arith_SubIOp (ConstantLikeMatcher APIntAttr:$c0), $x, $ovf1), 62 (ConstantLikeMatcher APIntAttr:$c1), $ovf2), 63 (Arith_SubIOp (Arith_ConstantOp (AddIntAttrs $res, $c0, $c1)), $x, 64 (MergeOverflow $ovf1, $ovf2))>; 65 66def IsScalarOrSplatNegativeOne : 67 Constraint<And<[ 68 CPred<"succeeded(getIntOrSplatIntValue($0))">, 69 CPred<"getIntOrSplatIntValue($0)->isAllOnes()">]>>; 70 71// addi(x, muli(y, -1)) -> subi(x, y) 72def AddIMulNegativeOneRhs : 73 Pat<(Arith_AddIOp 74 $x, 75 (Arith_MulIOp $y, (ConstantLikeMatcher AnyAttr:$c0), $ovf1), $ovf2), 76 (Arith_SubIOp $x, $y, DefOverflow), // TODO: overflow flags 77 [(IsScalarOrSplatNegativeOne $c0)]>; 78 79// addi(muli(x, -1), y) -> subi(y, x) 80def AddIMulNegativeOneLhs : 81 Pat<(Arith_AddIOp 82 (Arith_MulIOp $x, (ConstantLikeMatcher AnyAttr:$c0), $ovf1), 83 $y, $ovf2), 84 (Arith_SubIOp $y, $x, DefOverflow), // TODO: overflow flags 85 [(IsScalarOrSplatNegativeOne $c0)]>; 86 87// muli(muli(x, c0), c1) -> muli(x, c0 * c1) 88def MulIMulIConstant : 89 Pat<(Arith_MulIOp:$res 90 (Arith_MulIOp $x, (ConstantLikeMatcher APIntAttr:$c0), $ovf1), 91 (ConstantLikeMatcher APIntAttr:$c1), $ovf2), 92 (Arith_MulIOp $x, (Arith_ConstantOp (MulIntAttrs $res, $c0, $c1)), 93 (MergeOverflow $ovf1, $ovf2))>; 94 95//===----------------------------------------------------------------------===// 96// AddUIExtendedOp 97//===----------------------------------------------------------------------===// 98 99// addui_extended(x, y) -> [addi(x, y), x], when the `overflow` result has no 100// uses. Since the 'overflow' result is unused, any replacement value will do. 101def AddUIExtendedToAddI: 102 Pattern<(Arith_AddUIExtendedOp:$res $x, $y), 103 [(Arith_AddIOp $x, $y, DefOverflow), (replaceWithValue $x)], 104 [(Constraint<CPred<"$0.getUses().empty()">> $res__1)]>; 105 106//===----------------------------------------------------------------------===// 107// SubIOp 108//===----------------------------------------------------------------------===// 109 110// subi(addi(x, c0), c1) -> addi(x, c0 - c1) 111def SubIRHSAddConstant : 112 Pat<(Arith_SubIOp:$res 113 (Arith_AddIOp $x, (ConstantLikeMatcher APIntAttr:$c0), $ovf1), 114 (ConstantLikeMatcher APIntAttr:$c1), $ovf2), 115 (Arith_AddIOp $x, (Arith_ConstantOp (SubIntAttrs $res, $c0, $c1)), 116 DefOverflow)>; // TODO: overflow flags 117 118// subi(c1, addi(x, c0)) -> subi(c1 - c0, x) 119def SubILHSAddConstant : 120 Pat<(Arith_SubIOp:$res 121 (ConstantLikeMatcher APIntAttr:$c1), 122 (Arith_AddIOp $x, (ConstantLikeMatcher APIntAttr:$c0), $ovf1), $ovf2), 123 (Arith_SubIOp (Arith_ConstantOp (SubIntAttrs $res, $c1, $c0)), $x, 124 (MergeOverflow $ovf1, $ovf2))>; 125 126// subi(subi(x, c0), c1) -> subi(x, c0 + c1) 127def SubIRHSSubConstantRHS : 128 Pat<(Arith_SubIOp:$res 129 (Arith_SubIOp $x, (ConstantLikeMatcher APIntAttr:$c0), $ovf1), 130 (ConstantLikeMatcher APIntAttr:$c1), $ovf2), 131 (Arith_SubIOp $x, (Arith_ConstantOp (AddIntAttrs $res, $c0, $c1)), 132 (MergeOverflow $ovf1, $ovf2))>; 133 134// subi(subi(c0, x), c1) -> subi(c0 - c1, x) 135def SubIRHSSubConstantLHS : 136 Pat<(Arith_SubIOp:$res 137 (Arith_SubIOp (ConstantLikeMatcher APIntAttr:$c0), $x, $ovf1), 138 (ConstantLikeMatcher APIntAttr:$c1), $ovf2), 139 (Arith_SubIOp (Arith_ConstantOp (SubIntAttrs $res, $c0, $c1)), $x, 140 (MergeOverflow $ovf1, $ovf2))>; 141 142// subi(c1, subi(x, c0)) -> subi(c0 + c1, x) 143def SubILHSSubConstantRHS : 144 Pat<(Arith_SubIOp:$res 145 (ConstantLikeMatcher APIntAttr:$c1), 146 (Arith_SubIOp $x, (ConstantLikeMatcher APIntAttr:$c0), $ovf1), $ovf2), 147 (Arith_SubIOp (Arith_ConstantOp (AddIntAttrs $res, $c0, $c1)), $x, 148 (MergeOverflow $ovf1, $ovf2))>; 149 150// subi(c1, subi(c0, x)) -> addi(x, c1 - c0) 151def SubILHSSubConstantLHS : 152 Pat<(Arith_SubIOp:$res 153 (ConstantLikeMatcher APIntAttr:$c1), 154 (Arith_SubIOp (ConstantLikeMatcher APIntAttr:$c0), $x, $ovf1), $ovf2), 155 (Arith_AddIOp $x, (Arith_ConstantOp (SubIntAttrs $res, $c1, $c0)), 156 (MergeOverflow $ovf1, $ovf2))>; 157 158// subi(subi(a, b), a) -> subi(0, b) 159def SubISubILHSRHSLHS : 160 Pat<(Arith_SubIOp:$res (Arith_SubIOp $x, $y, $ovf1), $x, $ovf2), 161 (Arith_SubIOp (Arith_ConstantOp (GetZeroAttr $y)), $y, 162 (MergeOverflow $ovf1, $ovf2))>; 163 164//===----------------------------------------------------------------------===// 165// MulSIExtendedOp 166//===----------------------------------------------------------------------===// 167 168// mulsi_extended(x, y) -> [muli(x, y), x], when the `high` result is unused. 169// Since the `high` result it not used, any replacement value will do. 170def MulSIExtendedToMulI : 171 Pattern<(Arith_MulSIExtendedOp:$res $x, $y), 172 [(Arith_MulIOp $x, $y, DefOverflow), (replaceWithValue $x)], 173 [(Constraint<CPred<"$0.getUses().empty()">> $res__1)]>; 174 175 176def IsScalarOrSplatOne : 177 Constraint<And<[ 178 CPred<"succeeded(getIntOrSplatIntValue($0))">, 179 CPred<"getIntOrSplatIntValue($0)->isStrictlyPositive()">, 180 CPred<"*getIntOrSplatIntValue($0) == 1">]>>; 181 182// mulsi_extended(x, 1) -> [x, extsi(cmpi slt, x, 0)] 183def MulSIExtendedRHSOne : 184 Pattern<(Arith_MulSIExtendedOp $x, (ConstantLikeMatcher AnyAttr:$c1)), 185 [(replaceWithValue $x), 186 (Arith_ExtSIOp(Arith_CmpIOp 187 ConstantEnumCase<Arith_CmpIPredicateAttr, "slt">, 188 $x, 189 (Arith_ConstantOp (GetZeroAttr $x))))], 190 [(IsScalarOrSplatOne $c1)]>; 191 192//===----------------------------------------------------------------------===// 193// MulUIExtendedOp 194//===----------------------------------------------------------------------===// 195 196// mului_extended(x, y) -> [muli(x, y), x], when the `high` result is unused. 197// Since the `high` result it not used, any replacement value will do. 198def MulUIExtendedToMulI : 199 Pattern<(Arith_MulUIExtendedOp:$res $x, $y), 200 [(Arith_MulIOp $x, $y, DefOverflow), (replaceWithValue $x)], 201 [(Constraint<CPred<"$0.getUses().empty()">> $res__1)]>; 202 203//===----------------------------------------------------------------------===// 204// XOrIOp 205//===----------------------------------------------------------------------===// 206 207// xori is commutative and will be canonicalized to have its constants appear 208// as the second operand. 209 210// not(cmpi(pred, a, b)) -> cmpi(~pred, a, b), where not(x) is xori(x, 1) 211def InvertPredicate : NativeCodeCall<"invertPredicate($0)">; 212def XOrINotCmpI : 213 Pat<(Arith_XOrIOp 214 (Arith_CmpIOp $pred, $a, $b), 215 (ConstantLikeMatcher ConstantAttr<I1Attr, "1">)), 216 (Arith_CmpIOp (InvertPredicate $pred), $a, $b)>; 217 218// xor extui(x), extui(y) -> extui(xor(x,y)) 219def XOrIOfExtUI : 220 Pat<(Arith_XOrIOp (Arith_ExtUIOp $x), (Arith_ExtUIOp $y)), (Arith_ExtUIOp (Arith_XOrIOp $x, $y)), 221 [(Constraint<CPred<"$0.getType() == $1.getType()">> $x, $y)]>; 222 223// xor extsi(x), extsi(y) -> extsi(xor(x,y)) 224def XOrIOfExtSI : 225 Pat<(Arith_XOrIOp (Arith_ExtSIOp $x), (Arith_ExtSIOp $y)), (Arith_ExtSIOp (Arith_XOrIOp $x, $y)), 226 [(Constraint<CPred<"$0.getType() == $1.getType()">> $x, $y)]>; 227 228//===----------------------------------------------------------------------===// 229// CmpIOp 230//===----------------------------------------------------------------------===// 231 232// cmpi(== or !=, a ext iNN, b ext iNN) == cmpi(== or !=, a, b) 233def CmpIExtSI : 234 Pat<(Arith_CmpIOp $pred, 235 (Arith_ExtSIOp $a), 236 (Arith_ExtSIOp $b)), 237 (Arith_CmpIOp $pred, $a, $b), 238 [(Constraint<CPred<"$0.getType() == $1.getType()">> $a, $b), 239 (Constraint< 240 CPred<"$0.getValue() == arith::CmpIPredicate::eq || " 241 "$0.getValue() == arith::CmpIPredicate::ne">> $pred)]>; 242 243// cmpi(== or !=, a ext iNN, b ext iNN) == cmpi(== or !=, a, b) 244def CmpIExtUI : 245 Pat<(Arith_CmpIOp $pred, 246 (Arith_ExtUIOp $a), 247 (Arith_ExtUIOp $b)), 248 (Arith_CmpIOp $pred, $a, $b), 249 [(Constraint<CPred<"$0.getType() == $1.getType()">> $a, $b), 250 (Constraint< 251 CPred<"$0.getValue() == arith::CmpIPredicate::eq || " 252 "$0.getValue() == arith::CmpIPredicate::ne">> $pred)]>; 253 254//===----------------------------------------------------------------------===// 255// SelectOp 256//===----------------------------------------------------------------------===// 257 258// select(not(pred), a, b) => select(pred, b, a) 259def SelectNotCond : 260 Pat<(SelectOp (Arith_XOrIOp $pred, (ConstantLikeMatcher APIntAttr:$ones)), $a, $b), 261 (SelectOp $pred, $b, $a), 262 [(IsScalarOrSplatNegativeOne $ones)]>; 263 264// select(pred, select(pred, a, b), c) => select(pred, a, c) 265def RedundantSelectTrue : 266 Pat<(SelectOp $pred, (SelectOp $pred, $a, $b), $c), 267 (SelectOp $pred, $a, $c)>; 268 269// select(pred, a, select(pred, b, c)) => select(pred, a, c) 270def RedundantSelectFalse : 271 Pat<(SelectOp $pred, $a, (SelectOp $pred, $b, $c)), 272 (SelectOp $pred, $a, $c)>; 273 274// select(pred, false, true) => not(pred) 275def SelectI1ToNot : 276 Pat<(SelectOp $pred, 277 (ConstantLikeMatcher ConstantAttr<I1Attr, "0">), 278 (ConstantLikeMatcher ConstantAttr<I1Attr, "1">)), 279 (Arith_XOrIOp $pred, (Arith_ConstantOp ConstantAttr<I1Attr, "1">))>; 280 281//===----------------------------------------------------------------------===// 282// IndexCastOp 283//===----------------------------------------------------------------------===// 284 285// index_cast(index_cast(x)) -> x, if dstType == srcType. 286def IndexCastOfIndexCast : 287 Pat<(Arith_IndexCastOp:$res (Arith_IndexCastOp $x)), 288 (replaceWithValue $x), 289 [(Constraint<CPred<"$0.getType() == $1.getType()">> $res, $x)]>; 290 291// index_cast(extsi(x)) -> index_cast(x) 292def IndexCastOfExtSI : 293 Pat<(Arith_IndexCastOp (Arith_ExtSIOp $x)), (Arith_IndexCastOp $x)>; 294 295//===----------------------------------------------------------------------===// 296// IndexCastUIOp 297//===----------------------------------------------------------------------===// 298 299// index_castui(index_castui(x)) -> x, if dstType == srcType. 300def IndexCastUIOfIndexCastUI : 301 Pat<(Arith_IndexCastUIOp:$res (Arith_IndexCastUIOp $x)), 302 (replaceWithValue $x), 303 [(Constraint<CPred<"$0.getType() == $1.getType()">> $res, $x)]>; 304 305// index_castui(extui(x)) -> index_castui(x) 306def IndexCastUIOfExtUI : 307 Pat<(Arith_IndexCastUIOp (Arith_ExtUIOp $x)), (Arith_IndexCastUIOp $x)>; 308 309 310//===----------------------------------------------------------------------===// 311// BitcastOp 312//===----------------------------------------------------------------------===// 313 314// bitcast(bitcast(x)) -> x 315def BitcastOfBitcast : 316 Pat<(Arith_BitcastOp (Arith_BitcastOp $x)), (replaceWithValue $x)>; 317 318//===----------------------------------------------------------------------===// 319// ExtSIOp 320//===----------------------------------------------------------------------===// 321 322// extsi(extui(x iN : iM) : iL) -> extui(x : iL) 323def ExtSIOfExtUI : 324 Pat<(Arith_ExtSIOp (Arith_ExtUIOp $x)), (Arith_ExtUIOp $x)>; 325 326//===----------------------------------------------------------------------===// 327// AndIOp 328//===----------------------------------------------------------------------===// 329 330// and extui(x), extui(y) -> extui(and(x,y)) 331def AndOfExtUI : 332 Pat<(Arith_AndIOp (Arith_ExtUIOp $x), (Arith_ExtUIOp $y)), 333 (Arith_ExtUIOp (Arith_AndIOp $x, $y)), 334 [(Constraint<CPred<"$0.getType() == $1.getType()">> $x, $y)]>; 335 336// and extsi(x), extsi(y) -> extsi(and(x,y)) 337def AndOfExtSI : 338 Pat<(Arith_AndIOp (Arith_ExtSIOp $x), (Arith_ExtSIOp $y)), 339 (Arith_ExtSIOp (Arith_AndIOp $x, $y)), 340 [(Constraint<CPred<"$0.getType() == $1.getType()">> $x, $y)]>; 341 342//===----------------------------------------------------------------------===// 343// OrIOp 344//===----------------------------------------------------------------------===// 345 346// or extui(x), extui(y) -> extui(or(x,y)) 347def OrOfExtUI : 348 Pat<(Arith_OrIOp (Arith_ExtUIOp $x), (Arith_ExtUIOp $y)), 349 (Arith_ExtUIOp (Arith_OrIOp $x, $y)), 350 [(Constraint<CPred<"$0.getType() == $1.getType()">> $x, $y)]>; 351 352// or extsi(x), extsi(y) -> extsi(or(x,y)) 353def OrOfExtSI : 354 Pat<(Arith_OrIOp (Arith_ExtSIOp $x), (Arith_ExtSIOp $y)), 355 (Arith_ExtSIOp (Arith_OrIOp $x, $y)), 356 [(Constraint<CPred<"$0.getType() == $1.getType()">> $x, $y)]>; 357 358//===----------------------------------------------------------------------===// 359// TruncIOp 360//===----------------------------------------------------------------------===// 361 362def ValuesWithSameType : 363 Constraint< 364 CPred<"llvm::all_equal({$0.getType(), $1.getType(), $2.getType()})">>; 365 366def ValueWiderThan : 367 Constraint<And<[ 368 CPred<"getScalarOrElementWidth($0) > getScalarOrElementWidth($1)">, 369 CPred<"getScalarOrElementWidth($1) > 0">]>>; 370 371def TruncationMatchesShiftAmount : 372 Constraint<And<[ 373 CPred<"succeeded(getIntOrSplatIntValue($2))">, 374 CPred<"(getScalarOrElementWidth($0) - getScalarOrElementWidth($1)) == " 375 "*getIntOrSplatIntValue($2)">]>>; 376 377// trunci(extsi(x)) -> extsi(x), when only the sign-extension bits are truncated 378def TruncIExtSIToExtSI : 379 Pat<(Arith_TruncIOp:$tr (Arith_ExtSIOp:$ext $x)), 380 (Arith_ExtSIOp $x), 381 [(ValueWiderThan $ext, $tr), 382 (ValueWiderThan $tr, $x)]>; 383 384// trunci(extui(x)) -> extui(x), when only the zero-extension bits are truncated 385def TruncIExtUIToExtUI : 386 Pat<(Arith_TruncIOp:$tr (Arith_ExtUIOp:$ext $x)), 387 (Arith_ExtUIOp $x), 388 [(ValueWiderThan $ext, $tr), 389 (ValueWiderThan $tr, $x)]>; 390 391// trunci(shrsi(x, c)) -> trunci(shrui(x, c)) 392def TruncIShrSIToTrunciShrUI : 393 Pat<(Arith_TruncIOp:$tr 394 (Arith_ShRSIOp $x, (ConstantLikeMatcher TypedAttrInterface:$c0))), 395 (Arith_TruncIOp (Arith_ShRUIOp $x, (Arith_ConstantOp (cast<"TypedAttr"> $c0)))), 396 [(TruncationMatchesShiftAmount $x, $tr, $c0)]>; 397 398// trunci(shrui(mul(sext(x), sext(y)), c)) -> mulsi_extended(x, y) 399def TruncIShrUIMulIToMulSIExtended : 400 Pat<(Arith_TruncIOp:$tr (Arith_ShRUIOp 401 (Arith_MulIOp:$mul 402 (Arith_ExtSIOp $x), (Arith_ExtSIOp $y), $ovf1), 403 (ConstantLikeMatcher AnyAttr:$c0))), 404 (Arith_MulSIExtendedOp:$res__1 $x, $y), 405 [(ValuesWithSameType $tr, $x, $y), 406 (ValueWiderThan $mul, $x), 407 (TruncationMatchesShiftAmount $mul, $x, $c0)]>; 408 409// trunci(shrui(mul(zext(x), zext(y)), c)) -> mului_extended(x, y) 410def TruncIShrUIMulIToMulUIExtended : 411 Pat<(Arith_TruncIOp:$tr (Arith_ShRUIOp 412 (Arith_MulIOp:$mul 413 (Arith_ExtUIOp $x), (Arith_ExtUIOp $y), $ovf1), 414 (ConstantLikeMatcher AnyAttr:$c0))), 415 (Arith_MulUIExtendedOp:$res__1 $x, $y), 416 [(ValuesWithSameType $tr, $x, $y), 417 (ValueWiderThan $mul, $x), 418 (TruncationMatchesShiftAmount $mul, $x, $c0)]>; 419 420//===----------------------------------------------------------------------===// 421// MulFOp 422//===----------------------------------------------------------------------===// 423 424// mulf(negf(x), negf(y)) -> mulf(x,y) 425// (retain fastmath flags of original mulf) 426def MulFOfNegF : 427 Pat<(Arith_MulFOp (Arith_NegFOp $x, $_), (Arith_NegFOp $y, $_), $fmf), 428 (Arith_MulFOp $x, $y, $fmf), 429 [(Constraint<CPred<"$0.getType() == $1.getType()">> $x, $y)]>; 430 431//===----------------------------------------------------------------------===// 432// DivFOp 433//===----------------------------------------------------------------------===// 434 435// divf(negf(x), negf(y)) -> divf(x,y) 436// (retain fastmath flags of original divf) 437def DivFOfNegF : 438 Pat<(Arith_DivFOp (Arith_NegFOp $x, $_), (Arith_NegFOp $y, $_), $fmf), 439 (Arith_DivFOp $x, $y, $fmf), 440 [(Constraint<CPred<"$0.getType() == $1.getType()">> $x, $y)]>; 441 442#endif // ARITH_PATTERNS 443