1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py 2; RUN: llc < %s -mtriple=aarch64-- | FileCheck %s 3 4declare i8 @llvm.fshl.i8(i8, i8, i8) 5declare i16 @llvm.fshl.i16(i16, i16, i16) 6declare i32 @llvm.fshl.i32(i32, i32, i32) 7declare i64 @llvm.fshl.i64(i64, i64, i64) 8declare i128 @llvm.fshl.i128(i128, i128, i128) 9declare <4 x i32> @llvm.fshl.v4i32(<4 x i32>, <4 x i32>, <4 x i32>) 10 11declare i8 @llvm.fshr.i8(i8, i8, i8) 12declare i16 @llvm.fshr.i16(i16, i16, i16) 13declare i32 @llvm.fshr.i32(i32, i32, i32) 14declare i64 @llvm.fshr.i64(i64, i64, i64) 15declare <4 x i32> @llvm.fshr.v4i32(<4 x i32>, <4 x i32>, <4 x i32>) 16 17; General case - all operands can be variables. 18 19define i32 @fshl_i32(i32 %x, i32 %y, i32 %z) { 20; CHECK-LABEL: fshl_i32: 21; CHECK: // %bb.0: 22; CHECK-NEXT: // kill: def $w2 killed $w2 def $x2 23; CHECK-NEXT: mvn w8, w2 24; CHECK-NEXT: lsr w9, w1, #1 25; CHECK-NEXT: lsl w10, w0, w2 26; CHECK-NEXT: lsr w8, w9, w8 27; CHECK-NEXT: orr w0, w10, w8 28; CHECK-NEXT: ret 29 %f = call i32 @llvm.fshl.i32(i32 %x, i32 %y, i32 %z) 30 ret i32 %f 31} 32 33define i64 @fshl_i64(i64 %x, i64 %y, i64 %z) { 34; CHECK-LABEL: fshl_i64: 35; CHECK: // %bb.0: 36; CHECK-NEXT: mvn w8, w2 37; CHECK-NEXT: lsr x9, x1, #1 38; CHECK-NEXT: lsl x10, x0, x2 39; CHECK-NEXT: lsr x8, x9, x8 40; CHECK-NEXT: orr x0, x10, x8 41; CHECK-NEXT: ret 42 %f = call i64 @llvm.fshl.i64(i64 %x, i64 %y, i64 %z) 43 ret i64 %f 44} 45 46define i128 @fshl_i128(i128 %x, i128 %y, i128 %z) nounwind { 47; CHECK-LABEL: fshl_i128: 48; CHECK: // %bb.0: 49; CHECK-NEXT: tst x4, #0x40 50; CHECK-NEXT: mvn w8, w4 51; CHECK-NEXT: csel x9, x2, x3, ne 52; CHECK-NEXT: csel x10, x3, x0, ne 53; CHECK-NEXT: lsr x9, x9, #1 54; CHECK-NEXT: lsl x11, x10, x4 55; CHECK-NEXT: csel x12, x0, x1, ne 56; CHECK-NEXT: lsr x10, x10, #1 57; CHECK-NEXT: lsr x9, x9, x8 58; CHECK-NEXT: lsl x12, x12, x4 59; CHECK-NEXT: lsr x8, x10, x8 60; CHECK-NEXT: orr x0, x11, x9 61; CHECK-NEXT: orr x1, x12, x8 62; CHECK-NEXT: ret 63 %f = call i128 @llvm.fshl.i128(i128 %x, i128 %y, i128 %z) 64 ret i128 %f 65} 66 67; Verify that weird types are minimally supported. 68declare i37 @llvm.fshl.i37(i37, i37, i37) 69define i37 @fshl_i37(i37 %x, i37 %y, i37 %z) { 70; CHECK-LABEL: fshl_i37: 71; CHECK: // %bb.0: 72; CHECK-NEXT: mov x9, #31883 73; CHECK-NEXT: and x8, x2, #0x1fffffffff 74; CHECK-NEXT: movk x9, #3542, lsl #16 75; CHECK-NEXT: ubfiz x10, x1, #26, #37 76; CHECK-NEXT: movk x9, #51366, lsl #32 77; CHECK-NEXT: movk x9, #56679, lsl #48 78; CHECK-NEXT: umulh x8, x8, x9 79; CHECK-NEXT: mov w9, #37 80; CHECK-NEXT: ubfx x8, x8, #5, #27 81; CHECK-NEXT: msub w8, w8, w9, w2 82; CHECK-NEXT: mvn w9, w8 83; CHECK-NEXT: lsl x8, x0, x8 84; CHECK-NEXT: lsr x9, x10, x9 85; CHECK-NEXT: orr x0, x8, x9 86; CHECK-NEXT: ret 87 %f = call i37 @llvm.fshl.i37(i37 %x, i37 %y, i37 %z) 88 ret i37 %f 89} 90 91; extract(concat(0b1110000, 0b1111111) << 2) = 0b1000011 92 93declare i7 @llvm.fshl.i7(i7, i7, i7) 94define i7 @fshl_i7_const_fold() { 95; CHECK-LABEL: fshl_i7_const_fold: 96; CHECK: // %bb.0: 97; CHECK-NEXT: mov w0, #67 98; CHECK-NEXT: ret 99 %f = call i7 @llvm.fshl.i7(i7 112, i7 127, i7 2) 100 ret i7 %f 101} 102 103define i8 @fshl_i8_const_fold_overshift_1() { 104; CHECK-LABEL: fshl_i8_const_fold_overshift_1: 105; CHECK: // %bb.0: 106; CHECK-NEXT: mov w0, #128 107; CHECK-NEXT: ret 108 %f = call i8 @llvm.fshl.i8(i8 255, i8 0, i8 15) 109 ret i8 %f 110} 111 112define i8 @fshl_i8_const_fold_overshift_2() { 113; CHECK-LABEL: fshl_i8_const_fold_overshift_2: 114; CHECK: // %bb.0: 115; CHECK-NEXT: mov w0, #120 116; CHECK-NEXT: ret 117 %f = call i8 @llvm.fshl.i8(i8 15, i8 15, i8 11) 118 ret i8 %f 119} 120 121define i8 @fshl_i8_const_fold_overshift_3() { 122; CHECK-LABEL: fshl_i8_const_fold_overshift_3: 123; CHECK: // %bb.0: 124; CHECK-NEXT: mov w0, wzr 125; CHECK-NEXT: ret 126 %f = call i8 @llvm.fshl.i8(i8 0, i8 225, i8 8) 127 ret i8 %f 128} 129 130; With constant shift amount, this is 'extr'. 131 132define i32 @fshl_i32_const_shift(i32 %x, i32 %y) { 133; CHECK-LABEL: fshl_i32_const_shift: 134; CHECK: // %bb.0: 135; CHECK-NEXT: extr w0, w0, w1, #23 136; CHECK-NEXT: ret 137 %f = call i32 @llvm.fshl.i32(i32 %x, i32 %y, i32 9) 138 ret i32 %f 139} 140 141; Check modulo math on shift amount. 142 143define i32 @fshl_i32_const_overshift(i32 %x, i32 %y) { 144; CHECK-LABEL: fshl_i32_const_overshift: 145; CHECK: // %bb.0: 146; CHECK-NEXT: extr w0, w0, w1, #23 147; CHECK-NEXT: ret 148 %f = call i32 @llvm.fshl.i32(i32 %x, i32 %y, i32 41) 149 ret i32 %f 150} 151 152; 64-bit should also work. 153 154define i64 @fshl_i64_const_overshift(i64 %x, i64 %y) { 155; CHECK-LABEL: fshl_i64_const_overshift: 156; CHECK: // %bb.0: 157; CHECK-NEXT: extr x0, x0, x1, #23 158; CHECK-NEXT: ret 159 %f = call i64 @llvm.fshl.i64(i64 %x, i64 %y, i64 105) 160 ret i64 %f 161} 162 163; This should work without any node-specific logic. 164 165define i8 @fshl_i8_const_fold() { 166; CHECK-LABEL: fshl_i8_const_fold: 167; CHECK: // %bb.0: 168; CHECK-NEXT: mov w0, #128 169; CHECK-NEXT: ret 170 %f = call i8 @llvm.fshl.i8(i8 255, i8 0, i8 7) 171 ret i8 %f 172} 173 174; Repeat everything for funnel shift right. 175 176; General case - all operands can be variables. 177 178define i32 @fshr_i32(i32 %x, i32 %y, i32 %z) { 179; CHECK-LABEL: fshr_i32: 180; CHECK: // %bb.0: 181; CHECK-NEXT: // kill: def $w2 killed $w2 def $x2 182; CHECK-NEXT: mvn w8, w2 183; CHECK-NEXT: lsl w9, w0, #1 184; CHECK-NEXT: lsr w10, w1, w2 185; CHECK-NEXT: lsl w8, w9, w8 186; CHECK-NEXT: orr w0, w8, w10 187; CHECK-NEXT: ret 188 %f = call i32 @llvm.fshr.i32(i32 %x, i32 %y, i32 %z) 189 ret i32 %f 190} 191 192define i64 @fshr_i64(i64 %x, i64 %y, i64 %z) { 193; CHECK-LABEL: fshr_i64: 194; CHECK: // %bb.0: 195; CHECK-NEXT: mvn w8, w2 196; CHECK-NEXT: lsl x9, x0, #1 197; CHECK-NEXT: lsr x10, x1, x2 198; CHECK-NEXT: lsl x8, x9, x8 199; CHECK-NEXT: orr x0, x8, x10 200; CHECK-NEXT: ret 201 %f = call i64 @llvm.fshr.i64(i64 %x, i64 %y, i64 %z) 202 ret i64 %f 203} 204 205; Verify that weird types are minimally supported. 206declare i37 @llvm.fshr.i37(i37, i37, i37) 207define i37 @fshr_i37(i37 %x, i37 %y, i37 %z) { 208; CHECK-LABEL: fshr_i37: 209; CHECK: // %bb.0: 210; CHECK-NEXT: mov x9, #31883 211; CHECK-NEXT: and x8, x2, #0x1fffffffff 212; CHECK-NEXT: movk x9, #3542, lsl #16 213; CHECK-NEXT: lsl x10, x1, #27 214; CHECK-NEXT: movk x9, #51366, lsl #32 215; CHECK-NEXT: lsl x11, x0, #1 216; CHECK-NEXT: movk x9, #56679, lsl #48 217; CHECK-NEXT: umulh x8, x8, x9 218; CHECK-NEXT: mov w9, #37 219; CHECK-NEXT: lsr x8, x8, #5 220; CHECK-NEXT: msub w8, w8, w9, w2 221; CHECK-NEXT: add w8, w8, #27 222; CHECK-NEXT: mvn w9, w8 223; CHECK-NEXT: lsr x8, x10, x8 224; CHECK-NEXT: lsl x9, x11, x9 225; CHECK-NEXT: orr x0, x9, x8 226; CHECK-NEXT: ret 227 %f = call i37 @llvm.fshr.i37(i37 %x, i37 %y, i37 %z) 228 ret i37 %f 229} 230 231; extract(concat(0b1110000, 0b1111111) >> 2) = 0b0011111 232 233declare i7 @llvm.fshr.i7(i7, i7, i7) 234define i7 @fshr_i7_const_fold() { 235; CHECK-LABEL: fshr_i7_const_fold: 236; CHECK: // %bb.0: 237; CHECK-NEXT: mov w0, #31 238; CHECK-NEXT: ret 239 %f = call i7 @llvm.fshr.i7(i7 112, i7 127, i7 2) 240 ret i7 %f 241} 242 243define i8 @fshr_i8_const_fold_overshift_1() { 244; CHECK-LABEL: fshr_i8_const_fold_overshift_1: 245; CHECK: // %bb.0: 246; CHECK-NEXT: mov w0, #254 247; CHECK-NEXT: ret 248 %f = call i8 @llvm.fshr.i8(i8 255, i8 0, i8 15) 249 ret i8 %f 250} 251 252define i8 @fshr_i8_const_fold_overshift_2() { 253; CHECK-LABEL: fshr_i8_const_fold_overshift_2: 254; CHECK: // %bb.0: 255; CHECK-NEXT: mov w0, #225 256; CHECK-NEXT: ret 257 %f = call i8 @llvm.fshr.i8(i8 15, i8 15, i8 11) 258 ret i8 %f 259} 260 261define i8 @fshr_i8_const_fold_overshift_3() { 262; CHECK-LABEL: fshr_i8_const_fold_overshift_3: 263; CHECK: // %bb.0: 264; CHECK-NEXT: mov w0, #255 265; CHECK-NEXT: ret 266 %f = call i8 @llvm.fshr.i8(i8 0, i8 255, i8 8) 267 ret i8 %f 268} 269 270; With constant shift amount, this is 'extr'. 271 272define i32 @fshr_i32_const_shift(i32 %x, i32 %y) { 273; CHECK-LABEL: fshr_i32_const_shift: 274; CHECK: // %bb.0: 275; CHECK-NEXT: extr w0, w0, w1, #9 276; CHECK-NEXT: ret 277 %f = call i32 @llvm.fshr.i32(i32 %x, i32 %y, i32 9) 278 ret i32 %f 279} 280 281; Check modulo math on shift amount. 41-32=9. 282 283define i32 @fshr_i32_const_overshift(i32 %x, i32 %y) { 284; CHECK-LABEL: fshr_i32_const_overshift: 285; CHECK: // %bb.0: 286; CHECK-NEXT: extr w0, w0, w1, #9 287; CHECK-NEXT: ret 288 %f = call i32 @llvm.fshr.i32(i32 %x, i32 %y, i32 41) 289 ret i32 %f 290} 291 292; 64-bit should also work. 105-64 = 41. 293 294define i64 @fshr_i64_const_overshift(i64 %x, i64 %y) { 295; CHECK-LABEL: fshr_i64_const_overshift: 296; CHECK: // %bb.0: 297; CHECK-NEXT: extr x0, x0, x1, #41 298; CHECK-NEXT: ret 299 %f = call i64 @llvm.fshr.i64(i64 %x, i64 %y, i64 105) 300 ret i64 %f 301} 302 303; This should work without any node-specific logic. 304 305define i8 @fshr_i8_const_fold() { 306; CHECK-LABEL: fshr_i8_const_fold: 307; CHECK: // %bb.0: 308; CHECK-NEXT: mov w0, #254 309; CHECK-NEXT: ret 310 %f = call i8 @llvm.fshr.i8(i8 255, i8 0, i8 7) 311 ret i8 %f 312} 313 314define i32 @fshl_i32_shift_by_bitwidth(i32 %x, i32 %y) { 315; CHECK-LABEL: fshl_i32_shift_by_bitwidth: 316; CHECK: // %bb.0: 317; CHECK-NEXT: ret 318 %f = call i32 @llvm.fshl.i32(i32 %x, i32 %y, i32 32) 319 ret i32 %f 320} 321 322define i32 @fshr_i32_shift_by_bitwidth(i32 %x, i32 %y) { 323; CHECK-LABEL: fshr_i32_shift_by_bitwidth: 324; CHECK: // %bb.0: 325; CHECK-NEXT: mov w0, w1 326; CHECK-NEXT: ret 327 %f = call i32 @llvm.fshr.i32(i32 %x, i32 %y, i32 32) 328 ret i32 %f 329} 330 331define <4 x i32> @fshl_v4i32_shift_by_bitwidth(<4 x i32> %x, <4 x i32> %y) { 332; CHECK-LABEL: fshl_v4i32_shift_by_bitwidth: 333; CHECK: // %bb.0: 334; CHECK-NEXT: ret 335 %f = call <4 x i32> @llvm.fshl.v4i32(<4 x i32> %x, <4 x i32> %y, <4 x i32> <i32 32, i32 32, i32 32, i32 32>) 336 ret <4 x i32> %f 337} 338 339define <4 x i32> @fshr_v4i32_shift_by_bitwidth(<4 x i32> %x, <4 x i32> %y) { 340; CHECK-LABEL: fshr_v4i32_shift_by_bitwidth: 341; CHECK: // %bb.0: 342; CHECK-NEXT: mov v0.16b, v1.16b 343; CHECK-NEXT: ret 344 %f = call <4 x i32> @llvm.fshr.v4i32(<4 x i32> %x, <4 x i32> %y, <4 x i32> <i32 32, i32 32, i32 32, i32 32>) 345 ret <4 x i32> %f 346} 347 348define i32 @or_shl_fshl(i32 %x, i32 %y, i32 %s) { 349; CHECK-LABEL: or_shl_fshl: 350; CHECK: // %bb.0: 351; CHECK-NEXT: mov w8, w2 352; CHECK-NEXT: mvn w9, w2 353; CHECK-NEXT: lsr w10, w1, #1 354; CHECK-NEXT: lsr w9, w10, w9 355; CHECK-NEXT: lsl w8, w0, w8 356; CHECK-NEXT: lsl w10, w1, w2 357; CHECK-NEXT: orr w8, w8, w9 358; CHECK-NEXT: orr w0, w8, w10 359; CHECK-NEXT: ret 360 %shy = shl i32 %y, %s 361 %fun = call i32 @llvm.fshl.i32(i32 %x, i32 %y, i32 %s) 362 %or = or i32 %fun, %shy 363 ret i32 %or 364} 365 366define i32 @or_shl_rotl(i32 %x, i32 %y, i32 %s) { 367; CHECK-LABEL: or_shl_rotl: 368; CHECK: // %bb.0: 369; CHECK-NEXT: neg w8, w2 370; CHECK-NEXT: lsl w9, w0, w2 371; CHECK-NEXT: ror w8, w1, w8 372; CHECK-NEXT: orr w0, w8, w9 373; CHECK-NEXT: ret 374 %shx = shl i32 %x, %s 375 %rot = call i32 @llvm.fshl.i32(i32 %y, i32 %y, i32 %s) 376 %or = or i32 %rot, %shx 377 ret i32 %or 378} 379 380define i32 @or_shl_fshl_commute(i32 %x, i32 %y, i32 %s) { 381; CHECK-LABEL: or_shl_fshl_commute: 382; CHECK: // %bb.0: 383; CHECK-NEXT: mov w8, w2 384; CHECK-NEXT: mvn w9, w2 385; CHECK-NEXT: lsr w10, w1, #1 386; CHECK-NEXT: lsr w9, w10, w9 387; CHECK-NEXT: lsl w8, w0, w8 388; CHECK-NEXT: lsl w10, w1, w2 389; CHECK-NEXT: orr w8, w8, w9 390; CHECK-NEXT: orr w0, w10, w8 391; CHECK-NEXT: ret 392 %shy = shl i32 %y, %s 393 %fun = call i32 @llvm.fshl.i32(i32 %x, i32 %y, i32 %s) 394 %or = or i32 %shy, %fun 395 ret i32 %or 396} 397 398define i32 @or_shl_rotl_commute(i32 %x, i32 %y, i32 %s) { 399; CHECK-LABEL: or_shl_rotl_commute: 400; CHECK: // %bb.0: 401; CHECK-NEXT: neg w8, w2 402; CHECK-NEXT: lsl w9, w0, w2 403; CHECK-NEXT: ror w8, w1, w8 404; CHECK-NEXT: orr w0, w9, w8 405; CHECK-NEXT: ret 406 %shx = shl i32 %x, %s 407 %rot = call i32 @llvm.fshl.i32(i32 %y, i32 %y, i32 %s) 408 %or = or i32 %shx, %rot 409 ret i32 %or 410} 411 412define i32 @or_lshr_fshr(i32 %x, i32 %y, i32 %s) { 413; CHECK-LABEL: or_lshr_fshr: 414; CHECK: // %bb.0: 415; CHECK-NEXT: mov w8, w2 416; CHECK-NEXT: mvn w9, w2 417; CHECK-NEXT: lsl w10, w1, #1 418; CHECK-NEXT: lsr w8, w0, w8 419; CHECK-NEXT: lsl w9, w10, w9 420; CHECK-NEXT: lsr w10, w1, w2 421; CHECK-NEXT: orr w8, w9, w8 422; CHECK-NEXT: orr w0, w8, w10 423; CHECK-NEXT: ret 424 %shy = lshr i32 %y, %s 425 %fun = call i32 @llvm.fshr.i32(i32 %y, i32 %x, i32 %s) 426 %or = or i32 %fun, %shy 427 ret i32 %or 428} 429 430define i32 @or_lshr_rotr(i32 %x, i32 %y, i32 %s) { 431; CHECK-LABEL: or_lshr_rotr: 432; CHECK: // %bb.0: 433; CHECK-NEXT: lsr w8, w0, w2 434; CHECK-NEXT: ror w9, w1, w2 435; CHECK-NEXT: orr w0, w9, w8 436; CHECK-NEXT: ret 437 %shx = lshr i32 %x, %s 438 %rot = call i32 @llvm.fshr.i32(i32 %y, i32 %y, i32 %s) 439 %or = or i32 %rot, %shx 440 ret i32 %or 441} 442 443define i32 @or_lshr_fshr_commute(i32 %x, i32 %y, i32 %s) { 444; CHECK-LABEL: or_lshr_fshr_commute: 445; CHECK: // %bb.0: 446; CHECK-NEXT: mov w8, w2 447; CHECK-NEXT: mvn w9, w2 448; CHECK-NEXT: lsl w10, w1, #1 449; CHECK-NEXT: lsr w8, w0, w8 450; CHECK-NEXT: lsl w9, w10, w9 451; CHECK-NEXT: lsr w10, w1, w2 452; CHECK-NEXT: orr w8, w9, w8 453; CHECK-NEXT: orr w0, w10, w8 454; CHECK-NEXT: ret 455 %shy = lshr i32 %y, %s 456 %fun = call i32 @llvm.fshr.i32(i32 %y, i32 %x, i32 %s) 457 %or = or i32 %shy, %fun 458 ret i32 %or 459} 460 461define i32 @or_lshr_rotr_commute(i32 %x, i32 %y, i32 %s) { 462; CHECK-LABEL: or_lshr_rotr_commute: 463; CHECK: // %bb.0: 464; CHECK-NEXT: lsr w8, w0, w2 465; CHECK-NEXT: ror w9, w1, w2 466; CHECK-NEXT: orr w0, w8, w9 467; CHECK-NEXT: ret 468 %shx = lshr i32 %x, %s 469 %rot = call i32 @llvm.fshr.i32(i32 %y, i32 %y, i32 %s) 470 %or = or i32 %shx, %rot 471 ret i32 %or 472} 473 474define i32 @or_shl_fshl_simplify(i32 %x, i32 %y, i32 %s) { 475; CHECK-LABEL: or_shl_fshl_simplify: 476; CHECK: // %bb.0: 477; CHECK-NEXT: // kill: def $w2 killed $w2 def $x2 478; CHECK-NEXT: mvn w8, w2 479; CHECK-NEXT: lsr w9, w0, #1 480; CHECK-NEXT: lsl w10, w1, w2 481; CHECK-NEXT: lsr w8, w9, w8 482; CHECK-NEXT: orr w0, w10, w8 483; CHECK-NEXT: ret 484 %shy = shl i32 %y, %s 485 %fun = call i32 @llvm.fshl.i32(i32 %y, i32 %x, i32 %s) 486 %or = or i32 %fun, %shy 487 ret i32 %or 488} 489 490define i32 @or_lshr_fshr_simplify(i32 %x, i32 %y, i32 %s) { 491; CHECK-LABEL: or_lshr_fshr_simplify: 492; CHECK: // %bb.0: 493; CHECK-NEXT: // kill: def $w2 killed $w2 def $x2 494; CHECK-NEXT: mvn w8, w2 495; CHECK-NEXT: lsl w9, w0, #1 496; CHECK-NEXT: lsr w10, w1, w2 497; CHECK-NEXT: lsl w8, w9, w8 498; CHECK-NEXT: orr w0, w8, w10 499; CHECK-NEXT: ret 500 %shy = lshr i32 %y, %s 501 %fun = call i32 @llvm.fshr.i32(i32 %x, i32 %y, i32 %s) 502 %or = or i32 %shy, %fun 503 ret i32 %or 504} 505