; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc -mtriple=riscv32 -mattr=+experimental-p -enable-p-ext-codegen -verify-machineinstrs < %s | FileCheck --check-prefixes=CHECK,CHECK-RV32 %s
; RUN: llc -mtriple=riscv64 -mattr=+experimental-p -enable-p-ext-codegen -verify-machineinstrs < %s | FileCheck --check-prefixes=CHECK,CHECK-RV64 %s

; Test basic add/sub operations for v2i16
define void @test_padd_h(ptr %ret_ptr, ptr %a_ptr, ptr %b_ptr) {
; CHECK-LABEL: test_padd_h:
; CHECK:       # %bb.0:
; CHECK-NEXT:    lw a1, 0(a1)
; CHECK-NEXT:    lw a2, 0(a2)
; CHECK-NEXT:    padd.h a1, a1, a2
; CHECK-NEXT:    sw a1, 0(a0)
; CHECK-NEXT:    ret
  %a = load <2 x i16>, ptr %a_ptr
  %b = load <2 x i16>, ptr %b_ptr
  %res = add <2 x i16> %a, %b
  store <2 x i16> %res, ptr %ret_ptr
  ret void
}

define void @test_psub_h(ptr %ret_ptr, ptr %a_ptr, ptr %b_ptr) {
; CHECK-LABEL: test_psub_h:
; CHECK:       # %bb.0:
; CHECK-NEXT:    lw a1, 0(a1)
; CHECK-NEXT:    lw a2, 0(a2)
; CHECK-NEXT:    psub.h a1, a1, a2
; CHECK-NEXT:    sw a1, 0(a0)
; CHECK-NEXT:    ret
  %a = load <2 x i16>, ptr %a_ptr
  %b = load <2 x i16>, ptr %b_ptr
  %res = sub <2 x i16> %a, %b
  store <2 x i16> %res, ptr %ret_ptr
  ret void
}

; Test basic add/sub operations for v4i8
define void @test_padd_b(ptr %ret_ptr, ptr %a_ptr, ptr %b_ptr) {
; CHECK-LABEL: test_padd_b:
; CHECK:       # %bb.0:
; CHECK-NEXT:    lw a1, 0(a1)
; CHECK-NEXT:    lw a2, 0(a2)
; CHECK-NEXT:    padd.b a1, a1, a2
; CHECK-NEXT:    sw a1, 0(a0)
; CHECK-NEXT:    ret
  %a = load <4 x i8>, ptr %a_ptr
  %b = load <4 x i8>, ptr %b_ptr
  %res = add <4 x i8> %a, %b
  store <4 x i8> %res, ptr %ret_ptr
  ret void
}

define void @test_psub_b(ptr %ret_ptr, ptr %a_ptr, ptr %b_ptr) {
; CHECK-LABEL: test_psub_b:
; CHECK:       # %bb.0:
; CHECK-NEXT:    lw a1, 0(a1)
; CHECK-NEXT:    lw a2, 0(a2)
; CHECK-NEXT:    psub.b a1, a1, a2
; CHECK-NEXT:    sw a1, 0(a0)
; CHECK-NEXT:    ret
  %a = load <4 x i8>, ptr %a_ptr
  %b = load <4 x i8>, ptr %b_ptr
  %res = sub <4 x i8> %a, %b
  store <4 x i8> %res, ptr %ret_ptr
  ret void
}

; Test saturating add operations for v2i16
define void @test_psadd_h(ptr %ret_ptr, ptr %a_ptr, ptr %b_ptr) {
; CHECK-LABEL: test_psadd_h:
; CHECK:       # %bb.0:
; CHECK-NEXT:    lw a1, 0(a1)
; CHECK-NEXT:    lw a2, 0(a2)
; CHECK-NEXT:    psadd.h a1, a1, a2
; CHECK-NEXT:    sw a1, 0(a0)
; CHECK-NEXT:    ret
  %a = load <2 x i16>, ptr %a_ptr
  %b = load <2 x i16>, ptr %b_ptr
  %res = call <2 x i16> @llvm.sadd.sat.v2i16(<2 x i16> %a, <2 x i16> %b)
  store <2 x i16> %res, ptr %ret_ptr
  ret void
}

define void @test_psaddu_h(ptr %ret_ptr, ptr %a_ptr, ptr %b_ptr) {
; CHECK-LABEL: test_psaddu_h:
; CHECK:       # %bb.0:
; CHECK-NEXT:    lw a1, 0(a1)
; CHECK-NEXT:    lw a2, 0(a2)
; CHECK-NEXT:    psaddu.h a1, a1, a2
; CHECK-NEXT:    sw a1, 0(a0)
; CHECK-NEXT:    ret
  %a = load <2 x i16>, ptr %a_ptr
  %b = load <2 x i16>, ptr %b_ptr
  %res = call <2 x i16> @llvm.uadd.sat.v2i16(<2 x i16> %a, <2 x i16> %b)
  store <2 x i16> %res, ptr %ret_ptr
  ret void
}

; Test saturating sub operations for v2i16
define void @test_pssub_h(ptr %ret_ptr, ptr %a_ptr, ptr %b_ptr) {
; CHECK-LABEL: test_pssub_h:
; CHECK:       # %bb.0:
; CHECK-NEXT:    lw a1, 0(a1)
; CHECK-NEXT:    lw a2, 0(a2)
; CHECK-NEXT:    pssub.h a1, a1, a2
; CHECK-NEXT:    sw a1, 0(a0)
; CHECK-NEXT:    ret
  %a = load <2 x i16>, ptr %a_ptr
  %b = load <2 x i16>, ptr %b_ptr
  %res = call <2 x i16> @llvm.ssub.sat.v2i16(<2 x i16> %a, <2 x i16> %b)
  store <2 x i16> %res, ptr %ret_ptr
  ret void
}

define void @test_pssubu_h(ptr %ret_ptr, ptr %a_ptr, ptr %b_ptr) {
; CHECK-LABEL: test_pssubu_h:
; CHECK:       # %bb.0:
; CHECK-NEXT:    lw a1, 0(a1)
; CHECK-NEXT:    lw a2, 0(a2)
; CHECK-NEXT:    pssubu.h a1, a1, a2
; CHECK-NEXT:    sw a1, 0(a0)
; CHECK-NEXT:    ret
  %a = load <2 x i16>, ptr %a_ptr
  %b = load <2 x i16>, ptr %b_ptr
  %res = call <2 x i16> @llvm.usub.sat.v2i16(<2 x i16> %a, <2 x i16> %b)
  store <2 x i16> %res, ptr %ret_ptr
  ret void
}

; Test saturating add operations for v4i8
define void @test_psadd_b(ptr %ret_ptr, ptr %a_ptr, ptr %b_ptr) {
; CHECK-LABEL: test_psadd_b:
; CHECK:       # %bb.0:
; CHECK-NEXT:    lw a1, 0(a1)
; CHECK-NEXT:    lw a2, 0(a2)
; CHECK-NEXT:    psadd.b a1, a1, a2
; CHECK-NEXT:    sw a1, 0(a0)
; CHECK-NEXT:    ret
  %a = load <4 x i8>, ptr %a_ptr
  %b = load <4 x i8>, ptr %b_ptr
  %res = call <4 x i8> @llvm.sadd.sat.v4i8(<4 x i8> %a, <4 x i8> %b)
  store <4 x i8> %res, ptr %ret_ptr
  ret void
}

define void @test_psaddu_b(ptr %ret_ptr, ptr %a_ptr, ptr %b_ptr) {
; CHECK-LABEL: test_psaddu_b:
; CHECK:       # %bb.0:
; CHECK-NEXT:    lw a1, 0(a1)
; CHECK-NEXT:    lw a2, 0(a2)
; CHECK-NEXT:    psaddu.b a1, a1, a2
; CHECK-NEXT:    sw a1, 0(a0)
; CHECK-NEXT:    ret
  %a = load <4 x i8>, ptr %a_ptr
  %b = load <4 x i8>, ptr %b_ptr
  %res = call <4 x i8> @llvm.uadd.sat.v4i8(<4 x i8> %a, <4 x i8> %b)
  store <4 x i8> %res, ptr %ret_ptr
  ret void
}

; Test saturating sub operations for v4i8
define void @test_pssub_b(ptr %ret_ptr, ptr %a_ptr, ptr %b_ptr) {
; CHECK-LABEL: test_pssub_b:
; CHECK:       # %bb.0:
; CHECK-NEXT:    lw a1, 0(a1)
; CHECK-NEXT:    lw a2, 0(a2)
; CHECK-NEXT:    pssub.b a1, a1, a2
; CHECK-NEXT:    sw a1, 0(a0)
; CHECK-NEXT:    ret
  %a = load <4 x i8>, ptr %a_ptr
  %b = load <4 x i8>, ptr %b_ptr
  %res = call <4 x i8> @llvm.ssub.sat.v4i8(<4 x i8> %a, <4 x i8> %b)
  store <4 x i8> %res, ptr %ret_ptr
  ret void
}

define void @test_pssubu_b(ptr %ret_ptr, ptr %a_ptr, ptr %b_ptr) {
; CHECK-LABEL: test_pssubu_b:
; CHECK:       # %bb.0:
; CHECK-NEXT:    lw a1, 0(a1)
; CHECK-NEXT:    lw a2, 0(a2)
; CHECK-NEXT:    pssubu.b a1, a1, a2
; CHECK-NEXT:    sw a1, 0(a0)
; CHECK-NEXT:    ret
  %a = load <4 x i8>, ptr %a_ptr
  %b = load <4 x i8>, ptr %b_ptr
  %res = call <4 x i8> @llvm.usub.sat.v4i8(<4 x i8> %a, <4 x i8> %b)
  store <4 x i8> %res, ptr %ret_ptr
  ret void
}

; Test averaging floor signed operations for v2i16
define void @test_paadd_h(ptr %ret_ptr, ptr %a_ptr, ptr %b_ptr) {
; CHECK-LABEL: test_paadd_h:
; CHECK:       # %bb.0:
; CHECK-NEXT:    lw a1, 0(a1)
; CHECK-NEXT:    lw a2, 0(a2)
; CHECK-NEXT:    paadd.h a1, a1, a2
; CHECK-NEXT:    sw a1, 0(a0)
; CHECK-NEXT:    ret
  %a = load <2 x i16>, ptr %a_ptr
  %b = load <2 x i16>, ptr %b_ptr
  %ext.a = sext <2 x i16> %a to <2 x i32>
  %ext.b = sext <2 x i16> %b to <2 x i32>
  %add = add nsw <2 x i32> %ext.a, %ext.b
  %shift = ashr <2 x i32> %add, <i32 1, i32 1>
  %res = trunc <2 x i32> %shift to <2 x i16>
  store <2 x i16> %res, ptr %ret_ptr
  ret void
}

; Test averaging floor unsigned operations for v2i16
define void @test_paaddu_h(ptr %ret_ptr, ptr %a_ptr, ptr %b_ptr) {
; CHECK-LABEL: test_paaddu_h:
; CHECK:       # %bb.0:
; CHECK-NEXT:    lw a1, 0(a1)
; CHECK-NEXT:    lw a2, 0(a2)
; CHECK-NEXT:    paaddu.h a1, a1, a2
; CHECK-NEXT:    sw a1, 0(a0)
; CHECK-NEXT:    ret
  %a = load <2 x i16>, ptr %a_ptr
  %b = load <2 x i16>, ptr %b_ptr
  %and = and <2 x i16> %a, %b
  %xor = xor <2 x i16> %a, %b
  %shift = lshr <2 x i16> %xor, <i16 1, i16 1>
  %res = add <2 x i16> %and, %shift
  store <2 x i16> %res, ptr %ret_ptr
  ret void
}

; Test averaging floor signed operations for v4i8
define void @test_paadd_b(ptr %ret_ptr, ptr %a_ptr, ptr %b_ptr) {
; CHECK-LABEL: test_paadd_b:
; CHECK:       # %bb.0:
; CHECK-NEXT:    lw a1, 0(a1)
; CHECK-NEXT:    lw a2, 0(a2)
; CHECK-NEXT:    paadd.b a1, a1, a2
; CHECK-NEXT:    sw a1, 0(a0)
; CHECK-NEXT:    ret
  %a = load <4 x i8>, ptr %a_ptr
  %b = load <4 x i8>, ptr %b_ptr
  %ext.a = sext <4 x i8> %a to <4 x i16>
  %ext.b = sext <4 x i8> %b to <4 x i16>
  %add = add nsw <4 x i16> %ext.a, %ext.b
  %shift = ashr <4 x i16> %add, <i16 1, i16 1, i16 1, i16 1>
  %res = trunc <4 x i16> %shift to <4 x i8>
  store <4 x i8> %res, ptr %ret_ptr
  ret void
}

; Test averaging floor unsigned operations for v4i8
define void @test_paaddu_b(ptr %ret_ptr, ptr %a_ptr, ptr %b_ptr) {
; CHECK-LABEL: test_paaddu_b:
; CHECK:       # %bb.0:
; CHECK-NEXT:    lw a1, 0(a1)
; CHECK-NEXT:    lw a2, 0(a2)
; CHECK-NEXT:    paaddu.b a1, a1, a2
; CHECK-NEXT:    sw a1, 0(a0)
; CHECK-NEXT:    ret
  %a = load <4 x i8>, ptr %a_ptr
  %b = load <4 x i8>, ptr %b_ptr
  %and = and <4 x i8> %a, %b
  %xor = xor <4 x i8> %a, %b
  %shift = lshr <4 x i8> %xor, <i8 1, i8 1, i8 1, i8 1>
  %res = add <4 x i8> %and, %shift
  store <4 x i8> %res, ptr %ret_ptr
  ret void
}

; Test absolute difference signed for v2i16
define void @test_pdif_h(ptr %ret_ptr, ptr %a_ptr, ptr %b_ptr) {
; CHECK-LABEL: test_pdif_h:
; CHECK:       # %bb.0:
; CHECK-NEXT:    lw a1, 0(a1)
; CHECK-NEXT:    lw a2, 0(a2)
; CHECK-NEXT:    pdif.h a1, a1, a2
; CHECK-NEXT:    sw a1, 0(a0)
; CHECK-NEXT:    ret
  %a = load <2 x i16>, ptr %a_ptr
  %b = load <2 x i16>, ptr %b_ptr
  %min = call <2 x i16> @llvm.smin.v2i16(<2 x i16> %a, <2 x i16> %b)
  %max = call <2 x i16> @llvm.smax.v2i16(<2 x i16> %a, <2 x i16> %b)
  %res = sub <2 x i16> %max, %min
  store <2 x i16> %res, ptr %ret_ptr
  ret void
}

; Test absolute difference unsigned for v2i16
define void @test_pdifu_h(ptr %ret_ptr, ptr %a_ptr, ptr %b_ptr) {
; CHECK-LABEL: test_pdifu_h:
; CHECK:       # %bb.0:
; CHECK-NEXT:    lw a1, 0(a1)
; CHECK-NEXT:    lw a2, 0(a2)
; CHECK-NEXT:    pdifu.h a1, a1, a2
; CHECK-NEXT:    sw a1, 0(a0)
; CHECK-NEXT:    ret
  %a = load <2 x i16>, ptr %a_ptr
  %b = load <2 x i16>, ptr %b_ptr
  %min = call <2 x i16> @llvm.umin.v2i16(<2 x i16> %a, <2 x i16> %b)
  %max = call <2 x i16> @llvm.umax.v2i16(<2 x i16> %a, <2 x i16> %b)
  %res = sub <2 x i16> %max, %min
  store <2 x i16> %res, ptr %ret_ptr
  ret void
}

; Test absolute difference signed for v4i8
define void @test_pdif_b(ptr %ret_ptr, ptr %a_ptr, ptr %b_ptr) {
; CHECK-LABEL: test_pdif_b:
; CHECK:       # %bb.0:
; CHECK-NEXT:    lw a1, 0(a1)
; CHECK-NEXT:    lw a2, 0(a2)
; CHECK-NEXT:    pdif.b a1, a1, a2
; CHECK-NEXT:    sw a1, 0(a0)
; CHECK-NEXT:    ret
  %a = load <4 x i8>, ptr %a_ptr
  %b = load <4 x i8>, ptr %b_ptr
  %min = call <4 x i8> @llvm.smin.v4i8(<4 x i8> %a, <4 x i8> %b)
  %max = call <4 x i8> @llvm.smax.v4i8(<4 x i8> %a, <4 x i8> %b)
  %res = sub <4 x i8> %max, %min
  store <4 x i8> %res, ptr %ret_ptr
  ret void
}

; Test absolute difference unsigned for v4i8
define void @test_pdifu_b(ptr %ret_ptr, ptr %a_ptr, ptr %b_ptr) {
; CHECK-LABEL: test_pdifu_b:
; CHECK:       # %bb.0:
; CHECK-NEXT:    lw a1, 0(a1)
; CHECK-NEXT:    lw a2, 0(a2)
; CHECK-NEXT:    pdifu.b a1, a1, a2
; CHECK-NEXT:    sw a1, 0(a0)
; CHECK-NEXT:    ret
  %a = load <4 x i8>, ptr %a_ptr
  %b = load <4 x i8>, ptr %b_ptr
  %min = call <4 x i8> @llvm.umin.v4i8(<4 x i8> %a, <4 x i8> %b)
  %max = call <4 x i8> @llvm.umax.v4i8(<4 x i8> %a, <4 x i8> %b)
  %res = sub <4 x i8> %max, %min
  store <4 x i8> %res, ptr %ret_ptr
  ret void
}

; Test averaging floor subtraction signed for v2i16
; pasub pattern: (a - b) arithmetic shift right 1
define void @test_pasub_h(ptr %ret_ptr, ptr %a_ptr, ptr %b_ptr) {
; CHECK-LABEL: test_pasub_h:
; CHECK:       # %bb.0:
; CHECK-NEXT:    lw a1, 0(a1)
; CHECK-NEXT:    lw a2, 0(a2)
; CHECK-NEXT:    pasub.h a1, a1, a2
; CHECK-NEXT:    sw a1, 0(a0)
; CHECK-NEXT:    ret
  %a = load <2 x i16>, ptr %a_ptr
  %b = load <2 x i16>, ptr %b_ptr
  %a_ext = sext <2 x i16> %a to <2 x i32>
  %b_ext = sext <2 x i16> %b to <2 x i32>
  %sub = sub <2 x i32> %a_ext, %b_ext
  %res = ashr <2 x i32> %sub, <i32 1, i32 1>
  %res_trunc = trunc <2 x i32> %res to <2 x i16>
  store <2 x i16> %res_trunc, ptr %ret_ptr
  ret void
}

; Test averaging floor subtraction unsigned for v2i16
; pasubu pattern: (a - b) logical shift right 1
define void @test_pasubu_h(ptr %ret_ptr, ptr %a_ptr, ptr %b_ptr) {
; CHECK-LABEL: test_pasubu_h:
; CHECK:       # %bb.0:
; CHECK-NEXT:    lw a1, 0(a1)
; CHECK-NEXT:    lw a2, 0(a2)
; CHECK-NEXT:    pasubu.h a1, a1, a2
; CHECK-NEXT:    sw a1, 0(a0)
; CHECK-NEXT:    ret
  %a = load <2 x i16>, ptr %a_ptr
  %b = load <2 x i16>, ptr %b_ptr
  %a_ext = zext <2 x i16> %a to <2 x i32>
  %b_ext = zext <2 x i16> %b to <2 x i32>
  %sub = sub <2 x i32> %a_ext, %b_ext
  %res = lshr <2 x i32> %sub, <i32 1, i32 1>
  %res_trunc = trunc <2 x i32> %res to <2 x i16>
  store <2 x i16> %res_trunc, ptr %ret_ptr
  ret void
}

; Test averaging floor subtraction signed for v4i8
define void @test_pasub_b(ptr %ret_ptr, ptr %a_ptr, ptr %b_ptr) {
; CHECK-LABEL: test_pasub_b:
; CHECK:       # %bb.0:
; CHECK-NEXT:    lw a1, 0(a1)
; CHECK-NEXT:    lw a2, 0(a2)
; CHECK-NEXT:    pasub.b a1, a1, a2
; CHECK-NEXT:    sw a1, 0(a0)
; CHECK-NEXT:    ret
  %a = load <4 x i8>, ptr %a_ptr
  %b = load <4 x i8>, ptr %b_ptr
  %a_ext = sext <4 x i8> %a to <4 x i16>
  %b_ext = sext <4 x i8> %b to <4 x i16>
  %sub = sub <4 x i16> %a_ext, %b_ext
  %res = ashr <4 x i16> %sub, <i16 1, i16 1, i16 1, i16 1>
  %res_trunc = trunc <4 x i16> %res to <4 x i8>
  store <4 x i8> %res_trunc, ptr %ret_ptr
  ret void
}

; Test averaging floor subtraction unsigned for v4i8
define void @test_pasubu_b(ptr %ret_ptr, ptr %a_ptr, ptr %b_ptr) {
; CHECK-LABEL: test_pasubu_b:
; CHECK:       # %bb.0:
; CHECK-NEXT:    lw a1, 0(a1)
; CHECK-NEXT:    lw a2, 0(a2)
; CHECK-NEXT:    pasubu.b a1, a1, a2
; CHECK-NEXT:    sw a1, 0(a0)
; CHECK-NEXT:    ret
  %a = load <4 x i8>, ptr %a_ptr
  %b = load <4 x i8>, ptr %b_ptr
  %a_ext = zext <4 x i8> %a to <4 x i16>
  %b_ext = zext <4 x i8> %b to <4 x i16>
  %sub = sub <4 x i16> %a_ext, %b_ext
  %res = lshr <4 x i16> %sub, <i16 1, i16 1, i16 1, i16 1>
  %res_trunc = trunc <4 x i16> %res to <4 x i8>
  store <4 x i8> %res_trunc, ptr %ret_ptr
  ret void
}

; Test PLI (pack load immediate) for v2i16
define void @test_pli_h(ptr %ret_ptr) {
; CHECK-LABEL: test_pli_h:
; CHECK:       # %bb.0:
; CHECK-NEXT:    pli.h a1, 42
; CHECK-NEXT:    sw a1, 0(a0)
; CHECK-NEXT:    ret
  %res = add <2 x i16> <i16 42, i16 42>, <i16 0, i16 0>
  store <2 x i16> %res, ptr %ret_ptr
  ret void
}

define void @test_pli_h_negative(ptr %ret_ptr) {
; CHECK-LABEL: test_pli_h_negative:
; CHECK:       # %bb.0:
; CHECK-NEXT:    pli.h a1, -5
; CHECK-NEXT:    sw a1, 0(a0)
; CHECK-NEXT:    ret
  %res = add <2 x i16> <i16 -5, i16 -5>, <i16 0, i16 0>
  store <2 x i16> %res, ptr %ret_ptr
  ret void
}

; Test PLI for v4i8 with unsigned immediate
define void @test_pli_b(ptr %ret_ptr) {
; CHECK-LABEL: test_pli_b:
; CHECK:       # %bb.0:
; CHECK-NEXT:    pli.b a1, 32
; CHECK-NEXT:    sw a1, 0(a0)
; CHECK-NEXT:    ret
  %res = add <4 x i8> <i8 32, i8 32, i8 32, i8 32>, <i8 0, i8 0, i8 0, i8 0>
  store <4 x i8> %res, ptr %ret_ptr
  ret void
}

define void @test_pli_b_negative(ptr %ret_ptr) {
; CHECK-RV32-LABEL: test_pli_b_negative:
; CHECK-RV32:       # %bb.0:
; CHECK-RV32-NEXT:    pli.b a1, -2
; CHECK-RV32-NEXT:    sw a1, 0(a0)
; CHECK-RV32-NEXT:    ret
;
; CHECK-RV64-LABEL: test_pli_b_negative:
; CHECK-RV64:       # %bb.0:
; CHECK-RV64-NEXT:    pli.h a1, -258
; CHECK-RV64-NEXT:    sw a1, 0(a0)
; CHECK-RV64-NEXT:    ret
  %res = add <4 x i8> <i8 -2, i8 -2, i8 -2, i8 -2>, <i8 0, i8 0, i8 0, i8 0>
  store <4 x i8> %res, ptr %ret_ptr
  ret void
}

define void @test_extract_vector_16(ptr %ret_ptr, ptr %a_ptr) {
; CHECK-LABEL: test_extract_vector_16:
; CHECK:       # %bb.0:
; CHECK-NEXT:    lw a1, 0(a1)
; CHECK-NEXT:    sh a1, 0(a0)
; CHECK-NEXT:    ret
  %a = load <2 x i16>, ptr %a_ptr
  %extracted = extractelement <2 x i16> %a, i32 0
  store i16 %extracted, ptr %ret_ptr
  ret void
}

define void @test_extract_vector_16_elem1(ptr %ret_ptr, ptr %a_ptr) {
; CHECK-RV32-LABEL: test_extract_vector_16_elem1:
; CHECK-RV32:       # %bb.0:
; CHECK-RV32-NEXT:    lhu a1, 2(a1)
; CHECK-RV32-NEXT:    sh a1, 0(a0)
; CHECK-RV32-NEXT:    ret
;
; CHECK-RV64-LABEL: test_extract_vector_16_elem1:
; CHECK-RV64:       # %bb.0:
; CHECK-RV64-NEXT:    lw a1, 0(a1)
; CHECK-RV64-NEXT:    srli a1, a1, 16
; CHECK-RV64-NEXT:    sh a1, 0(a0)
; CHECK-RV64-NEXT:    ret
  %a = load <2 x i16>, ptr %a_ptr
  %extracted = extractelement <2 x i16> %a, i32 1
  store i16 %extracted, ptr %ret_ptr
  ret void
}

define void @test_extract_vector_8(ptr %ret_ptr, ptr %a_ptr) {
; CHECK-LABEL: test_extract_vector_8:
; CHECK:       # %bb.0:
; CHECK-NEXT:    lw a1, 0(a1)
; CHECK-NEXT:    sb a1, 0(a0)
; CHECK-NEXT:    ret
  %a = load <4 x i8>, ptr %a_ptr
  %extracted = extractelement <4 x i8> %a, i32 0
  store i8 %extracted, ptr %ret_ptr
  ret void
}

define void @test_extract_vector_8_elem1(ptr %ret_ptr, ptr %a_ptr) {
; CHECK-LABEL: test_extract_vector_8_elem1:
; CHECK:       # %bb.0:
; CHECK-NEXT:    lw a1, 0(a1)
; CHECK-NEXT:    srli a1, a1, 8
; CHECK-NEXT:    sb a1, 0(a0)
; CHECK-NEXT:    ret
  %a = load <4 x i8>, ptr %a_ptr
  %extracted = extractelement <4 x i8> %a, i32 1
  store i8 %extracted, ptr %ret_ptr
  ret void
}

; Test for splat
define void @test_non_const_splat_i8(ptr %ret_ptr, ptr %a_ptr, i8 %elt) {
; CHECK-LABEL: test_non_const_splat_i8:
; CHECK:       # %bb.0:
; CHECK-NEXT:    padd.bs a1, zero, a2
; CHECK-NEXT:    sw a1, 0(a0)
; CHECK-NEXT:    ret
  %a = load <4 x i8>, ptr %a_ptr
  %insert = insertelement <4 x i8> poison, i8 %elt, i32 0
  %splat = shufflevector <4 x i8> %insert, <4 x i8> poison, <4 x i32> zeroinitializer
  store <4 x i8> %splat, ptr %ret_ptr
  ret void
}

define void @test_non_const_splat_i16(ptr %ret_ptr, ptr %a_ptr, i16 %elt) {
; CHECK-LABEL: test_non_const_splat_i16:
; CHECK:       # %bb.0:
; CHECK-NEXT:    padd.hs a1, zero, a2
; CHECK-NEXT:    sw a1, 0(a0)
; CHECK-NEXT:    ret
  %a = load <2 x i16>, ptr %a_ptr
  %insert = insertelement <2 x i16> poison, i16 %elt, i32 0
  %splat = shufflevector <2 x i16> %insert, <2 x i16> poison, <2 x i32> zeroinitializer
  store <2 x i16> %splat, ptr %ret_ptr
  ret void
}

define void @test_build_vector_i8(i8 %a, i8 %c, i8 %b, i8 %d, ptr %ret_ptr) {
; CHECK-RV32-LABEL: test_build_vector_i8:
; CHECK-RV32:       # %bb.0:
; CHECK-RV32-NEXT:    ppack.dh a0, a0, a2
; CHECK-RV32-NEXT:    pack a0, a0, a1
; CHECK-RV32-NEXT:    sw a0, 0(a4)
; CHECK-RV32-NEXT:    ret
;
; CHECK-RV64-LABEL: test_build_vector_i8:
; CHECK-RV64:       # %bb.0:
; CHECK-RV64-NEXT:    ppack.h a1, a1, a3
; CHECK-RV64-NEXT:    ppack.h a0, a0, a2
; CHECK-RV64-NEXT:    ppack.w a0, a0, a1
; CHECK-RV64-NEXT:    sw a0, 0(a4)
; CHECK-RV64-NEXT:    ret
  %v0 = insertelement <4 x i8> poison, i8 %a, i32 0
  %v1 = insertelement <4 x i8> %v0, i8 %b, i32 1
  %v2 = insertelement <4 x i8> %v1, i8 %c, i32 2
  %v3 = insertelement <4 x i8> %v2, i8 %d, i32 3
  store <4 x i8> %v3, ptr %ret_ptr
  ret void
}

define void @test_build_vector_i16(ptr %ret_ptr, i16 %a, i16 %b) {
; CHECK-RV32-LABEL: test_build_vector_i16:
; CHECK-RV32:       # %bb.0:
; CHECK-RV32-NEXT:    pack a1, a1, a2
; CHECK-RV32-NEXT:    sw a1, 0(a0)
; CHECK-RV32-NEXT:    ret
;
; CHECK-RV64-LABEL: test_build_vector_i16:
; CHECK-RV64:       # %bb.0:
; CHECK-RV64-NEXT:    ppack.w a1, a1, a2
; CHECK-RV64-NEXT:    sw a1, 0(a0)
; CHECK-RV64-NEXT:    ret
  %v0 = insertelement <2 x i16> poison, i16 %a, i32 0
  %v1 = insertelement <2 x i16> %v0, i16 %b, i32 1
  store <2 x i16> %v1, ptr %ret_ptr
  ret void
}

; Test logical shift left immediate for v2i16
define void @test_pslli_h(ptr %ret_ptr, ptr %a_ptr) {
; CHECK-LABEL: test_pslli_h:
; CHECK:       # %bb.0:
; CHECK-NEXT:    lw a1, 0(a1)
; CHECK-NEXT:    pslli.h a1, a1, 2
; CHECK-NEXT:    sw a1, 0(a0)
; CHECK-NEXT:    ret
  %a = load <2 x i16>, ptr %a_ptr
  %res = shl <2 x i16> %a, splat(i16 2)
  store <2 x i16> %res, ptr %ret_ptr
  ret void
}

; Test logical shift left immediate for v4i8
define void @test_pslli_b(ptr %ret_ptr, ptr %a_ptr) {
; CHECK-LABEL: test_pslli_b:
; CHECK:       # %bb.0:
; CHECK-NEXT:    lw a1, 0(a1)
; CHECK-NEXT:    pslli.b a1, a1, 2
; CHECK-NEXT:    sw a1, 0(a0)
; CHECK-NEXT:    ret
  %a = load <4 x i8>, ptr %a_ptr
  %res = shl <4 x i8> %a, splat(i8 2)
  store <4 x i8> %res, ptr %ret_ptr
  ret void
}

; Test arithmetic saturation shift left immediate for v2i16
define void @test_psslai_h(ptr %ret_ptr, ptr %a_ptr) {
; CHECK-LABEL: test_psslai_h:
; CHECK:       # %bb.0:
; CHECK-NEXT:    lw a1, 0(a1)
; CHECK-NEXT:    psslai.h a1, a1, 2
; CHECK-NEXT:    sw a1, 0(a0)
; CHECK-NEXT:    ret
  %a = load <2 x i16>, ptr %a_ptr
  %res = call <2 x i16> @llvm.sshl.sat.v2i16(<2 x i16> %a, <2 x i16> splat(i16 2))
  store <2 x i16> %res, ptr %ret_ptr
  ret void
}
