1 ; RUN: llc < %s -march=arm64 -aarch64-atomic-cfg-tidy=0 | FileCheck %s 2 3 ; 4 ; Get the actual value of the overflow bit. 5 ; 6 define i1 @saddo.i32(i32 %v1, i32 %v2, i32* %res) { 7 entry: 8 ; CHECK-LABEL: saddo.i32 9 ; CHECK: adds w8, w0, w1 10 ; CHECK-NEXT: cset w0, vs 11 %t = call {i32, i1} @llvm.sadd.with.overflow.i32(i32 %v1, i32 %v2) 12 %val = extractvalue {i32, i1} %t, 0 13 %obit = extractvalue {i32, i1} %t, 1 14 store i32 %val, i32* %res 15 ret i1 %obit 16 } 17 18 define i1 @saddo.i64(i64 %v1, i64 %v2, i64* %res) { 19 entry: 20 ; CHECK-LABEL: saddo.i64 21 ; CHECK: adds x8, x0, x1 22 ; CHECK-NEXT: cset w0, vs 23 %t = call {i64, i1} @llvm.sadd.with.overflow.i64(i64 %v1, i64 %v2) 24 %val = extractvalue {i64, i1} %t, 0 25 %obit = extractvalue {i64, i1} %t, 1 26 store i64 %val, i64* %res 27 ret i1 %obit 28 } 29 30 define i1 @uaddo.i32(i32 %v1, i32 %v2, i32* %res) { 31 entry: 32 ; CHECK-LABEL: uaddo.i32 33 ; CHECK: adds w8, w0, w1 34 ; CHECK-NEXT: cset w0, hs 35 %t = call {i32, i1} @llvm.uadd.with.overflow.i32(i32 %v1, i32 %v2) 36 %val = extractvalue {i32, i1} %t, 0 37 %obit = extractvalue {i32, i1} %t, 1 38 store i32 %val, i32* %res 39 ret i1 %obit 40 } 41 42 define i1 @uaddo.i64(i64 %v1, i64 %v2, i64* %res) { 43 entry: 44 ; CHECK-LABEL: uaddo.i64 45 ; CHECK: adds x8, x0, x1 46 ; CHECK-NEXT: cset w0, hs 47 %t = call {i64, i1} @llvm.uadd.with.overflow.i64(i64 %v1, i64 %v2) 48 %val = extractvalue {i64, i1} %t, 0 49 %obit = extractvalue {i64, i1} %t, 1 50 store i64 %val, i64* %res 51 ret i1 %obit 52 } 53 54 define i1 @ssubo.i32(i32 %v1, i32 %v2, i32* %res) { 55 entry: 56 ; CHECK-LABEL: ssubo.i32 57 ; CHECK: subs w8, w0, w1 58 ; CHECK-NEXT: cset w0, vs 59 %t = call {i32, i1} @llvm.ssub.with.overflow.i32(i32 %v1, i32 %v2) 60 %val = extractvalue {i32, i1} %t, 0 61 %obit = extractvalue {i32, i1} %t, 1 62 store i32 %val, i32* %res 63 ret i1 %obit 64 } 65 66 define i1 @ssubo.i64(i64 %v1, i64 %v2, i64* %res) { 67 entry: 68 ; CHECK-LABEL: ssubo.i64 69 ; CHECK: subs x8, x0, x1 70 ; CHECK-NEXT: cset w0, vs 71 %t = call {i64, i1} @llvm.ssub.with.overflow.i64(i64 %v1, i64 %v2) 72 %val = extractvalue {i64, i1} %t, 0 73 %obit = extractvalue {i64, i1} %t, 1 74 store i64 %val, i64* %res 75 ret i1 %obit 76 } 77 78 define i1 @usubo.i32(i32 %v1, i32 %v2, i32* %res) { 79 entry: 80 ; CHECK-LABEL: usubo.i32 81 ; CHECK: subs w8, w0, w1 82 ; CHECK-NEXT: cset w0, lo 83 %t = call {i32, i1} @llvm.usub.with.overflow.i32(i32 %v1, i32 %v2) 84 %val = extractvalue {i32, i1} %t, 0 85 %obit = extractvalue {i32, i1} %t, 1 86 store i32 %val, i32* %res 87 ret i1 %obit 88 } 89 90 define i1 @usubo.i64(i64 %v1, i64 %v2, i64* %res) { 91 entry: 92 ; CHECK-LABEL: usubo.i64 93 ; CHECK: subs x8, x0, x1 94 ; CHECK-NEXT: cset w0, lo 95 %t = call {i64, i1} @llvm.usub.with.overflow.i64(i64 %v1, i64 %v2) 96 %val = extractvalue {i64, i1} %t, 0 97 %obit = extractvalue {i64, i1} %t, 1 98 store i64 %val, i64* %res 99 ret i1 %obit 100 } 101 102 define i1 @smulo.i32(i32 %v1, i32 %v2, i32* %res) { 103 entry: 104 ; CHECK-LABEL: smulo.i32 105 ; CHECK: smull x8, w0, w1 106 ; CHECK-NEXT: lsr x9, x8, #32 107 ; CHECK-NEXT: cmp w9, w8, asr #31 108 ; CHECK-NEXT: cset w0, ne 109 %t = call {i32, i1} @llvm.smul.with.overflow.i32(i32 %v1, i32 %v2) 110 %val = extractvalue {i32, i1} %t, 0 111 %obit = extractvalue {i32, i1} %t, 1 112 store i32 %val, i32* %res 113 ret i1 %obit 114 } 115 116 define i1 @smulo.i64(i64 %v1, i64 %v2, i64* %res) { 117 entry: 118 ; CHECK-LABEL: smulo.i64 119 ; CHECK: mul x8, x0, x1 120 ; CHECK-NEXT: smulh x9, x0, x1 121 ; CHECK-NEXT: cmp x9, x8, asr #63 122 ; CHECK-NEXT: cset w0, ne 123 %t = call {i64, i1} @llvm.smul.with.overflow.i64(i64 %v1, i64 %v2) 124 %val = extractvalue {i64, i1} %t, 0 125 %obit = extractvalue {i64, i1} %t, 1 126 store i64 %val, i64* %res 127 ret i1 %obit 128 } 129 130 define i1 @umulo.i32(i32 %v1, i32 %v2, i32* %res) { 131 entry: 132 ; CHECK-LABEL: umulo.i32 133 ; CHECK: umull x8, w0, w1 134 ; CHECK-NEXT: cmp xzr, x8, lsr #32 135 ; CHECK-NEXT: cset w0, ne 136 %t = call {i32, i1} @llvm.umul.with.overflow.i32(i32 %v1, i32 %v2) 137 %val = extractvalue {i32, i1} %t, 0 138 %obit = extractvalue {i32, i1} %t, 1 139 store i32 %val, i32* %res 140 ret i1 %obit 141 } 142 143 define i1 @umulo.i64(i64 %v1, i64 %v2, i64* %res) { 144 entry: 145 ; CHECK-LABEL: umulo.i64 146 ; CHECK: umulh x8, x0, x1 147 ; CHECK-NEXT: cmp xzr, x8 148 ; CHECK-NEXT: cset w8, ne 149 ; CHECK-NEXT: mul x9, x0, x1 150 %t = call {i64, i1} @llvm.umul.with.overflow.i64(i64 %v1, i64 %v2) 151 %val = extractvalue {i64, i1} %t, 0 152 %obit = extractvalue {i64, i1} %t, 1 153 store i64 %val, i64* %res 154 ret i1 %obit 155 } 156 157 158 ; 159 ; Check the use of the overflow bit in combination with a select instruction. 160 ; 161 define i32 @saddo.select.i32(i32 %v1, i32 %v2) { 162 entry: 163 ; CHECK-LABEL: saddo.select.i32 164 ; CHECK: cmn w0, w1 165 ; CHECK-NEXT: csel w0, w0, w1, vs 166 %t = call {i32, i1} @llvm.sadd.with.overflow.i32(i32 %v1, i32 %v2) 167 %obit = extractvalue {i32, i1} %t, 1 168 %ret = select i1 %obit, i32 %v1, i32 %v2 169 ret i32 %ret 170 } 171 172 define i64 @saddo.select.i64(i64 %v1, i64 %v2) { 173 entry: 174 ; CHECK-LABEL: saddo.select.i64 175 ; CHECK: cmn x0, x1 176 ; CHECK-NEXT: csel x0, x0, x1, vs 177 %t = call {i64, i1} @llvm.sadd.with.overflow.i64(i64 %v1, i64 %v2) 178 %obit = extractvalue {i64, i1} %t, 1 179 %ret = select i1 %obit, i64 %v1, i64 %v2 180 ret i64 %ret 181 } 182 183 define i32 @uaddo.select.i32(i32 %v1, i32 %v2) { 184 entry: 185 ; CHECK-LABEL: uaddo.select.i32 186 ; CHECK: cmn w0, w1 187 ; CHECK-NEXT: csel w0, w0, w1, hs 188 %t = call {i32, i1} @llvm.uadd.with.overflow.i32(i32 %v1, i32 %v2) 189 %obit = extractvalue {i32, i1} %t, 1 190 %ret = select i1 %obit, i32 %v1, i32 %v2 191 ret i32 %ret 192 } 193 194 define i64 @uaddo.select.i64(i64 %v1, i64 %v2) { 195 entry: 196 ; CHECK-LABEL: uaddo.select.i64 197 ; CHECK: cmn x0, x1 198 ; CHECK-NEXT: csel x0, x0, x1, hs 199 %t = call {i64, i1} @llvm.uadd.with.overflow.i64(i64 %v1, i64 %v2) 200 %obit = extractvalue {i64, i1} %t, 1 201 %ret = select i1 %obit, i64 %v1, i64 %v2 202 ret i64 %ret 203 } 204 205 define i32 @ssubo.select.i32(i32 %v1, i32 %v2) { 206 entry: 207 ; CHECK-LABEL: ssubo.select.i32 208 ; CHECK: cmp w0, w1 209 ; CHECK-NEXT: csel w0, w0, w1, vs 210 %t = call {i32, i1} @llvm.ssub.with.overflow.i32(i32 %v1, i32 %v2) 211 %obit = extractvalue {i32, i1} %t, 1 212 %ret = select i1 %obit, i32 %v1, i32 %v2 213 ret i32 %ret 214 } 215 216 define i64 @ssubo.select.i64(i64 %v1, i64 %v2) { 217 entry: 218 ; CHECK-LABEL: ssubo.select.i64 219 ; CHECK: cmp x0, x1 220 ; CHECK-NEXT: csel x0, x0, x1, vs 221 %t = call {i64, i1} @llvm.ssub.with.overflow.i64(i64 %v1, i64 %v2) 222 %obit = extractvalue {i64, i1} %t, 1 223 %ret = select i1 %obit, i64 %v1, i64 %v2 224 ret i64 %ret 225 } 226 227 define i32 @usubo.select.i32(i32 %v1, i32 %v2) { 228 entry: 229 ; CHECK-LABEL: usubo.select.i32 230 ; CHECK: cmp w0, w1 231 ; CHECK-NEXT: csel w0, w0, w1, lo 232 %t = call {i32, i1} @llvm.usub.with.overflow.i32(i32 %v1, i32 %v2) 233 %obit = extractvalue {i32, i1} %t, 1 234 %ret = select i1 %obit, i32 %v1, i32 %v2 235 ret i32 %ret 236 } 237 238 define i64 @usubo.select.i64(i64 %v1, i64 %v2) { 239 entry: 240 ; CHECK-LABEL: usubo.select.i64 241 ; CHECK: cmp x0, x1 242 ; CHECK-NEXT: csel x0, x0, x1, lo 243 %t = call {i64, i1} @llvm.usub.with.overflow.i64(i64 %v1, i64 %v2) 244 %obit = extractvalue {i64, i1} %t, 1 245 %ret = select i1 %obit, i64 %v1, i64 %v2 246 ret i64 %ret 247 } 248 249 define i32 @smulo.select.i32(i32 %v1, i32 %v2) { 250 entry: 251 ; CHECK-LABEL: smulo.select.i32 252 ; CHECK: smull x8, w0, w1 253 ; CHECK-NEXT: lsr x9, x8, #32 254 ; CHECK-NEXT: cmp w9, w8, asr #31 255 ; CHECK-NEXT: csel w0, w0, w1, ne 256 %t = call {i32, i1} @llvm.smul.with.overflow.i32(i32 %v1, i32 %v2) 257 %obit = extractvalue {i32, i1} %t, 1 258 %ret = select i1 %obit, i32 %v1, i32 %v2 259 ret i32 %ret 260 } 261 262 define i64 @smulo.select.i64(i64 %v1, i64 %v2) { 263 entry: 264 ; CHECK-LABEL: smulo.select.i64 265 ; CHECK: mul x8, x0, x1 266 ; CHECK-NEXT: smulh x9, x0, x1 267 ; CHECK-NEXT: cmp x9, x8, asr #63 268 ; CHECK-NEXT: csel x0, x0, x1, ne 269 %t = call {i64, i1} @llvm.smul.with.overflow.i64(i64 %v1, i64 %v2) 270 %obit = extractvalue {i64, i1} %t, 1 271 %ret = select i1 %obit, i64 %v1, i64 %v2 272 ret i64 %ret 273 } 274 275 define i32 @umulo.select.i32(i32 %v1, i32 %v2) { 276 entry: 277 ; CHECK-LABEL: umulo.select.i32 278 ; CHECK: umull x8, w0, w1 279 ; CHECK-NEXT: cmp xzr, x8, lsr #32 280 ; CHECK-NEXT: csel w0, w0, w1, ne 281 %t = call {i32, i1} @llvm.umul.with.overflow.i32(i32 %v1, i32 %v2) 282 %obit = extractvalue {i32, i1} %t, 1 283 %ret = select i1 %obit, i32 %v1, i32 %v2 284 ret i32 %ret 285 } 286 287 define i64 @umulo.select.i64(i64 %v1, i64 %v2) { 288 entry: 289 ; CHECK-LABEL: umulo.select.i64 290 ; CHECK: umulh x8, x0, x1 291 ; CHECK-NEXT: cmp xzr, x8 292 ; CHECK-NEXT: csel x0, x0, x1, ne 293 %t = call {i64, i1} @llvm.umul.with.overflow.i64(i64 %v1, i64 %v2) 294 %obit = extractvalue {i64, i1} %t, 1 295 %ret = select i1 %obit, i64 %v1, i64 %v2 296 ret i64 %ret 297 } 298 299 300 ; 301 ; Check the use of the overflow bit in combination with a branch instruction. 302 ; 303 define i1 @saddo.br.i32(i32 %v1, i32 %v2) { 304 entry: 305 ; CHECK-LABEL: saddo.br.i32 306 ; CHECK: cmn w0, w1 307 ; CHECK-NEXT: b.vc 308 %t = call {i32, i1} @llvm.sadd.with.overflow.i32(i32 %v1, i32 %v2) 309 %val = extractvalue {i32, i1} %t, 0 310 %obit = extractvalue {i32, i1} %t, 1 311 br i1 %obit, label %overflow, label %continue 312 313 overflow: 314 ret i1 false 315 316 continue: 317 ret i1 true 318 } 319 320 define i1 @saddo.br.i64(i64 %v1, i64 %v2) { 321 entry: 322 ; CHECK-LABEL: saddo.br.i64 323 ; CHECK: cmn x0, x1 324 ; CHECK-NEXT: b.vc 325 %t = call {i64, i1} @llvm.sadd.with.overflow.i64(i64 %v1, i64 %v2) 326 %val = extractvalue {i64, i1} %t, 0 327 %obit = extractvalue {i64, i1} %t, 1 328 br i1 %obit, label %overflow, label %continue 329 330 overflow: 331 ret i1 false 332 333 continue: 334 ret i1 true 335 } 336 337 define i1 @uaddo.br.i32(i32 %v1, i32 %v2) { 338 entry: 339 ; CHECK-LABEL: uaddo.br.i32 340 ; CHECK: cmn w0, w1 341 ; CHECK-NEXT: b.lo 342 %t = call {i32, i1} @llvm.uadd.with.overflow.i32(i32 %v1, i32 %v2) 343 %val = extractvalue {i32, i1} %t, 0 344 %obit = extractvalue {i32, i1} %t, 1 345 br i1 %obit, label %overflow, label %continue 346 347 overflow: 348 ret i1 false 349 350 continue: 351 ret i1 true 352 } 353 354 define i1 @uaddo.br.i64(i64 %v1, i64 %v2) { 355 entry: 356 ; CHECK-LABEL: uaddo.br.i64 357 ; CHECK: cmn x0, x1 358 ; CHECK-NEXT: b.lo 359 %t = call {i64, i1} @llvm.uadd.with.overflow.i64(i64 %v1, i64 %v2) 360 %val = extractvalue {i64, i1} %t, 0 361 %obit = extractvalue {i64, i1} %t, 1 362 br i1 %obit, label %overflow, label %continue 363 364 overflow: 365 ret i1 false 366 367 continue: 368 ret i1 true 369 } 370 371 define i1 @ssubo.br.i32(i32 %v1, i32 %v2) { 372 entry: 373 ; CHECK-LABEL: ssubo.br.i32 374 ; CHECK: cmp w0, w1 375 ; CHECK-NEXT: b.vc 376 %t = call {i32, i1} @llvm.ssub.with.overflow.i32(i32 %v1, i32 %v2) 377 %val = extractvalue {i32, i1} %t, 0 378 %obit = extractvalue {i32, i1} %t, 1 379 br i1 %obit, label %overflow, label %continue 380 381 overflow: 382 ret i1 false 383 384 continue: 385 ret i1 true 386 } 387 388 define i1 @ssubo.br.i64(i64 %v1, i64 %v2) { 389 entry: 390 ; CHECK-LABEL: ssubo.br.i64 391 ; CHECK: cmp x0, x1 392 ; CHECK-NEXT: b.vc 393 %t = call {i64, i1} @llvm.ssub.with.overflow.i64(i64 %v1, i64 %v2) 394 %val = extractvalue {i64, i1} %t, 0 395 %obit = extractvalue {i64, i1} %t, 1 396 br i1 %obit, label %overflow, label %continue 397 398 overflow: 399 ret i1 false 400 401 continue: 402 ret i1 true 403 } 404 405 define i1 @usubo.br.i32(i32 %v1, i32 %v2) { 406 entry: 407 ; CHECK-LABEL: usubo.br.i32 408 ; CHECK: cmp w0, w1 409 ; CHECK-NEXT: b.hs 410 %t = call {i32, i1} @llvm.usub.with.overflow.i32(i32 %v1, i32 %v2) 411 %val = extractvalue {i32, i1} %t, 0 412 %obit = extractvalue {i32, i1} %t, 1 413 br i1 %obit, label %overflow, label %continue 414 415 overflow: 416 ret i1 false 417 418 continue: 419 ret i1 true 420 } 421 422 define i1 @usubo.br.i64(i64 %v1, i64 %v2) { 423 entry: 424 ; CHECK-LABEL: usubo.br.i64 425 ; CHECK: cmp x0, x1 426 ; CHECK-NEXT: b.hs 427 %t = call {i64, i1} @llvm.usub.with.overflow.i64(i64 %v1, i64 %v2) 428 %val = extractvalue {i64, i1} %t, 0 429 %obit = extractvalue {i64, i1} %t, 1 430 br i1 %obit, label %overflow, label %continue 431 432 overflow: 433 ret i1 false 434 435 continue: 436 ret i1 true 437 } 438 439 define i1 @smulo.br.i32(i32 %v1, i32 %v2) { 440 entry: 441 ; CHECK-LABEL: smulo.br.i32 442 ; CHECK: smull x8, w0, w1 443 ; CHECK-NEXT: lsr x9, x8, #32 444 ; CHECK-NEXT: cmp w9, w8, asr #31 445 ; CHECK-NEXT: b.eq 446 %t = call {i32, i1} @llvm.smul.with.overflow.i32(i32 %v1, i32 %v2) 447 %val = extractvalue {i32, i1} %t, 0 448 %obit = extractvalue {i32, i1} %t, 1 449 br i1 %obit, label %overflow, label %continue 450 451 overflow: 452 ret i1 false 453 454 continue: 455 ret i1 true 456 } 457 458 define i1 @smulo.br.i64(i64 %v1, i64 %v2) { 459 entry: 460 ; CHECK-LABEL: smulo.br.i64 461 ; CHECK: mul x8, x0, x1 462 ; CHECK-NEXT: smulh x9, x0, x1 463 ; CHECK-NEXT: cmp x9, x8, asr #63 464 ; CHECK-NEXT: b.eq 465 %t = call {i64, i1} @llvm.smul.with.overflow.i64(i64 %v1, i64 %v2) 466 %val = extractvalue {i64, i1} %t, 0 467 %obit = extractvalue {i64, i1} %t, 1 468 br i1 %obit, label %overflow, label %continue 469 470 overflow: 471 ret i1 false 472 473 continue: 474 ret i1 true 475 } 476 477 define i1 @umulo.br.i32(i32 %v1, i32 %v2) { 478 entry: 479 ; CHECK-LABEL: umulo.br.i32 480 ; CHECK: umull x8, w0, w1 481 ; CHECK-NEXT: cmp xzr, x8, lsr #32 482 ; CHECK-NEXT: b.eq 483 %t = call {i32, i1} @llvm.umul.with.overflow.i32(i32 %v1, i32 %v2) 484 %val = extractvalue {i32, i1} %t, 0 485 %obit = extractvalue {i32, i1} %t, 1 486 br i1 %obit, label %overflow, label %continue 487 488 overflow: 489 ret i1 false 490 491 continue: 492 ret i1 true 493 } 494 495 define i1 @umulo.br.i64(i64 %v1, i64 %v2) { 496 entry: 497 ; CHECK-LABEL: umulo.br.i64 498 ; CHECK: umulh x8, x0, x1 499 ; CHECK-NEXT: cbz 500 %t = call {i64, i1} @llvm.umul.with.overflow.i64(i64 %v1, i64 %v2) 501 %val = extractvalue {i64, i1} %t, 0 502 %obit = extractvalue {i64, i1} %t, 1 503 br i1 %obit, label %overflow, label %continue 504 505 overflow: 506 ret i1 false 507 508 continue: 509 ret i1 true 510 } 511 512 declare {i32, i1} @llvm.sadd.with.overflow.i32(i32, i32) nounwind readnone 513 declare {i64, i1} @llvm.sadd.with.overflow.i64(i64, i64) nounwind readnone 514 declare {i32, i1} @llvm.uadd.with.overflow.i32(i32, i32) nounwind readnone 515 declare {i64, i1} @llvm.uadd.with.overflow.i64(i64, i64) nounwind readnone 516 declare {i32, i1} @llvm.ssub.with.overflow.i32(i32, i32) nounwind readnone 517 declare {i64, i1} @llvm.ssub.with.overflow.i64(i64, i64) nounwind readnone 518 declare {i32, i1} @llvm.usub.with.overflow.i32(i32, i32) nounwind readnone 519 declare {i64, i1} @llvm.usub.with.overflow.i64(i64, i64) nounwind readnone 520 declare {i32, i1} @llvm.smul.with.overflow.i32(i32, i32) nounwind readnone 521 declare {i64, i1} @llvm.smul.with.overflow.i64(i64, i64) nounwind readnone 522 declare {i32, i1} @llvm.umul.with.overflow.i32(i32, i32) nounwind readnone 523 declare {i64, i1} @llvm.umul.with.overflow.i64(i64, i64) nounwind readnone 524 525