; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
; RUN: llc --mtriple=loongarch32 --mattr=+32s,+lsx < %s | FileCheck %s --check-prefixes=CHECK,LA32
; RUN: llc --mtriple=loongarch64 --mattr=+lsx < %s | FileCheck %s --check-prefixes=CHECK,LA64

define void @rotl_v16i8(ptr %dst, ptr %src, i8 signext %a0) nounwind {
; CHECK-LABEL: rotl_v16i8:
; CHECK:       # %bb.0:
; CHECK-NEXT:    vld $vr0, $a1, 0
; CHECK-NEXT:    vreplgr2vr.b $vr1, $a2
; CHECK-NEXT:    vneg.b $vr1, $vr1
; CHECK-NEXT:    vrotr.b $vr0, $vr0, $vr1
; CHECK-NEXT:    vst $vr0, $a0, 0
; CHECK-NEXT:    ret
  %v0 = load <16 x i8>, ptr %src
  %v1.ele = insertelement <16 x i8> poison, i8 %a0, i8 0
  %v1 = shufflevector <16 x i8> %v1.ele, <16 x i8> poison, <16 x i32> zeroinitializer
  %v1.sub = sub <16 x i8> splat (i8 8), %v1
  %b = shl <16 x i8> %v0, %v1
  %c = lshr <16 x i8> %v0, %v1.sub
  %d = or <16 x i8> %b, %c
  store <16 x i8> %d, ptr %dst
  ret void
}

define void @rotr_v16i8(ptr %dst, ptr %src, i8 signext %a0) nounwind {
; CHECK-LABEL: rotr_v16i8:
; CHECK:       # %bb.0:
; CHECK-NEXT:    vld $vr0, $a1, 0
; CHECK-NEXT:    vreplgr2vr.b $vr1, $a2
; CHECK-NEXT:    vrotr.b $vr0, $vr0, $vr1
; CHECK-NEXT:    vst $vr0, $a0, 0
; CHECK-NEXT:    ret
  %v0 = load <16 x i8>, ptr %src
  %v1.ele = insertelement <16 x i8> poison, i8 %a0, i8 0
  %v1 = shufflevector <16 x i8> %v1.ele, <16 x i8> poison, <16 x i32> zeroinitializer
  %v1.sub = sub <16 x i8> splat (i8 8), %v1
  %b = lshr <16 x i8> %v0, %v1
  %c = shl <16 x i8> %v0, %v1.sub
  %d = or <16 x i8> %b, %c
  store <16 x i8> %d, ptr %dst
  ret void
}

define void @rotr_v16i8_imm(ptr %dst, ptr %src) nounwind {
; CHECK-LABEL: rotr_v16i8_imm:
; CHECK:       # %bb.0:
; CHECK-NEXT:    vld $vr0, $a1, 0
; CHECK-NEXT:    vrotri.b $vr0, $vr0, 2
; CHECK-NEXT:    vst $vr0, $a0, 0
; CHECK-NEXT:    ret
  %v0 = load <16 x i8>, ptr %src
  %b = lshr <16 x i8> %v0, splat (i8 2)
  %c = shl <16 x i8> %v0, splat (i8 6)
  %d = or <16 x i8> %b, %c
  store <16 x i8> %d, ptr %dst
  ret void
}

define void @rotl_v8i16(ptr %dst, ptr %src, i16 signext %a0) nounwind {
; CHECK-LABEL: rotl_v8i16:
; CHECK:       # %bb.0:
; CHECK-NEXT:    vld $vr0, $a1, 0
; CHECK-NEXT:    vreplgr2vr.h $vr1, $a2
; CHECK-NEXT:    vneg.h $vr1, $vr1
; CHECK-NEXT:    vrotr.h $vr0, $vr0, $vr1
; CHECK-NEXT:    vst $vr0, $a0, 0
; CHECK-NEXT:    ret
  %v0 = load <8 x i16>, ptr %src
  %v1.ele = insertelement <8 x i16> poison, i16 %a0, i16 0
  %v1 = shufflevector <8 x i16> %v1.ele, <8 x i16> poison, <8 x i32> zeroinitializer
  %v1.sub = sub <8 x i16> splat (i16 16), %v1
  %b = shl <8 x i16> %v0, %v1
  %c = lshr <8 x i16> %v0, %v1.sub
  %d = or <8 x i16> %b, %c
  store <8 x i16> %d, ptr %dst
  ret void
}

define void @rotr_v8i16(ptr %dst, ptr %src, i16 signext %a0) nounwind {
; CHECK-LABEL: rotr_v8i16:
; CHECK:       # %bb.0:
; CHECK-NEXT:    vld $vr0, $a1, 0
; CHECK-NEXT:    vreplgr2vr.h $vr1, $a2
; CHECK-NEXT:    vrotr.h $vr0, $vr0, $vr1
; CHECK-NEXT:    vst $vr0, $a0, 0
; CHECK-NEXT:    ret
  %v0 = load <8 x i16>, ptr %src
  %v1.ele = insertelement <8 x i16> poison, i16 %a0, i16 0
  %v1 = shufflevector <8 x i16> %v1.ele, <8 x i16> poison, <8 x i32> zeroinitializer
  %v1.sub = sub <8 x i16> splat (i16 16), %v1
  %b = lshr <8 x i16> %v0, %v1
  %c = shl <8 x i16> %v0, %v1.sub
  %d = or <8 x i16> %b, %c
  store <8 x i16> %d, ptr %dst
  ret void
}

define void @rotr_v8i16_imm(ptr %dst, ptr %src) nounwind {
; CHECK-LABEL: rotr_v8i16_imm:
; CHECK:       # %bb.0:
; CHECK-NEXT:    vld $vr0, $a1, 0
; CHECK-NEXT:    vrotri.h $vr0, $vr0, 2
; CHECK-NEXT:    vst $vr0, $a0, 0
; CHECK-NEXT:    ret
  %v0 = load <8 x i16>, ptr %src
  %b = lshr <8 x i16> %v0, splat (i16 2)
  %c = shl <8 x i16> %v0, splat (i16 14)
  %d = or <8 x i16> %b, %c
  store <8 x i16> %d, ptr %dst
  ret void
}

define void @rotl_v4i32(ptr %dst, ptr %src, i32 signext %a0) nounwind {
; CHECK-LABEL: rotl_v4i32:
; CHECK:       # %bb.0:
; CHECK-NEXT:    vld $vr0, $a1, 0
; CHECK-NEXT:    vreplgr2vr.w $vr1, $a2
; CHECK-NEXT:    vneg.w $vr1, $vr1
; CHECK-NEXT:    vrotr.w $vr0, $vr0, $vr1
; CHECK-NEXT:    vst $vr0, $a0, 0
; CHECK-NEXT:    ret
  %v0 = load <4 x i32>, ptr %src
  %v1.ele = insertelement <4 x i32> poison, i32 %a0, i32 0
  %v1 = shufflevector <4 x i32> %v1.ele, <4 x i32> poison, <4 x i32> zeroinitializer
  %v1.sub = sub <4 x i32> splat (i32 32), %v1
  %b = shl <4 x i32> %v0, %v1
  %c = lshr <4 x i32> %v0, %v1.sub
  %d = or <4 x i32> %b, %c
  store <4 x i32> %d, ptr %dst
  ret void
}

define void @rotr_v4i32(ptr %dst, ptr %src, i32 signext %a0) nounwind {
; CHECK-LABEL: rotr_v4i32:
; CHECK:       # %bb.0:
; CHECK-NEXT:    vld $vr0, $a1, 0
; CHECK-NEXT:    vreplgr2vr.w $vr1, $a2
; CHECK-NEXT:    vrotr.w $vr0, $vr0, $vr1
; CHECK-NEXT:    vst $vr0, $a0, 0
; CHECK-NEXT:    ret
  %v0 = load <4 x i32>, ptr %src
  %v1.ele = insertelement <4 x i32> poison, i32 %a0, i32 0
  %v1 = shufflevector <4 x i32> %v1.ele, <4 x i32> poison, <4 x i32> zeroinitializer
  %v1.sub = sub <4 x i32> splat (i32 32), %v1
  %b = lshr <4 x i32> %v0, %v1
  %c = shl <4 x i32> %v0, %v1.sub
  %d = or <4 x i32> %b, %c
  store <4 x i32> %d, ptr %dst
  ret void
}

define void @rotr_v4i32_imm(ptr %dst, ptr %src) nounwind {
; CHECK-LABEL: rotr_v4i32_imm:
; CHECK:       # %bb.0:
; CHECK-NEXT:    vld $vr0, $a1, 0
; CHECK-NEXT:    vrotri.w $vr0, $vr0, 2
; CHECK-NEXT:    vst $vr0, $a0, 0
; CHECK-NEXT:    ret
  %v0 = load <4 x i32>, ptr %src
  %b = lshr <4 x i32> %v0, splat (i32 2)
  %c = shl <4 x i32> %v0, splat (i32 30)
  %d = or <4 x i32> %b, %c
  store <4 x i32> %d, ptr %dst
  ret void
}

define void @rotl_v2i64(ptr %dst, ptr %src, i64 %a0) nounwind {
; LA32-LABEL: rotl_v2i64:
; LA32:       # %bb.0:
; LA32-NEXT:    vld $vr0, $a1, 0
; LA32-NEXT:    vinsgr2vr.w $vr1, $a2, 0
; LA32-NEXT:    vinsgr2vr.w $vr1, $a2, 2
; LA32-NEXT:    vneg.d $vr1, $vr1
; LA32-NEXT:    vrotr.d $vr0, $vr0, $vr1
; LA32-NEXT:    vst $vr0, $a0, 0
; LA32-NEXT:    ret
;
; LA64-LABEL: rotl_v2i64:
; LA64:       # %bb.0:
; LA64-NEXT:    vld $vr0, $a1, 0
; LA64-NEXT:    vreplgr2vr.d $vr1, $a2
; LA64-NEXT:    vneg.d $vr1, $vr1
; LA64-NEXT:    vrotr.d $vr0, $vr0, $vr1
; LA64-NEXT:    vst $vr0, $a0, 0
; LA64-NEXT:    ret
  %v0 = load <2 x i64>, ptr %src
  %v1.ele = insertelement <2 x i64> poison, i64 %a0, i64 0
  %v1 = shufflevector <2 x i64> %v1.ele, <2 x i64> poison, <2 x i32> zeroinitializer
  %v1.sub = sub <2 x i64> splat (i64 64), %v1
  %b = shl <2 x i64> %v0, %v1
  %c = lshr <2 x i64> %v0, %v1.sub
  %d = or <2 x i64> %b, %c
  store <2 x i64> %d, ptr %dst
  ret void
}

define void @rotr_v2i64(ptr %dst, ptr %src, i64 %a0) nounwind {
; LA32-LABEL: rotr_v2i64:
; LA32:       # %bb.0:
; LA32-NEXT:    vld $vr0, $a1, 0
; LA32-NEXT:    vinsgr2vr.w $vr1, $a2, 0
; LA32-NEXT:    vinsgr2vr.w $vr1, $a2, 2
; LA32-NEXT:    vrotr.d $vr0, $vr0, $vr1
; LA32-NEXT:    vst $vr0, $a0, 0
; LA32-NEXT:    ret
;
; LA64-LABEL: rotr_v2i64:
; LA64:       # %bb.0:
; LA64-NEXT:    vld $vr0, $a1, 0
; LA64-NEXT:    vreplgr2vr.d $vr1, $a2
; LA64-NEXT:    vrotr.d $vr0, $vr0, $vr1
; LA64-NEXT:    vst $vr0, $a0, 0
; LA64-NEXT:    ret
  %v0 = load <2 x i64>, ptr %src
  %v1.ele = insertelement <2 x i64> poison, i64 %a0, i64 0
  %v1 = shufflevector <2 x i64> %v1.ele, <2 x i64> poison, <2 x i32> zeroinitializer
  %v1.sub = sub <2 x i64> splat (i64 64), %v1
  %b = lshr <2 x i64> %v0, %v1
  %c = shl <2 x i64> %v0, %v1.sub
  %d = or <2 x i64> %b, %c
  store <2 x i64> %d, ptr %dst
  ret void
}

define void @rotr_v2i64_imm(ptr %dst, ptr %src) nounwind {
; LA32-LABEL: rotr_v2i64_imm:
; LA32:       # %bb.0:
; LA32-NEXT:    vld $vr0, $a1, 0
; LA32-NEXT:    vrepli.w $vr1, -62
; LA32-NEXT:    vrotr.d $vr0, $vr0, $vr1
; LA32-NEXT:    vst $vr0, $a0, 0
; LA32-NEXT:    ret
;
; LA64-LABEL: rotr_v2i64_imm:
; LA64:       # %bb.0:
; LA64-NEXT:    vld $vr0, $a1, 0
; LA64-NEXT:    vrotri.d $vr0, $vr0, 2
; LA64-NEXT:    vst $vr0, $a0, 0
; LA64-NEXT:    ret
  %v0 = load <2 x i64>, ptr %src
  %b = lshr <2 x i64> %v0, splat (i64 2)
  %c = shl <2 x i64> %v0, splat (i64 62)
  %d = or <2 x i64> %b, %c
  store <2 x i64> %d, ptr %dst
  ret void
}
