; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 4 ; RUN: llc -mtriple=aarch64 -mattr=+sve < %s -o - | FileCheck --check-prefixes=CHECK,SVE %s ; RUN: llc -mtriple=aarch64 -mattr=+sve2 < %s -o - | FileCheck --check-prefixes=CHECK,SVE2 %s define @xar_nxv2i64_l( %x, %y) { ; SVE-LABEL: xar_nxv2i64_l: ; SVE: // %bb.0: ; SVE-NEXT: eor z0.d, z0.d, z1.d ; SVE-NEXT: lsr z1.d, z0.d, #4 ; SVE-NEXT: lsl z0.d, z0.d, #60 ; SVE-NEXT: orr z0.d, z0.d, z1.d ; SVE-NEXT: ret ; ; SVE2-LABEL: xar_nxv2i64_l: ; SVE2: // %bb.0: ; SVE2-NEXT: xar z0.d, z0.d, z1.d, #4 ; SVE2-NEXT: ret %a = xor %x, %y %b = call @llvm.fshl.nxv2i64( %a, %a, splat (i64 60)) ret %b } define @xar_nxv2i64_r( %x, %y) { ; SVE-LABEL: xar_nxv2i64_r: ; SVE: // %bb.0: ; SVE-NEXT: eor z0.d, z0.d, z1.d ; SVE-NEXT: lsl z1.d, z0.d, #60 ; SVE-NEXT: lsr z0.d, z0.d, #4 ; SVE-NEXT: orr z0.d, z0.d, z1.d ; SVE-NEXT: ret ; ; SVE2-LABEL: xar_nxv2i64_r: ; SVE2: // %bb.0: ; SVE2-NEXT: xar z0.d, z0.d, z1.d, #4 ; SVE2-NEXT: ret %a = xor %x, %y %b = call @llvm.fshr.nxv2i64( %a, %a, splat (i64 4)) ret %b } define @xar_nxv4i32_l( %x, %y) { ; SVE-LABEL: xar_nxv4i32_l: ; SVE: // %bb.0: ; SVE-NEXT: eor z0.d, z0.d, z1.d ; SVE-NEXT: lsr z1.s, z0.s, #4 ; SVE-NEXT: lsl z0.s, z0.s, #28 ; SVE-NEXT: orr z0.d, z0.d, z1.d ; SVE-NEXT: ret ; ; SVE2-LABEL: xar_nxv4i32_l: ; SVE2: // %bb.0: ; SVE2-NEXT: xar z0.s, z0.s, z1.s, #4 ; SVE2-NEXT: ret %a = xor %x, %y %b = call @llvm.fshl.nxv4i32( %a, %a, splat (i32 28)) ret %b } define @xar_nxv4i32_r( %x, %y) { ; SVE-LABEL: xar_nxv4i32_r: ; SVE: // %bb.0: ; SVE-NEXT: eor z0.d, z0.d, z1.d ; SVE-NEXT: lsl z1.s, z0.s, #28 ; SVE-NEXT: lsr z0.s, z0.s, #4 ; SVE-NEXT: orr z0.d, z0.d, z1.d ; SVE-NEXT: ret ; ; SVE2-LABEL: xar_nxv4i32_r: ; SVE2: // %bb.0: ; SVE2-NEXT: xar z0.s, z0.s, z1.s, #4 ; SVE2-NEXT: ret %a = xor %x, %y %b = call @llvm.fshr.nxv4i32( %a, %a, splat (i32 4)) ret %b } define @xar_nxv8i16_l( %x, %y) { ; SVE-LABEL: xar_nxv8i16_l: ; SVE: // %bb.0: ; SVE-NEXT: eor z0.d, z0.d, z1.d ; SVE-NEXT: lsr z1.h, z0.h, #4 ; SVE-NEXT: lsl z0.h, z0.h, #12 ; SVE-NEXT: orr z0.d, z0.d, z1.d ; SVE-NEXT: ret ; ; SVE2-LABEL: xar_nxv8i16_l: ; SVE2: // %bb.0: ; SVE2-NEXT: xar z0.h, z0.h, z1.h, #4 ; SVE2-NEXT: ret %a = xor %x, %y %b = call @llvm.fshl.nxv8i16( %a, %a, splat (i16 12)) ret %b } define @xar_nxv8i16_r( %x, %y) { ; SVE-LABEL: xar_nxv8i16_r: ; SVE: // %bb.0: ; SVE-NEXT: eor z0.d, z0.d, z1.d ; SVE-NEXT: lsl z1.h, z0.h, #12 ; SVE-NEXT: lsr z0.h, z0.h, #4 ; SVE-NEXT: orr z0.d, z0.d, z1.d ; SVE-NEXT: ret ; ; SVE2-LABEL: xar_nxv8i16_r: ; SVE2: // %bb.0: ; SVE2-NEXT: xar z0.h, z0.h, z1.h, #4 ; SVE2-NEXT: ret %a = xor %x, %y %b = call @llvm.fshr.nxv8i16( %a, %a, splat (i16 4)) ret %b } define @xar_nxv16i8_l( %x, %y) { ; SVE-LABEL: xar_nxv16i8_l: ; SVE: // %bb.0: ; SVE-NEXT: eor z0.d, z0.d, z1.d ; SVE-NEXT: lsr z1.b, z0.b, #4 ; SVE-NEXT: lsl z0.b, z0.b, #4 ; SVE-NEXT: orr z0.d, z0.d, z1.d ; SVE-NEXT: ret ; ; SVE2-LABEL: xar_nxv16i8_l: ; SVE2: // %bb.0: ; SVE2-NEXT: xar z0.b, z0.b, z1.b, #4 ; SVE2-NEXT: ret %a = xor %x, %y %b = call @llvm.fshl.nxv16i8( %a, %a, splat (i8 4)) ret %b } define @xar_nxv16i8_r( %x, %y) { ; SVE-LABEL: xar_nxv16i8_r: ; SVE: // %bb.0: ; SVE-NEXT: eor z0.d, z0.d, z1.d ; SVE-NEXT: lsl z1.b, z0.b, #4 ; SVE-NEXT: lsr z0.b, z0.b, #4 ; SVE-NEXT: orr z0.d, z0.d, z1.d ; SVE-NEXT: ret ; ; SVE2-LABEL: xar_nxv16i8_r: ; SVE2: // %bb.0: ; SVE2-NEXT: xar z0.b, z0.b, z1.b, #4 ; SVE2-NEXT: ret %a = xor %x, %y %b = call @llvm.fshr.nxv16i8( %a, %a, splat (i8 4)) ret %b } ; Shift is not a constant. define @xar_nxv2i64_l_neg1( %x, %y, %z) { ; CHECK-LABEL: xar_nxv2i64_l_neg1: ; CHECK: // %bb.0: ; CHECK-NEXT: movprfx z3, z2 ; CHECK-NEXT: subr z3.d, z3.d, #0 // =0x0 ; CHECK-NEXT: eor z0.d, z0.d, z1.d ; CHECK-NEXT: and z2.d, z2.d, #0x3f ; CHECK-NEXT: ptrue p0.d ; CHECK-NEXT: and z3.d, z3.d, #0x3f ; CHECK-NEXT: lslr z2.d, p0/m, z2.d, z0.d ; CHECK-NEXT: lsr z0.d, p0/m, z0.d, z3.d ; CHECK-NEXT: orr z0.d, z2.d, z0.d ; CHECK-NEXT: ret %a = xor %x, %y %b = call @llvm.fshl.nxv2i64( %a, %a, %z) ret %b } ; OR instead of an XOR. ; TODO: We could use usra instruction here for SVE2. define @xar_nxv2i64_l_neg2_1( %x, %y) { ; SVE-LABEL: xar_nxv2i64_l_neg2_1: ; SVE: // %bb.0: ; SVE-NEXT: orr z0.d, z0.d, z1.d ; SVE-NEXT: lsr z1.d, z0.d, #4 ; SVE-NEXT: lsl z0.d, z0.d, #60 ; SVE-NEXT: orr z0.d, z0.d, z1.d ; SVE-NEXT: ret ; ; SVE2-LABEL: xar_nxv2i64_l_neg2_1: ; SVE2: // %bb.0: ; SVE2-NEXT: movi v2.2d, #0000000000000000 ; SVE2-NEXT: orr z0.d, z0.d, z1.d ; SVE2-NEXT: xar z0.d, z0.d, z2.d, #4 ; SVE2-NEXT: ret %a = or %x, %y %b = call @llvm.fshl.nxv2i64( %a, %a, splat (i64 60)) ret %b } define @xar_nxv2i32_l_neg2_2( %x, %y) { ; SVE-LABEL: xar_nxv2i32_l_neg2_2: ; SVE: // %bb.0: ; SVE-NEXT: orr z0.d, z0.d, z1.d ; SVE-NEXT: lsr z1.s, z0.s, #4 ; SVE-NEXT: lsl z0.s, z0.s, #28 ; SVE-NEXT: orr z0.d, z0.d, z1.d ; SVE-NEXT: ret ; ; SVE2-LABEL: xar_nxv2i32_l_neg2_2: ; SVE2: // %bb.0: ; SVE2-NEXT: movi v2.2d, #0000000000000000 ; SVE2-NEXT: orr z0.d, z0.d, z1.d ; SVE2-NEXT: xar z0.s, z0.s, z2.s, #4 ; SVE2-NEXT: ret %a = or %x, %y %b = call @llvm.fshl.nxv4i32( %a, %a, splat (i32 60)) ret %b } define @xar_nxv2i16_l_neg2_3( %x, %y) { ; SVE-LABEL: xar_nxv2i16_l_neg2_3: ; SVE: // %bb.0: ; SVE-NEXT: orr z0.d, z0.d, z1.d ; SVE-NEXT: lsr z1.h, z0.h, #4 ; SVE-NEXT: lsl z0.h, z0.h, #12 ; SVE-NEXT: orr z0.d, z0.d, z1.d ; SVE-NEXT: ret ; ; SVE2-LABEL: xar_nxv2i16_l_neg2_3: ; SVE2: // %bb.0: ; SVE2-NEXT: movi v2.2d, #0000000000000000 ; SVE2-NEXT: orr z0.d, z0.d, z1.d ; SVE2-NEXT: xar z0.h, z0.h, z2.h, #4 ; SVE2-NEXT: ret %a = or %x, %y %b = call @llvm.fshl.nxv8i16( %a, %a, splat (i16 60)) ret %b } define @xar_nxv2i8_l_neg2_4( %x, %y) { ; SVE-LABEL: xar_nxv2i8_l_neg2_4: ; SVE: // %bb.0: ; SVE-NEXT: orr z0.d, z0.d, z1.d ; SVE-NEXT: lsr z1.b, z0.b, #4 ; SVE-NEXT: lsl z0.b, z0.b, #4 ; SVE-NEXT: orr z0.d, z0.d, z1.d ; SVE-NEXT: ret ; ; SVE2-LABEL: xar_nxv2i8_l_neg2_4: ; SVE2: // %bb.0: ; SVE2-NEXT: movi v2.2d, #0000000000000000 ; SVE2-NEXT: orr z0.d, z0.d, z1.d ; SVE2-NEXT: xar z0.b, z0.b, z2.b, #4 ; SVE2-NEXT: ret %a = or %x, %y %b = call @llvm.fshl.nxv16i8( %a, %a, splat (i8 60)) ret %b } ; Rotate amount is 0. define @xar_nxv2i64_l_neg3( %x, %y) { ; CHECK-LABEL: xar_nxv2i64_l_neg3: ; CHECK: // %bb.0: ; CHECK-NEXT: eor z0.d, z0.d, z1.d ; CHECK-NEXT: ret %a = xor %x, %y %b = call @llvm.fshl.nxv2i64( %a, %a, splat (i64 64)) ret %b } ; Uses individual shifts instead of funnel shifts, just one test. define @xar_nxv2i64_shifts( %x, %y) { ; SVE-LABEL: xar_nxv2i64_shifts: ; SVE: // %bb.0: ; SVE-NEXT: eor z0.d, z0.d, z1.d ; SVE-NEXT: lsr z1.d, z0.d, #4 ; SVE-NEXT: lsl z0.d, z0.d, #60 ; SVE-NEXT: orr z0.d, z0.d, z1.d ; SVE-NEXT: ret ; ; SVE2-LABEL: xar_nxv2i64_shifts: ; SVE2: // %bb.0: ; SVE2-NEXT: xar z0.d, z0.d, z1.d, #4 ; SVE2-NEXT: ret %xor = xor %x, %y %shl = shl %xor, splat (i64 60) %shr = lshr %xor, splat (i64 4) %or = or %shl, %shr ret %or } ; Not a rotate operation as 60 + 3 != 64 define @xar_nxv2i64_shifts_neg( %x, %y) { ; CHECK-LABEL: xar_nxv2i64_shifts_neg: ; CHECK: // %bb.0: ; CHECK-NEXT: eor z0.d, z0.d, z1.d ; CHECK-NEXT: lsl z1.d, z0.d, #60 ; CHECK-NEXT: lsr z0.d, z0.d, #3 ; CHECK-NEXT: orr z0.d, z1.d, z0.d ; CHECK-NEXT: ret %xor = xor %x, %y %shl = shl %xor, splat (i64 60) %shr = lshr %xor, splat (i64 3) %or = or %shl, %shr ret %or } ; Don't use XAR if REV[BHW] can be used. define @revb_nxv8i16( %r) { ; CHECK-LABEL: revb_nxv8i16: ; CHECK: // %bb.0: ; CHECK-NEXT: ptrue p0.h ; CHECK-NEXT: revb z0.h, p0/m, z0.h ; CHECK-NEXT: ret %or = tail call @llvm.fshl( %r, %r, splat (i16 8)) ret %or } define @revh_nxv4i32( %r) { ; CHECK-LABEL: revh_nxv4i32: ; CHECK: // %bb.0: ; CHECK-NEXT: ptrue p0.s ; CHECK-NEXT: revh z0.s, p0/m, z0.s ; CHECK-NEXT: ret %or = tail call @llvm.fshl( %r, %r, splat (i32 16)) ret %or } define @revw_nx2i64( %r) { ; CHECK-LABEL: revw_nx2i64: ; CHECK: // %bb.0: ; CHECK-NEXT: ptrue p0.d ; CHECK-NEXT: revw z0.d, p0/m, z0.d ; CHECK-NEXT: ret %or = tail call @llvm.fshl( %r, %r, splat (i64 32)) ret %or } ; As above, one test with rotate right. define @revw_nx2i64_r( %a) { ; CHECK-LABEL: revw_nx2i64_r: ; CHECK: // %bb.0: ; CHECK-NEXT: ptrue p0.d ; CHECK-NEXT: revw z0.d, p0/m, z0.d ; CHECK-NEXT: ret %r = tail call @llvm.fshr( %a, %a, splat (i64 32)) ret %r } ; As above, one test with predicated shifts instead of rotate left. define @revh_nx4i32_shifts_l( %pg, %a) { ; CHECK-LABEL: revh_nx4i32_shifts_l: ; CHECK: // %bb.0: ; CHECK-NEXT: revh z0.s, p0/m, z0.s ; CHECK-NEXT: ret %shl = tail call @llvm.aarch64.sve.lsl.u( %pg, %a, splat (i32 16)) %shr = tail call @llvm.aarch64.sve.lsr.u( %pg, %a, splat (i32 16)) %or = or %shl, %shr ret %or } ; As above, one test with predicated shifts instead of rotate right. define @revb_nx8i16_shifts_r( %pg, %a) { ; CHECK-LABEL: revb_nx8i16_shifts_r: ; CHECK: // %bb.0: ; CHECK-NEXT: revb z0.h, p0/m, z0.h ; CHECK-NEXT: ret %shr = tail call @llvm.aarch64.sve.lsr.u( %pg, %a, splat (i16 8)) %shl = tail call @llvm.aarch64.sve.lsl.u( %pg, %a, splat (i16 8)) %or = or %shr, %shl ret %or } declare @llvm.fshl.nxv2i64(, , ) declare @llvm.fshl.nxv4i32(, , ) declare @llvm.fshl.nxv8i16(, , ) declare @llvm.fshl.nxv16i8(, , ) declare @llvm.fshr.nxv2i64(, , ) declare @llvm.fshr.nxv4i32(, , ) declare @llvm.fshr.nxv8i16(, , ) declare @llvm.fshr.nxv16i8(, , )