1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py 2; RUN: llc < %s -mtriple=aarch64-- | FileCheck %s 3 4declare { i128, i1 } @llvm.uadd.with.overflow.i128(i128, i128) 5declare i128 @llvm.uadd.sat.i128(i128, i128) 6 7declare { i128, i1 } @llvm.usub.with.overflow.i128(i128, i128) 8declare i128 @llvm.usub.sat.i128(i128, i128) 9 10declare { i128, i1 } @llvm.umul.with.overflow.i128(i128, i128) 11declare i128 @llvm.umul.sat.i128(i128, i128) 12 13declare { i128, i1 } @llvm.sadd.with.overflow.i128(i128, i128) 14declare i128 @llvm.sadd.sat.i128(i128, i128) 15 16declare { i128, i1 } @llvm.ssub.with.overflow.i128(i128, i128) 17declare i128 @llvm.ssub.sat.i128(i128, i128) 18 19declare { i128, i1 } @llvm.smul.with.overflow.i128(i128, i128) 20declare i128 @llvm.smul.sat.i128(i128, i128) 21 22define i128 @u128_add(i128 %x, i128 %y) { 23; CHECK-LABEL: u128_add: 24; CHECK: // %bb.0: 25; CHECK-NEXT: adds x0, x0, x2 26; CHECK-NEXT: adcs x1, x1, x3 27; CHECK-NEXT: ret 28 %1 = add i128 %x, %y 29 ret i128 %1 30} 31 32define { i128, i8 } @u128_checked_add(i128 %x, i128 %y) { 33; CHECK-LABEL: u128_checked_add: 34; CHECK: // %bb.0: 35; CHECK-NEXT: adds x0, x0, x2 36; CHECK-NEXT: adcs x1, x1, x3 37; CHECK-NEXT: cset w8, hs 38; CHECK-NEXT: eor w2, w8, #0x1 39; CHECK-NEXT: ret 40 %1 = tail call { i128, i1 } @llvm.uadd.with.overflow.i128(i128 %x, i128 %y) 41 %2 = extractvalue { i128, i1 } %1, 0 42 %3 = extractvalue { i128, i1 } %1, 1 43 %4 = xor i1 %3, true 44 %5 = zext i1 %4 to i8 45 %6 = insertvalue { i128, i8 } undef, i128 %2, 0 46 %7 = insertvalue { i128, i8 } %6, i8 %5, 1 47 ret { i128, i8 } %7 48} 49 50define { i128, i8 } @u128_overflowing_add(i128 %x, i128 %y) { 51; CHECK-LABEL: u128_overflowing_add: 52; CHECK: // %bb.0: 53; CHECK-NEXT: adds x0, x0, x2 54; CHECK-NEXT: adcs x1, x1, x3 55; CHECK-NEXT: cset w2, hs 56; CHECK-NEXT: ret 57 %1 = tail call { i128, i1 } @llvm.uadd.with.overflow.i128(i128 %x, i128 %y) 58 %2 = extractvalue { i128, i1 } %1, 0 59 %3 = extractvalue { i128, i1 } %1, 1 60 %4 = zext i1 %3 to i8 61 %5 = insertvalue { i128, i8 } undef, i128 %2, 0 62 %6 = insertvalue { i128, i8 } %5, i8 %4, 1 63 ret { i128, i8 } %6 64} 65 66define i128 @u128_saturating_add(i128 %x, i128 %y) { 67; CHECK-LABEL: u128_saturating_add: 68; CHECK: // %bb.0: 69; CHECK-NEXT: adds x8, x0, x2 70; CHECK-NEXT: adcs x9, x1, x3 71; CHECK-NEXT: cset w10, hs 72; CHECK-NEXT: cmp w10, #0 73; CHECK-NEXT: csinv x0, x8, xzr, eq 74; CHECK-NEXT: csinv x1, x9, xzr, eq 75; CHECK-NEXT: ret 76 %1 = tail call i128 @llvm.uadd.sat.i128(i128 %x, i128 %y) 77 ret i128 %1 78} 79 80define i128 @u128_sub(i128 %x, i128 %y) { 81; CHECK-LABEL: u128_sub: 82; CHECK: // %bb.0: 83; CHECK-NEXT: subs x0, x0, x2 84; CHECK-NEXT: sbcs x1, x1, x3 85; CHECK-NEXT: ret 86 %1 = sub i128 %x, %y 87 ret i128 %1 88} 89 90define { i128, i8 } @u128_checked_sub(i128 %x, i128 %y) { 91; CHECK-LABEL: u128_checked_sub: 92; CHECK: // %bb.0: 93; CHECK-NEXT: subs x0, x0, x2 94; CHECK-NEXT: sbcs x1, x1, x3 95; CHECK-NEXT: cset w8, lo 96; CHECK-NEXT: eor w2, w8, #0x1 97; CHECK-NEXT: ret 98 %1 = tail call { i128, i1 } @llvm.usub.with.overflow.i128(i128 %x, i128 %y) 99 %2 = extractvalue { i128, i1 } %1, 0 100 %3 = extractvalue { i128, i1 } %1, 1 101 %4 = xor i1 %3, true 102 %5 = zext i1 %4 to i8 103 %6 = insertvalue { i128, i8 } undef, i128 %2, 0 104 %7 = insertvalue { i128, i8 } %6, i8 %5, 1 105 ret { i128, i8 } %7 106} 107 108define { i128, i8 } @u128_overflowing_sub(i128 %x, i128 %y) { 109; CHECK-LABEL: u128_overflowing_sub: 110; CHECK: // %bb.0: 111; CHECK-NEXT: subs x0, x0, x2 112; CHECK-NEXT: sbcs x1, x1, x3 113; CHECK-NEXT: cset w2, lo 114; CHECK-NEXT: ret 115 %1 = tail call { i128, i1 } @llvm.usub.with.overflow.i128(i128 %x, i128 %y) 116 %2 = extractvalue { i128, i1 } %1, 0 117 %3 = extractvalue { i128, i1 } %1, 1 118 %4 = zext i1 %3 to i8 119 %5 = insertvalue { i128, i8 } undef, i128 %2, 0 120 %6 = insertvalue { i128, i8 } %5, i8 %4, 1 121 ret { i128, i8 } %6 122} 123 124define i128 @u128_saturating_sub(i128 %x, i128 %y) { 125; CHECK-LABEL: u128_saturating_sub: 126; CHECK: // %bb.0: 127; CHECK-NEXT: subs x8, x0, x2 128; CHECK-NEXT: sbcs x9, x1, x3 129; CHECK-NEXT: cset w10, lo 130; CHECK-NEXT: cmp w10, #0 131; CHECK-NEXT: csel x0, xzr, x8, ne 132; CHECK-NEXT: csel x1, xzr, x9, ne 133; CHECK-NEXT: ret 134 %1 = tail call i128 @llvm.usub.sat.i128(i128 %x, i128 %y) 135 ret i128 %1 136} 137 138define i128 @i128_add(i128 %x, i128 %y) { 139; CHECK-LABEL: i128_add: 140; CHECK: // %bb.0: 141; CHECK-NEXT: adds x0, x0, x2 142; CHECK-NEXT: adcs x1, x1, x3 143; CHECK-NEXT: ret 144 %1 = add i128 %x, %y 145 ret i128 %1 146} 147 148define { i128, i8 } @i128_checked_add(i128 %x, i128 %y) { 149; CHECK-LABEL: i128_checked_add: 150; CHECK: // %bb.0: 151; CHECK-NEXT: adds x0, x0, x2 152; CHECK-NEXT: adcs x1, x1, x3 153; CHECK-NEXT: cset w8, vs 154; CHECK-NEXT: eor w2, w8, #0x1 155; CHECK-NEXT: ret 156 %1 = tail call { i128, i1 } @llvm.sadd.with.overflow.i128(i128 %x, i128 %y) 157 %2 = extractvalue { i128, i1 } %1, 0 158 %3 = extractvalue { i128, i1 } %1, 1 159 %4 = xor i1 %3, true 160 %5 = zext i1 %4 to i8 161 %6 = insertvalue { i128, i8 } undef, i128 %2, 0 162 %7 = insertvalue { i128, i8 } %6, i8 %5, 1 163 ret { i128, i8 } %7 164} 165 166define { i128, i8 } @i128_overflowing_add(i128 %x, i128 %y) { 167; CHECK-LABEL: i128_overflowing_add: 168; CHECK: // %bb.0: 169; CHECK-NEXT: adds x0, x0, x2 170; CHECK-NEXT: adcs x1, x1, x3 171; CHECK-NEXT: cset w2, vs 172; CHECK-NEXT: ret 173 %1 = tail call { i128, i1 } @llvm.sadd.with.overflow.i128(i128 %x, i128 %y) 174 %2 = extractvalue { i128, i1 } %1, 0 175 %3 = extractvalue { i128, i1 } %1, 1 176 %4 = zext i1 %3 to i8 177 %5 = insertvalue { i128, i8 } undef, i128 %2, 0 178 %6 = insertvalue { i128, i8 } %5, i8 %4, 1 179 ret { i128, i8 } %6 180} 181 182define i128 @i128_saturating_add(i128 %x, i128 %y) { 183; CHECK-LABEL: i128_saturating_add: 184; CHECK: // %bb.0: 185; CHECK-NEXT: adds x8, x0, x2 186; CHECK-NEXT: adcs x9, x1, x3 187; CHECK-NEXT: asr x10, x9, #63 188; CHECK-NEXT: cset w11, vs 189; CHECK-NEXT: cmp w11, #0 190; CHECK-NEXT: eor x11, x10, #0x8000000000000000 191; CHECK-NEXT: csel x0, x10, x8, ne 192; CHECK-NEXT: csel x1, x11, x9, ne 193; CHECK-NEXT: ret 194 %1 = tail call i128 @llvm.sadd.sat.i128(i128 %x, i128 %y) 195 ret i128 %1 196} 197 198define i128 @i128_sub(i128 %x, i128 %y) { 199; CHECK-LABEL: i128_sub: 200; CHECK: // %bb.0: 201; CHECK-NEXT: subs x0, x0, x2 202; CHECK-NEXT: sbcs x1, x1, x3 203; CHECK-NEXT: ret 204 %1 = sub i128 %x, %y 205 ret i128 %1 206} 207 208define { i128, i8 } @i128_checked_sub(i128 %x, i128 %y) { 209; CHECK-LABEL: i128_checked_sub: 210; CHECK: // %bb.0: 211; CHECK-NEXT: subs x0, x0, x2 212; CHECK-NEXT: sbcs x1, x1, x3 213; CHECK-NEXT: cset w8, vs 214; CHECK-NEXT: eor w2, w8, #0x1 215; CHECK-NEXT: ret 216 %1 = tail call { i128, i1 } @llvm.ssub.with.overflow.i128(i128 %x, i128 %y) 217 %2 = extractvalue { i128, i1 } %1, 0 218 %3 = extractvalue { i128, i1 } %1, 1 219 %4 = xor i1 %3, true 220 %5 = zext i1 %4 to i8 221 %6 = insertvalue { i128, i8 } undef, i128 %2, 0 222 %7 = insertvalue { i128, i8 } %6, i8 %5, 1 223 ret { i128, i8 } %7 224} 225 226define { i128, i8 } @i128_overflowing_sub(i128 %x, i128 %y) { 227; CHECK-LABEL: i128_overflowing_sub: 228; CHECK: // %bb.0: 229; CHECK-NEXT: subs x0, x0, x2 230; CHECK-NEXT: sbcs x1, x1, x3 231; CHECK-NEXT: cset w2, vs 232; CHECK-NEXT: ret 233 %1 = tail call { i128, i1 } @llvm.ssub.with.overflow.i128(i128 %x, i128 %y) 234 %2 = extractvalue { i128, i1 } %1, 0 235 %3 = extractvalue { i128, i1 } %1, 1 236 %4 = zext i1 %3 to i8 237 %5 = insertvalue { i128, i8 } undef, i128 %2, 0 238 %6 = insertvalue { i128, i8 } %5, i8 %4, 1 239 ret { i128, i8 } %6 240} 241 242define i128 @i128_saturating_sub(i128 %x, i128 %y) { 243; CHECK-LABEL: i128_saturating_sub: 244; CHECK: // %bb.0: 245; CHECK-NEXT: subs x8, x0, x2 246; CHECK-NEXT: sbcs x9, x1, x3 247; CHECK-NEXT: asr x10, x9, #63 248; CHECK-NEXT: cset w11, vs 249; CHECK-NEXT: cmp w11, #0 250; CHECK-NEXT: eor x11, x10, #0x8000000000000000 251; CHECK-NEXT: csel x0, x10, x8, ne 252; CHECK-NEXT: csel x1, x11, x9, ne 253; CHECK-NEXT: ret 254 %1 = tail call i128 @llvm.ssub.sat.i128(i128 %x, i128 %y) 255 ret i128 %1 256} 257 258define i128 @u128_mul(i128 %x, i128 %y) { 259; CHECK-LABEL: u128_mul: 260; CHECK: // %bb.0: 261; CHECK-NEXT: umulh x8, x0, x2 262; CHECK-NEXT: madd x8, x0, x3, x8 263; CHECK-NEXT: mul x0, x0, x2 264; CHECK-NEXT: madd x1, x1, x2, x8 265; CHECK-NEXT: ret 266 %1 = mul i128 %x, %y 267 ret i128 %1 268} 269 270define { i128, i8 } @u128_checked_mul(i128 %x, i128 %y) { 271; CHECK-LABEL: u128_checked_mul: 272; CHECK: // %bb.0: 273; CHECK-NEXT: mul x8, x3, x0 274; CHECK-NEXT: umulh x9, x0, x2 275; CHECK-NEXT: madd x8, x1, x2, x8 276; CHECK-NEXT: umulh x10, x1, x2 277; CHECK-NEXT: adds x8, x9, x8 278; CHECK-NEXT: cset w9, hs 279; CHECK-NEXT: cmp x1, #0 280; CHECK-NEXT: ccmp x3, #0, #4, ne 281; CHECK-NEXT: mov x1, x8 282; CHECK-NEXT: ccmp xzr, x10, #0, eq 283; CHECK-NEXT: umulh x10, x3, x0 284; CHECK-NEXT: mul x0, x0, x2 285; CHECK-NEXT: ccmp xzr, x10, #0, eq 286; CHECK-NEXT: cset w10, ne 287; CHECK-NEXT: orr w9, w10, w9 288; CHECK-NEXT: eor w2, w9, #0x1 289; CHECK-NEXT: ret 290 %1 = tail call { i128, i1 } @llvm.umul.with.overflow.i128(i128 %x, i128 %y) 291 %2 = extractvalue { i128, i1 } %1, 0 292 %3 = extractvalue { i128, i1 } %1, 1 293 %4 = xor i1 %3, true 294 %5 = zext i1 %4 to i8 295 %6 = insertvalue { i128, i8 } undef, i128 %2, 0 296 %7 = insertvalue { i128, i8 } %6, i8 %5, 1 297 ret { i128, i8 } %7 298} 299 300define { i128, i8 } @u128_overflowing_mul(i128 %x, i128 %y) { 301; CHECK-LABEL: u128_overflowing_mul: 302; CHECK: // %bb.0: 303; CHECK-NEXT: mul x8, x3, x0 304; CHECK-NEXT: umulh x9, x0, x2 305; CHECK-NEXT: madd x8, x1, x2, x8 306; CHECK-NEXT: umulh x10, x1, x2 307; CHECK-NEXT: adds x8, x9, x8 308; CHECK-NEXT: cset w9, hs 309; CHECK-NEXT: cmp x1, #0 310; CHECK-NEXT: ccmp x3, #0, #4, ne 311; CHECK-NEXT: mov x1, x8 312; CHECK-NEXT: ccmp xzr, x10, #0, eq 313; CHECK-NEXT: umulh x10, x3, x0 314; CHECK-NEXT: mul x0, x0, x2 315; CHECK-NEXT: ccmp xzr, x10, #0, eq 316; CHECK-NEXT: cset w10, ne 317; CHECK-NEXT: orr w2, w10, w9 318; CHECK-NEXT: ret 319 %1 = tail call { i128, i1 } @llvm.umul.with.overflow.i128(i128 %x, i128 %y) 320 %2 = extractvalue { i128, i1 } %1, 0 321 %3 = extractvalue { i128, i1 } %1, 1 322 %4 = zext i1 %3 to i8 323 %5 = insertvalue { i128, i8 } undef, i128 %2, 0 324 %6 = insertvalue { i128, i8 } %5, i8 %4, 1 325 ret { i128, i8 } %6 326} 327 328define i128 @u128_saturating_mul(i128 %x, i128 %y) { 329; CHECK-LABEL: u128_saturating_mul: 330; CHECK: // %bb.0: 331; CHECK-NEXT: mul x8, x3, x0 332; CHECK-NEXT: umulh x9, x0, x2 333; CHECK-NEXT: madd x8, x1, x2, x8 334; CHECK-NEXT: umulh x10, x1, x2 335; CHECK-NEXT: adds x8, x9, x8 336; CHECK-NEXT: cset w9, hs 337; CHECK-NEXT: cmp x1, #0 338; CHECK-NEXT: ccmp x3, #0, #4, ne 339; CHECK-NEXT: ccmp xzr, x10, #0, eq 340; CHECK-NEXT: umulh x10, x3, x0 341; CHECK-NEXT: ccmp xzr, x10, #0, eq 342; CHECK-NEXT: cset w10, ne 343; CHECK-NEXT: orr w9, w10, w9 344; CHECK-NEXT: mul x10, x0, x2 345; CHECK-NEXT: cmp w9, #0 346; CHECK-NEXT: csinv x0, x10, xzr, eq 347; CHECK-NEXT: csinv x1, x8, xzr, eq 348; CHECK-NEXT: ret 349 %1 = tail call { i128, i1 } @llvm.umul.with.overflow.i128(i128 %x, i128 %y) 350 %2 = extractvalue { i128, i1 } %1, 0 351 %3 = extractvalue { i128, i1 } %1, 1 352 %4 = select i1 %3, i128 -1, i128 %2 353 ret i128 %4 354} 355 356define i128 @i128_mul(i128 %x, i128 %y) { 357; CHECK-LABEL: i128_mul: 358; CHECK: // %bb.0: 359; CHECK-NEXT: umulh x8, x0, x2 360; CHECK-NEXT: madd x8, x0, x3, x8 361; CHECK-NEXT: mul x0, x0, x2 362; CHECK-NEXT: madd x1, x1, x2, x8 363; CHECK-NEXT: ret 364 %1 = mul i128 %x, %y 365 ret i128 %1 366} 367 368define { i128, i8 } @i128_checked_mul(i128 %x, i128 %y) { 369; CHECK-LABEL: i128_checked_mul: 370; CHECK: // %bb.0: 371; CHECK-NEXT: stp x30, xzr, [sp, #-16]! // 8-byte Folded Spill 372; CHECK-NEXT: .cfi_def_cfa_offset 16 373; CHECK-NEXT: .cfi_offset w30, -16 374; CHECK-NEXT: add x4, sp, #8 375; CHECK-NEXT: bl __muloti4 376; CHECK-NEXT: ldr x8, [sp, #8] 377; CHECK-NEXT: cmp x8, #0 378; CHECK-NEXT: cset w2, eq 379; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload 380; CHECK-NEXT: ret 381 %1 = tail call { i128, i1 } @llvm.smul.with.overflow.i128(i128 %x, i128 %y) 382 %2 = extractvalue { i128, i1 } %1, 0 383 %3 = extractvalue { i128, i1 } %1, 1 384 %4 = xor i1 %3, true 385 %5 = zext i1 %4 to i8 386 %6 = insertvalue { i128, i8 } undef, i128 %2, 0 387 %7 = insertvalue { i128, i8 } %6, i8 %5, 1 388 ret { i128, i8 } %7 389} 390 391define { i128, i8 } @i128_overflowing_mul(i128 %x, i128 %y) { 392; CHECK-LABEL: i128_overflowing_mul: 393; CHECK: // %bb.0: 394; CHECK-NEXT: stp x30, xzr, [sp, #-16]! // 8-byte Folded Spill 395; CHECK-NEXT: .cfi_def_cfa_offset 16 396; CHECK-NEXT: .cfi_offset w30, -16 397; CHECK-NEXT: add x4, sp, #8 398; CHECK-NEXT: bl __muloti4 399; CHECK-NEXT: ldr x8, [sp, #8] 400; CHECK-NEXT: cmp x8, #0 401; CHECK-NEXT: cset w2, ne 402; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload 403; CHECK-NEXT: ret 404 %1 = tail call { i128, i1 } @llvm.smul.with.overflow.i128(i128 %x, i128 %y) 405 %2 = extractvalue { i128, i1 } %1, 0 406 %3 = extractvalue { i128, i1 } %1, 1 407 %4 = zext i1 %3 to i8 408 %5 = insertvalue { i128, i8 } undef, i128 %2, 0 409 %6 = insertvalue { i128, i8 } %5, i8 %4, 1 410 ret { i128, i8 } %6 411} 412 413define i128 @i128_saturating_mul(i128 %x, i128 %y) { 414; CHECK-LABEL: i128_saturating_mul: 415; CHECK: // %bb.0: 416; CHECK-NEXT: str x30, [sp, #-32]! // 8-byte Folded Spill 417; CHECK-NEXT: .cfi_def_cfa_offset 32 418; CHECK-NEXT: stp x20, x19, [sp, #16] // 16-byte Folded Spill 419; CHECK-NEXT: .cfi_offset w19, -8 420; CHECK-NEXT: .cfi_offset w20, -16 421; CHECK-NEXT: .cfi_offset w30, -32 422; CHECK-NEXT: add x4, sp, #8 423; CHECK-NEXT: mov x19, x3 424; CHECK-NEXT: mov x20, x1 425; CHECK-NEXT: str xzr, [sp, #8] 426; CHECK-NEXT: bl __muloti4 427; CHECK-NEXT: ldr x8, [sp, #8] 428; CHECK-NEXT: eor x9, x19, x20 429; CHECK-NEXT: ldp x20, x19, [sp, #16] // 16-byte Folded Reload 430; CHECK-NEXT: asr x9, x9, #63 431; CHECK-NEXT: eor x10, x9, #0x7fffffffffffffff 432; CHECK-NEXT: cmp x8, #0 433; CHECK-NEXT: csinv x0, x0, x9, eq 434; CHECK-NEXT: csel x1, x10, x1, ne 435; CHECK-NEXT: ldr x30, [sp], #32 // 8-byte Folded Reload 436; CHECK-NEXT: ret 437 %1 = tail call { i128, i1 } @llvm.smul.with.overflow.i128(i128 %x, i128 %y) 438 %2 = extractvalue { i128, i1 } %1, 0 439 %3 = extractvalue { i128, i1 } %1, 1 440 %4 = xor i128 %y, %x 441 %5 = icmp sgt i128 %4, -1 442 %6 = select i1 %5, i128 170141183460469231731687303715884105727, i128 -170141183460469231731687303715884105728 443 %7 = select i1 %3, i128 %6, i128 %2 444 ret i128 %7 445} 446