1// RUN: mlir-opt -int-range-optimizations -canonicalize %s | FileCheck %s 2 3// CHECK-LABEL: func @add_min_max 4// CHECK: %[[c3:.*]] = arith.constant 3 : index 5// CHECK: return %[[c3]] 6func.func @add_min_max(%a: index, %b: index) -> index { 7 %c1 = arith.constant 1 : index 8 %c2 = arith.constant 2 : index 9 %0 = arith.minsi %a, %c1 : index 10 %1 = arith.maxsi %0, %c1 : index 11 %2 = arith.minui %b, %c2 : index 12 %3 = arith.maxui %2, %c2 : index 13 %4 = arith.addi %1, %3 : index 14 func.return %4 : index 15} 16 17// CHECK-LABEL: func @add_lower_bound 18// CHECK: %[[sge:.*]] = arith.cmpi sge 19// CHECK: return %[[sge]] 20func.func @add_lower_bound(%a : i32, %b : i32) -> i1 { 21 %c1 = arith.constant 1 : i32 22 %c2 = arith.constant 2 : i32 23 %0 = arith.maxsi %a, %c1 : i32 24 %1 = arith.maxsi %b, %c1 : i32 25 %2 = arith.addi %0, %1 : i32 26 %3 = arith.cmpi sge, %2, %c2 : i32 27 %4 = arith.cmpi uge, %2, %c2 : i32 28 %5 = arith.andi %3, %4 : i1 29 func.return %5 : i1 30} 31 32// CHECK-LABEL: func @sub_signed_vs_unsigned 33// CHECK-NOT: arith.cmpi sle 34// CHECK: %[[unsigned:.*]] = arith.cmpi ule 35// CHECK: return %[[unsigned]] : i1 36func.func @sub_signed_vs_unsigned(%v : i64) -> i1 { 37 %c0 = arith.constant 0 : i64 38 %c2 = arith.constant 2 : i64 39 %c-5 = arith.constant -5 : i64 40 %0 = arith.minsi %v, %c2 : i64 41 %1 = arith.maxsi %0, %c-5 : i64 42 %2 = arith.subi %1, %c2 : i64 43 %3 = arith.cmpi sle, %2, %c0 : i64 44 %4 = arith.cmpi ule, %2, %c0 : i64 45 %5 = arith.andi %3, %4 : i1 46 func.return %5 : i1 47} 48 49// CHECK-LABEL: func @multiply_negatives 50// CHECK: %[[false:.*]] = arith.constant false 51// CHECK: return %[[false]] 52func.func @multiply_negatives(%a : index, %b : index) -> i1 { 53 %c2 = arith.constant 2 : index 54 %c3 = arith.constant 3 : index 55 %c_1 = arith.constant -1 : index 56 %c_2 = arith.constant -2 : index 57 %c_4 = arith.constant -4 : index 58 %c_12 = arith.constant -12 : index 59 %0 = arith.maxsi %a, %c2 : index 60 %1 = arith.minsi %0, %c3 : index 61 %2 = arith.minsi %b, %c_1 : index 62 %3 = arith.maxsi %2, %c_4 : index 63 %4 = arith.muli %1, %3 : index 64 %5 = arith.cmpi slt, %4, %c_12 : index 65 %6 = arith.cmpi slt, %c_1, %4 : index 66 %7 = arith.ori %5, %6 : i1 67 func.return %7 : i1 68} 69 70// CHECK-LABEL: func @multiply_unsigned_bounds 71// CHECK: %[[true:.*]] = arith.constant true 72// CHECK: return %[[true]] 73func.func @multiply_unsigned_bounds(%a : i16, %b : i16) -> i1 { 74 %c0 = arith.constant 0 : i16 75 %c4 = arith.constant 4 : i16 76 %c_mask = arith.constant 0x3fff : i16 77 %c_bound = arith.constant 0xfffc : i16 78 %0 = arith.andi %a, %c_mask : i16 79 %1 = arith.minui %b, %c4 : i16 80 %2 = arith.muli %0, %1 : i16 81 %3 = arith.cmpi uge, %2, %c0 : i16 82 %4 = arith.cmpi ule, %2, %c_bound : i16 83 %5 = arith.andi %3, %4 : i1 84 func.return %5 : i1 85} 86 87// CHECK-LABEL: @for_loop_with_increasing_arg 88// CHECK: %[[ret:.*]] = arith.cmpi ule 89// CHECK: return %[[ret]] 90func.func @for_loop_with_increasing_arg() -> i1 { 91 %c0 = arith.constant 0 : index 92 %c1 = arith.constant 1 : index 93 %c4 = arith.constant 4 : index 94 %c16 = arith.constant 16 : index 95 %0 = scf.for %arg0 = %c0 to %c4 step %c1 iter_args(%arg1 = %c0) -> index { 96 %10 = arith.addi %arg0, %arg1 : index 97 scf.yield %10 : index 98 } 99 %1 = arith.cmpi ule, %0, %c16 : index 100 func.return %1 : i1 101} 102 103// CHECK-LABEL: @for_loop_with_constant_result 104// CHECK: %[[true:.*]] = arith.constant true 105// CHECK: return %[[true]] 106func.func @for_loop_with_constant_result() -> i1 { 107 %c0 = arith.constant 0 : index 108 %c1 = arith.constant 1 : index 109 %c4 = arith.constant 4 : index 110 %true = arith.constant true 111 %0 = scf.for %arg0 = %c0 to %c4 step %c1 iter_args(%arg1 = %true) -> i1 { 112 %10 = arith.cmpi ule, %arg0, %c4 : index 113 %11 = arith.andi %10, %arg1 : i1 114 scf.yield %11 : i1 115 } 116 func.return %0 : i1 117} 118 119// Test to catch a bug present in some versions of the data flow analysis 120// CHECK-LABEL: func @while_false 121// CHECK: %[[false:.*]] = arith.constant false 122// CHECK: scf.condition(%[[false]]) 123func.func @while_false(%arg0 : index) -> index { 124 %c0 = arith.constant 0 : index 125 %c1 = arith.constant 1 : index 126 %c2 = arith.constant 2 : index 127 %0 = arith.divui %arg0, %c2 : index 128 %1 = scf.while (%arg1 = %0) : (index) -> index { 129 %2 = arith.cmpi slt, %arg1, %c0 : index 130 scf.condition(%2) %arg1 : index 131 } do { 132 ^bb0(%arg2 : index): 133 scf.yield %c2 : index 134 } 135 func.return %1 : index 136} 137 138// CHECK-LABEL: func @div_bounds_positive 139// CHECK: %[[true:.*]] = arith.constant true 140// CHECK: return %[[true]] 141func.func @div_bounds_positive(%arg0 : index) -> i1 { 142 %c0 = arith.constant 0 : index 143 %c2 = arith.constant 2 : index 144 %c4 = arith.constant 4 : index 145 %0 = arith.maxsi %arg0, %c2 : index 146 %1 = arith.divsi %c4, %0 : index 147 %2 = arith.divui %c4, %0 : index 148 149 %3 = arith.cmpi sge, %1, %c0 : index 150 %4 = arith.cmpi sle, %1, %c2 : index 151 %5 = arith.cmpi sge, %2, %c0 : index 152 %6 = arith.cmpi sle, %1, %c2 : index 153 154 %7 = arith.andi %3, %4 : i1 155 %8 = arith.andi %7, %5 : i1 156 %9 = arith.andi %8, %6 : i1 157 func.return %9 : i1 158} 159 160// CHECK-LABEL: func @div_bounds_negative 161// CHECK: %[[true:.*]] = arith.constant true 162// CHECK: return %[[true]] 163func.func @div_bounds_negative(%arg0 : index) -> i1 { 164 %c0 = arith.constant 0 : index 165 %c_2 = arith.constant -2 : index 166 %c4 = arith.constant 4 : index 167 %0 = arith.minsi %arg0, %c_2 : index 168 %1 = arith.divsi %c4, %0 : index 169 %2 = arith.divui %c4, %0 : index 170 171 %3 = arith.cmpi sle, %1, %c0 : index 172 %4 = arith.cmpi sge, %1, %c_2 : index 173 %5 = arith.cmpi eq, %2, %c0 : index 174 175 %7 = arith.andi %3, %4 : i1 176 %8 = arith.andi %7, %5 : i1 177 func.return %8 : i1 178} 179 180// CHECK-LABEL: func @div_zero_undefined 181// CHECK: %[[true:.*]] = arith.constant true 182// CHECK: return %[[true]] 183func.func @div_zero_undefined(%arg0 : index) -> i1 { 184 %c0 = arith.constant 0 : index 185 %c1 = arith.constant 1 : index 186 %c4 = arith.constant 4 : index 187 %0 = arith.andi %arg0, %c1 : index 188 %1 = arith.divui %c4, %0 : index 189 %2 = arith.cmpi ule, %1, %c4 : index 190 func.return %2 : i1 191} 192 193// CHECK-LABEL: func @div_refine_min 194// CHECK: %[[true:.*]] = arith.constant true 195// CHECK: return %[[true]] 196func.func @div_refine_min(%arg0 : index) -> i1 { 197 %c0 = arith.constant 1 : index 198 %c1 = arith.constant 2 : index 199 %c4 = arith.constant 4 : index 200 %0 = arith.andi %arg0, %c1 : index 201 %1 = arith.divui %c4, %0 : index 202 %2 = arith.cmpi uge, %1, %c0 : index 203 func.return %2 : i1 204} 205 206// CHECK-LABEL: func @ceil_divui 207// CHECK: %[[ret:.*]] = arith.cmpi eq 208// CHECK: return %[[ret]] 209func.func @ceil_divui(%arg0 : index) -> i1 { 210 %c0 = arith.constant 0 : index 211 %c1 = arith.constant 1 : index 212 %c3 = arith.constant 3 : index 213 %c4 = arith.constant 4 : index 214 215 %0 = arith.minui %arg0, %c3 : index 216 %1 = arith.maxui %0, %c1 : index 217 %2 = arith.ceildivui %1, %c4 : index 218 %3 = arith.cmpi eq, %2, %c1 : index 219 220 %4 = arith.maxui %0, %c0 : index 221 %5 = arith.ceildivui %4, %c4 : index 222 %6 = arith.cmpi eq, %5, %c1 : index 223 %7 = arith.andi %3, %6 : i1 224 func.return %7 : i1 225} 226 227// CHECK-LABEL: func @ceil_divsi 228// CHECK: %[[ret:.*]] = arith.cmpi eq 229// CHECK: return %[[ret]] 230func.func @ceil_divsi(%arg0 : index) -> i1 { 231 %c0 = arith.constant 0 : index 232 %c1 = arith.constant 1 : index 233 %c3 = arith.constant 3 : index 234 %c4 = arith.constant 4 : index 235 %c-4 = arith.constant -4 : index 236 237 %0 = arith.minsi %arg0, %c3 : index 238 %1 = arith.maxsi %0, %c1 : index 239 %2 = arith.ceildivsi %1, %c4 : index 240 %3 = arith.cmpi eq, %2, %c1 : index 241 %4 = arith.ceildivsi %1, %c-4 : index 242 %5 = arith.cmpi eq, %4, %c0 : index 243 %6 = arith.andi %3, %5 : i1 244 245 %7 = arith.maxsi %0, %c0 : index 246 %8 = arith.ceildivsi %7, %c4 : index 247 %9 = arith.cmpi eq, %8, %c1 : index 248 %10 = arith.andi %6, %9 : i1 249 func.return %10 : i1 250} 251 252// There was a bug, which was causing this expr errorneously fold to constant 253// CHECK-LABEL: func @ceil_divsi_full_range 254// CHECK-SAME: (%[[arg:.*]]: index) 255// CHECK: %[[c64:.*]] = arith.constant 64 : index 256// CHECK: %[[ret:.*]] = arith.ceildivsi %[[arg]], %[[c64]] : index 257// CHECK: return %[[ret]] 258func.func @ceil_divsi_full_range(%6: index) -> index { 259 %c64 = arith.constant 64 : index 260 %55 = arith.ceildivsi %6, %c64 : index 261 return %55 : index 262} 263 264// CHECK-LABEL: func @ceil_divsi_intmin_bug_115293 265// CHECK: %[[ret:.*]] = arith.constant true 266// CHECK: return %[[ret]] 267func.func @ceil_divsi_intmin_bug_115293() -> i1 { 268 %intMin_i64 = test.with_bounds { smin = -9223372036854775808 : si64, smax = -9223372036854775808 : si64, umin = 9223372036854775808 : ui64, umax = 9223372036854775808 : ui64 } : i64 269 %denom_i64 = test.with_bounds { smin = 1189465982 : si64, smax = 1189465982 : si64, umin = 1189465982 : ui64, umax = 1189465982 : ui64 } : i64 270 %res_i64 = test.with_bounds { smin = 7754212542 : si64, smax = 7754212542 : si64, umin = 7754212542 : ui64, umax = 7754212542 : ui64 } : i64 271 272 %0 = arith.ceildivsi %intMin_i64, %denom_i64 : i64 273 %1 = arith.cmpi eq, %0, %res_i64 : i64 274 func.return %1 : i1 275} 276 277// CHECK-LABEL: func @floor_divsi 278// CHECK: %[[true:.*]] = arith.constant true 279// CHECK: return %[[true]] 280func.func @floor_divsi(%arg0 : index) -> i1 { 281 %c4 = arith.constant 4 : index 282 %c-1 = arith.constant -1 : index 283 %c-3 = arith.constant -3 : index 284 %c-4 = arith.constant -4 : index 285 286 %0 = arith.minsi %arg0, %c-1 : index 287 %1 = arith.maxsi %0, %c-4 : index 288 %2 = arith.floordivsi %1, %c4 : index 289 %3 = arith.cmpi eq, %2, %c-1 : index 290 func.return %3 : i1 291} 292 293// CHECK-LABEL: func @remui_base 294// CHECK: %[[true:.*]] = arith.constant true 295// CHECK: return %[[true]] 296func.func @remui_base(%arg0 : index, %arg1 : index ) -> i1 { 297 %c2 = arith.constant 2 : index 298 %c4 = arith.constant 4 : index 299 300 %0 = arith.minui %arg1, %c4 : index 301 %1 = arith.maxui %0, %c2 : index 302 %2 = arith.remui %arg0, %1 : index 303 %3 = arith.cmpi ult, %2, %c4 : index 304 func.return %3 : i1 305} 306 307// CHECK-LABEL: func @remui_base_maybe_zero 308// CHECK: %[[true:.*]] = arith.constant true 309// CHECK: return %[[true]] 310func.func @remui_base_maybe_zero(%arg0 : index, %arg1 : index ) -> i1 { 311 %c4 = arith.constant 4 : index 312 %c5 = arith.constant 5 : index 313 314 %0 = arith.minui %arg1, %c4 : index 315 %1 = arith.remui %arg0, %0 : index 316 %2 = arith.cmpi ult, %1, %c5 : index 317 func.return %2 : i1 318} 319 320// CHECK-LABEL: func @remsi_base 321// CHECK: %[[ret:.*]] = arith.cmpi sge 322// CHECK: return %[[ret]] 323func.func @remsi_base(%arg0 : index, %arg1 : index ) -> i1 { 324 %c0 = arith.constant 0 : index 325 %c2 = arith.constant 2 : index 326 %c4 = arith.constant 4 : index 327 %c-4 = arith.constant -4 : index 328 %true = arith.constant true 329 330 %0 = arith.minsi %arg1, %c4 : index 331 %1 = arith.maxsi %0, %c2 : index 332 %2 = arith.remsi %arg0, %1 : index 333 %3 = arith.cmpi sgt, %2, %c-4 : index 334 %4 = arith.cmpi slt, %2, %c4 : index 335 %5 = arith.cmpi sge, %2, %c0 : index 336 %6 = arith.andi %3, %4 : i1 337 %7 = arith.andi %5, %6 : i1 338 func.return %7 : i1 339} 340 341// CHECK-LABEL: func @remsi_positive 342// CHECK: %[[true:.*]] = arith.constant true 343// CHECK: return %[[true]] 344func.func @remsi_positive(%arg0 : index, %arg1 : index ) -> i1 { 345 %c0 = arith.constant 0 : index 346 %c2 = arith.constant 2 : index 347 %c4 = arith.constant 4 : index 348 %true = arith.constant true 349 350 %0 = arith.minsi %arg1, %c4 : index 351 %1 = arith.maxsi %0, %c2 : index 352 %2 = arith.maxsi %arg0, %c0 : index 353 %3 = arith.remsi %2, %1 : index 354 %4 = arith.cmpi sge, %3, %c0 : index 355 %5 = arith.cmpi slt, %3, %c4 : index 356 %6 = arith.andi %4, %5 : i1 357 func.return %6 : i1 358} 359 360// CHECK-LABEL: func @remui_restricted 361// CHECK: %[[true:.*]] = arith.constant true 362// CHECK: return %[[true]] 363func.func @remui_restricted(%arg0 : index) -> i1 { 364 %c2 = arith.constant 2 : index 365 %c3 = arith.constant 3 : index 366 %c4 = arith.constant 4 : index 367 368 %0 = arith.minui %arg0, %c3 : index 369 %1 = arith.maxui %0, %c2 : index 370 %2 = arith.remui %1, %c4 : index 371 %3 = arith.cmpi ule, %2, %c3 : index 372 %4 = arith.cmpi uge, %2, %c2 : index 373 %5 = arith.andi %3, %4 : i1 374 func.return %5 : i1 375} 376 377// CHECK-LABEL: func @remsi_restricted 378// CHECK: %[[true:.*]] = arith.constant true 379// CHECK: return %[[true]] 380func.func @remsi_restricted(%arg0 : index) -> i1 { 381 %c2 = arith.constant 2 : index 382 %c3 = arith.constant 3 : index 383 %c-4 = arith.constant -4 : index 384 385 %0 = arith.minsi %arg0, %c3 : index 386 %1 = arith.maxsi %0, %c2 : index 387 %2 = arith.remsi %1, %c-4 : index 388 %3 = arith.cmpi ule, %2, %c3 : index 389 %4 = arith.cmpi uge, %2, %c2 : index 390 %5 = arith.andi %3, %4 : i1 391 func.return %5 : i1 392} 393 394// CHECK-LABEL: func @remui_restricted_fails 395// CHECK: %[[ret:.*]] = arith.cmpi ne 396// CHECK: return %[[ret]] 397func.func @remui_restricted_fails(%arg0 : index) -> i1 { 398 %c2 = arith.constant 2 : index 399 %c3 = arith.constant 3 : index 400 %c4 = arith.constant 4 : index 401 %c5 = arith.constant 5 : index 402 403 %0 = arith.minui %arg0, %c5 : index 404 %1 = arith.maxui %0, %c3 : index 405 %2 = arith.remui %1, %c4 : index 406 %3 = arith.cmpi ne, %2, %c2 : index 407 func.return %3 : i1 408} 409 410// CHECK-LABEL: func @remsi_restricted_fails 411// CHECK: %[[ret:.*]] = arith.cmpi ne 412// CHECK: return %[[ret]] 413func.func @remsi_restricted_fails(%arg0 : index) -> i1 { 414 %c2 = arith.constant 2 : index 415 %c3 = arith.constant 3 : index 416 %c5 = arith.constant 5 : index 417 %c-4 = arith.constant -4 : index 418 419 %0 = arith.minsi %arg0, %c5 : index 420 %1 = arith.maxsi %0, %c3 : index 421 %2 = arith.remsi %1, %c-4 : index 422 %3 = arith.cmpi ne, %2, %c2 : index 423 func.return %3 : i1 424} 425 426// CHECK-LABEL: func @andi 427// CHECK: %[[ret:.*]] = arith.cmpi ugt 428// CHECK: return %[[ret]] 429func.func @andi(%arg0 : index) -> i1 { 430 %c2 = arith.constant 2 : index 431 %c5 = arith.constant 5 : index 432 %c7 = arith.constant 7 : index 433 434 %0 = arith.minsi %arg0, %c5 : index 435 %1 = arith.maxsi %0, %c2 : index 436 %2 = arith.andi %1, %c7 : index 437 %3 = arith.cmpi ugt, %2, %c5 : index 438 %4 = arith.cmpi ule, %2, %c7 : index 439 %5 = arith.andi %3, %4 : i1 440 func.return %5 : i1 441} 442 443// CHECK-LABEL: func @andi_doesnt_make_nonnegative 444// CHECK: %[[ret:.*]] = arith.cmpi sge 445// CHECK: return %[[ret]] 446func.func @andi_doesnt_make_nonnegative(%arg0 : index) -> i1 { 447 %c0 = arith.constant 0 : index 448 %c1 = arith.constant 1 : index 449 %0 = arith.addi %arg0, %c1 : index 450 %1 = arith.andi %arg0, %0 : index 451 %2 = arith.cmpi sge, %1, %c0 : index 452 func.return %2 : i1 453} 454 455 456// CHECK-LABEL: func @ori 457// CHECK: %[[true:.*]] = arith.constant true 458// CHECK: return %[[true]] 459func.func @ori(%arg0 : i128, %arg1 : i128) -> i1 { 460 %c-1 = arith.constant -1 : i128 461 %c0 = arith.constant 0 : i128 462 463 %0 = arith.minsi %arg1, %c-1 : i128 464 %1 = arith.ori %arg0, %0 : i128 465 %2 = arith.cmpi slt, %1, %c0 : i128 466 func.return %2 : i1 467} 468 469// CHECK-LABEL: func @xori_issue_82168 470// arith.cmpi was erroneously folded to %false, see Issue #82168. 471// CHECK: %[[R:.*]] = arith.cmpi eq, %{{.*}}, %{{.*}} : i64 472// CHECK: return %[[R]] 473func.func @xori_issue_82168() -> i1 { 474 %c0_i64 = arith.constant 0 : i64 475 %c2060639849_i64 = arith.constant 2060639849 : i64 476 %2 = test.with_bounds { umin = 2060639849 : i64, umax = 2060639850 : i64, smin = 2060639849 : i64, smax = 2060639850 : i64 } : i64 477 %3 = arith.xori %2, %c2060639849_i64 : i64 478 %4 = arith.cmpi eq, %3, %c0_i64 : i64 479 func.return %4 : i1 480} 481 482// CHECK-LABEL: func @xori_i1 483// CHECK-DAG: %[[true:.*]] = arith.constant true 484// CHECK-DAG: %[[false:.*]] = arith.constant false 485// CHECK: return %[[true]], %[[false]] 486func.func @xori_i1() -> (i1, i1) { 487 %true = arith.constant true 488 %1 = test.with_bounds { umin = 0 : i1, umax = 0 : i1, smin = 0 : i1, smax = 0 : i1 } : i1 489 %2 = test.with_bounds { umin = 1 : i1, umax = 1 : i1, smin = 1 : i1, smax = 1 : i1 } : i1 490 %3 = arith.xori %1, %true : i1 491 %4 = arith.xori %2, %true : i1 492 func.return %3, %4 : i1, i1 493} 494 495// CHECK-LABEL: func @xori 496// CHECK: %[[false:.*]] = arith.constant false 497// CHECK: return %[[false]] 498func.func @xori(%arg0 : i64, %arg1 : i64) -> i1 { 499 %c0 = arith.constant 0 : i64 500 %c7 = arith.constant 7 : i64 501 %c15 = arith.constant 15 : i64 502 %true = arith.constant true 503 504 %0 = arith.minui %arg0, %c7 : i64 505 %1 = arith.minui %arg1, %c15 : i64 506 %2 = arith.xori %0, %1 : i64 507 %3 = arith.cmpi sle, %2, %c15 : i64 508 %4 = arith.xori %3, %true : i1 509 func.return %4 : i1 510} 511 512// CHECK-LABEL: func @extui 513// CHECK: %[[true:.*]] = arith.constant true 514// CHECK: return %[[true]] 515func.func @extui(%arg0 : i16) -> i1 { 516 %ci16_max = arith.constant 0xffff : i32 517 %0 = arith.extui %arg0 : i16 to i32 518 %1 = arith.cmpi ule, %0, %ci16_max : i32 519 func.return %1 : i1 520} 521 522// CHECK-LABEL: func @extsi 523// CHECK: %[[true:.*]] = arith.constant true 524// CHECK: return %[[true]] 525func.func @extsi(%arg0 : i16) -> i1 { 526 %ci16_smax = arith.constant 0x7fff : i32 527 %ci16_smin = arith.constant 0xffff8000 : i32 528 %0 = arith.extsi %arg0 : i16 to i32 529 %1 = arith.cmpi sle, %0, %ci16_smax : i32 530 %2 = arith.cmpi sge, %0, %ci16_smin : i32 531 %3 = arith.andi %1, %2 : i1 532 func.return %3 : i1 533} 534 535// CHECK-LABEL: func @trunci 536// CHECK: %[[true:.*]] = arith.constant true 537// CHECK: return %[[true]] 538func.func @trunci(%arg0 : i32) -> i1 { 539 %c-14_i32 = arith.constant -14 : i32 540 %c-14_i16 = arith.constant -14 : i16 541 %ci16_smin = arith.constant 0xffff8000 : i32 542 %0 = arith.minsi %arg0, %c-14_i32 : i32 543 %1 = arith.maxsi %0, %ci16_smin : i32 544 %2 = arith.trunci %1 : i32 to i16 545 %3 = arith.cmpi sle, %2, %c-14_i16 : i16 546 %4 = arith.extsi %2 : i16 to i32 547 %5 = arith.cmpi sle, %4, %c-14_i32 : i32 548 %6 = arith.cmpi sge, %4, %ci16_smin : i32 549 %7 = arith.andi %3, %5 : i1 550 %8 = arith.andi %7, %6 : i1 551 func.return %8 : i1 552} 553 554// CHECK-LABEL: func @index_cast 555// CHECK: %[[true:.*]] = arith.constant true 556// CHECK: return %[[true]] 557func.func @index_cast(%arg0 : index) -> i1 { 558 %ci32_smin = arith.constant 0xffffffff80000000 : i64 559 %0 = arith.index_cast %arg0 : index to i32 560 %1 = arith.index_cast %0 : i32 to index 561 %2 = arith.index_cast %ci32_smin : i64 to index 562 %3 = arith.cmpi sge, %1, %2 : index 563 func.return %3 : i1 564} 565 566// CHECK-LABEL: func @shli 567// CHECK: %[[ret:.*]] = arith.cmpi sgt 568// CHECK: return %[[ret]] 569func.func @shli(%arg0 : i32, %arg1 : i1) -> i1 { 570 %c2 = arith.constant 2 : i32 571 %c4 = arith.constant 4 : i32 572 %c8 = arith.constant 8 : i32 573 %c32 = arith.constant 32 : i32 574 %c-1 = arith.constant -1 : i32 575 %c-16 = arith.constant -16 : i32 576 %0 = arith.maxsi %arg0, %c-1 : i32 577 %1 = arith.minsi %0, %c2 : i32 578 %2 = arith.select %arg1, %c2, %c4 : i32 579 %3 = arith.shli %1, %2 : i32 580 %4 = arith.cmpi sge, %3, %c-16 : i32 581 %5 = arith.cmpi sle, %3, %c32 : i32 582 %6 = arith.cmpi sgt, %3, %c8 : i32 583 %7 = arith.andi %4, %5 : i1 584 %8 = arith.andi %7, %6 : i1 585 func.return %8 : i1 586} 587 588// CHECK-LABEL: func @shrui 589// CHECK: %[[ret:.*]] = arith.cmpi uge 590// CHECK: return %[[ret]] 591func.func @shrui(%arg0 : i1) -> i1 { 592 %c2 = arith.constant 2 : i32 593 %c4 = arith.constant 4 : i32 594 %c8 = arith.constant 8 : i32 595 %c32 = arith.constant 32 : i32 596 %0 = arith.select %arg0, %c2, %c4 : i32 597 %1 = arith.shrui %c32, %0 : i32 598 %2 = arith.cmpi ule, %1, %c8 : i32 599 %3 = arith.cmpi uge, %1, %c2 : i32 600 %4 = arith.cmpi uge, %1, %c8 : i32 601 %5 = arith.andi %2, %3 : i1 602 %6 = arith.andi %5, %4 : i1 603 func.return %6 : i1 604} 605 606// CHECK-LABEL: func @shrsi 607// CHECK: %[[ret:.*]] = arith.cmpi slt 608// CHECK: return %[[ret]] 609func.func @shrsi(%arg0 : i32, %arg1 : i1) -> i1 { 610 %c2 = arith.constant 2 : i32 611 %c4 = arith.constant 4 : i32 612 %c8 = arith.constant 8 : i32 613 %c32 = arith.constant 32 : i32 614 %c-8 = arith.constant -8 : i32 615 %c-32 = arith.constant -32 : i32 616 %0 = arith.maxsi %arg0, %c-32 : i32 617 %1 = arith.minsi %0, %c32 : i32 618 %2 = arith.select %arg1, %c2, %c4 : i32 619 %3 = arith.shrsi %1, %2 : i32 620 %4 = arith.cmpi sge, %3, %c-8 : i32 621 %5 = arith.cmpi sle, %3, %c8 : i32 622 %6 = arith.cmpi slt, %3, %c2 : i32 623 %7 = arith.andi %4, %5 : i1 624 %8 = arith.andi %7, %6 : i1 625 func.return %8 : i1 626} 627 628// CHECK-LABEL: func @no_aggressive_eq 629// CHECK: %[[ret:.*]] = arith.cmpi eq 630// CHECK: return %[[ret]] 631func.func @no_aggressive_eq(%arg0 : index) -> i1 { 632 %c1 = arith.constant 1 : index 633 %0 = arith.andi %arg0, %c1 : index 634 %1 = arith.minui %arg0, %c1 : index 635 %2 = arith.cmpi eq, %0, %1 : index 636 func.return %2 : i1 637} 638 639// CHECK-LABEL: func @select_union 640// CHECK: %[[ret:.*]] = arith.cmpi ne 641// CHECK: return %[[ret]] 642 643func.func @select_union(%arg0 : index, %arg1 : i1) -> i1 { 644 %c64 = arith.constant 64 : index 645 %c100 = arith.constant 100 : index 646 %c128 = arith.constant 128 : index 647 %c192 = arith.constant 192 : index 648 %0 = arith.remui %arg0, %c64 : index 649 %1 = arith.addi %0, %c128 : index 650 %2 = arith.select %arg1, %0, %1 : index 651 %3 = arith.cmpi slt, %2, %c192 : index 652 %4 = arith.cmpi ne, %c100, %2 : index 653 %5 = arith.andi %3, %4 : i1 654 func.return %5 : i1 655} 656 657// CHECK-LABEL: func @if_union 658// CHECK: %[[true:.*]] = arith.constant true 659// CHECK: return %[[true]] 660func.func @if_union(%arg0 : index, %arg1 : i1) -> i1 { 661 %c4 = arith.constant 4 : index 662 %c16 = arith.constant 16 : index 663 %c-1 = arith.constant -1 : index 664 %c-4 = arith.constant -4 : index 665 %0 = arith.minui %arg0, %c4 : index 666 %1 = scf.if %arg1 -> index { 667 %10 = arith.muli %0, %0 : index 668 scf.yield %10 : index 669 } else { 670 %20 = arith.muli %0, %c-1 : index 671 scf.yield %20 : index 672 } 673 %2 = arith.cmpi sle, %1, %c16 : index 674 %3 = arith.cmpi sge, %1, %c-4 : index 675 %4 = arith.andi %2, %3 : i1 676 func.return %4 : i1 677} 678 679// CHECK-LABEL: func @branch_union 680// CHECK: %[[true:.*]] = arith.constant true 681// CHECK: return %[[true]] 682func.func @branch_union(%arg0 : index, %arg1 : i1) -> i1 { 683 %c4 = arith.constant 4 : index 684 %c16 = arith.constant 16 : index 685 %c-1 = arith.constant -1 : index 686 %c-4 = arith.constant -4 : index 687 %0 = arith.minui %arg0, %c4 : index 688 cf.cond_br %arg1, ^bb1, ^bb2 689^bb1 : 690 %1 = arith.muli %0, %0 : index 691 cf.br ^bb3(%1 : index) 692^bb2 : 693 %2 = arith.muli %0, %c-1 : index 694 cf.br ^bb3(%2 : index) 695^bb3(%3 : index) : 696 %4 = arith.cmpi sle, %3, %c16 : index 697 %5 = arith.cmpi sge, %3, %c-4 : index 698 %6 = arith.andi %4, %5 : i1 699 func.return %6 : i1 700} 701 702// CHECK-LABEL: func @loop_bound_not_inferred_with_branch 703// CHECK-DAG: %[[min:.*]] = arith.cmpi sge 704// CHECK-DAG: %[[max:.*]] = arith.cmpi slt 705// CHECK-DAG: %[[ret:.*]] = arith.andi %[[min]], %[[max]] 706// CHECK: return %[[ret]] 707func.func @loop_bound_not_inferred_with_branch(%arg0 : index, %arg1 : i1) -> i1 { 708 %c0 = arith.constant 0 : index 709 %c1 = arith.constant 1 : index 710 %c4 = arith.constant 4 : index 711 %0 = arith.minui %arg0, %c4 : index 712 cf.br ^bb2(%c0 : index) 713^bb1(%1 : index) : 714 %2 = arith.addi %1, %c1 : index 715 cf.br ^bb2(%2 : index) 716^bb2(%3 : index): 717 %4 = arith.cmpi ult, %3, %c4 : index 718 cf.cond_br %4, ^bb1(%3 : index), ^bb3(%3 : index) 719^bb3(%5 : index) : 720 %6 = arith.cmpi sge, %5, %c0 : index 721 %7 = arith.cmpi slt, %5, %c4 : index 722 %8 = arith.andi %6, %7 : i1 723 func.return %8 : i1 724} 725 726// Test fon a bug where the noive implementation of trunctation led to the cast 727// value being set to [0, 0]. 728// CHECK-LABEL: func.func @truncation_spillover 729// CHECK: %[[unreplaced:.*]] = arith.index_cast 730// CHECK: memref.store %[[unreplaced]] 731func.func @truncation_spillover(%arg0 : memref<?xi32>) -> index { 732 %c0 = arith.constant 0 : index 733 %c1 = arith.constant 1 : index 734 %c2 = arith.constant 2 : index 735 %c49 = arith.constant 49 : index 736 %0 = scf.for %arg1 = %c0 to %c2 step %c1 iter_args(%arg2 = %c0) -> index { 737 %1 = arith.divsi %arg2, %c49 : index 738 %2 = arith.index_cast %1 : index to i32 739 memref.store %2, %arg0[%c0] : memref<?xi32> 740 %3 = arith.addi %arg2, %arg1 : index 741 scf.yield %3 : index 742 } 743 func.return %0 : index 744} 745 746// CHECK-LABEL: func.func @trunc_catches_overflow 747// CHECK: %[[sge:.*]] = arith.cmpi sge 748// CHECK: return %[[sge]] 749func.func @trunc_catches_overflow(%arg0 : i16) -> i1 { 750 %c0_i16 = arith.constant 0 : i16 751 %c130_i16 = arith.constant 130 : i16 752 %c0_i8 = arith.constant 0 : i8 753 %0 = arith.maxui %arg0, %c0_i16 : i16 754 %1 = arith.minui %0, %c130_i16 : i16 755 %2 = arith.trunci %1 : i16 to i8 756 %3 = arith.cmpi sge, %2, %c0_i8 : i8 757 %4 = arith.cmpi uge, %2, %c0_i8 : i8 758 %5 = arith.andi %3, %4 : i1 759 func.return %5 : i1 760} 761 762// CHECK-LABEL: func.func @trunc_respects_same_high_half 763// CHECK: %[[false:.*]] = arith.constant false 764// CHECK: return %[[false]] 765func.func @trunc_respects_same_high_half(%arg0 : i16) -> i1 { 766 %c256_i16 = arith.constant 256 : i16 767 %c257_i16 = arith.constant 257 : i16 768 %c2_i8 = arith.constant 2 : i8 769 %0 = arith.maxui %arg0, %c256_i16 : i16 770 %1 = arith.minui %0, %c257_i16 : i16 771 %2 = arith.trunci %1 : i16 to i8 772 %3 = arith.cmpi sge, %2, %c2_i8 : i8 773 func.return %3 : i1 774} 775 776// CHECK-LABEL: func.func @trunc_handles_small_signed_ranges 777// CHECK: %[[true:.*]] = arith.constant true 778// CHECK: return %[[true]] 779func.func @trunc_handles_small_signed_ranges(%arg0 : i16) -> i1 { 780 %c-2_i16 = arith.constant -2 : i16 781 %c2_i16 = arith.constant 2 : i16 782 %c-2_i8 = arith.constant -2 : i8 783 %c2_i8 = arith.constant 2 : i8 784 %0 = arith.maxsi %arg0, %c-2_i16 : i16 785 %1 = arith.minsi %0, %c2_i16 : i16 786 %2 = arith.trunci %1 : i16 to i8 787 %3 = arith.cmpi sge, %2, %c-2_i8 : i8 788 %4 = arith.cmpi sle, %2, %c2_i8 : i8 789 %5 = arith.andi %3, %4 : i1 790 func.return %5 : i1 791} 792 793/// Catch a bug that crept in during an earlier refactoring that made unsigned 794/// extension use the signed ranges 795 796// CHECK-LABEL: func.func @extui_uses_unsigned 797// CHECK: %[[true:.*]] = arith.constant true 798// CHECK: return %[[true]] 799func.func @extui_uses_unsigned(%arg0 : i32) -> i1 { 800 %ci32_smin = arith.constant 0x80000000 : i32 801 %ci32_smin_64 = arith.constant 0x80000000 : i64 802 %c0_i64 = arith.constant 0 : i64 803 %0 = arith.minui %arg0, %ci32_smin : i32 804 %1 = arith.extui %0 : i32 to i64 805 %2 = arith.cmpi sge, %1, %c0_i64 : i64 806 %3 = arith.cmpi ule, %1, %ci32_smin_64 : i64 807 %4 = arith.andi %2, %3 : i1 808 func.return %4 : i1 809} 810 811/// Catch a bug that caused a crash in getLoopBoundFromFold when 812/// SparseConstantPropagation is loaded in the solver. 813 814// CHECK-LABEL: func.func @caller( 815// CHECK-SAME: %[[VAL_0:.*]]: memref<?xindex, 4>) { 816// CHECK: call @callee(%[[VAL_0]]) : (memref<?xindex, 4>) -> () 817// CHECK: return 818// CHECK: } 819func.func @caller(%arg0: memref<?xindex, 4>) { 820 call @callee(%arg0) : (memref<?xindex, 4>) -> () 821 return 822} 823 824// CHECK-LABEL: func.func private @callee( 825// CHECK-SAME: %[[VAL_0:.*]]: memref<?xindex, 4>) { 826// CHECK: return 827// CHECK: } 828func.func private @callee(%arg0: memref<?xindex, 4>) { 829 %c1 = arith.constant 1 : index 830 %c0 = arith.constant 0 : index 831 %0 = affine.load %arg0[0] : memref<?xindex, 4> 832 scf.for %arg1 = %c0 to %0 step %c1 { 833 } 834 return 835} 836 837// CHECK-LABEL: func @test_i8_bounds 838// CHECK: test.reflect_bounds {smax = 127 : si8, smin = -128 : si8, umax = 255 : ui8, umin = 0 : ui8} 839func.func @test_i8_bounds() -> i8 { 840 %cst1 = arith.constant 1 : i8 841 %0 = test.with_bounds { umin = 0 : i8, umax = 255 : i8, smin = -128 : i8, smax = 127 : i8 } : i8 842 %1 = arith.addi %0, %cst1 : i8 843 %2 = test.reflect_bounds %1 : i8 844 return %2: i8 845} 846 847// CHECK-LABEL: func @test_add_1 848// CHECK: test.reflect_bounds {smax = 127 : si8, smin = -128 : si8, umax = 255 : ui8, umin = 0 : ui8} 849func.func @test_add_1() -> i8 { 850 %cst1 = arith.constant 1 : i8 851 %0 = test.with_bounds { umin = 0 : i8, umax = 255 : i8, smin = -128 : i8, smax = 127 : i8 } : i8 852 %1 = arith.addi %0, %cst1 : i8 853 %2 = test.reflect_bounds %1 : i8 854 return %2: i8 855} 856 857// Tests below check inference with overflow flags. 858 859// CHECK-LABEL: func @test_add_i8_wrap1 860// CHECK: test.reflect_bounds {smax = 127 : si8, smin = -128 : si8, umax = 128 : ui8, umin = 1 : ui8} 861func.func @test_add_i8_wrap1() -> i8 { 862 %cst1 = arith.constant 1 : i8 863 %0 = test.with_bounds { umin = 0 : i8, umax = 127 : i8, smin = 0 : i8, smax = 127 : i8 } : i8 864 // smax overflow 865 %1 = arith.addi %0, %cst1 : i8 866 %2 = test.reflect_bounds %1 : i8 867 return %2: i8 868} 869 870// CHECK-LABEL: func @test_add_i8_wrap2 871// CHECK: test.reflect_bounds {smax = 127 : si8, smin = -128 : si8, umax = 128 : ui8, umin = 1 : ui8} 872func.func @test_add_i8_wrap2() -> i8 { 873 %cst1 = arith.constant 1 : i8 874 %0 = test.with_bounds { umin = 0 : i8, umax = 127 : i8, smin = 0 : i8, smax = 127 : i8 } : i8 875 // smax overflow 876 %1 = arith.addi %0, %cst1 overflow<nuw> : i8 877 %2 = test.reflect_bounds %1 : i8 878 return %2: i8 879} 880 881// CHECK-LABEL: func @test_add_i8_nowrap 882// CHECK: test.reflect_bounds {smax = 127 : si8, smin = 1 : si8, umax = 127 : ui8, umin = 1 : ui8} 883func.func @test_add_i8_nowrap() -> i8 { 884 %cst1 = arith.constant 1 : i8 885 %0 = test.with_bounds { umin = 0 : i8, umax = 127 : i8, smin = 0 : i8, smax = 127 : i8 } : i8 886 // nsw flag stops smax from overflowing 887 %1 = arith.addi %0, %cst1 overflow<nsw> : i8 888 %2 = test.reflect_bounds %1 : i8 889 return %2: i8 890} 891 892// CHECK-LABEL: func @test_sub_i8_wrap1 893// CHECK: test.reflect_bounds {smax = 5 : si8, smin = -10 : si8, umax = 255 : ui8, umin = 0 : ui8} %1 : i8 894func.func @test_sub_i8_wrap1() -> i8 { 895 %cst10 = arith.constant 10 : i8 896 %0 = test.with_bounds { umin = 0 : i8, umax = 15 : i8, smin = 0 : i8, smax = 15 : i8 } : i8 897 // umin underflows 898 %1 = arith.subi %0, %cst10 : i8 899 %2 = test.reflect_bounds %1 : i8 900 return %2: i8 901} 902 903// CHECK-LABEL: func @test_sub_i8_wrap2 904// CHECK: test.reflect_bounds {smax = 5 : si8, smin = -10 : si8, umax = 255 : ui8, umin = 0 : ui8} %1 : i8 905func.func @test_sub_i8_wrap2() -> i8 { 906 %cst10 = arith.constant 10 : i8 907 %0 = test.with_bounds { umin = 0 : i8, umax = 15 : i8, smin = 0 : i8, smax = 15 : i8 } : i8 908 // umin underflows 909 %1 = arith.subi %0, %cst10 overflow<nsw> : i8 910 %2 = test.reflect_bounds %1 : i8 911 return %2: i8 912} 913 914// CHECK-LABEL: func @test_sub_i8_nowrap 915// CHECK: test.reflect_bounds {smax = 5 : si8, smin = 0 : si8, umax = 5 : ui8, umin = 0 : ui8} 916func.func @test_sub_i8_nowrap() -> i8 { 917 %cst10 = arith.constant 10 : i8 918 %0 = test.with_bounds { umin = 0 : i8, umax = 15 : i8, smin = 0 : i8, smax = 15 : i8 } : i8 919 // nuw flag stops umin from underflowing 920 %1 = arith.subi %0, %cst10 overflow<nuw> : i8 921 %2 = test.reflect_bounds %1 : i8 922 return %2: i8 923} 924 925// CHECK-LABEL: func @test_mul_i8_wrap 926// CHECK: test.reflect_bounds {smax = 127 : si8, smin = -128 : si8, umax = 200 : ui8, umin = 100 : ui8} 927func.func @test_mul_i8_wrap() -> i8 { 928 %cst10 = arith.constant 10 : i8 929 %0 = test.with_bounds { umin = 10 : i8, umax = 20 : i8, smin = 10 : i8, smax = 20 : i8 } : i8 930 // smax overflows 931 %1 = arith.muli %0, %cst10 : i8 932 %2 = test.reflect_bounds %1 : i8 933 return %2: i8 934} 935 936// CHECK-LABEL: func @test_mul_i8_nowrap 937// CHECK: test.reflect_bounds {smax = 127 : si8, smin = 100 : si8, umax = 127 : ui8, umin = 100 : ui8} 938func.func @test_mul_i8_nowrap() -> i8 { 939 %cst10 = arith.constant 10 : i8 940 %0 = test.with_bounds { umin = 10 : i8, umax = 20 : i8, smin = 10 : i8, smax = 20 : i8 } : i8 941 // nsw stops overflow 942 %1 = arith.muli %0, %cst10 overflow<nsw> : i8 943 %2 = test.reflect_bounds %1 : i8 944 return %2: i8 945} 946 947// CHECK-LABEL: func @test_shl_i8_wrap1 948// CHECK: test.reflect_bounds {smax = 127 : si8, smin = -128 : si8, umax = 160 : ui8, umin = 80 : ui8} 949func.func @test_shl_i8_wrap1() -> i8 { 950 %cst3 = arith.constant 3 : i8 951 %0 = test.with_bounds { umin = 10 : i8, umax = 20 : i8, smin = 10 : i8, smax = 20 : i8 } : i8 952 // smax overflows 953 %1 = arith.shli %0, %cst3 : i8 954 %2 = test.reflect_bounds %1 : i8 955 return %2: i8 956} 957 958// CHECK-LABEL: func @test_shl_i8_wrap2 959// CHECK: test.reflect_bounds {smax = 127 : si8, smin = -128 : si8, umax = 160 : ui8, umin = 80 : ui8} 960func.func @test_shl_i8_wrap2() -> i8 { 961 %cst3 = arith.constant 3 : i8 962 %0 = test.with_bounds { umin = 10 : i8, umax = 20 : i8, smin = 10 : i8, smax = 20 : i8 } : i8 963 // smax overflows 964 %1 = arith.shli %0, %cst3 overflow<nuw> : i8 965 %2 = test.reflect_bounds %1 : i8 966 return %2: i8 967} 968 969// CHECK-LABEL: func @test_shl_i8_nowrap 970// CHECK: test.reflect_bounds {smax = 127 : si8, smin = 80 : si8, umax = 127 : ui8, umin = 80 : ui8} 971func.func @test_shl_i8_nowrap() -> i8 { 972 %cst3 = arith.constant 3 : i8 973 %0 = test.with_bounds { umin = 10 : i8, umax = 20 : ui8, smin = 10 : i8, smax = 20 : i8 } : i8 974 // nsw stops smax overflow 975 %1 = arith.shli %0, %cst3 overflow<nsw> : i8 976 %2 = test.reflect_bounds %1 : i8 977 return %2: i8 978} 979 980/// A test case to ensure that the ranges for unsupported ops are initialized 981/// properly to maxRange, rather than left uninitialized. 982/// In this test case, the previous behavior would leave the ranges for %a and 983/// %b uninitialized, resulting in arith.cmpf's range not being updated, even 984/// though it has an integer valued result. 985 986// CHECK-LABEL: func @test_cmpf_propagates 987// CHECK: test.reflect_bounds {smax = 2 : index, smin = 1 : index, umax = 2 : index, umin = 1 : index} 988func.func @test_cmpf_propagates(%a: f32, %b: f32) -> index { 989 %c1 = arith.constant 1 : index 990 %c2 = arith.constant 2 : index 991 992 %0 = arith.cmpf ueq, %a, %b : f32 993 %1 = arith.select %0, %c1, %c2 : index 994 %2 = test.reflect_bounds %1 : index 995 func.return %2 : index 996} 997 998// CHECK-LABEL: func @zero_trip_loop 999func.func @zero_trip_loop() { 1000 %idx1 = arith.constant 1 : index 1001 scf.for %arg0 = %idx1 to %idx1 step %idx1 { 1002 %138 = index.floordivs %arg0, %arg0 1003 } 1004 return 1005} 1006 1007// CHECK-LABEL: func @zero_trip_loop2 1008func.func @zero_trip_loop2() { 1009 %idx1 = arith.constant 1 : index 1010 %idxm1 = arith.constant -1 : index 1011 scf.for %arg0 = %idx1 to %idx1 step %idxm1 { 1012 %138 = index.floordivs %arg0, %arg0 1013 } 1014 return 1015} 1016