[llvm] f3c577e - [AArch64][SVE] Add fixed length codegen for FP_TO_{S,U}INT/{S,U}INT_TO_FP

Bradley Smith via llvm-commits llvm-commits at lists.llvm.org
Tue May 25 04:55:35 PDT 2021


Author: Bradley Smith
Date: 2021-05-25T12:54:55+01:00
New Revision: f3c577ed38e55dca46692313f5b76688a115861a

URL: https://github.com/llvm/llvm-project/commit/f3c577ed38e55dca46692313f5b76688a115861a
DIFF: https://github.com/llvm/llvm-project/commit/f3c577ed38e55dca46692313f5b76688a115861a.diff

LOG: [AArch64][SVE] Add fixed length codegen for FP_TO_{S,U}INT/{S,U}INT_TO_FP

Depends on D102607

Differential Revision: https://reviews.llvm.org/D102777

Added: 
    llvm/test/CodeGen/AArch64/sve-fixed-length-fp-to-int.ll
    llvm/test/CodeGen/AArch64/sve-fixed-length-int-to-fp.ll

Modified: 
    llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
    llvm/lib/Target/AArch64/AArch64ISelLowering.h

Removed: 
    llvm/test/CodeGen/AArch64/sve-fixed-length-fp-converts.ll


################################################################################
diff  --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index 204d1a8081ab3..d949a6e95d32c 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -1482,6 +1482,8 @@ void AArch64TargetLowering::addTypeForFixedLengthSVE(MVT VT) {
   setOperationAction(ISD::FNEG, VT, Custom);
   setOperationAction(ISD::FP_EXTEND, VT, Custom);
   setOperationAction(ISD::FP_ROUND, VT, Custom);
+  setOperationAction(ISD::FP_TO_SINT, VT, Custom);
+  setOperationAction(ISD::FP_TO_UINT, VT, Custom);
   setOperationAction(ISD::FRINT, VT, Custom);
   setOperationAction(ISD::FROUND, VT, Custom);
   setOperationAction(ISD::FROUNDEVEN, VT, Custom);
@@ -1501,6 +1503,7 @@ void AArch64TargetLowering::addTypeForFixedLengthSVE(MVT VT) {
   setOperationAction(ISD::SHL, VT, Custom);
   setOperationAction(ISD::SIGN_EXTEND, VT, Custom);
   setOperationAction(ISD::SIGN_EXTEND_INREG, VT, Custom);
+  setOperationAction(ISD::SINT_TO_FP, VT, Custom);
   setOperationAction(ISD::SMAX, VT, Custom);
   setOperationAction(ISD::SMIN, VT, Custom);
   setOperationAction(ISD::SPLAT_VECTOR, VT, Custom);
@@ -1510,6 +1513,7 @@ void AArch64TargetLowering::addTypeForFixedLengthSVE(MVT VT) {
   setOperationAction(ISD::SUB, VT, Custom);
   setOperationAction(ISD::TRUNCATE, VT, Custom);
   setOperationAction(ISD::UDIV, VT, Custom);
+  setOperationAction(ISD::UINT_TO_FP, VT, Custom);
   setOperationAction(ISD::UMAX, VT, Custom);
   setOperationAction(ISD::UMIN, VT, Custom);
   setOperationAction(ISD::VECREDUCE_ADD, VT, Custom);
@@ -3260,6 +3264,9 @@ SDValue AArch64TargetLowering::LowerVectorFP_TO_INT(SDValue Op,
     return LowerToPredicatedOp(Op, DAG, Opcode);
   }
 
+  if (useSVEForFixedLengthVectorVT(VT) || useSVEForFixedLengthVectorVT(InVT))
+    return LowerFixedLengthFPToIntToSVE(Op, DAG);
+
   unsigned NumElts = InVT.getVectorNumElements();
 
   // f16 conversions are promoted to f32 when full fp16 is not supported.
@@ -3384,6 +3391,9 @@ SDValue AArch64TargetLowering::LowerVectorINT_TO_FP(SDValue Op,
     return LowerToPredicatedOp(Op, DAG, Opcode);
   }
 
+  if (useSVEForFixedLengthVectorVT(VT) || useSVEForFixedLengthVectorVT(InVT))
+    return LowerFixedLengthIntToFPToSVE(Op, DAG);
+
   uint64_t VTSize = VT.getFixedSizeInBits();
   uint64_t InVTSize = InVT.getFixedSizeInBits();
   if (VTSize < InVTSize) {
@@ -17994,6 +18004,95 @@ AArch64TargetLowering::LowerFixedLengthFPRoundToSVE(SDValue Op,
   return DAG.getNode(ISD::BITCAST, DL, VT, Val);
 }
 
+SDValue
+AArch64TargetLowering::LowerFixedLengthIntToFPToSVE(SDValue Op,
+                                                    SelectionDAG &DAG) const {
+  EVT VT = Op.getValueType();
+  assert(VT.isFixedLengthVector() && "Expected fixed length vector type!");
+
+  bool IsSigned = Op.getOpcode() == ISD::SINT_TO_FP;
+  unsigned Opcode = IsSigned ? AArch64ISD::SINT_TO_FP_MERGE_PASSTHRU
+                             : AArch64ISD::UINT_TO_FP_MERGE_PASSTHRU;
+
+  SDLoc DL(Op);
+  SDValue Val = Op.getOperand(0);
+  EVT SrcVT = Val.getValueType();
+  EVT ContainerDstVT = getContainerForFixedLengthVector(DAG, VT);
+  EVT ContainerSrcVT = getContainerForFixedLengthVector(DAG, SrcVT);
+
+  if (ContainerSrcVT.getVectorElementType().getSizeInBits() <=
+      ContainerDstVT.getVectorElementType().getSizeInBits()) {
+    SDValue Pg = getPredicateForVector(DAG, DL, VT);
+
+    Val = DAG.getNode(IsSigned ? ISD::SIGN_EXTEND : ISD::ZERO_EXTEND, DL,
+                      VT.changeTypeToInteger(), Val);
+
+    Val = convertToScalableVector(DAG, ContainerSrcVT, Val);
+    Val = getSVESafeBitCast(ContainerDstVT.changeTypeToInteger(), Val, DAG);
+    // Safe to use a larger than specified operand since we just unpacked the
+    // data, hence the upper bits are zero.
+    Val = DAG.getNode(Opcode, DL, ContainerDstVT, Pg, Val,
+                      DAG.getUNDEF(ContainerDstVT));
+    return convertFromScalableVector(DAG, VT, Val);
+  } else {
+    EVT CvtVT = ContainerSrcVT.changeVectorElementType(
+        ContainerDstVT.getVectorElementType());
+    SDValue Pg = getPredicateForVector(DAG, DL, CvtVT);
+
+    Val = convertToScalableVector(DAG, ContainerSrcVT, Val);
+    Val = DAG.getNode(Opcode, DL, CvtVT, Pg, Val, DAG.getUNDEF(CvtVT));
+    Val = getSVESafeBitCast(ContainerSrcVT, Val, DAG);
+    Val = convertFromScalableVector(DAG, SrcVT, Val);
+
+    Val = DAG.getNode(ISD::TRUNCATE, DL, VT.changeTypeToInteger(), Val);
+    return DAG.getNode(ISD::BITCAST, DL, VT, Val);
+  }
+}
+
+SDValue
+AArch64TargetLowering::LowerFixedLengthFPToIntToSVE(SDValue Op,
+                                                    SelectionDAG &DAG) const {
+  EVT VT = Op.getValueType();
+  assert(VT.isFixedLengthVector() && "Expected fixed length vector type!");
+
+  bool IsSigned = Op.getOpcode() == ISD::FP_TO_SINT;
+  unsigned Opcode = IsSigned ? AArch64ISD::FCVTZS_MERGE_PASSTHRU
+                             : AArch64ISD::FCVTZU_MERGE_PASSTHRU;
+
+  SDLoc DL(Op);
+  SDValue Val = Op.getOperand(0);
+  EVT SrcVT = Val.getValueType();
+  EVT ContainerDstVT = getContainerForFixedLengthVector(DAG, VT);
+  EVT ContainerSrcVT = getContainerForFixedLengthVector(DAG, SrcVT);
+
+  if (ContainerSrcVT.getVectorElementType().getSizeInBits() <=
+      ContainerDstVT.getVectorElementType().getSizeInBits()) {
+    EVT CvtVT = ContainerDstVT.changeVectorElementType(
+      ContainerSrcVT.getVectorElementType());
+    SDValue Pg = getPredicateForVector(DAG, DL, VT);
+
+    Val = DAG.getNode(ISD::BITCAST, DL, SrcVT.changeTypeToInteger(), Val);
+    Val = DAG.getNode(ISD::ANY_EXTEND, DL, VT, Val);
+
+    Val = convertToScalableVector(DAG, ContainerSrcVT, Val);
+    Val = getSVESafeBitCast(CvtVT, Val, DAG);
+    Val = DAG.getNode(Opcode, DL, ContainerDstVT, Pg, Val,
+                      DAG.getUNDEF(ContainerDstVT));
+    return convertFromScalableVector(DAG, VT, Val);
+  } else {
+    EVT CvtVT = ContainerSrcVT.changeTypeToInteger();
+    SDValue Pg = getPredicateForVector(DAG, DL, CvtVT);
+
+    // Safe to use a larger than specified result since an fp_to_int where the
+    // result doesn't fit into the destination is undefined.
+    Val = convertToScalableVector(DAG, ContainerSrcVT, Val);
+    Val = DAG.getNode(Opcode, DL, CvtVT, Pg, Val, DAG.getUNDEF(CvtVT));
+    Val = convertFromScalableVector(DAG, SrcVT.changeTypeToInteger(), Val);
+
+    return DAG.getNode(ISD::TRUNCATE, DL, VT, Val);
+  }
+}
+
 SDValue AArch64TargetLowering::getSVESafeBitCast(EVT VT, SDValue Op,
                                                  SelectionDAG &DAG) const {
   SDLoc DL(Op);

diff  --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.h b/llvm/lib/Target/AArch64/AArch64ISelLowering.h
index d756bb4d1f69b..40734292f24d7 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.h
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.h
@@ -1005,6 +1005,8 @@ class AArch64TargetLowering : public TargetLowering {
                                              SelectionDAG &DAG) const;
   SDValue LowerFixedLengthFPExtendToSVE(SDValue Op, SelectionDAG &DAG) const;
   SDValue LowerFixedLengthFPRoundToSVE(SDValue Op, SelectionDAG &DAG) const;
+  SDValue LowerFixedLengthIntToFPToSVE(SDValue Op, SelectionDAG &DAG) const;
+  SDValue LowerFixedLengthFPToIntToSVE(SDValue Op, SelectionDAG &DAG) const;
 
   SDValue BuildSDIVPow2(SDNode *N, const APInt &Divisor, SelectionDAG &DAG,
                         SmallVectorImpl<SDNode *> &Created) const override;

diff  --git a/llvm/test/CodeGen/AArch64/sve-fixed-length-fp-converts.ll b/llvm/test/CodeGen/AArch64/sve-fixed-length-fp-converts.ll
deleted file mode 100644
index 86a4e74acaa61..0000000000000
--- a/llvm/test/CodeGen/AArch64/sve-fixed-length-fp-converts.ll
+++ /dev/null
@@ -1,70 +0,0 @@
-; RUN: llc -aarch64-sve-vector-bits-min=128  -asm-verbose=0 < %s | FileCheck %s -check-prefix=NO_SVE
-; RUN: llc -aarch64-sve-vector-bits-min=256  -asm-verbose=0 < %s | FileCheck %s
-; RUN: llc -aarch64-sve-vector-bits-min=384  -asm-verbose=0 < %s | FileCheck %s
-; RUN: llc -aarch64-sve-vector-bits-min=512  -asm-verbose=0 < %s | FileCheck %s
-; RUN: llc -aarch64-sve-vector-bits-min=640  -asm-verbose=0 < %s | FileCheck %s
-; RUN: llc -aarch64-sve-vector-bits-min=768  -asm-verbose=0 < %s | FileCheck %s
-; RUN: llc -aarch64-sve-vector-bits-min=896  -asm-verbose=0 < %s | FileCheck %s
-; RUN: llc -aarch64-sve-vector-bits-min=1024 -asm-verbose=0 < %s | FileCheck %s
-; RUN: llc -aarch64-sve-vector-bits-min=1152 -asm-verbose=0 < %s | FileCheck %s
-; RUN: llc -aarch64-sve-vector-bits-min=1280 -asm-verbose=0 < %s | FileCheck %s
-; RUN: llc -aarch64-sve-vector-bits-min=1408 -asm-verbose=0 < %s | FileCheck %s
-; RUN: llc -aarch64-sve-vector-bits-min=1536 -asm-verbose=0 < %s | FileCheck %s
-; RUN: llc -aarch64-sve-vector-bits-min=1664 -asm-verbose=0 < %s | FileCheck %s
-; RUN: llc -aarch64-sve-vector-bits-min=1792 -asm-verbose=0 < %s | FileCheck %s
-; RUN: llc -aarch64-sve-vector-bits-min=1920 -asm-verbose=0 < %s | FileCheck %s
-; RUN: llc -aarch64-sve-vector-bits-min=2048 -asm-verbose=0 < %s | FileCheck %s
-
-target triple = "aarch64-unknown-linux-gnu"
-
-; Don't use SVE when its registers are no bigger than NEON.
-; NO_SVE-NOT: z{0-9}
-
-; NOTE: fptrunc operations bigger than NEON are expanded. These tests just
-; ensure we've correctly set the operation action for fixed length vector types
-; that require SVE. They'll be updated to protect their expected code generation
-; when lowering it implemented.
-
-;
-; vector uint_to_fp i8 -> f32
-; AArch64 doesn't have a direct vector->f32 conversion instructions for
-; elements smaller than i32, so make sure inputs are promoted to i32 first.
-;
-
-define void @uitofp_v4i8_v4f32(<4 x i8>* %in, <4 x float>* %out) #0 {
-; CHECK-LABEL: uitofp_v4i8_v4f32:
-; CHECK-COUNT-1: ucvt
-  %vec = load <4 x i8>, <4 x i8>* %in
-  %conv = uitofp <4 x i8> %vec to <4 x float>
-  store <4 x float> %conv, <4 x float>* %out
-  ret void
-}
-
-define void @uitofp_v8i8_v8f32(<8 x i8>* %in, <8 x float>* %out) #0 {
-; CHECK-LABEL: uitofp_v8i8_v8f32:
-; CHECK-COUNT-8: ucvt
-  %vec = load <8 x i8>, <8 x i8>* %in
-  %conv = uitofp <8 x i8> %vec to <8 x float>
-  store <8 x float> %conv, <8 x float>* %out
-  ret void
-}
-
-define void @uitofp_v16i8_v16f32(<16 x i8>* %in, <16 x float>* %out) #0 {
-; CHECK-LABEL: uitofp_v16i8_v16f32:
-; CHECK-COUNT-16: ucvt
-  %vec = load <16 x i8>, <16 x i8>* %in
-  %conv = uitofp <16 x i8> %vec to <16 x float>
-  store <16 x float> %conv, <16 x float>* %out
-  ret void
-}
-
-define void @uitofp_v32i8_v32f32(<32 x i8>* %in, <32 x float>* %out) #0 {
-; CHECK-LABEL: uitofp_v32i8_v32f32:
-; CHECK-COUNT-32: ucvt
-  %vec = load <32 x i8>, <32 x i8>* %in
-  %conv = uitofp <32 x i8> %vec to <32 x float>
-  store <32 x float> %conv, <32 x float>* %out
-  ret void
-}
-
-attributes #0 = { nounwind "target-features"="+sve" }

diff  --git a/llvm/test/CodeGen/AArch64/sve-fixed-length-fp-to-int.ll b/llvm/test/CodeGen/AArch64/sve-fixed-length-fp-to-int.ll
new file mode 100644
index 0000000000000..16880c7c493e5
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/sve-fixed-length-fp-to-int.ll
@@ -0,0 +1,1761 @@
+; RUN: llc -aarch64-sve-vector-bits-min=128  -asm-verbose=0 < %s | FileCheck %s -check-prefix=NO_SVE
+; RUN: llc -aarch64-sve-vector-bits-min=256  -asm-verbose=0 < %s | FileCheck %s -check-prefixes=CHECK,VBITS_EQ_256
+; RUN: llc -aarch64-sve-vector-bits-min=384  -asm-verbose=0 < %s | FileCheck %s -check-prefixes=CHECK
+; RUN: llc -aarch64-sve-vector-bits-min=512  -asm-verbose=0 < %s | FileCheck %s -check-prefixes=CHECK,VBITS_GE_512
+; RUN: llc -aarch64-sve-vector-bits-min=640  -asm-verbose=0 < %s | FileCheck %s -check-prefixes=CHECK,VBITS_GE_512
+; RUN: llc -aarch64-sve-vector-bits-min=768  -asm-verbose=0 < %s | FileCheck %s -check-prefixes=CHECK,VBITS_GE_512
+; RUN: llc -aarch64-sve-vector-bits-min=896  -asm-verbose=0 < %s | FileCheck %s -check-prefixes=CHECK,VBITS_GE_512
+; RUN: llc -aarch64-sve-vector-bits-min=1024 -asm-verbose=0 < %s | FileCheck %s -check-prefixes=CHECK,VBITS_GE_512,VBITS_GE_1024
+; RUN: llc -aarch64-sve-vector-bits-min=1152 -asm-verbose=0 < %s | FileCheck %s -check-prefixes=CHECK,VBITS_GE_512,VBITS_GE_1024
+; RUN: llc -aarch64-sve-vector-bits-min=1280 -asm-verbose=0 < %s | FileCheck %s -check-prefixes=CHECK,VBITS_GE_512,VBITS_GE_1024
+; RUN: llc -aarch64-sve-vector-bits-min=1408 -asm-verbose=0 < %s | FileCheck %s -check-prefixes=CHECK,VBITS_GE_512,VBITS_GE_1024
+; RUN: llc -aarch64-sve-vector-bits-min=1536 -asm-verbose=0 < %s | FileCheck %s -check-prefixes=CHECK,VBITS_GE_512,VBITS_GE_1024
+; RUN: llc -aarch64-sve-vector-bits-min=1664 -asm-verbose=0 < %s | FileCheck %s -check-prefixes=CHECK,VBITS_GE_512,VBITS_GE_1024
+; RUN: llc -aarch64-sve-vector-bits-min=1792 -asm-verbose=0 < %s | FileCheck %s -check-prefixes=CHECK,VBITS_GE_512,VBITS_GE_1024
+; RUN: llc -aarch64-sve-vector-bits-min=1920 -asm-verbose=0 < %s | FileCheck %s -check-prefixes=CHECK,VBITS_GE_512,VBITS_GE_1024
+; RUN: llc -aarch64-sve-vector-bits-min=2048 -asm-verbose=0 < %s | FileCheck %s -check-prefixes=CHECK,VBITS_GE_512,VBITS_GE_1024,VBITS_GE_2048
+
+target triple = "aarch64-unknown-linux-gnu"
+
+; Don't use SVE when its registers are no bigger than NEON.
+; NO_SVE-NOT: ptrue
+
+;
+; FCVTZU H -> H
+;
+
+; Don't use SVE for 64-bit vectors.
+define <4 x i16> @fcvtzu_v4f16_v4i16(<4 x half> %op1) #0 {
+; CHECK-LABEL: fcvtzu_v4f16_v4i16:
+; CHECK: fcvtzu v0.4h, v0.4h
+; CHECK-NEXT: ret
+  %res = fptoui <4 x half> %op1 to <4 x i16>
+  ret <4 x i16> %res
+}
+
+; Don't use SVE for 128-bit vectors.
+define void @fcvtzu_v8f16_v8i16(<8 x half>* %a, <8 x i16>* %b) #0 {
+; CHECK-LABEL: fcvtzu_v8f16_v8i16:
+; CHECK: ldr q0, [x0]
+; CHECK-NEXT: fcvtzu v0.8h, v0.8h
+; CHECK-NEXT: str q0, [x1]
+; CHECK-NEXT: ret
+  %op1 = load <8 x half>, <8 x half>* %a
+  %res = fptoui <8 x half> %op1 to <8 x i16>
+  store <8 x i16> %res, <8 x i16>* %b
+  ret void
+}
+
+define void @fcvtzu_v16f16_v16i16(<16 x half>* %a, <16 x i16>* %b) #0 {
+; CHECK-LABEL: fcvtzu_v16f16_v16i16:
+; CHECK: ptrue [[PG:p[0-9]+]].h, vl16
+; CHECK-NEXT: ld1h { [[OP:z[0-9]+]].h }, [[PG]]/z, [x0]
+; CHECK-NEXT: fcvtzu [[RES:z[0-9]+]].h, [[PG]]/m, [[OP]].h
+; CHECK-NEXT: st1h { [[RES]].h }, [[PG]], [x1]
+; CHECK-NEXT: ret
+  %op1 = load <16 x half>, <16 x half>* %a
+  %res = fptoui <16 x half> %op1 to <16 x i16>
+  store <16 x i16> %res, <16 x i16>* %b
+  ret void
+}
+
+define void @fcvtzu_v32f16_v32i16(<32 x half>* %a, <32 x i16>* %b) #0 {
+; CHECK-LABEL: fcvtzu_v32f16_v32i16:
+; VBITS_GE_512: ptrue [[PG:p[0-9]+]].h, vl32
+; VBITS_GE_512-NEXT: ld1h { [[OP:z[0-9]+]].h }, [[PG]]/z, [x0]
+; VBITS_GE_512-NEXT: fcvtzu [[RES:z[0-9]+]].h, [[PG]]/m, [[OP]].h
+; VBITS_GE_512-NEXT: st1h { [[RES]].h }, [[PG]], [x1]
+; VBITS_GE_512-NEXT: ret
+
+; Ensure sensible type legalisation.
+; VBITS_EQ_256: ptrue [[PG:p[0-9]+]].h, vl16
+; VBITS_EQ_256-NEXT: add x8, x0, #32
+; VBITS_EQ_256-NEXT: ld1h { [[LO:z[0-9]+]].h }, [[PG]]/z, [x0]
+; VBITS_EQ_256-NEXT: ld1h { [[HI:z[0-9]+]].h }, [[PG]]/z, [x8]
+; VBITS_EQ_256-NEXT: add x8, x1, #32
+; VBITS_EQ_256-NEXT: fcvtzu [[RES_LO:z[0-9]+]].h, [[PG]]/m, [[LO]].h
+; VBITS_EQ_256-NEXT: fcvtzu [[RES_HI:z[0-9]+]].h, [[PG]]/m, [[HI]].h
+; VBITS_EQ_256-NEXT: st1h { [[RES_LO]].h }, [[PG]], [x1]
+; VBITS_EQ_256-NEXT: st1h { [[RES_HI]].h }, [[PG]], [x8]
+; VBITS_EQ_256-NEXT: ret
+  %op1 = load <32 x half>, <32 x half>* %a
+  %res = fptoui <32 x half> %op1 to <32 x i16>
+  store <32 x i16> %res, <32 x i16>* %b
+  ret void
+}
+
+define void @fcvtzu_v64f16_v64i16(<64 x half>* %a, <64 x i16>* %b) #0 {
+; CHECK-LABEL: fcvtzu_v64f16_v64i16:
+; VBITS_GE_1024: ptrue [[PG:p[0-9]+]].h, vl64
+; VBITS_GE_1024-NEXT: ld1h { [[OP:z[0-9]+]].h }, [[PG]]/z, [x0]
+; VBITS_GE_1024-NEXT: fcvtzu [[RES:z[0-9]+]].h, [[PG]]/m, [[OP]].h
+; VBITS_GE_1024-NEXT: st1h { [[RES]].h }, [[PG]], [x1]
+; VBITS_GE_1024-NEXT: ret
+  %op1 = load <64 x half>, <64 x half>* %a
+  %res = fptoui <64 x half> %op1 to <64 x i16>
+  store <64 x i16> %res, <64 x i16>* %b
+  ret void
+}
+
+define void @fcvtzu_v128f16_v128i16(<128 x half>* %a, <128 x i16>* %b) #0 {
+; CHECK-LABEL: fcvtzu_v128f16_v128i16:
+; VBITS_GE_2048: ptrue [[PG:p[0-9]+]].h, vl128
+; VBITS_GE_2048-NEXT: ld1h { [[OP:z[0-9]+]].h }, [[PG]]/z, [x0]
+; VBITS_GE_2048-NEXT: fcvtzu [[RES:z[0-9]+]].h, [[PG]]/m, [[OP]].h
+; VBITS_GE_2048-NEXT: st1h { [[RES]].h }, [[PG]], [x1]
+; VBITS_GE_2048-NEXT: ret
+  %op1 = load <128 x half>, <128 x half>* %a
+  %res = fptoui <128 x half> %op1 to <128 x i16>
+  store <128 x i16> %res, <128 x i16>* %b
+  ret void
+}
+
+;
+; FCVTZU H -> S
+;
+
+; Don't use SVE for 64-bit vectors.
+define <2 x i32> @fcvtzu_v2f16_v2i32(<2 x half> %op1) #0 {
+; CHECK-LABEL: fcvtzu_v2f16_v2i32:
+; CHECK: fcvtl v0.4s, v0.4h
+; CHECK-NEXT: fcvtzu v0.4s, v0.4s
+; CHECK-NEXT: ret
+  %res = fptoui <2 x half> %op1 to <2 x i32>
+  ret <2 x i32> %res
+}
+
+; Don't use SVE for 128-bit vectors.
+define <4 x i32> @fcvtzu_v4f16_v4i32(<4 x half> %op1) #0 {
+; CHECK-LABEL: fcvtzu_v4f16_v4i32:
+; CHECK: fcvtzu v0.4s, v0.4s
+; CHECK-NEXT: ret
+  %res = fptoui <4 x half> %op1 to <4 x i32>
+  ret <4 x i32> %res
+}
+
+define void @fcvtzu_v8f16_v8i32(<8 x half>* %a, <8 x i32>* %b) #0 {
+; CHECK-LABEL: fcvtzu_v8f16_v8i32:
+; CHECK: ldr q[[OP:[0-9]+]], [x0]
+; CHECK-NEXT: ptrue [[PG:p[0-9]+]].s, vl8
+; CHECK-NEXT: uunpklo [[UPK:z[0-9]+]].s, z[[OP]].h
+; CHECK-NEXT: fcvtzu [[RES:z[0-9]+]].s, [[PG]]/m, [[UPK]].h
+; CHECK-NEXT: st1w { [[RES]].s }, [[PG]], [x1]
+; CHECK-NEXT: ret
+  %op1 = load <8 x half>, <8 x half>* %a
+  %res = fptoui <8 x half> %op1 to <8 x i32>
+  store <8 x i32> %res, <8 x i32>* %b
+  ret void
+}
+
+define void @fcvtzu_v16f16_v16i32(<16 x half>* %a, <16 x i32>* %b) #0 {
+; CHECK-LABEL: fcvtzu_v16f16_v16i32:
+; VBITS_GE_512: ptrue [[PG1:p[0-9]+]].h, vl16
+; VBITS_GE_512-NEXT: ld1h { [[OP:z[0-9]+]].h }, [[PG1]]/z, [x0]
+; VBITS_GE_512-NEXT: ptrue [[PG2:p[0-9]+]].s, vl16
+; VBITS_GE_512-NEXT: uunpklo [[UPK:z[0-9]+]].s, [[OP]].h
+; VBITS_GE_512-NEXT: fcvtzu [[RES:z[0-9]+]].s, [[PG2]]/m, [[UPK]].h
+; VBITS_GE_512-NEXT: st1w { [[RES]].s }, [[PG1]], [x1]
+; VBITS_GE_512-NEXT: ret
+
+; Ensure sensible type legalisation - fixed type extract_subvector codegen is poor currently.
+; VBITS_EQ_256: ptrue [[PG1:p[0-9]+]].h, vl16
+; VBITS_EQ_256-DAG: ld1h { [[VEC:z[0-9]+]].h }, [[PG1]]/z, [x0]
+; VBITS_EQ_256-DAG: st1h { [[VEC:z[0-9]+]].h }, [[PG1]], [x8]
+; VBITS_EQ_256-DAG: ldp q[[LO:[0-9]+]], q[[HI:[0-9]+]], [sp]
+; VBITS_EQ_256-NEXT: ptrue [[PG2:p[0-9]+]].s, vl8
+; VBITS_EQ_256-NEXT: add x8, x1, #32
+; VBITS_EQ_256-NEXT: uunpklo [[UPK_LO:z[0-9]+]].s, z[[LO]].h
+; VBITS_EQ_256-NEXT: uunpklo [[UPK_HI:z[0-9]+]].s, z[[HI]].h
+; VBITS_EQ_256-NEXT: fcvtzu [[RES_LO:z[0-9]+]].s, [[PG2]]/m, [[UPK_LO]].h
+; VBITS_EQ_256-NEXT: fcvtzu [[RES_HI:z[0-9]+]].s, [[PG2]]/m, [[UPK_HI]].h
+; VBITS_EQ_256-NEXT: st1w { [[RES_HI]].s }, [[PG2]], [x8]
+; VBITS_EQ_256-NEXT: st1w { [[RES_LO]].s }, [[PG2]], [x1]
+  %op1 = load <16 x half>, <16 x half>* %a
+  %res = fptoui <16 x half> %op1 to <16 x i32>
+  store <16 x i32> %res, <16 x i32>* %b
+  ret void
+}
+
+define void @fcvtzu_v32f16_v32i32(<32 x half>* %a, <32 x i32>* %b) #0 {
+; CHECK-LABEL: fcvtzu_v32f16_v32i32:
+; VBITS_GE_1024: ptrue [[PG1:p[0-9]+]].h, vl32
+; VBITS_GE_1024-NEXT: ld1h { [[OP:z[0-9]+]].h }, [[PG1]]/z, [x0]
+; VBITS_GE_1024-NEXT: ptrue [[PG2:p[0-9]+]].s, vl32
+; VBITS_GE_1024-NEXT: uunpklo [[UPK:z[0-9]+]].s, [[OP]].h
+; VBITS_GE_1024-NEXT: fcvtzu [[RES:z[0-9]+]].s, [[PG2]]/m, [[UPK]].h
+; VBITS_GE_1024-NEXT: st1w { [[RES]].s }, [[PG1]], [x1]
+; VBITS_GE_1024-NEXT: ret
+  %op1 = load <32 x half>, <32 x half>* %a
+  %res = fptoui <32 x half> %op1 to <32 x i32>
+  store <32 x i32> %res, <32 x i32>* %b
+  ret void
+}
+
+define void @fcvtzu_v64f16_v64i32(<64 x half>* %a, <64 x i32>* %b) #0 {
+; CHECK-LABEL: fcvtzu_v64f16_v64i32:
+; VBITS_GE_2048: ptrue [[PG1:p[0-9]+]].h, vl64
+; VBITS_GE_2048-NEXT: ld1h { [[OP:z[0-9]+]].h }, [[PG1]]/z, [x0]
+; VBITS_GE_2048-NEXT: ptrue [[PG2:p[0-9]+]].s, vl64
+; VBITS_GE_2048-NEXT: uunpklo [[UPK:z[0-9]+]].s, [[OP]].h
+; VBITS_GE_2048-NEXT: fcvtzu [[RES:z[0-9]+]].s, [[PG2]]/m, [[UPK]].h
+; VBITS_GE_2048-NEXT: st1w { [[RES]].s }, [[PG1]], [x1]
+; VBITS_GE_2048-NEXT: ret
+  %op1 = load <64 x half>, <64 x half>* %a
+  %res = fptoui <64 x half> %op1 to <64 x i32>
+  store <64 x i32> %res, <64 x i32>* %b
+  ret void
+}
+
+;
+; FCVTZU H -> D
+;
+
+; Don't use SVE for 64-bit vectors.
+define <1 x i64> @fcvtzu_v1f16_v1i64(<1 x half> %op1) #0 {
+; CHECK-LABEL: fcvtzu_v1f16_v1i64:
+; CHECK: fcvtzu x8, h0
+; CHECK-NEXT: fmov d0, x8
+; CHECK-NEXT: ret
+  %res = fptoui <1 x half> %op1 to <1 x i64>
+  ret <1 x i64> %res
+}
+
+; v2f16 is not legal for NEON, so use SVE
+define <2 x i64> @fcvtzu_v2f16_v2i64(<2 x half> %op1) #0 {
+; CHECK-LABEL: fcvtzu_v2f16_v2i64:
+; CHECK: ptrue [[PG:p[0-9]+]].d, vl4
+; CHECK-NEXT: uunpklo [[UPK1:z[0-9]+]].s, z0.h
+; CHECK-NEXT: uunpklo [[UPK2:z[0-9]+]].d, [[UPK1]].s
+; CHECK-NEXT: fcvtzu z0.d, [[PG]]/m, [[UPK2]].h
+; CHECK-NEXT: ret
+  %res = fptoui <2 x half> %op1 to <2 x i64>
+  ret <2 x i64> %res
+}
+
+define void @fcvtzu_v4f16_v4i64(<4 x half>* %a, <4 x i64>* %b) #0 {
+; CHECK-LABEL: fcvtzu_v4f16_v4i64:
+; CHECK: ldr d[[OP:[0-9]+]], [x0]
+; CHECK-NEXT: ptrue [[PG:p[0-9]+]].d, vl4
+; CHECK-NEXT: uunpklo [[UPK1:z[0-9]+]].s, z[[OP]].h
+; CHECK-NEXT: uunpklo [[UPK2:z[0-9]+]].d, [[UPK1]].s
+; CHECK-NEXT: fcvtzu [[RES:z[0-9]+]].d, [[PG]]/m, [[UPK2]].h
+; CHECK-NEXT: st1d { [[RES]].d }, [[PG]], [x1]
+; CHECK-NEXT: ret
+  %op1 = load <4 x half>, <4 x half>* %a
+  %res = fptoui <4 x half> %op1 to <4 x i64>
+  store <4 x i64> %res, <4 x i64>* %b
+  ret void
+}
+
+define void @fcvtzu_v8f16_v8i64(<8 x half>* %a, <8 x i64>* %b) #0 {
+; CHECK-LABEL: fcvtzu_v8f16_v8i64:
+; VBITS_GE_512: ldr q[[OP:[0-9]+]], [x0]
+; VBITS_GE_512-NEXT: ptrue [[PG:p[0-9]+]].d, vl8
+; VBITS_GE_512-NEXT: uunpklo [[UPK1:z[0-9]+]].s, z[[OP]].h
+; VBITS_GE_512-NEXT: uunpklo [[UPK2:z[0-9]+]].d, [[UPK1]].s
+; VBITS_GE_512-NEXT: fcvtzu [[RES:z[0-9]+]].d, [[PG]]/m, [[UPK2]].h
+; VBITS_GE_512-NEXT: st1d { [[RES]].d }, [[PG]], [x1]
+; VBITS_GE_512-NEXT: ret
+
+; Ensure sensible type legalisation.
+; VBITS_EQ_256: ldr q[[OP:[0-9]+]], [x0]
+; VBITS_EQ_256-NEXT: ptrue [[PG1:p[0-9]+]].d, vl4
+; VBITS_EQ_256-NEXT: add x8, x1, #32
+; VBITS_EQ_256-NEXT: ext v[[HI:[0-9]+]].16b, v[[LO:[0-9]+]].16b, v[[OP]].16b, #8
+; VBITS_EQ_256-NEXT: uunpklo [[UPK1_LO:z[0-9]+]].s, z[[LO]].h
+; VBITS_EQ_256-NEXT: uunpklo [[UPK1_HI:z[0-9]+]].s, z[[HI]].h
+; VBITS_EQ_256-NEXT: uunpklo [[UPK2_LO:z[0-9]+]].d, [[UPK1_LO]].s
+; VBITS_EQ_256-NEXT: uunpklo [[UPK2_HI:z[0-9]+]].d, [[UPK1_HI]].s
+; VBITS_EQ_256-NEXT: fcvtzu [[RES_LO:z[0-9]+]].d, [[PG2]]/m, [[UPK2_LO]].h
+; VBITS_EQ_256-NEXT: fcvtzu [[RES_HI:z[0-9]+]].d, [[PG2]]/m, [[UPK2_HI]].h
+; VBITS_EQ_256-NEXT: st1d { [[RES_LO]].d }, [[PG2]], [x1]
+; VBITS_EQ_256-NEXT: st1d { [[RES_HI]].d }, [[PG2]], [x8]
+; VBITS_EQ_256-NEXT: ret
+  %op1 = load <8 x half>, <8 x half>* %a
+  %res = fptoui <8 x half> %op1 to <8 x i64>
+  store <8 x i64> %res, <8 x i64>* %b
+  ret void
+}
+
+define void @fcvtzu_v16f16_v16i64(<16 x half>* %a, <16 x i64>* %b) #0 {
+; CHECK-LABEL: fcvtzu_v16f16_v16i64:
+; VBITS_GE_1024: ptrue [[PG1:p[0-9]+]].h, vl16
+; VBITS_GE_1024-NEXT: ld1h { [[OP:z[0-9]+]].h }, [[PG1]]/z, [x0]
+; VBITS_GE_1024-NEXT: ptrue [[PG2:p[0-9]+]].d, vl16
+; VBITS_GE_1024-NEXT: uunpklo [[UPK1:z[0-9]+]].s, [[OP]].h
+; VBITS_GE_1024-NEXT: uunpklo [[UPK2:z[0-9]+]].d, [[UPK1]].s
+; VBITS_GE_1024-NEXT: fcvtzu [[RES:z[0-9]+]].d, [[PG2]]/m, [[UPK2]].h
+; VBITS_GE_1024-NEXT: st1d { [[RES]].d }, [[PG1]], [x1]
+; VBITS_GE_1024-NEXT: ret
+  %op1 = load <16 x half>, <16 x half>* %a
+  %res = fptoui <16 x half> %op1 to <16 x i64>
+  store <16 x i64> %res, <16 x i64>* %b
+  ret void
+}
+
+define void @fcvtzu_v32f16_v32i64(<32 x half>* %a, <32 x i64>* %b) #0 {
+; CHECK-LABEL: fcvtzu_v32f16_v32i64:
+; VBITS_GE_2048: ptrue [[PG1:p[0-9]+]].h, vl32
+; VBITS_GE_2048-NEXT: ld1h { [[OP:z[0-9]+]].h }, [[PG1]]/z, [x0]
+; VBITS_GE_2048-NEXT: ptrue [[PG2:p[0-9]+]].d, vl32
+; VBITS_GE_2048-NEXT: uunpklo [[UPK1:z[0-9]+]].s, [[OP]].h
+; VBITS_GE_2048-NEXT: uunpklo [[UPK2:z[0-9]+]].d, [[UPK]].s
+; VBITS_GE_2048-NEXT: fcvtzu [[RES:z[0-9]+]].d, [[PG2]]/m, [[UPK2]].h
+; VBITS_GE_2048-NEXT: st1d { [[RES]].d }, [[PG1]], [x1]
+; VBITS_GE_2048-NEXT: ret
+  %op1 = load <32 x half>, <32 x half>* %a
+  %res = fptoui <32 x half> %op1 to <32 x i64>
+  store <32 x i64> %res, <32 x i64>* %b
+  ret void
+}
+
+;
+; FCVTZU S -> H
+;
+
+; Don't use SVE for 64-bit vectors.
+define <2 x i16> @fcvtzu_v2f32_v2i16(<2 x float> %op1) #0 {
+; CHECK-LABEL: fcvtzu_v2f32_v2i16:
+; CHECK: fcvtzs v0.2s, v0.2s
+; CHECK-NEXT: ret
+  %res = fptoui <2 x float> %op1 to <2 x i16>
+  ret <2 x i16> %res
+}
+
+; Don't use SVE for 128-bit vectors.
+define <4 x i16> @fcvtzu_v4f32_v4i16(<4 x float> %op1) #0 {
+; CHECK-LABEL: fcvtzu_v4f32_v4i16:
+; CHECK: fcvtzu v0.4s, v0.4s
+; CHECK-NEXT: mov w8, v0.s[1]
+; CHECK-NEXT: mov w9, v0.s[2]
+; CHECK-NEXT: mov w10, v0.s[3]
+; CHECK-NEXT: mov v0.h[1], w8
+; CHECK-NEXT: mov v0.h[2], w9
+; CHECK-NEXT: mov v0.h[3], w10
+; CHECK-NEXT: ret
+  %res = fptoui <4 x float> %op1 to <4 x i16>
+  ret <4 x i16> %res
+}
+
+define <8 x i16> @fcvtzu_v8f32_v8i16(<8 x float>* %a) #0 {
+; CHECK-LABEL: fcvtzu_v8f32_v8i16:
+; CHECK: ptrue [[PG1:p[0-9]+]].s, vl8
+; CHECK-NEXT: ld1w { [[OP:z[0-9]+]].s }, [[PG1]]/z, [x0]
+; CHECK-NEXT: ptrue [[PG2:p[0-9]+]].s
+; CHECK-NEXT: fcvtzu [[CVT:z[0-9]+]].s, [[PG2]]/m, [[OP]].s
+; CHECK-NEXT: uzp1 z0.h, [[CVT]].h, [[CVT]].h
+; CHECK-NEXT: ret
+  %op1 = load <8 x float>, <8 x float>* %a
+  %res = fptoui <8 x float> %op1 to <8 x i16>
+  ret <8 x i16> %res
+}
+
+define void @fcvtzu_v16f32_v16i16(<16 x float>* %a, <16 x i16>* %b) #0 {
+; CHECK-LABEL: fcvtzu_v16f32_v16i16:
+; VBITS_GE_512: ptrue [[PG1:p[0-9]+]].s, vl16
+; VBITS_GE_512-NEXT: ld1w { [[OP:z[0-9]+]].s }, [[PG1]]/z, [x0]
+; VBITS_GE_512-NEXT: ptrue [[PG2:p[0-9]+]].s
+; VBITS_GE_512-NEXT: fcvtzu [[CVT:z[0-9]+]].s, [[PG2]]/m, [[OP]].s
+; VBITS_GE_512-NEXT: uzp1 [[RES:z[0-9]+]].h, [[CVT]].h, [[CVT]].h
+; VBITS_GE_512-NEXT: ptrue [[PG3:p[0-9]+]].h, vl16
+; VBITS_GE_512-NEXT: st1h { [[RES]].h }, [[PG3]], [x1]
+; VBITS_GE_512-NEXT: ret
+
+; Ensure sensible type legalisation.
+; VBITS_EQ_256: add x8, x0, #32
+; VBITS_EQ_256-NEXT: ptrue [[PG1:p[0-9]+]].s, vl8
+; VBITS_EQ_256-NEXT: ld1w { [[HI:z[0-9]+]].s }, [[PG]]/z, [x8]
+; VBITS_EQ_256-NEXT: ld1w { [[LO:z[0-9]+]].s }, [[PG]]/z, [x0]
+; VBITS_EQ_256-NEXT: ptrue [[PG2:p[0-9]+]].s
+; VBITS_EQ_256-NEXT: ptrue [[PG3:p[0-9]+]].h, vl8
+; VBITS_EQ_256-NEXT: fcvtzu [[CVT_HI:z[0-9]+]].s, [[PG2]]/m, [[HI]].s
+; VBITS_EQ_256-NEXT: fcvtzu [[CVT_LO:z[0-9]+]].s, [[PG2]]/m, [[LO]].s
+; VBITS_EQ_256-NEXT: uzp1 [[RES_LO:z[0-9]+]].h, [[CVT_LO]].h, [[CVT_LO]].h
+; VBITS_EQ_256-NEXT: uzp1 [[RES_HI:z[0-9]+]].h, [[CVT_HI]].h, [[CVT_HI]].h
+; VBITS_EQ_256-NEXT: splice [[RES:z[0-9]+]].h, [[PG3]], [[RES_LO]].h, [[RES_HI]].h
+; VBITS_EQ_256-NEXT: ptrue [[PG4:p[0-9]+]].h, vl16
+; VBITS_EQ_256-NEXT: st1h { [[RES]].h }, [[PG4]], [x1]
+; VBITS_EQ_256-NEXT: ret
+  %op1 = load <16 x float>, <16 x float>* %a
+  %res = fptoui <16 x float> %op1 to <16 x i16>
+  store <16 x i16> %res, <16 x i16>* %b
+  ret void
+}
+
+define void @fcvtzu_v32f32_v32i16(<32 x float>* %a, <32 x i16>* %b) #0 {
+; CHECK-LABEL: fcvtzu_v32f32_v32i16:
+; VBITS_GE_1024: ptrue [[PG1:p[0-9]+]].s, vl32
+; VBITS_GE_1024-NEXT: ld1w { [[OP:z[0-9]+]].s }, [[PG1]]/z, [x0]
+; VBITS_GE_1024-NEXT: ptrue [[PG2:p[0-9]+]].s
+; VBITS_GE_1024-NEXT: fcvtzu [[CVT:z[0-9]+]].s, [[PG2]]/m, [[OP]].s
+; VBITS_GE_1024-NEXT: uzp1 [[RES:z[0-9]+]].h, [[CVT]].h, [[CVT]].h
+; VBITS_GE_1024-NEXT: ptrue [[PG3:p[0-9]+]].h, vl32
+; VBITS_GE_1024-NEXT: st1h { [[RES]].h }, [[PG3]], [x1]
+; VBITS_GE_1024-NEXT: ret
+  %op1 = load <32 x float>, <32 x float>* %a
+  %res = fptoui <32 x float> %op1 to <32 x i16>
+  store <32 x i16> %res, <32 x i16>* %b
+  ret void
+}
+
+define void @fcvtzu_v64f32_v64i16(<64 x float>* %a, <64 x i16>* %b) #0 {
+; CHECK-LABEL: fcvtzu_v64f32_v64i16:
+; VBITS_GE_2048: ptrue [[PG1:p[0-9]+]].s, vl64
+; VBITS_GE_2048-NEXT: ld1w { [[OP:z[0-9]+]].s }, [[PG1]]/z, [x0]
+; VBITS_GE_2048-NEXT: ptrue [[PG2:p[0-9]+]].s
+; VBITS_GE_2048-NEXT: fcvtzu [[RES:z[0-9]+]].s, [[PG2]]/m, [[UPK]].s
+; VBITS_GE_2048-NEXT: uzp1 [[RES:z[0-9]+]].h, [[CVT]].h, [[CVT]].h
+; VBITS_GE_2048-NEXT: ptrue [[PG3:p[0-9]+]].h, vl64
+; VBITS_GE_2048-NEXT: st1h { [[RES]].h }, [[PG3]], [x1]
+; VBITS_GE_2048-NEXT: ret
+  %op1 = load <64 x float>, <64 x float>* %a
+  %res = fptoui <64 x float> %op1 to <64 x i16>
+  store <64 x i16> %res, <64 x i16>* %b
+  ret void
+}
+
+;
+; FCVTZU S -> S
+;
+
+; Don't use SVE for 64-bit vectors.
+define <2 x i32> @fcvtzu_v2f32_v2i32(<2 x float> %op1) #0 {
+; CHECK-LABEL: fcvtzu_v2f32_v2i32:
+; CHECK: fcvtzu v0.2s, v0.2s
+; CHECK-NEXT: ret
+  %res = fptoui <2 x float> %op1 to <2 x i32>
+  ret <2 x i32> %res
+}
+
+; Don't use SVE for 128-bit vectors.
+define <4 x i32> @fcvtzu_v4f32_v4i32(<4 x float> %op1) #0 {
+; CHECK-LABEL: fcvtzu_v4f32_v4i32:
+; CHECK: fcvtzu v0.4s, v0.4s
+; CHECK-NEXT: ret
+  %res = fptoui <4 x float> %op1 to <4 x i32>
+  ret <4 x i32> %res
+}
+
+define void @fcvtzu_v8f32_v8i32(<8 x float>* %a, <8 x i32>* %b) #0 {
+; CHECK-LABEL: fcvtzu_v8f32_v8i32:
+; CHECK: ptrue [[PG:p[0-9]+]].s, vl8
+; CHECK-NEXT: ld1w { [[OP:z[0-9]+]].s }, [[PG]]/z, [x0]
+; CHECK-NEXT: fcvtzu [[RES:z[0-9]+]].s, [[PG]]/m, [[OP]].s
+; CHECK-NEXT: st1w { [[RES]].s }, [[PG]], [x1]
+; CHECK-NEXT: ret
+  %op1 = load <8 x float>, <8 x float>* %a
+  %res = fptoui <8 x float> %op1 to <8 x i32>
+  store <8 x i32> %res, <8 x i32>* %b
+  ret void
+}
+
+define void @fcvtzu_v16f32_v16i32(<16 x float>* %a, <16 x i32>* %b) #0 {
+; CHECK-LABEL: fcvtzu_v16f32_v16i32:
+; VBITS_GE_512: ptrue [[PG:p[0-9]+]].s, vl16
+; VBITS_GE_512-NEXT: ld1w { [[OP:z[0-9]+]].s }, [[PG]]/z, [x0]
+; VBITS_GE_512-NEXT: fcvtzu [[RES:z[0-9]+]].s, [[PG]]/m, [[OP]].s
+; VBITS_GE_512-NEXT: st1w { [[RES]].s }, [[PG]], [x1]
+; VBITS_GE_512-NEXT: ret
+
+; Ensure sensible type legalisation.
+; VBITS_EQ_256: ptrue [[PG:p[0-9]+]].s, vl8
+; VBITS_EQ_256-NEXT: add x8, x0, #32
+; VBITS_EQ_256-NEXT: ld1w { [[LO:z[0-9]+]].s }, [[PG]]/z, [x0]
+; VBITS_EQ_256-NEXT: ld1w { [[HI:z[0-9]+]].s }, [[PG]]/z, [x8]
+; VBITS_EQ_256-NEXT: add x8, x1, #32
+; VBITS_EQ_256-NEXT: fcvtzu [[RES_LO:z[0-9]+]].s, [[PG]]/m, [[LO]].s
+; VBITS_EQ_256-NEXT: fcvtzu [[RES_HI:z[0-9]+]].s, [[PG]]/m, [[HI]].s
+; VBITS_EQ_256-NEXT: st1w { [[RES_LO]].s }, [[PG]], [x1]
+; VBITS_EQ_256-NEXT: st1w { [[RES_HI]].s }, [[PG]], [x8]
+; VBITS_EQ_256-NEXT: ret
+  %op1 = load <16 x float>, <16 x float>* %a
+  %res = fptoui <16 x float> %op1 to <16 x i32>
+  store <16 x i32> %res, <16 x i32>* %b
+  ret void
+}
+
+define void @fcvtzu_v32f32_v32i32(<32 x float>* %a, <32 x i32>* %b) #0 {
+; CHECK-LABEL: fcvtzu_v32f32_v32i32:
+; VBITS_GE_1024: ptrue [[PG:p[0-9]+]].s, vl32
+; VBITS_GE_1024-NEXT: ld1w { [[OP:z[0-9]+]].s }, [[PG]]/z, [x0]
+; VBITS_GE_1024-NEXT: fcvtzu [[RES:z[0-9]+]].s, [[PG]]/m, [[OP]].s
+; VBITS_GE_1024-NEXT: st1w { [[RES]].s }, [[PG]], [x1]
+; VBITS_GE_1024-NEXT: ret
+  %op1 = load <32 x float>, <32 x float>* %a
+  %res = fptoui <32 x float> %op1 to <32 x i32>
+  store <32 x i32> %res, <32 x i32>* %b
+  ret void
+}
+
+define void @fcvtzu_v64f32_v64i32(<64 x float>* %a, <64 x i32>* %b) #0 {
+; CHECK-LABEL: fcvtzu_v64f32_v64i32:
+; VBITS_GE_2048: ptrue [[PG:p[0-9]+]].s, vl64
+; VBITS_GE_2048-NEXT: ld1w { [[OP:z[0-9]+]].s }, [[PG]]/z, [x0]
+; VBITS_GE_2048-NEXT: fcvtzu [[RES:z[0-9]+]].s, [[PG]]/m, [[OP]].s
+; VBITS_GE_2048-NEXT: st1w { [[RES]].s }, [[PG]], [x1]
+; VBITS_GE_2048-NEXT: ret
+  %op1 = load <64 x float>, <64 x float>* %a
+  %res = fptoui <64 x float> %op1 to <64 x i32>
+  store <64 x i32> %res, <64 x i32>* %b
+  ret void
+}
+
+;
+; FCVTZU S -> D
+;
+
+; Don't use SVE for 64-bit vectors.
+define <1 x i64> @fcvtzu_v1f32_v1i64(<1 x float> %op1) #0 {
+; CHECK-LABEL: fcvtzu_v1f32_v1i64:
+; CHECK: fcvtl v0.2d, v0.2s
+; CHECK-NEXT: fcvtzu v0.2d, v0.2d
+; CHECK-NEXT: ret
+  %res = fptoui <1 x float> %op1 to <1 x i64>
+  ret <1 x i64> %res
+}
+
+; Don't use SVE for 128-bit vectors.
+define <2 x i64> @fcvtzu_v2f32_v2i64(<2 x float> %op1) #0 {
+; CHECK-LABEL: fcvtzu_v2f32_v2i64:
+; CHECK: fcvtl v0.2d, v0.2s
+; CHECK-NEXT: fcvtzu v0.2d, v0.2d
+; CHECK-NEXT: ret
+  %res = fptoui <2 x float> %op1 to <2 x i64>
+  ret <2 x i64> %res
+}
+
+define void @fcvtzu_v4f32_v4i64(<4 x float>* %a, <4 x i64>* %b) #0 {
+; CHECK-LABEL: fcvtzu_v4f32_v4i64:
+; CHECK: ldr q[[OP:[0-9]+]], [x0]
+; CHECK-NEXT: ptrue [[PG:p[0-9]+]].d, vl4
+; CHECK-NEXT: uunpklo [[UPK:z[0-9]+]].d, z[[OP]].s
+; CHECK-NEXT: fcvtzu [[RES:z[0-9]+]].d, [[PG]]/m, [[UPK]].s
+; CHECK-NEXT: st1d { [[RES]].d }, [[PG]], [x1]
+; CHECK-NEXT: ret
+  %op1 = load <4 x float>, <4 x float>* %a
+  %res = fptoui <4 x float> %op1 to <4 x i64>
+  store <4 x i64> %res, <4 x i64>* %b
+  ret void
+}
+
+define void @fcvtzu_v8f32_v8i64(<8 x float>* %a, <8 x i64>* %b) #0 {
+; CHECK-LABEL: fcvtzu_v8f32_v8i64:
+; VBITS_GE_512: ptrue [[PG1:p[0-9]+]].s, vl8
+; VBITS_GE_512-NEXT: ld1w { [[OP:z[0-9]+]].s }, [[PG1]]/z, [x0]
+; VBITS_GE_512-NEXT: ptrue [[PG:p[0-9]+]].d, vl8
+; VBITS_GE_512-NEXT: uunpklo [[UPK:z[0-9]+]].d, [[OP]].s
+; VBITS_GE_512-NEXT: fcvtzu [[RES:z[0-9]+]].d, [[PG1]]/m, [[UPK]].s
+; VBITS_GE_512-NEXT: st1d { [[RES]].d }, [[PG1]], [x1]
+; VBITS_GE_512-NEXT: ret
+
+; Ensure sensible type legalisation - fixed type extract_subvector codegen is poor currently.
+; VBITS_EQ_256: ptrue [[PG1:p[0-9]+]].s, vl8
+; VBITS_EQ_256-DAG: ld1w { [[VEC:z[0-9]+]].s }, [[PG1]]/z, [x0]
+; VBITS_EQ_256-DAG: st1w { [[VEC:z[0-9]+]].s }, [[PG1]], [x8]
+; VBITS_EQ_256-DAG: ldp q[[LO:[0-9]+]], q[[HI:[0-9]+]], [sp]
+; VBITS_EQ_256-NEXT: ptrue [[PG2:p[0-9]+]].d, vl4
+; VBITS_EQ_256-NEXT: add x8, x1, #32
+; VBITS_EQ_256-NEXT: uunpklo [[UPK_LO:z[0-9]+]].d, z[[LO]].s
+; VBITS_EQ_256-NEXT: uunpklo [[UPK_HI:z[0-9]+]].d, z[[HI]].s
+; VBITS_EQ_256-NEXT: fcvtzu [[RES_LO:z[0-9]+]].d, [[PG2]]/m, [[UPK_LO]].s
+; VBITS_EQ_256-NEXT: fcvtzu [[RES_HI:z[0-9]+]].d, [[PG2]]/m, [[UPK_HI]].s
+; VBITS_EQ_256-NEXT: st1d { [[RES_HI]].d }, [[PG2]], [x8]
+; VBITS_EQ_256-NEXT: st1d { [[RES_LO]].d }, [[PG2]], [x1]
+  %op1 = load <8 x float>, <8 x float>* %a
+  %res = fptoui <8 x float> %op1 to <8 x i64>
+  store <8 x i64> %res, <8 x i64>* %b
+  ret void
+}
+
+define void @fcvtzu_v16f32_v16i64(<16 x float>* %a, <16 x i64>* %b) #0 {
+; CHECK-LABEL: fcvtzu_v16f32_v16i64:
+; VBITS_GE_1024: ptrue [[PG1:p[0-9]+]].s, vl16
+; VBITS_GE_1024-NEXT: ld1w { [[OP:z[0-9]+]].s }, [[PG1]]/z, [x0]
+; VBITS_GE_1024-NEXT: ptrue [[PG2:p[0-9]+]].d, vl16
+; VBITS_GE_1024-NEXT: uunpklo [[UPK:z[0-9]+]].d, [[OP]].s
+; VBITS_GE_1024-NEXT: fcvtzu [[RES:z[0-9]+]].d, [[PG2]]/m, [[UPK]].s
+; VBITS_GE_1024-NEXT: st1d { [[RES]].d }, [[PG1]], [x1]
+; VBITS_GE_1024-NEXT: ret
+  %op1 = load <16 x float>, <16 x float>* %a
+  %res = fptoui <16 x float> %op1 to <16 x i64>
+  store <16 x i64> %res, <16 x i64>* %b
+  ret void
+}
+
+define void @fcvtzu_v32f32_v32i64(<32 x float>* %a, <32 x i64>* %b) #0 {
+; CHECK-LABEL: fcvtzu_v32f32_v32i64:
+; VBITS_GE_2048: ptrue [[PG1:p[0-9]+]].s, vl32
+; VBITS_GE_2048-NEXT: ld1w { [[OP:z[0-9]+]].s }, [[PG1]]/z, [x0]
+; VBITS_GE_2048-NEXT: ptrue [[PG2:p[0-9]+]].d, vl32
+; VBITS_GE_2048-NEXT: uunpklo [[UPK:z[0-9]+]].d, [[OP]].s
+; VBITS_GE_2048-NEXT: fcvtzu [[RES:z[0-9]+]].d, [[PG2]]/m, [[UPK]].s
+; VBITS_GE_2048-NEXT: st1d { [[RES]].d }, [[PG1]], [x1]
+; VBITS_GE_2048-NEXT: ret
+  %op1 = load <32 x float>, <32 x float>* %a
+  %res = fptoui <32 x float> %op1 to <32 x i64>
+  store <32 x i64> %res, <32 x i64>* %b
+  ret void
+}
+
+
+;
+; FCVTZU D -> H
+;
+
+; v1f64 is perfered to be widened to v4f64, so use SVE
+define <1 x i16> @fcvtzu_v1f64_v1i16(<1 x double> %op1) #0 {
+; CHECK-LABEL: fcvtzu_v1f64_v1i16:
+; CHECK: ptrue [[PG:p[0-9]+]].d
+; CHECK-NEXT: fcvtzu [[CVT:z[0-9]+]].d, [[PG]]/m, z0.d
+; CHECK-NEXT: uzp1 [[UZP:z[0-9]+]].s, [[CVT]].s, [[CVT]].s
+; CHECK-NEXT: uzp1 z0.h, [[UZP]].h, [[UZP]].h
+; CHECK-NEXT: ret
+  %res = fptoui <1 x double> %op1 to <1 x i16>
+  ret <1 x i16> %res
+}
+
+; Don't use SVE for 128-bit vectors.
+define <2 x i16> @fcvtzu_v2f64_v2i16(<2 x double> %op1) #0 {
+; CHECK-LABEL: fcvtzu_v2f64_v2i16:
+; CHECK: fcvtzs v0.2d, v0.2d
+; CHECK-NEXT: xtn v0.2s, v0.2d
+; CHECK-NEXT: ret
+  %res = fptoui <2 x double> %op1 to <2 x i16>
+  ret <2 x i16> %res
+}
+
+define <4 x i16> @fcvtzu_v4f64_v4i16(<4 x double>* %a) #0 {
+; CHECK-LABEL: fcvtzu_v4f64_v4i16:
+; CHECK: ptrue [[PG1:p[0-9]+]].d, vl4
+; CHECK-NEXT: ld1d { [[OP:z[0-9]+]].d }, [[PG1]]/z, [x0]
+; CHECK-NEXT: ptrue [[PG2:p[0-9]+]].d
+; CHECK-NEXT: fcvtzu [[CVT:z[0-9]+]].d, [[PG2]]/m, [[OP]].d
+; CHECK-NEXT: uzp1 [[UZP:z[0-9]+]].s, [[CVT]].s, [[CVT]].s
+; CHECK-NEXT: uzp1 z0.h, [[UZP]].h, [[UZP]].h
+; CHECK-NEXT: ret
+  %op1 = load <4 x double>, <4 x double>* %a
+  %res = fptoui <4 x double> %op1 to <4 x i16>
+  ret <4 x i16> %res
+}
+
+define <8 x i16> @fcvtzu_v8f64_v8i16(<8 x double>* %a) #0 {
+; CHECK-LABEL: fcvtzu_v8f64_v8i16:
+; VBITS_GE_512: ptrue [[PG1:p[0-9]+]].d, vl8
+; VBITS_GE_512-NEXT: ld1d { [[OP:z[0-9]+]].d }, [[PG1]]/z, [x0]
+; VBITS_GE_512-NEXT: ptrue [[PG2:p[0-9]+]].d
+; VBITS_GE_512-NEXT: fcvtzu [[CVT:z[0-9]+]].d, [[PG2]]/m, [[OP]].d
+; VBITS_GE_512-NEXT: uzp1 [[UZP:z[0-9]+]].s, [[CVT]].s, [[CVT]].s
+; VBITS_GE_512-NEXT: uzp1 z0.h, [[UZP]].h, [[UZP]].h
+; VBITS_GE_512-NEXT: ret
+
+; Ensure sensible type legalisation.
+; VBITS_EQ_256: add x8, x0, #32
+; VBITS_EQ_256-NEXT: ptrue [[PG1:p[0-9]+]].d, vl4
+; VBITS_EQ_256-NEXT: ld1d { [[HI:z[0-9]+]].d }, [[PG]]/z, [x8]
+; VBITS_EQ_256-NEXT: ld1d { [[LO:z[0-9]+]].d }, [[PG]]/z, [x0]
+; VBITS_EQ_256-NEXT: ptrue [[PG2:p[0-9]+]].d
+; VBITS_EQ_256-NEXT: fcvtzu [[CVT_HI:z[0-9]+]].d, [[PG2]]/m, [[HI]].d
+; VBITS_EQ_256-NEXT: fcvtzu [[CVT_LO:z[0-9]+]].d, [[PG2]]/m, [[LO]].d
+; VBITS_EQ_256-NEXT: uzp1 [[UZP_LO:z[0-9]+]].s, [[CVT_LO]].s, [[CVT_LO]].s
+; VBITS_EQ_256-NEXT: uzp1 [[UZP_HI:z[0-9]+]].s, [[CVT_HI]].s, [[CVT_HI]].s
+; VBITS_EQ_256-NEXT: uzp1 z[[RES_LO:[0-9]+]].h, [[UZP_LO]].h, [[UZP_LO]].h
+; VBITS_EQ_256-NEXT: uzp1 z[[RES_HI:[0-9]+]].h, [[UZP_HI]].h, [[UZP_HI]].h
+; VBITS_EQ_256-NEXT: mov v[[RES_LO]].d[1], v[[RES_HI]].d[0]
+; VBITS_EQ_256-NEXT: ret
+  %op1 = load <8 x double>, <8 x double>* %a
+  %res = fptoui <8 x double> %op1 to <8 x i16>
+  ret <8 x i16> %res
+}
+
+define void @fcvtzu_v16f64_v16i16(<16 x double>* %a, <16 x i16>* %b) #0 {
+; CHECK-LABEL: fcvtzu_v16f64_v16i16:
+; VBITS_GE_1024: ptrue [[PG1:p[0-9]+]].d, vl16
+; VBITS_GE_1024-NEXT: ld1d { [[OP:z[0-9]+]].d }, [[PG1]]/z, [x0]
+; VBITS_GE_1024-NEXT: ptrue [[PG2:p[0-9]+]].d
+; VBITS_GE_1024-NEXT: fcvtzu [[CVT:z[0-9]+]].d, [[PG2]]/m, [[OP]].d
+; VBITS_GE_1024-NEXT: uzp1 [[UZP:z[0-9]+]].s, [[CVT]].s, [[CVT]].s
+; VBITS_GE_1024-NEXT: uzp1 [[RES:z[0-9]+]].h, [[UZP]].h, [[UZP]].h
+; VBITS_GE_1024-NEXT: ptrue [[PG3:p[0-9]+]].h, vl16
+; VBITS_GE_1024-NEXT: st1h { [[RES]].h }, [[PG3]], [x1]
+; VBITS_GE_1024-NEXT: ret
+  %op1 = load <16 x double>, <16 x double>* %a
+  %res = fptoui <16 x double> %op1 to <16 x i16>
+  store <16 x i16> %res, <16 x i16>* %b
+  ret void
+}
+
+define void @fcvtzu_v32f64_v32i16(<32 x double>* %a, <32 x i16>* %b) #0 {
+; CHECK-LABEL: fcvtzu_v32f64_v32i16:
+; VBITS_GE_2048: ptrue [[PG1:p[0-9]+]].d, vl32
+; VBITS_GE_2048-NEXT: ld1d { [[OP:z[0-9]+]].d }, [[PG1]]/z, [x0]
+; VBITS_GE_2048-NEXT: ptrue [[PG2:p[0-9]+]].d
+; VBITS_GE_2048-NEXT: fcvtzu [[CVT:z[0-9]+]].d, [[PG2]]/m, [[OP]].d
+; VBITS_GE_2048-NEXT: uzp1 [[UZP:z[0-9]+]].s, [[CVT]].s, [[CVT]].s
+; VBITS_GE_2048-NEXT: uzp1 [[RES:z[0-9]+]].h, [[UZP]].h, [[UZP]].h
+; VBITS_GE_2048-NEXT: ptrue [[PG3:p[0-9]+]].h, vl32
+; VBITS_GE_2048-NEXT: st1h { [[RES]].h }, [[PG3]], [x1]
+; VBITS_GE_2048-NEXT: ret
+  %op1 = load <32 x double>, <32 x double>* %a
+  %res = fptoui <32 x double> %op1 to <32 x i16>
+  store <32 x i16> %res, <32 x i16>* %b
+  ret void
+}
+
+;
+; FCVTZU D -> S
+;
+
+; Don't use SVE for 64-bit vectors.
+define <1 x i32> @fcvtzu_v1f64_v1i32(<1 x double> %op1) #0 {
+; CHECK-LABEL: fcvtzu_v1f64_v1i32:
+; CHECK: fcvtzu v0.2d, v0.2d
+; CHECK-NEXT: xtn v0.2s, v0.2d
+; CHECK-NEXT: ret
+  %res = fptoui <1 x double> %op1 to <1 x i32>
+  ret <1 x i32> %res
+}
+
+; Don't use SVE for 128-bit vectors.
+define <2 x i32> @fcvtzu_v2f64_v2i32(<2 x double> %op1) #0 {
+; CHECK-LABEL: fcvtzu_v2f64_v2i32:
+; CHECK: fcvtzu v0.2d, v0.2d
+; CHECK-NEXT: xtn v0.2s, v0.2d
+; CHECK-NEXT: ret
+  %res = fptoui <2 x double> %op1 to <2 x i32>
+  ret <2 x i32> %res
+}
+
+define <4 x i32> @fcvtzu_v4f64_v4i32(<4 x double>* %a) #0 {
+; CHECK-LABEL: fcvtzu_v4f64_v4i32:
+; CHECK: ptrue [[PG1:p[0-9]+]].d, vl4
+; CHECK-NEXT: ld1d { [[OP:z[0-9]+]].d }, [[PG1]]/z, [x0]
+; CHECK-NEXT: ptrue [[PG2:p[0-9]+]].d
+; CHECK-NEXT: fcvtzu [[CVT:z[0-9]+]].d, [[PG2]]/m, [[OP]].d
+; CHECK-NEXT: uzp1 z0.s, [[CVT]].s, [[CVT]].s
+; CHECK-NEXT: ret
+  %op1 = load <4 x double>, <4 x double>* %a
+  %res = fptoui <4 x double> %op1 to <4 x i32>
+  ret <4 x i32> %res
+}
+
+define void @fcvtzu_v8f64_v8i32(<8 x double>* %a, <8 x i32>* %b) #0 {
+; CHECK-LABEL: fcvtzu_v8f64_v8i32:
+; VBITS_GE_512: ptrue [[PG1:p[0-9]+]].d, vl8
+; VBITS_GE_512-NEXT: ld1d { [[OP:z[0-9]+]].d }, [[PG1]]/z, [x0]
+; VBITS_GE_512-NEXT: ptrue [[PG2:p[0-9]+]].d
+; VBITS_GE_512-NEXT: fcvtzu [[CVT:z[0-9]+]].d, [[PG2]]/m, [[OP]].d
+; VBITS_GE_512-NEXT: uzp1 [[RES:z[0-9]+]].s, [[CVT]].s, [[CVT]].s
+; VBITS_GE_512-NEXT: ptrue [[PG3:p[0-9]+]].s, vl8
+; VBITS_GE_512-NEXT: st1w { [[RES]].s }, [[PG3]], [x1]
+; VBITS_GE_512-NEXT: ret
+
+; Ensure sensible type legalisation.
+; VBITS_EQ_256: add x8, x0, #32
+; VBITS_EQ_256-NEXT: ptrue [[PG1:p[0-9]+]].d, vl4
+; VBITS_EQ_256-NEXT: ld1d { [[HI:z[0-9]+]].d }, [[PG]]/z, [x8]
+; VBITS_EQ_256-NEXT: ld1d { [[LO:z[0-9]+]].d }, [[PG]]/z, [x0]
+; VBITS_EQ_256-NEXT: ptrue [[PG2:p[0-9]+]].d
+; VBITS_EQ_256-NEXT: ptrue [[PG3:p[0-9]+]].s, vl4
+; VBITS_EQ_256-NEXT: fcvtzu [[CVT_HI:z[0-9]+]].d, [[PG2]]/m, [[HI]].d
+; VBITS_EQ_256-NEXT: fcvtzu [[CVT_LO:z[0-9]+]].d, [[PG2]]/m, [[LO]].d
+; VBITS_EQ_256-NEXT: uzp1 [[RES_LO:z[0-9]+]].s, [[CVT_LO]].s, [[CVT_LO]].s
+; VBITS_EQ_256-NEXT: uzp1 [[RES_HI:z[0-9]+]].s, [[CVT_HI]].s, [[CVT_HI]].s
+; VBITS_EQ_256-NEXT: splice [[RES:z[0-9]+]].s, [[PG3]], [[RES_LO]].s, [[RES_HI]].s
+; VBITS_EQ_256-NEXT: ptrue [[PG4:p[0-9]+]].s, vl8
+; VBITS_EQ_256-NEXT: st1w { [[RES]].s }, [[PG4]], [x1]
+; VBITS_EQ_256-NEXT: ret
+  %op1 = load <8 x double>, <8 x double>* %a
+  %res = fptoui <8 x double> %op1 to <8 x i32>
+  store <8 x i32> %res, <8 x i32>* %b
+  ret void
+}
+
+define void @fcvtzu_v16f64_v16i32(<16 x double>* %a, <16 x i32>* %b) #0 {
+; CHECK-LABEL: fcvtzu_v16f64_v16i32:
+; VBITS_GE_1024: ptrue [[PG1:p[0-9]+]].d, vl16
+; VBITS_GE_1024-NEXT: ld1d { [[OP:z[0-9]+]].d }, [[PG1]]/z, [x0]
+; VBITS_GE_1024-NEXT: ptrue [[PG2:p[0-9]+]].d
+; VBITS_GE_1024-NEXT: fcvtzu [[CVT:z[0-9]+]].d, [[PG2]]/m, [[OP]].d
+; VBITS_GE_1024-NEXT: uzp1 [[RES:z[0-9]+]].s, [[CVT]].s, [[CVT]].s
+; VBITS_GE_1024-NEXT: ptrue [[PG3:p[0-9]+]].s, vl16
+; VBITS_GE_1024-NEXT: st1w { [[RES]].s }, [[PG3]], [x1]
+; VBITS_GE_1024-NEXT: ret
+  %op1 = load <16 x double>, <16 x double>* %a
+  %res = fptoui <16 x double> %op1 to <16 x i32>
+  store <16 x i32> %res, <16 x i32>* %b
+  ret void
+}
+
+define void @fcvtzu_v32f64_v32i32(<32 x double>* %a, <32 x i32>* %b) #0 {
+; CHECK-LABEL: fcvtzu_v32f64_v32i32:
+; VBITS_GE_2048: ptrue [[PG1:p[0-9]+]].d, vl32
+; VBITS_GE_2048-NEXT: ld1d { [[OP:z[0-9]+]].d }, [[PG1]]/z, [x0]
+; VBITS_GE_2048-NEXT: ptrue [[PG2:p[0-9]+]].d
+; VBITS_GE_2048-NEXT: fcvtzu [[CVT:z[0-9]+]].d, [[PG2]]/m, [[OP]].d
+; VBITS_GE_2048-NEXT: uzp1 [[RES:z[0-9]+]].s, [[CVT]].s, [[CVT]].s
+; VBITS_GE_2048-NEXT: ptrue [[PG3:p[0-9]+]].s, vl32
+; VBITS_GE_2048-NEXT: st1w { [[RES]].s }, [[PG3]], [x1]
+; VBITS_GE_2048-NEXT: ret
+  %op1 = load <32 x double>, <32 x double>* %a
+  %res = fptoui <32 x double> %op1 to <32 x i32>
+  store <32 x i32> %res, <32 x i32>* %b
+  ret void
+}
+
+;
+; FCVTZU D -> D
+;
+
+; Don't use SVE for 64-bit vectors.
+define <1 x i64> @fcvtzu_v1f64_v1i64(<1 x double> %op1) #0 {
+; CHECK-LABEL: fcvtzu_v1f64_v1i64:
+; CHECK: fcvtzu x8, d0
+; CHECK: fmov d0, x8
+; CHECK-NEXT: ret
+  %res = fptoui <1 x double> %op1 to <1 x i64>
+  ret <1 x i64> %res
+}
+
+; Don't use SVE for 128-bit vectors.
+define <2 x i64> @fcvtzu_v2f64_v2i64(<2 x double> %op1) #0 {
+; CHECK-LABEL: fcvtzu_v2f64_v2i64:
+; CHECK: fcvtzu v0.2d, v0.2d
+; CHECK-NEXT: ret
+  %res = fptoui <2 x double> %op1 to <2 x i64>
+  ret <2 x i64> %res
+}
+
+define void @fcvtzu_v4f64_v4i64(<4 x double>* %a, <4 x i64>* %b) #0 {
+; CHECK-LABEL: fcvtzu_v4f64_v4i64:
+; CHECK: ptrue [[PG:p[0-9]+]].d, vl4
+; CHECK-NEXT: ld1d { [[OP:z[0-9]+]].d }, [[PG]]/z, [x0]
+; CHECK-NEXT: fcvtzu [[RES:z[0-9]+]].d, [[PG]]/m, [[OP]].d
+; CHECK-NEXT: st1d { [[RES]].d }, [[PG]], [x1]
+; CHECK-NEXT: ret
+  %op1 = load <4 x double>, <4 x double>* %a
+  %res = fptoui <4 x double> %op1 to <4 x i64>
+  store <4 x i64> %res, <4 x i64>* %b
+  ret void
+}
+
+define void @fcvtzu_v8f64_v8i64(<8 x double>* %a, <8 x i64>* %b) #0 {
+; CHECK-LABEL: fcvtzu_v8f64_v8i64:
+; VBITS_GE_512: ptrue [[PG:p[0-9]+]].d, vl8
+; VBITS_GE_512-NEXT: ld1d { [[OP:z[0-9]+]].d }, [[PG]]/z, [x0]
+; VBITS_GE_512-NEXT: fcvtzu [[RES:z[0-9]+]].d, [[PG]]/m, [[OP]].d
+; VBITS_GE_512-NEXT: st1d { [[RES]].d }, [[PG]], [x1]
+; VBITS_GE_512-NEXT: ret
+
+; Ensure sensible type legalisation.
+; VBITS_EQ_256: ptrue [[PG:p[0-9]+]].d, vl4
+; VBITS_EQ_256-NEXT: add x8, x0, #32
+; VBITS_EQ_256-NEXT: ld1d { [[LO:z[0-9]+]].d }, [[PG]]/z, [x0]
+; VBITS_EQ_256-NEXT: ld1d { [[HI:z[0-9]+]].d }, [[PG]]/z, [x8]
+; VBITS_EQ_256-NEXT: add x8, x1, #32
+; VBITS_EQ_256-NEXT: fcvtzu [[RES_LO:z[0-9]+]].d, [[PG]]/m, [[LO]].d
+; VBITS_EQ_256-NEXT: fcvtzu [[RES_HI:z[0-9]+]].d, [[PG]]/m, [[HI]].d
+; VBITS_EQ_256-NEXT: st1d { [[RES_LO]].d }, [[PG]], [x1]
+; VBITS_EQ_256-NEXT: st1d { [[RES_HI]].d }, [[PG]], [x8]
+; VBITS_EQ_256-NEXT: ret
+  %op1 = load <8 x double>, <8 x double>* %a
+  %res = fptoui <8 x double> %op1 to <8 x i64>
+  store <8 x i64> %res, <8 x i64>* %b
+  ret void
+}
+
+define void @fcvtzu_v16f64_v16i64(<16 x double>* %a, <16 x i64>* %b) #0 {
+; CHECK-LABEL: fcvtzu_v16f64_v16i64:
+; VBITS_GE_1024: ptrue [[PG:p[0-9]+]].d, vl16
+; VBITS_GE_1024-NEXT: ld1d { [[OP:z[0-9]+]].d }, [[PG]]/z, [x0]
+; VBITS_GE_1024-NEXT: fcvtzu [[RES:z[0-9]+]].d, [[PG]]/m, [[OP]].d
+; VBITS_GE_1024-NEXT: st1d { [[RES]].d }, [[PG]], [x1]
+; VBITS_GE_1024-NEXT: ret
+  %op1 = load <16 x double>, <16 x double>* %a
+  %res = fptoui <16 x double> %op1 to <16 x i64>
+  store <16 x i64> %res, <16 x i64>* %b
+  ret void
+}
+
+define void @fcvtzu_v32f64_v32i64(<32 x double>* %a, <32 x i64>* %b) #0 {
+; CHECK-LABEL: fcvtzu_v32f64_v32i64:
+; VBITS_GE_2048: ptrue [[PG:p[0-9]+]].d, vl32
+; VBITS_GE_2048-NEXT: ld1d { [[OP:z[0-9]+]].d }, [[PG]]/z, [x0]
+; VBITS_GE_2048-NEXT: fcvtzu [[RES:z[0-9]+]].d, [[PG]]/m, [[OP]].d
+; VBITS_GE_2048-NEXT: st1d { [[RES]].d }, [[PG]], [x1]
+; VBITS_GE_2048-NEXT: ret
+  %op1 = load <32 x double>, <32 x double>* %a
+  %res = fptoui <32 x double> %op1 to <32 x i64>
+  store <32 x i64> %res, <32 x i64>* %b
+  ret void
+}
+
+;
+; FCVTZS H -> H
+;
+
+; Don't use SVE for 64-bit vectors.
+define <4 x i16> @fcvtzs_v4f16_v4i16(<4 x half> %op1) #0 {
+; CHECK-LABEL: fcvtzs_v4f16_v4i16:
+; CHECK: fcvtzs v0.4h, v0.4h
+; CHECK-NEXT: ret
+  %res = fptosi <4 x half> %op1 to <4 x i16>
+  ret <4 x i16> %res
+}
+
+; Don't use SVE for 128-bit vectors.
+define void @fcvtzs_v8f16_v8i16(<8 x half>* %a, <8 x i16>* %b) #0 {
+; CHECK-LABEL: fcvtzs_v8f16_v8i16:
+; CHECK: ldr q0, [x0]
+; CHECK-NEXT: fcvtzs v0.8h, v0.8h
+; CHECK-NEXT: str q0, [x1]
+; CHECK-NEXT: ret
+  %op1 = load <8 x half>, <8 x half>* %a
+  %res = fptosi <8 x half> %op1 to <8 x i16>
+  store <8 x i16> %res, <8 x i16>* %b
+  ret void
+}
+
+define void @fcvtzs_v16f16_v16i16(<16 x half>* %a, <16 x i16>* %b) #0 {
+; CHECK-LABEL: fcvtzs_v16f16_v16i16:
+; CHECK: ptrue [[PG:p[0-9]+]].h, vl16
+; CHECK-NEXT: ld1h { [[OP:z[0-9]+]].h }, [[PG]]/z, [x0]
+; CHECK-NEXT: fcvtzs [[RES:z[0-9]+]].h, [[PG]]/m, [[OP]].h
+; CHECK-NEXT: st1h { [[RES]].h }, [[PG]], [x1]
+; CHECK-NEXT: ret
+  %op1 = load <16 x half>, <16 x half>* %a
+  %res = fptosi <16 x half> %op1 to <16 x i16>
+  store <16 x i16> %res, <16 x i16>* %b
+  ret void
+}
+
+define void @fcvtzs_v32f16_v32i16(<32 x half>* %a, <32 x i16>* %b) #0 {
+; CHECK-LABEL: fcvtzs_v32f16_v32i16:
+; VBITS_GE_512: ptrue [[PG:p[0-9]+]].h, vl32
+; VBITS_GE_512-NEXT: ld1h { [[OP:z[0-9]+]].h }, [[PG]]/z, [x0]
+; VBITS_GE_512-NEXT: fcvtzs [[RES:z[0-9]+]].h, [[PG]]/m, [[OP]].h
+; VBITS_GE_512-NEXT: st1h { [[RES]].h }, [[PG]], [x1]
+; VBITS_GE_512-NEXT: ret
+
+; Ensure sensible type legalisation.
+; VBITS_EQ_256: ptrue [[PG:p[0-9]+]].h, vl16
+; VBITS_EQ_256-NEXT: add x8, x0, #32
+; VBITS_EQ_256-NEXT: ld1h { [[LO:z[0-9]+]].h }, [[PG]]/z, [x0]
+; VBITS_EQ_256-NEXT: ld1h { [[HI:z[0-9]+]].h }, [[PG]]/z, [x8]
+; VBITS_EQ_256-NEXT: add x8, x1, #32
+; VBITS_EQ_256-NEXT: fcvtzs [[RES_LO:z[0-9]+]].h, [[PG]]/m, [[LO]].h
+; VBITS_EQ_256-NEXT: fcvtzs [[RES_HI:z[0-9]+]].h, [[PG]]/m, [[HI]].h
+; VBITS_EQ_256-NEXT: st1h { [[RES_LO]].h }, [[PG]], [x1]
+; VBITS_EQ_256-NEXT: st1h { [[RES_HI]].h }, [[PG]], [x8]
+; VBITS_EQ_256-NEXT: ret
+  %op1 = load <32 x half>, <32 x half>* %a
+  %res = fptosi <32 x half> %op1 to <32 x i16>
+  store <32 x i16> %res, <32 x i16>* %b
+  ret void
+}
+
+define void @fcvtzs_v64f16_v64i16(<64 x half>* %a, <64 x i16>* %b) #0 {
+; CHECK-LABEL: fcvtzs_v64f16_v64i16:
+; VBITS_GE_1024: ptrue [[PG:p[0-9]+]].h, vl64
+; VBITS_GE_1024-NEXT: ld1h { [[OP:z[0-9]+]].h }, [[PG]]/z, [x0]
+; VBITS_GE_1024-NEXT: fcvtzs [[RES:z[0-9]+]].h, [[PG]]/m, [[OP]].h
+; VBITS_GE_1024-NEXT: st1h { [[RES]].h }, [[PG]], [x1]
+; VBITS_GE_1024-NEXT: ret
+  %op1 = load <64 x half>, <64 x half>* %a
+  %res = fptosi <64 x half> %op1 to <64 x i16>
+  store <64 x i16> %res, <64 x i16>* %b
+  ret void
+}
+
+define void @fcvtzs_v128f16_v128i16(<128 x half>* %a, <128 x i16>* %b) #0 {
+; CHECK-LABEL: fcvtzs_v128f16_v128i16:
+; VBITS_GE_2048: ptrue [[PG:p[0-9]+]].h, vl128
+; VBITS_GE_2048-NEXT: ld1h { [[OP:z[0-9]+]].h }, [[PG]]/z, [x0]
+; VBITS_GE_2048-NEXT: fcvtzs [[RES:z[0-9]+]].h, [[PG]]/m, [[OP]].h
+; VBITS_GE_2048-NEXT: st1h { [[RES]].h }, [[PG]], [x1]
+; VBITS_GE_2048-NEXT: ret
+  %op1 = load <128 x half>, <128 x half>* %a
+  %res = fptosi <128 x half> %op1 to <128 x i16>
+  store <128 x i16> %res, <128 x i16>* %b
+  ret void
+}
+
+;
+; FCVTZS H -> S
+;
+
+; Don't use SVE for 64-bit vectors.
+define <2 x i32> @fcvtzs_v2f16_v2i32(<2 x half> %op1) #0 {
+; CHECK-LABEL: fcvtzs_v2f16_v2i32:
+; CHECK: fcvtl v0.4s, v0.4h
+; CHECK-NEXT: fcvtzs v0.4s, v0.4s
+; CHECK-NEXT: ret
+  %res = fptosi <2 x half> %op1 to <2 x i32>
+  ret <2 x i32> %res
+}
+
+; Don't use SVE for 128-bit vectors.
+define <4 x i32> @fcvtzs_v4f16_v4i32(<4 x half> %op1) #0 {
+; CHECK-LABEL: fcvtzs_v4f16_v4i32:
+; CHECK: fcvtzs v0.4s, v0.4s
+; CHECK-NEXT: ret
+  %res = fptosi <4 x half> %op1 to <4 x i32>
+  ret <4 x i32> %res
+}
+
+define void @fcvtzs_v8f16_v8i32(<8 x half>* %a, <8 x i32>* %b) #0 {
+; CHECK-LABEL: fcvtzs_v8f16_v8i32:
+; CHECK: ldr q[[OP:[0-9]+]], [x0]
+; CHECK-NEXT: ptrue [[PG:p[0-9]+]].s, vl8
+; CHECK-NEXT: uunpklo [[UPK:z[0-9]+]].s, z[[OP]].h
+; CHECK-NEXT: fcvtzs [[RES:z[0-9]+]].s, [[PG]]/m, [[UPK]].h
+; CHECK-NEXT: st1w { [[RES]].s }, [[PG]], [x1]
+; CHECK-NEXT: ret
+  %op1 = load <8 x half>, <8 x half>* %a
+  %res = fptosi <8 x half> %op1 to <8 x i32>
+  store <8 x i32> %res, <8 x i32>* %b
+  ret void
+}
+
+define void @fcvtzs_v16f16_v16i32(<16 x half>* %a, <16 x i32>* %b) #0 {
+; CHECK-LABEL: fcvtzs_v16f16_v16i32:
+; VBITS_GE_512: ptrue [[PG1:p[0-9]+]].h, vl16
+; VBITS_GE_512-NEXT: ld1h { [[OP:z[0-9]+]].h }, [[PG1]]/z, [x0]
+; VBITS_GE_512-NEXT: ptrue [[PG2:p[0-9]+]].s, vl16
+; VBITS_GE_512-NEXT: uunpklo [[UPK:z[0-9]+]].s, [[OP]].h
+; VBITS_GE_512-NEXT: fcvtzs [[RES:z[0-9]+]].s, [[PG2]]/m, [[UPK]].h
+; VBITS_GE_512-NEXT: st1w { [[RES]].s }, [[PG1]], [x1]
+; VBITS_GE_512-NEXT: ret
+
+; Ensure sensible type legalisation - fixed type extract_subvector codegen is poor currently.
+; VBITS_EQ_256: ptrue [[PG1:p[0-9]+]].h, vl16
+; VBITS_EQ_256-DAG: ld1h { [[VEC:z[0-9]+]].h }, [[PG1]]/z, [x0]
+; VBITS_EQ_256-DAG: st1h { [[VEC:z[0-9]+]].h }, [[PG1]], [x8]
+; VBITS_EQ_256-DAG: ldp q[[LO:[0-9]+]], q[[HI:[0-9]+]], [sp]
+; VBITS_EQ_256-NEXT: ptrue [[PG2:p[0-9]+]].s, vl8
+; VBITS_EQ_256-NEXT: add x8, x1, #32
+; VBITS_EQ_256-NEXT: uunpklo [[UPK_LO:z[0-9]+]].s, z[[LO]].h
+; VBITS_EQ_256-NEXT: uunpklo [[UPK_HI:z[0-9]+]].s, z[[HI]].h
+; VBITS_EQ_256-NEXT: fcvtzs [[RES_LO:z[0-9]+]].s, [[PG2]]/m, [[UPK_LO]].h
+; VBITS_EQ_256-NEXT: fcvtzs [[RES_HI:z[0-9]+]].s, [[PG2]]/m, [[UPK_HI]].h
+; VBITS_EQ_256-NEXT: st1w { [[RES_HI]].s }, [[PG2]], [x8]
+; VBITS_EQ_256-NEXT: st1w { [[RES_LO]].s }, [[PG2]], [x1]
+  %op1 = load <16 x half>, <16 x half>* %a
+  %res = fptosi <16 x half> %op1 to <16 x i32>
+  store <16 x i32> %res, <16 x i32>* %b
+  ret void
+}
+
+define void @fcvtzs_v32f16_v32i32(<32 x half>* %a, <32 x i32>* %b) #0 {
+; CHECK-LABEL: fcvtzs_v32f16_v32i32:
+; VBITS_GE_1024: ptrue [[PG1:p[0-9]+]].h, vl32
+; VBITS_GE_1024-NEXT: ld1h { [[OP:z[0-9]+]].h }, [[PG1]]/z, [x0]
+; VBITS_GE_1024-NEXT: ptrue [[PG2:p[0-9]+]].s, vl32
+; VBITS_GE_1024-NEXT: uunpklo [[UPK:z[0-9]+]].s, [[OP]].h
+; VBITS_GE_1024-NEXT: fcvtzs [[RES:z[0-9]+]].s, [[PG2]]/m, [[UPK]].h
+; VBITS_GE_1024-NEXT: st1w { [[RES]].s }, [[PG1]], [x1]
+; VBITS_GE_1024-NEXT: ret
+  %op1 = load <32 x half>, <32 x half>* %a
+  %res = fptosi <32 x half> %op1 to <32 x i32>
+  store <32 x i32> %res, <32 x i32>* %b
+  ret void
+}
+
+define void @fcvtzs_v64f16_v64i32(<64 x half>* %a, <64 x i32>* %b) #0 {
+; CHECK-LABEL: fcvtzs_v64f16_v64i32:
+; VBITS_GE_2048: ptrue [[PG1:p[0-9]+]].h, vl64
+; VBITS_GE_2048-NEXT: ld1h { [[OP:z[0-9]+]].h }, [[PG1]]/z, [x0]
+; VBITS_GE_2048-NEXT: ptrue [[PG2:p[0-9]+]].s, vl64
+; VBITS_GE_2048-NEXT: uunpklo [[UPK:z[0-9]+]].s, [[OP]].h
+; VBITS_GE_2048-NEXT: fcvtzs [[RES:z[0-9]+]].s, [[PG2]]/m, [[UPK]].h
+; VBITS_GE_2048-NEXT: st1w { [[RES]].s }, [[PG1]], [x1]
+; VBITS_GE_2048-NEXT: ret
+  %op1 = load <64 x half>, <64 x half>* %a
+  %res = fptosi <64 x half> %op1 to <64 x i32>
+  store <64 x i32> %res, <64 x i32>* %b
+  ret void
+}
+
+;
+; FCVTZS H -> D
+;
+
+; Don't use SVE for 64-bit vectors.
+define <1 x i64> @fcvtzs_v1f16_v1i64(<1 x half> %op1) #0 {
+; CHECK-LABEL: fcvtzs_v1f16_v1i64:
+; CHECK: fcvtzs x8, h0
+; CHECK-NEXT: fmov d0, x8
+; CHECK-NEXT: ret
+  %res = fptosi <1 x half> %op1 to <1 x i64>
+  ret <1 x i64> %res
+}
+
+; v2f16 is not legal for NEON, so use SVE
+define <2 x i64> @fcvtzs_v2f16_v2i64(<2 x half> %op1) #0 {
+; CHECK-LABEL: fcvtzs_v2f16_v2i64:
+; CHECK: ptrue [[PG:p[0-9]+]].d, vl4
+; CHECK-NEXT: uunpklo [[UPK1:z[0-9]+]].s, z0.h
+; CHECK-NEXT: uunpklo [[UPK2:z[0-9]+]].d, [[UPK1]].s
+; CHECK-NEXT: fcvtzs z0.d, [[PG]]/m, [[UPK2]].h
+; CHECK-NEXT: ret
+  %res = fptosi <2 x half> %op1 to <2 x i64>
+  ret <2 x i64> %res
+}
+
+define void @fcvtzs_v4f16_v4i64(<4 x half>* %a, <4 x i64>* %b) #0 {
+; CHECK-LABEL: fcvtzs_v4f16_v4i64:
+; CHECK: ldr d[[OP:[0-9]+]], [x0]
+; CHECK-NEXT: ptrue [[PG:p[0-9]+]].d, vl4
+; CHECK-NEXT: uunpklo [[UPK1:z[0-9]+]].s, z[[OP]].h
+; CHECK-NEXT: uunpklo [[UPK2:z[0-9]+]].d, [[UPK1]].s
+; CHECK-NEXT: fcvtzs [[RES:z[0-9]+]].d, [[PG]]/m, [[UPK2]].h
+; CHECK-NEXT: st1d { [[RES]].d }, [[PG]], [x1]
+; CHECK-NEXT: ret
+  %op1 = load <4 x half>, <4 x half>* %a
+  %res = fptosi <4 x half> %op1 to <4 x i64>
+  store <4 x i64> %res, <4 x i64>* %b
+  ret void
+}
+
+define void @fcvtzs_v8f16_v8i64(<8 x half>* %a, <8 x i64>* %b) #0 {
+; CHECK-LABEL: fcvtzs_v8f16_v8i64:
+; VBITS_GE_512: ldr q[[OP:[0-9]+]], [x0]
+; VBITS_GE_512-NEXT: ptrue [[PG:p[0-9]+]].d, vl8
+; VBITS_GE_512-NEXT: uunpklo [[UPK1:z[0-9]+]].s, z[[OP]].h
+; VBITS_GE_512-NEXT: uunpklo [[UPK2:z[0-9]+]].d, [[UPK1]].s
+; VBITS_GE_512-NEXT: fcvtzs [[RES:z[0-9]+]].d, [[PG]]/m, [[UPK2]].h
+; VBITS_GE_512-NEXT: st1d { [[RES]].d }, [[PG]], [x1]
+; VBITS_GE_512-NEXT: ret
+
+; Ensure sensible type legalisation.
+; VBITS_EQ_256: ldr q[[OP:[0-9]+]], [x0]
+; VBITS_EQ_256-NEXT: ptrue [[PG1:p[0-9]+]].d, vl4
+; VBITS_EQ_256-NEXT: add x8, x1, #32
+; VBITS_EQ_256-NEXT: ext v[[HI:[0-9]+]].16b, v[[LO:[0-9]+]].16b, v[[OP]].16b, #8
+; VBITS_EQ_256-NEXT: uunpklo [[UPK1_LO:z[0-9]+]].s, z[[LO]].h
+; VBITS_EQ_256-NEXT: uunpklo [[UPK1_HI:z[0-9]+]].s, z[[HI]].h
+; VBITS_EQ_256-NEXT: uunpklo [[UPK2_LO:z[0-9]+]].d, [[UPK1_LO]].s
+; VBITS_EQ_256-NEXT: uunpklo [[UPK2_HI:z[0-9]+]].d, [[UPK1_HI]].s
+; VBITS_EQ_256-NEXT: fcvtzs [[RES_LO:z[0-9]+]].d, [[PG2]]/m, [[UPK2_LO]].h
+; VBITS_EQ_256-NEXT: fcvtzs [[RES_HI:z[0-9]+]].d, [[PG2]]/m, [[UPK2_HI]].h
+; VBITS_EQ_256-NEXT: st1d { [[RES_LO]].d }, [[PG2]], [x1]
+; VBITS_EQ_256-NEXT: st1d { [[RES_HI]].d }, [[PG2]], [x8]
+; VBITS_EQ_256-NEXT: ret
+  %op1 = load <8 x half>, <8 x half>* %a
+  %res = fptosi <8 x half> %op1 to <8 x i64>
+  store <8 x i64> %res, <8 x i64>* %b
+  ret void
+}
+
+define void @fcvtzs_v16f16_v16i64(<16 x half>* %a, <16 x i64>* %b) #0 {
+; CHECK-LABEL: fcvtzs_v16f16_v16i64:
+; VBITS_GE_1024: ptrue [[PG1:p[0-9]+]].h, vl16
+; VBITS_GE_1024-NEXT: ld1h { [[OP:z[0-9]+]].h }, [[PG1]]/z, [x0]
+; VBITS_GE_1024-NEXT: ptrue [[PG2:p[0-9]+]].d, vl16
+; VBITS_GE_1024-NEXT: uunpklo [[UPK1:z[0-9]+]].s, [[OP]].h
+; VBITS_GE_1024-NEXT: uunpklo [[UPK2:z[0-9]+]].d, [[UPK1]].s
+; VBITS_GE_1024-NEXT: fcvtzs [[RES:z[0-9]+]].d, [[PG2]]/m, [[UPK2]].h
+; VBITS_GE_1024-NEXT: st1d { [[RES]].d }, [[PG1]], [x1]
+; VBITS_GE_1024-NEXT: ret
+  %op1 = load <16 x half>, <16 x half>* %a
+  %res = fptosi <16 x half> %op1 to <16 x i64>
+  store <16 x i64> %res, <16 x i64>* %b
+  ret void
+}
+
+define void @fcvtzs_v32f16_v32i64(<32 x half>* %a, <32 x i64>* %b) #0 {
+; CHECK-LABEL: fcvtzs_v32f16_v32i64:
+; VBITS_GE_2048: ptrue [[PG1:p[0-9]+]].h, vl32
+; VBITS_GE_2048-NEXT: ld1h { [[OP:z[0-9]+]].h }, [[PG1]]/z, [x0]
+; VBITS_GE_2048-NEXT: ptrue [[PG2:p[0-9]+]].d, vl32
+; VBITS_GE_2048-NEXT: uunpklo [[UPK1:z[0-9]+]].s, [[OP]].h
+; VBITS_GE_2048-NEXT: uunpklo [[UPK2:z[0-9]+]].d, [[UPK]].s
+; VBITS_GE_2048-NEXT: fcvtzs [[RES:z[0-9]+]].d, [[PG2]]/m, [[UPK2]].h
+; VBITS_GE_2048-NEXT: st1d { [[RES]].d }, [[PG1]], [x1]
+; VBITS_GE_2048-NEXT: ret
+  %op1 = load <32 x half>, <32 x half>* %a
+  %res = fptosi <32 x half> %op1 to <32 x i64>
+  store <32 x i64> %res, <32 x i64>* %b
+  ret void
+}
+
+;
+; FCVTZS S -> H
+;
+
+; Don't use SVE for 64-bit vectors.
+define <2 x i16> @fcvtzs_v2f32_v2i16(<2 x float> %op1) #0 {
+; CHECK-LABEL: fcvtzs_v2f32_v2i16:
+; CHECK: fcvtzs v0.2s, v0.2s
+; CHECK-NEXT: ret
+  %res = fptosi <2 x float> %op1 to <2 x i16>
+  ret <2 x i16> %res
+}
+
+; Don't use SVE for 128-bit vectors.
+define <4 x i16> @fcvtzs_v4f32_v4i16(<4 x float> %op1) #0 {
+; CHECK-LABEL: fcvtzs_v4f32_v4i16:
+; CHECK: fcvtzs v0.4s, v0.4s
+; CHECK-NEXT: mov w8, v0.s[1]
+; CHECK-NEXT: mov w9, v0.s[2]
+; CHECK-NEXT: mov w10, v0.s[3]
+; CHECK-NEXT: mov v0.h[1], w8
+; CHECK-NEXT: mov v0.h[2], w9
+; CHECK-NEXT: mov v0.h[3], w10
+; CHECK-NEXT: ret
+  %res = fptosi <4 x float> %op1 to <4 x i16>
+  ret <4 x i16> %res
+}
+
+define <8 x i16> @fcvtzs_v8f32_v8i16(<8 x float>* %a) #0 {
+; CHECK-LABEL: fcvtzs_v8f32_v8i16:
+; CHECK: ptrue [[PG1:p[0-9]+]].s, vl8
+; CHECK-NEXT: ld1w { [[OP:z[0-9]+]].s }, [[PG1]]/z, [x0]
+; CHECK-NEXT: ptrue [[PG2:p[0-9]+]].s
+; CHECK-NEXT: fcvtzs [[CVT:z[0-9]+]].s, [[PG2]]/m, [[OP]].s
+; CHECK-NEXT: uzp1 z0.h, [[CVT]].h, [[CVT]].h
+; CHECK-NEXT: ret
+  %op1 = load <8 x float>, <8 x float>* %a
+  %res = fptosi <8 x float> %op1 to <8 x i16>
+  ret <8 x i16> %res
+}
+
+define void @fcvtzs_v16f32_v16i16(<16 x float>* %a, <16 x i16>* %b) #0 {
+; CHECK-LABEL: fcvtzs_v16f32_v16i16:
+; VBITS_GE_512: ptrue [[PG1:p[0-9]+]].s, vl16
+; VBITS_GE_512-NEXT: ld1w { [[OP:z[0-9]+]].s }, [[PG1]]/z, [x0]
+; VBITS_GE_512-NEXT: ptrue [[PG2:p[0-9]+]].s
+; VBITS_GE_512-NEXT: fcvtzs [[CVT:z[0-9]+]].s, [[PG2]]/m, [[OP]].s
+; VBITS_GE_512-NEXT: uzp1 [[RES:z[0-9]+]].h, [[CVT]].h, [[CVT]].h
+; VBITS_GE_512-NEXT: ptrue [[PG3:p[0-9]+]].h, vl16
+; VBITS_GE_512-NEXT: st1h { [[RES]].h }, [[PG3]], [x1]
+; VBITS_GE_512-NEXT: ret
+
+; Ensure sensible type legalisation.
+; VBITS_EQ_256: add x8, x0, #32
+; VBITS_EQ_256-NEXT: ptrue [[PG1:p[0-9]+]].s, vl8
+; VBITS_EQ_256-NEXT: ld1w { [[HI:z[0-9]+]].s }, [[PG]]/z, [x8]
+; VBITS_EQ_256-NEXT: ld1w { [[LO:z[0-9]+]].s }, [[PG]]/z, [x0]
+; VBITS_EQ_256-NEXT: ptrue [[PG2:p[0-9]+]].s
+; VBITS_EQ_256-NEXT: ptrue [[PG3:p[0-9]+]].h, vl8
+; VBITS_EQ_256-NEXT: fcvtzs [[CVT_HI:z[0-9]+]].s, [[PG2]]/m, [[HI]].s
+; VBITS_EQ_256-NEXT: fcvtzs [[CVT_LO:z[0-9]+]].s, [[PG2]]/m, [[LO]].s
+; VBITS_EQ_256-NEXT: uzp1 [[RES_LO:z[0-9]+]].h, [[CVT_LO]].h, [[CVT_LO]].h
+; VBITS_EQ_256-NEXT: uzp1 [[RES_HI:z[0-9]+]].h, [[CVT_HI]].h, [[CVT_HI]].h
+; VBITS_EQ_256-NEXT: splice [[RES:z[0-9]+]].h, [[PG3]], [[RES_LO]].h, [[RES_HI]].h
+; VBITS_EQ_256-NEXT: ptrue [[PG4:p[0-9]+]].h, vl16
+; VBITS_EQ_256-NEXT: st1h { [[RES]].h }, [[PG4]], [x1]
+; VBITS_EQ_256-NEXT: ret
+  %op1 = load <16 x float>, <16 x float>* %a
+  %res = fptosi <16 x float> %op1 to <16 x i16>
+  store <16 x i16> %res, <16 x i16>* %b
+  ret void
+}
+
+define void @fcvtzs_v32f32_v32i16(<32 x float>* %a, <32 x i16>* %b) #0 {
+; CHECK-LABEL: fcvtzs_v32f32_v32i16:
+; VBITS_GE_1024: ptrue [[PG1:p[0-9]+]].s, vl32
+; VBITS_GE_1024-NEXT: ld1w { [[OP:z[0-9]+]].s }, [[PG1]]/z, [x0]
+; VBITS_GE_1024-NEXT: ptrue [[PG2:p[0-9]+]].s
+; VBITS_GE_1024-NEXT: fcvtzs [[CVT:z[0-9]+]].s, [[PG2]]/m, [[OP]].s
+; VBITS_GE_1024-NEXT: uzp1 [[RES:z[0-9]+]].h, [[CVT]].h, [[CVT]].h
+; VBITS_GE_1024-NEXT: ptrue [[PG3:p[0-9]+]].h, vl32
+; VBITS_GE_1024-NEXT: st1h { [[RES]].h }, [[PG3]], [x1]
+; VBITS_GE_1024-NEXT: ret
+  %op1 = load <32 x float>, <32 x float>* %a
+  %res = fptosi <32 x float> %op1 to <32 x i16>
+  store <32 x i16> %res, <32 x i16>* %b
+  ret void
+}
+
+define void @fcvtzs_v64f32_v64i16(<64 x float>* %a, <64 x i16>* %b) #0 {
+; CHECK-LABEL: fcvtzs_v64f32_v64i16:
+; VBITS_GE_2048: ptrue [[PG1:p[0-9]+]].s, vl64
+; VBITS_GE_2048-NEXT: ld1w { [[OP:z[0-9]+]].s }, [[PG1]]/z, [x0]
+; VBITS_GE_2048-NEXT: ptrue [[PG2:p[0-9]+]].s
+; VBITS_GE_2048-NEXT: fcvtzs [[RES:z[0-9]+]].s, [[PG2]]/m, [[UPK]].s
+; VBITS_GE_2048-NEXT: uzp1 [[RES:z[0-9]+]].h, [[CVT]].h, [[CVT]].h
+; VBITS_GE_2048-NEXT: ptrue [[PG3:p[0-9]+]].h, vl64
+; VBITS_GE_2048-NEXT: st1h { [[RES]].h }, [[PG3]], [x1]
+; VBITS_GE_2048-NEXT: ret
+  %op1 = load <64 x float>, <64 x float>* %a
+  %res = fptosi <64 x float> %op1 to <64 x i16>
+  store <64 x i16> %res, <64 x i16>* %b
+  ret void
+}
+
+;
+; FCVTZS S -> S
+;
+
+; Don't use SVE for 64-bit vectors.
+define <2 x i32> @fcvtzs_v2f32_v2i32(<2 x float> %op1) #0 {
+; CHECK-LABEL: fcvtzs_v2f32_v2i32:
+; CHECK: fcvtzs v0.2s, v0.2s
+; CHECK-NEXT: ret
+  %res = fptosi <2 x float> %op1 to <2 x i32>
+  ret <2 x i32> %res
+}
+
+; Don't use SVE for 128-bit vectors.
+define <4 x i32> @fcvtzs_v4f32_v4i32(<4 x float> %op1) #0 {
+; CHECK-LABEL: fcvtzs_v4f32_v4i32:
+; CHECK: fcvtzs v0.4s, v0.4s
+; CHECK-NEXT: ret
+  %res = fptosi <4 x float> %op1 to <4 x i32>
+  ret <4 x i32> %res
+}
+
+define void @fcvtzs_v8f32_v8i32(<8 x float>* %a, <8 x i32>* %b) #0 {
+; CHECK-LABEL: fcvtzs_v8f32_v8i32:
+; CHECK: ptrue [[PG:p[0-9]+]].s, vl8
+; CHECK-NEXT: ld1w { [[OP:z[0-9]+]].s }, [[PG]]/z, [x0]
+; CHECK-NEXT: fcvtzs [[RES:z[0-9]+]].s, [[PG]]/m, [[OP]].s
+; CHECK-NEXT: st1w { [[RES]].s }, [[PG]], [x1]
+; CHECK-NEXT: ret
+  %op1 = load <8 x float>, <8 x float>* %a
+  %res = fptosi <8 x float> %op1 to <8 x i32>
+  store <8 x i32> %res, <8 x i32>* %b
+  ret void
+}
+
+define void @fcvtzs_v16f32_v16i32(<16 x float>* %a, <16 x i32>* %b) #0 {
+; CHECK-LABEL: fcvtzs_v16f32_v16i32:
+; VBITS_GE_512: ptrue [[PG:p[0-9]+]].s, vl16
+; VBITS_GE_512-NEXT: ld1w { [[OP:z[0-9]+]].s }, [[PG]]/z, [x0]
+; VBITS_GE_512-NEXT: fcvtzs [[RES:z[0-9]+]].s, [[PG]]/m, [[OP]].s
+; VBITS_GE_512-NEXT: st1w { [[RES]].s }, [[PG]], [x1]
+; VBITS_GE_512-NEXT: ret
+
+; Ensure sensible type legalisation.
+; VBITS_EQ_256: ptrue [[PG:p[0-9]+]].s, vl8
+; VBITS_EQ_256-NEXT: add x8, x0, #32
+; VBITS_EQ_256-NEXT: ld1w { [[LO:z[0-9]+]].s }, [[PG]]/z, [x0]
+; VBITS_EQ_256-NEXT: ld1w { [[HI:z[0-9]+]].s }, [[PG]]/z, [x8]
+; VBITS_EQ_256-NEXT: add x8, x1, #32
+; VBITS_EQ_256-NEXT: fcvtzs [[RES_LO:z[0-9]+]].s, [[PG]]/m, [[LO]].s
+; VBITS_EQ_256-NEXT: fcvtzs [[RES_HI:z[0-9]+]].s, [[PG]]/m, [[HI]].s
+; VBITS_EQ_256-NEXT: st1w { [[RES_LO]].s }, [[PG]], [x1]
+; VBITS_EQ_256-NEXT: st1w { [[RES_HI]].s }, [[PG]], [x8]
+; VBITS_EQ_256-NEXT: ret
+  %op1 = load <16 x float>, <16 x float>* %a
+  %res = fptosi <16 x float> %op1 to <16 x i32>
+  store <16 x i32> %res, <16 x i32>* %b
+  ret void
+}
+
+define void @fcvtzs_v32f32_v32i32(<32 x float>* %a, <32 x i32>* %b) #0 {
+; CHECK-LABEL: fcvtzs_v32f32_v32i32:
+; VBITS_GE_1024: ptrue [[PG:p[0-9]+]].s, vl32
+; VBITS_GE_1024-NEXT: ld1w { [[OP:z[0-9]+]].s }, [[PG]]/z, [x0]
+; VBITS_GE_1024-NEXT: fcvtzs [[RES:z[0-9]+]].s, [[PG]]/m, [[OP]].s
+; VBITS_GE_1024-NEXT: st1w { [[RES]].s }, [[PG]], [x1]
+; VBITS_GE_1024-NEXT: ret
+  %op1 = load <32 x float>, <32 x float>* %a
+  %res = fptosi <32 x float> %op1 to <32 x i32>
+  store <32 x i32> %res, <32 x i32>* %b
+  ret void
+}
+
+define void @fcvtzs_v64f32_v64i32(<64 x float>* %a, <64 x i32>* %b) #0 {
+; CHECK-LABEL: fcvtzs_v64f32_v64i32:
+; VBITS_GE_2048: ptrue [[PG:p[0-9]+]].s, vl64
+; VBITS_GE_2048-NEXT: ld1w { [[OP:z[0-9]+]].s }, [[PG]]/z, [x0]
+; VBITS_GE_2048-NEXT: fcvtzs [[RES:z[0-9]+]].s, [[PG]]/m, [[OP]].s
+; VBITS_GE_2048-NEXT: st1w { [[RES]].s }, [[PG]], [x1]
+; VBITS_GE_2048-NEXT: ret
+  %op1 = load <64 x float>, <64 x float>* %a
+  %res = fptosi <64 x float> %op1 to <64 x i32>
+  store <64 x i32> %res, <64 x i32>* %b
+  ret void
+}
+
+;
+; FCVTZS S -> D
+;
+
+; Don't use SVE for 64-bit vectors.
+define <1 x i64> @fcvtzs_v1f32_v1i64(<1 x float> %op1) #0 {
+; CHECK-LABEL: fcvtzs_v1f32_v1i64:
+; CHECK: fcvtl v0.2d, v0.2s
+; CHECK-NEXT: fcvtzs v0.2d, v0.2d
+; CHECK-NEXT: ret
+  %res = fptosi <1 x float> %op1 to <1 x i64>
+  ret <1 x i64> %res
+}
+
+; Don't use SVE for 128-bit vectors.
+define <2 x i64> @fcvtzs_v2f32_v2i64(<2 x float> %op1) #0 {
+; CHECK-LABEL: fcvtzs_v2f32_v2i64:
+; CHECK: fcvtl v0.2d, v0.2s
+; CHECK-NEXT: fcvtzs v0.2d, v0.2d
+; CHECK-NEXT: ret
+  %res = fptosi <2 x float> %op1 to <2 x i64>
+  ret <2 x i64> %res
+}
+
+define void @fcvtzs_v4f32_v4i64(<4 x float>* %a, <4 x i64>* %b) #0 {
+; CHECK-LABEL: fcvtzs_v4f32_v4i64:
+; CHECK: ldr q[[OP:[0-9]+]], [x0]
+; CHECK-NEXT: ptrue [[PG:p[0-9]+]].d, vl4
+; CHECK-NEXT: uunpklo [[UPK:z[0-9]+]].d, z[[OP]].s
+; CHECK-NEXT: fcvtzs [[RES:z[0-9]+]].d, [[PG]]/m, [[UPK]].s
+; CHECK-NEXT: st1d { [[RES]].d }, [[PG]], [x1]
+; CHECK-NEXT: ret
+  %op1 = load <4 x float>, <4 x float>* %a
+  %res = fptosi <4 x float> %op1 to <4 x i64>
+  store <4 x i64> %res, <4 x i64>* %b
+  ret void
+}
+
+define void @fcvtzs_v8f32_v8i64(<8 x float>* %a, <8 x i64>* %b) #0 {
+; CHECK-LABEL: fcvtzs_v8f32_v8i64:
+; VBITS_GE_512: ptrue [[PG1:p[0-9]+]].s, vl8
+; VBITS_GE_512-NEXT: ld1w { [[OP:z[0-9]+]].s }, [[PG1]]/z, [x0]
+; VBITS_GE_512-NEXT: ptrue [[PG:p[0-9]+]].d, vl8
+; VBITS_GE_512-NEXT: uunpklo [[UPK:z[0-9]+]].d, [[OP]].s
+; VBITS_GE_512-NEXT: fcvtzs [[RES:z[0-9]+]].d, [[PG1]]/m, [[UPK]].s
+; VBITS_GE_512-NEXT: st1d { [[RES]].d }, [[PG1]], [x1]
+; VBITS_GE_512-NEXT: ret
+
+; Ensure sensible type legalisation - fixed type extract_subvector codegen is poor currently.
+; VBITS_EQ_256: ptrue [[PG1:p[0-9]+]].s, vl8
+; VBITS_EQ_256-DAG: ld1w { [[VEC:z[0-9]+]].s }, [[PG1]]/z, [x0]
+; VBITS_EQ_256-DAG: st1w { [[VEC:z[0-9]+]].s }, [[PG1]], [x8]
+; VBITS_EQ_256-DAG: ldp q[[LO:[0-9]+]], q[[HI:[0-9]+]], [sp]
+; VBITS_EQ_256-NEXT: ptrue [[PG2:p[0-9]+]].d, vl4
+; VBITS_EQ_256-NEXT: add x8, x1, #32
+; VBITS_EQ_256-NEXT: uunpklo [[UPK_LO:z[0-9]+]].d, z[[LO]].s
+; VBITS_EQ_256-NEXT: uunpklo [[UPK_HI:z[0-9]+]].d, z[[HI]].s
+; VBITS_EQ_256-NEXT: fcvtzs [[RES_LO:z[0-9]+]].d, [[PG2]]/m, [[UPK_LO]].s
+; VBITS_EQ_256-NEXT: fcvtzs [[RES_HI:z[0-9]+]].d, [[PG2]]/m, [[UPK_HI]].s
+; VBITS_EQ_256-NEXT: st1d { [[RES_HI]].d }, [[PG2]], [x8]
+; VBITS_EQ_256-NEXT: st1d { [[RES_LO]].d }, [[PG2]], [x1]
+  %op1 = load <8 x float>, <8 x float>* %a
+  %res = fptosi <8 x float> %op1 to <8 x i64>
+  store <8 x i64> %res, <8 x i64>* %b
+  ret void
+}
+
+define void @fcvtzs_v16f32_v16i64(<16 x float>* %a, <16 x i64>* %b) #0 {
+; CHECK-LABEL: fcvtzs_v16f32_v16i64:
+; VBITS_GE_1024: ptrue [[PG1:p[0-9]+]].s, vl16
+; VBITS_GE_1024-NEXT: ld1w { [[OP:z[0-9]+]].s }, [[PG1]]/z, [x0]
+; VBITS_GE_1024-NEXT: ptrue [[PG2:p[0-9]+]].d, vl16
+; VBITS_GE_1024-NEXT: uunpklo [[UPK:z[0-9]+]].d, [[OP]].s
+; VBITS_GE_1024-NEXT: fcvtzs [[RES:z[0-9]+]].d, [[PG2]]/m, [[UPK]].s
+; VBITS_GE_1024-NEXT: st1d { [[RES]].d }, [[PG1]], [x1]
+; VBITS_GE_1024-NEXT: ret
+  %op1 = load <16 x float>, <16 x float>* %a
+  %res = fptosi <16 x float> %op1 to <16 x i64>
+  store <16 x i64> %res, <16 x i64>* %b
+  ret void
+}
+
+define void @fcvtzs_v32f32_v32i64(<32 x float>* %a, <32 x i64>* %b) #0 {
+; CHECK-LABEL: fcvtzs_v32f32_v32i64:
+; VBITS_GE_2048: ptrue [[PG1:p[0-9]+]].s, vl32
+; VBITS_GE_2048-NEXT: ld1w { [[OP:z[0-9]+]].s }, [[PG1]]/z, [x0]
+; VBITS_GE_2048-NEXT: ptrue [[PG2:p[0-9]+]].d, vl32
+; VBITS_GE_2048-NEXT: uunpklo [[UPK:z[0-9]+]].d, [[OP]].s
+; VBITS_GE_2048-NEXT: fcvtzs [[RES:z[0-9]+]].d, [[PG2]]/m, [[UPK]].s
+; VBITS_GE_2048-NEXT: st1d { [[RES]].d }, [[PG1]], [x1]
+; VBITS_GE_2048-NEXT: ret
+  %op1 = load <32 x float>, <32 x float>* %a
+  %res = fptosi <32 x float> %op1 to <32 x i64>
+  store <32 x i64> %res, <32 x i64>* %b
+  ret void
+}
+
+
+;
+; FCVTZS D -> H
+;
+
+; v1f64 is perfered to be widened to v4f64, so use SVE
+define <1 x i16> @fcvtzs_v1f64_v1i16(<1 x double> %op1) #0 {
+; CHECK-LABEL: fcvtzs_v1f64_v1i16:
+; CHECK: ptrue [[PG:p[0-9]+]].d
+; CHECK-NEXT: fcvtzs [[CVT:z[0-9]+]].d, [[PG]]/m, z0.d
+; CHECK-NEXT: uzp1 [[UZP:z[0-9]+]].s, [[CVT]].s, [[CVT]].s
+; CHECK-NEXT: uzp1 z0.h, [[UZP]].h, [[UZP]].h
+; CHECK-NEXT: ret
+  %res = fptosi <1 x double> %op1 to <1 x i16>
+  ret <1 x i16> %res
+}
+
+; Don't use SVE for 128-bit vectors.
+define <2 x i16> @fcvtzs_v2f64_v2i16(<2 x double> %op1) #0 {
+; CHECK-LABEL: fcvtzs_v2f64_v2i16:
+; CHECK: fcvtzs v0.2d, v0.2d
+; CHECK-NEXT: xtn v0.2s, v0.2d
+; CHECK-NEXT: ret
+  %res = fptosi <2 x double> %op1 to <2 x i16>
+  ret <2 x i16> %res
+}
+
+define <4 x i16> @fcvtzs_v4f64_v4i16(<4 x double>* %a) #0 {
+; CHECK-LABEL: fcvtzs_v4f64_v4i16:
+; CHECK: ptrue [[PG1:p[0-9]+]].d, vl4
+; CHECK-NEXT: ld1d { [[OP:z[0-9]+]].d }, [[PG1]]/z, [x0]
+; CHECK-NEXT: ptrue [[PG2:p[0-9]+]].d
+; CHECK-NEXT: fcvtzs [[CVT:z[0-9]+]].d, [[PG2]]/m, [[OP]].d
+; CHECK-NEXT: uzp1 [[UZP:z[0-9]+]].s, [[CVT]].s, [[CVT]].s
+; CHECK-NEXT: uzp1 z0.h, [[UZP]].h, [[UZP]].h
+; CHECK-NEXT: ret
+  %op1 = load <4 x double>, <4 x double>* %a
+  %res = fptosi <4 x double> %op1 to <4 x i16>
+  ret <4 x i16> %res
+}
+
+define <8 x i16> @fcvtzs_v8f64_v8i16(<8 x double>* %a) #0 {
+; CHECK-LABEL: fcvtzs_v8f64_v8i16:
+; VBITS_GE_512: ptrue [[PG1:p[0-9]+]].d, vl8
+; VBITS_GE_512-NEXT: ld1d { [[OP:z[0-9]+]].d }, [[PG1]]/z, [x0]
+; VBITS_GE_512-NEXT: ptrue [[PG2:p[0-9]+]].d
+; VBITS_GE_512-NEXT: fcvtzs [[CVT:z[0-9]+]].d, [[PG2]]/m, [[OP]].d
+; VBITS_GE_512-NEXT: uzp1 [[UZP:z[0-9]+]].s, [[CVT]].s, [[CVT]].s
+; VBITS_GE_512-NEXT: uzp1 z0.h, [[UZP]].h, [[UZP]].h
+; VBITS_GE_512-NEXT: ret
+
+; Ensure sensible type legalisation.
+; VBITS_EQ_256: add x8, x0, #32
+; VBITS_EQ_256-NEXT: ptrue [[PG1:p[0-9]+]].d, vl4
+; VBITS_EQ_256-NEXT: ld1d { [[HI:z[0-9]+]].d }, [[PG]]/z, [x8]
+; VBITS_EQ_256-NEXT: ld1d { [[LO:z[0-9]+]].d }, [[PG]]/z, [x0]
+; VBITS_EQ_256-NEXT: ptrue [[PG2:p[0-9]+]].d
+; VBITS_EQ_256-NEXT: fcvtzs [[CVT_HI:z[0-9]+]].d, [[PG2]]/m, [[HI]].d
+; VBITS_EQ_256-NEXT: fcvtzs [[CVT_LO:z[0-9]+]].d, [[PG2]]/m, [[LO]].d
+; VBITS_EQ_256-NEXT: uzp1 [[UZP_LO:z[0-9]+]].s, [[CVT_LO]].s, [[CVT_LO]].s
+; VBITS_EQ_256-NEXT: uzp1 [[UZP_HI:z[0-9]+]].s, [[CVT_HI]].s, [[CVT_HI]].s
+; VBITS_EQ_256-NEXT: uzp1 z[[RES_LO:[0-9]+]].h, [[UZP_LO]].h, [[UZP_LO]].h
+; VBITS_EQ_256-NEXT: uzp1 z[[RES_HI:[0-9]+]].h, [[UZP_HI]].h, [[UZP_HI]].h
+; VBITS_EQ_256-NEXT: mov v[[RES_LO]].d[1], v[[RES_HI]].d[0]
+; VBITS_EQ_256-NEXT: ret
+  %op1 = load <8 x double>, <8 x double>* %a
+  %res = fptosi <8 x double> %op1 to <8 x i16>
+  ret <8 x i16> %res
+}
+
+define void @fcvtzs_v16f64_v16i16(<16 x double>* %a, <16 x i16>* %b) #0 {
+; CHECK-LABEL: fcvtzs_v16f64_v16i16:
+; VBITS_GE_1024: ptrue [[PG1:p[0-9]+]].d, vl16
+; VBITS_GE_1024-NEXT: ld1d { [[OP:z[0-9]+]].d }, [[PG1]]/z, [x0]
+; VBITS_GE_1024-NEXT: ptrue [[PG2:p[0-9]+]].d
+; VBITS_GE_1024-NEXT: fcvtzs [[CVT:z[0-9]+]].d, [[PG2]]/m, [[OP]].d
+; VBITS_GE_1024-NEXT: uzp1 [[UZP:z[0-9]+]].s, [[CVT]].s, [[CVT]].s
+; VBITS_GE_1024-NEXT: uzp1 [[RES:z[0-9]+]].h, [[UZP]].h, [[UZP]].h
+; VBITS_GE_1024-NEXT: ptrue [[PG3:p[0-9]+]].h, vl16
+; VBITS_GE_1024-NEXT: st1h { [[RES]].h }, [[PG3]], [x1]
+; VBITS_GE_1024-NEXT: ret
+  %op1 = load <16 x double>, <16 x double>* %a
+  %res = fptosi <16 x double> %op1 to <16 x i16>
+  store <16 x i16> %res, <16 x i16>* %b
+  ret void
+}
+
+define void @fcvtzs_v32f64_v32i16(<32 x double>* %a, <32 x i16>* %b) #0 {
+; CHECK-LABEL: fcvtzs_v32f64_v32i16:
+; VBITS_GE_2048: ptrue [[PG1:p[0-9]+]].d, vl32
+; VBITS_GE_2048-NEXT: ld1d { [[OP:z[0-9]+]].d }, [[PG1]]/z, [x0]
+; VBITS_GE_2048-NEXT: ptrue [[PG2:p[0-9]+]].d
+; VBITS_GE_2048-NEXT: fcvtzs [[CVT:z[0-9]+]].d, [[PG2]]/m, [[OP]].d
+; VBITS_GE_2048-NEXT: uzp1 [[UZP:z[0-9]+]].s, [[CVT]].s, [[CVT]].s
+; VBITS_GE_2048-NEXT: uzp1 [[RES:z[0-9]+]].h, [[UZP]].h, [[UZP]].h
+; VBITS_GE_2048-NEXT: ptrue [[PG3:p[0-9]+]].h, vl32
+; VBITS_GE_2048-NEXT: st1h { [[RES]].h }, [[PG3]], [x1]
+; VBITS_GE_2048-NEXT: ret
+  %op1 = load <32 x double>, <32 x double>* %a
+  %res = fptosi <32 x double> %op1 to <32 x i16>
+  store <32 x i16> %res, <32 x i16>* %b
+  ret void
+}
+
+;
+; FCVTZS D -> S
+;
+
+; Don't use SVE for 64-bit vectors.
+define <1 x i32> @fcvtzs_v1f64_v1i32(<1 x double> %op1) #0 {
+; CHECK-LABEL: fcvtzs_v1f64_v1i32:
+; CHECK: fcvtzs v0.2d, v0.2d
+; CHECK-NEXT: xtn v0.2s, v0.2d
+; CHECK-NEXT: ret
+  %res = fptosi <1 x double> %op1 to <1 x i32>
+  ret <1 x i32> %res
+}
+
+; Don't use SVE for 128-bit vectors.
+define <2 x i32> @fcvtzs_v2f64_v2i32(<2 x double> %op1) #0 {
+; CHECK-LABEL: fcvtzs_v2f64_v2i32:
+; CHECK: fcvtzs v0.2d, v0.2d
+; CHECK-NEXT: xtn v0.2s, v0.2d
+; CHECK-NEXT: ret
+  %res = fptosi <2 x double> %op1 to <2 x i32>
+  ret <2 x i32> %res
+}
+
+define <4 x i32> @fcvtzs_v4f64_v4i32(<4 x double>* %a) #0 {
+; CHECK-LABEL: fcvtzs_v4f64_v4i32:
+; CHECK: ptrue [[PG1:p[0-9]+]].d, vl4
+; CHECK-NEXT: ld1d { [[OP:z[0-9]+]].d }, [[PG1]]/z, [x0]
+; CHECK-NEXT: ptrue [[PG2:p[0-9]+]].d
+; CHECK-NEXT: fcvtzs [[CVT:z[0-9]+]].d, [[PG2]]/m, [[OP]].d
+; CHECK-NEXT: uzp1 z0.s, [[CVT]].s, [[CVT]].s
+; CHECK-NEXT: ret
+  %op1 = load <4 x double>, <4 x double>* %a
+  %res = fptosi <4 x double> %op1 to <4 x i32>
+  ret <4 x i32> %res
+}
+
+define void @fcvtzs_v8f64_v8i32(<8 x double>* %a, <8 x i32>* %b) #0 {
+; CHECK-LABEL: fcvtzs_v8f64_v8i32:
+; VBITS_GE_512: ptrue [[PG1:p[0-9]+]].d, vl8
+; VBITS_GE_512-NEXT: ld1d { [[OP:z[0-9]+]].d }, [[PG1]]/z, [x0]
+; VBITS_GE_512-NEXT: ptrue [[PG2:p[0-9]+]].d
+; VBITS_GE_512-NEXT: fcvtzs [[CVT:z[0-9]+]].d, [[PG2]]/m, [[OP]].d
+; VBITS_GE_512-NEXT: uzp1 [[RES:z[0-9]+]].s, [[CVT]].s, [[CVT]].s
+; VBITS_GE_512-NEXT: ptrue [[PG3:p[0-9]+]].s, vl8
+; VBITS_GE_512-NEXT: st1w { [[RES]].s }, [[PG3]], [x1]
+; VBITS_GE_512-NEXT: ret
+
+; Ensure sensible type legalisation.
+; VBITS_EQ_256: add x8, x0, #32
+; VBITS_EQ_256-NEXT: ptrue [[PG1:p[0-9]+]].d, vl4
+; VBITS_EQ_256-NEXT: ld1d { [[HI:z[0-9]+]].d }, [[PG]]/z, [x8]
+; VBITS_EQ_256-NEXT: ld1d { [[LO:z[0-9]+]].d }, [[PG]]/z, [x0]
+; VBITS_EQ_256-NEXT: ptrue [[PG2:p[0-9]+]].d
+; VBITS_EQ_256-NEXT: ptrue [[PG3:p[0-9]+]].s, vl4
+; VBITS_EQ_256-NEXT: fcvtzs [[CVT_HI:z[0-9]+]].d, [[PG2]]/m, [[HI]].d
+; VBITS_EQ_256-NEXT: fcvtzs [[CVT_LO:z[0-9]+]].d, [[PG2]]/m, [[LO]].d
+; VBITS_EQ_256-NEXT: uzp1 [[RES_LO:z[0-9]+]].s, [[CVT_LO]].s, [[CVT_LO]].s
+; VBITS_EQ_256-NEXT: uzp1 [[RES_HI:z[0-9]+]].s, [[CVT_HI]].s, [[CVT_HI]].s
+; VBITS_EQ_256-NEXT: splice [[RES:z[0-9]+]].s, [[PG3]], [[RES_LO]].s, [[RES_HI]].s
+; VBITS_EQ_256-NEXT: ptrue [[PG4:p[0-9]+]].s, vl8
+; VBITS_EQ_256-NEXT: st1w { [[RES]].s }, [[PG4]], [x1]
+; VBITS_EQ_256-NEXT: ret
+  %op1 = load <8 x double>, <8 x double>* %a
+  %res = fptosi <8 x double> %op1 to <8 x i32>
+  store <8 x i32> %res, <8 x i32>* %b
+  ret void
+}
+
+define void @fcvtzs_v16f64_v16i32(<16 x double>* %a, <16 x i32>* %b) #0 {
+; CHECK-LABEL: fcvtzs_v16f64_v16i32:
+; VBITS_GE_1024: ptrue [[PG1:p[0-9]+]].d, vl16
+; VBITS_GE_1024-NEXT: ld1d { [[OP:z[0-9]+]].d }, [[PG1]]/z, [x0]
+; VBITS_GE_1024-NEXT: ptrue [[PG2:p[0-9]+]].d
+; VBITS_GE_1024-NEXT: fcvtzs [[CVT:z[0-9]+]].d, [[PG2]]/m, [[OP]].d
+; VBITS_GE_1024-NEXT: uzp1 [[RES:z[0-9]+]].s, [[CVT]].s, [[CVT]].s
+; VBITS_GE_1024-NEXT: ptrue [[PG3:p[0-9]+]].s, vl16
+; VBITS_GE_1024-NEXT: st1w { [[RES]].s }, [[PG3]], [x1]
+; VBITS_GE_1024-NEXT: ret
+  %op1 = load <16 x double>, <16 x double>* %a
+  %res = fptosi <16 x double> %op1 to <16 x i32>
+  store <16 x i32> %res, <16 x i32>* %b
+  ret void
+}
+
+define void @fcvtzs_v32f64_v32i32(<32 x double>* %a, <32 x i32>* %b) #0 {
+; CHECK-LABEL: fcvtzs_v32f64_v32i32:
+; VBITS_GE_2048: ptrue [[PG1:p[0-9]+]].d, vl32
+; VBITS_GE_2048-NEXT: ld1d { [[OP:z[0-9]+]].d }, [[PG1]]/z, [x0]
+; VBITS_GE_2048-NEXT: ptrue [[PG2:p[0-9]+]].d
+; VBITS_GE_2048-NEXT: fcvtzs [[CVT:z[0-9]+]].d, [[PG2]]/m, [[OP]].d
+; VBITS_GE_2048-NEXT: uzp1 [[RES:z[0-9]+]].s, [[CVT]].s, [[CVT]].s
+; VBITS_GE_2048-NEXT: ptrue [[PG3:p[0-9]+]].s, vl32
+; VBITS_GE_2048-NEXT: st1w { [[RES]].s }, [[PG3]], [x1]
+; VBITS_GE_2048-NEXT: ret
+  %op1 = load <32 x double>, <32 x double>* %a
+  %res = fptosi <32 x double> %op1 to <32 x i32>
+  store <32 x i32> %res, <32 x i32>* %b
+  ret void
+}
+
+;
+; FCVTZS D -> D
+;
+
+; Don't use SVE for 64-bit vectors.
+define <1 x i64> @fcvtzs_v1f64_v1i64(<1 x double> %op1) #0 {
+; CHECK-LABEL: fcvtzs_v1f64_v1i64:
+; CHECK: fcvtzs x8, d0
+; CHECK: fmov d0, x8
+; CHECK-NEXT: ret
+  %res = fptosi <1 x double> %op1 to <1 x i64>
+  ret <1 x i64> %res
+}
+
+; Don't use SVE for 128-bit vectors.
+define <2 x i64> @fcvtzs_v2f64_v2i64(<2 x double> %op1) #0 {
+; CHECK-LABEL: fcvtzs_v2f64_v2i64:
+; CHECK: fcvtzs v0.2d, v0.2d
+; CHECK-NEXT: ret
+  %res = fptosi <2 x double> %op1 to <2 x i64>
+  ret <2 x i64> %res
+}
+
+define void @fcvtzs_v4f64_v4i64(<4 x double>* %a, <4 x i64>* %b) #0 {
+; CHECK-LABEL: fcvtzs_v4f64_v4i64:
+; CHECK: ptrue [[PG:p[0-9]+]].d, vl4
+; CHECK-NEXT: ld1d { [[OP:z[0-9]+]].d }, [[PG]]/z, [x0]
+; CHECK-NEXT: fcvtzs [[RES:z[0-9]+]].d, [[PG]]/m, [[OP]].d
+; CHECK-NEXT: st1d { [[RES]].d }, [[PG]], [x1]
+; CHECK-NEXT: ret
+  %op1 = load <4 x double>, <4 x double>* %a
+  %res = fptosi <4 x double> %op1 to <4 x i64>
+  store <4 x i64> %res, <4 x i64>* %b
+  ret void
+}
+
+define void @fcvtzs_v8f64_v8i64(<8 x double>* %a, <8 x i64>* %b) #0 {
+; CHECK-LABEL: fcvtzs_v8f64_v8i64:
+; VBITS_GE_512: ptrue [[PG:p[0-9]+]].d, vl8
+; VBITS_GE_512-NEXT: ld1d { [[OP:z[0-9]+]].d }, [[PG]]/z, [x0]
+; VBITS_GE_512-NEXT: fcvtzs [[RES:z[0-9]+]].d, [[PG]]/m, [[OP]].d
+; VBITS_GE_512-NEXT: st1d { [[RES]].d }, [[PG]], [x1]
+; VBITS_GE_512-NEXT: ret
+
+; Ensure sensible type legalisation.
+; VBITS_EQ_256: ptrue [[PG:p[0-9]+]].d, vl4
+; VBITS_EQ_256-NEXT: add x8, x0, #32
+; VBITS_EQ_256-NEXT: ld1d { [[LO:z[0-9]+]].d }, [[PG]]/z, [x0]
+; VBITS_EQ_256-NEXT: ld1d { [[HI:z[0-9]+]].d }, [[PG]]/z, [x8]
+; VBITS_EQ_256-NEXT: add x8, x1, #32
+; VBITS_EQ_256-NEXT: fcvtzs [[RES_LO:z[0-9]+]].d, [[PG]]/m, [[LO]].d
+; VBITS_EQ_256-NEXT: fcvtzs [[RES_HI:z[0-9]+]].d, [[PG]]/m, [[HI]].d
+; VBITS_EQ_256-NEXT: st1d { [[RES_LO]].d }, [[PG]], [x1]
+; VBITS_EQ_256-NEXT: st1d { [[RES_HI]].d }, [[PG]], [x8]
+; VBITS_EQ_256-NEXT: ret
+  %op1 = load <8 x double>, <8 x double>* %a
+  %res = fptosi <8 x double> %op1 to <8 x i64>
+  store <8 x i64> %res, <8 x i64>* %b
+  ret void
+}
+
+define void @fcvtzs_v16f64_v16i64(<16 x double>* %a, <16 x i64>* %b) #0 {
+; CHECK-LABEL: fcvtzs_v16f64_v16i64:
+; VBITS_GE_1024: ptrue [[PG:p[0-9]+]].d, vl16
+; VBITS_GE_1024-NEXT: ld1d { [[OP:z[0-9]+]].d }, [[PG]]/z, [x0]
+; VBITS_GE_1024-NEXT: fcvtzs [[RES:z[0-9]+]].d, [[PG]]/m, [[OP]].d
+; VBITS_GE_1024-NEXT: st1d { [[RES]].d }, [[PG]], [x1]
+; VBITS_GE_1024-NEXT: ret
+  %op1 = load <16 x double>, <16 x double>* %a
+  %res = fptosi <16 x double> %op1 to <16 x i64>
+  store <16 x i64> %res, <16 x i64>* %b
+  ret void
+}
+
+define void @fcvtzs_v32f64_v32i64(<32 x double>* %a, <32 x i64>* %b) #0 {
+; CHECK-LABEL: fcvtzs_v32f64_v32i64:
+; VBITS_GE_2048: ptrue [[PG:p[0-9]+]].d, vl32
+; VBITS_GE_2048-NEXT: ld1d { [[OP:z[0-9]+]].d }, [[PG]]/z, [x0]
+; VBITS_GE_2048-NEXT: fcvtzs [[RES:z[0-9]+]].d, [[PG]]/m, [[OP]].d
+; VBITS_GE_2048-NEXT: st1d { [[RES]].d }, [[PG]], [x1]
+; VBITS_GE_2048-NEXT: ret
+  %op1 = load <32 x double>, <32 x double>* %a
+  %res = fptosi <32 x double> %op1 to <32 x i64>
+  store <32 x i64> %res, <32 x i64>* %b
+  ret void
+}
+
+attributes #0 = { "target-features"="+sve" }

diff  --git a/llvm/test/CodeGen/AArch64/sve-fixed-length-int-to-fp.ll b/llvm/test/CodeGen/AArch64/sve-fixed-length-int-to-fp.ll
new file mode 100644
index 0000000000000..0a613156f7d09
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/sve-fixed-length-int-to-fp.ll
@@ -0,0 +1,1759 @@
+; RUN: llc -aarch64-sve-vector-bits-min=128  -asm-verbose=0 < %s | FileCheck %s -check-prefix=NO_SVE
+; RUN: llc -aarch64-sve-vector-bits-min=256  -asm-verbose=0 < %s | FileCheck %s -check-prefixes=CHECK,VBITS_EQ_256
+; RUN: llc -aarch64-sve-vector-bits-min=384  -asm-verbose=0 < %s | FileCheck %s -check-prefixes=CHECK
+; RUN: llc -aarch64-sve-vector-bits-min=512  -asm-verbose=0 < %s | FileCheck %s -check-prefixes=CHECK,VBITS_GE_512
+; RUN: llc -aarch64-sve-vector-bits-min=640  -asm-verbose=0 < %s | FileCheck %s -check-prefixes=CHECK,VBITS_GE_512
+; RUN: llc -aarch64-sve-vector-bits-min=768  -asm-verbose=0 < %s | FileCheck %s -check-prefixes=CHECK,VBITS_GE_512
+; RUN: llc -aarch64-sve-vector-bits-min=896  -asm-verbose=0 < %s | FileCheck %s -check-prefixes=CHECK,VBITS_GE_512
+; RUN: llc -aarch64-sve-vector-bits-min=1024 -asm-verbose=0 < %s | FileCheck %s -check-prefixes=CHECK,VBITS_GE_512,VBITS_GE_1024
+; RUN: llc -aarch64-sve-vector-bits-min=1152 -asm-verbose=0 < %s | FileCheck %s -check-prefixes=CHECK,VBITS_GE_512,VBITS_GE_1024
+; RUN: llc -aarch64-sve-vector-bits-min=1280 -asm-verbose=0 < %s | FileCheck %s -check-prefixes=CHECK,VBITS_GE_512,VBITS_GE_1024
+; RUN: llc -aarch64-sve-vector-bits-min=1408 -asm-verbose=0 < %s | FileCheck %s -check-prefixes=CHECK,VBITS_GE_512,VBITS_GE_1024
+; RUN: llc -aarch64-sve-vector-bits-min=1536 -asm-verbose=0 < %s | FileCheck %s -check-prefixes=CHECK,VBITS_GE_512,VBITS_GE_1024
+; RUN: llc -aarch64-sve-vector-bits-min=1664 -asm-verbose=0 < %s | FileCheck %s -check-prefixes=CHECK,VBITS_GE_512,VBITS_GE_1024
+; RUN: llc -aarch64-sve-vector-bits-min=1792 -asm-verbose=0 < %s | FileCheck %s -check-prefixes=CHECK,VBITS_GE_512,VBITS_GE_1024
+; RUN: llc -aarch64-sve-vector-bits-min=1920 -asm-verbose=0 < %s | FileCheck %s -check-prefixes=CHECK,VBITS_GE_512,VBITS_GE_1024
+; RUN: llc -aarch64-sve-vector-bits-min=2048 -asm-verbose=0 < %s | FileCheck %s -check-prefixes=CHECK,VBITS_GE_512,VBITS_GE_1024,VBITS_GE_2048
+
+target triple = "aarch64-unknown-linux-gnu"
+
+; Don't use SVE when its registers are no bigger than NEON.
+; NO_SVE-NOT: ptrue
+
+;
+; UCVTF H -> H
+;
+
+; Don't use SVE for 64-bit vectors.
+define <4 x half> @ucvtf_v4i16_v4f16(<4 x i16> %op1) #0 {
+; CHECK-LABEL: ucvtf_v4i16_v4f16:
+; CHECK: ucvtf v0.4h, v0.4h
+; CHECK-NEXT: ret
+  %res = uitofp <4 x i16> %op1 to <4 x half>
+  ret <4 x half> %res
+}
+
+; Don't use SVE for 128-bit vectors.
+define void @ucvtf_v8i16_v8f16(<8 x i16>* %a, <8 x half>* %b) #0 {
+; CHECK-LABEL: ucvtf_v8i16_v8f16:
+; CHECK: ldr q0, [x0]
+; CHECK-NEXT: ucvtf v0.8h, v0.8h
+; CHECK-NEXT: str q0, [x1]
+; CHECK-NEXT: ret
+  %op1 = load <8 x i16>, <8 x i16>* %a
+  %res = uitofp <8 x i16> %op1 to <8 x half>
+  store <8 x half> %res, <8 x half>* %b
+  ret void
+}
+
+define void @ucvtf_v16i16_v16f16(<16 x i16>* %a, <16 x half>* %b) #0 {
+; CHECK-LABEL: ucvtf_v16i16_v16f16:
+; CHECK: ptrue [[PG:p[0-9]+]].h, vl16
+; CHECK-NEXT: ld1h { [[OP:z[0-9]+]].h }, [[PG]]/z, [x0]
+; CHECK-NEXT: ucvtf [[RES:z[0-9]+]].h, [[PG]]/m, [[OP]].h
+; CHECK-NEXT: st1h { [[RES]].h }, [[PG]], [x1]
+; CHECK-NEXT: ret
+  %op1 = load <16 x i16>, <16 x i16>* %a
+  %res = uitofp <16 x i16> %op1 to <16 x half>
+  store <16 x half> %res, <16 x half>* %b
+  ret void
+}
+
+define void @ucvtf_v32i16_v32f16(<32 x i16>* %a, <32 x half>* %b) #0 {
+; CHECK-LABEL: ucvtf_v32i16_v32f16:
+; VBITS_GE_512: ptrue [[PG:p[0-9]+]].h, vl32
+; VBITS_GE_512-NEXT: ld1h { [[OP:z[0-9]+]].h }, [[PG]]/z, [x0]
+; VBITS_GE_512-NEXT: ucvtf [[RES:z[0-9]+]].h, [[PG]]/m, [[OP]].h
+; VBITS_GE_512-NEXT: st1h { [[RES]].h }, [[PG]], [x1]
+; VBITS_GE_512-NEXT: ret
+
+; Ensure sensible type legalisation.
+; VBITS_EQ_256: ptrue [[PG:p[0-9]+]].h, vl16
+; VBITS_EQ_256-NEXT: add x8, x0, #32
+; VBITS_EQ_256-NEXT: ld1h { [[LO:z[0-9]+]].h }, [[PG]]/z, [x0]
+; VBITS_EQ_256-NEXT: ld1h { [[HI:z[0-9]+]].h }, [[PG]]/z, [x8]
+; VBITS_EQ_256-NEXT: add x8, x1, #32
+; VBITS_EQ_256-NEXT: ucvtf [[RES_LO:z[0-9]+]].h, [[PG]]/m, [[LO]].h
+; VBITS_EQ_256-NEXT: ucvtf [[RES_HI:z[0-9]+]].h, [[PG]]/m, [[HI]].h
+; VBITS_EQ_256-NEXT: st1h { [[RES_LO]].h }, [[PG]], [x1]
+; VBITS_EQ_256-NEXT: st1h { [[RES_HI]].h }, [[PG]], [x8]
+; VBITS_EQ_256-NEXT: ret
+  %op1 = load <32 x i16>, <32 x i16>* %a
+  %res = uitofp <32 x i16> %op1 to <32 x half>
+  store <32 x half> %res, <32 x half>* %b
+  ret void
+}
+
+define void @ucvtf_v64i16_v64f16(<64 x i16>* %a, <64 x half>* %b) #0 {
+; CHECK-LABEL: ucvtf_v64i16_v64f16:
+; VBITS_GE_1024: ptrue [[PG:p[0-9]+]].h, vl64
+; VBITS_GE_1024-NEXT: ld1h { [[OP:z[0-9]+]].h }, [[PG]]/z, [x0]
+; VBITS_GE_1024-NEXT: ucvtf [[RES:z[0-9]+]].h, [[PG]]/m, [[OP]].h
+; VBITS_GE_1024-NEXT: st1h { [[RES]].h }, [[PG]], [x1]
+; VBITS_GE_1024-NEXT: ret
+  %op1 = load <64 x i16>, <64 x i16>* %a
+  %res = uitofp <64 x i16> %op1 to <64 x half>
+  store <64 x half> %res, <64 x half>* %b
+  ret void
+}
+
+define void @ucvtf_v128i16_v128f16(<128 x i16>* %a, <128 x half>* %b) #0 {
+; CHECK-LABEL: ucvtf_v128i16_v128f16:
+; VBITS_GE_2048: ptrue [[PG:p[0-9]+]].h, vl128
+; VBITS_GE_2048-NEXT: ld1h { [[OP:z[0-9]+]].h }, [[PG]]/z, [x0]
+; VBITS_GE_2048-NEXT: ucvtf [[RES:z[0-9]+]].h, [[PG]]/m, [[OP]].h
+; VBITS_GE_2048-NEXT: st1h { [[RES]].h }, [[PG]], [x1]
+; VBITS_GE_2048-NEXT: ret
+  %op1 = load <128 x i16>, <128 x i16>* %a
+  %res = uitofp <128 x i16> %op1 to <128 x half>
+  store <128 x half> %res, <128 x half>* %b
+  ret void
+}
+
+;
+; UCVTF H -> S
+;
+
+; Don't use SVE for 64-bit vectors.
+define <2 x float> @ucvtf_v2i16_v2f32(<2 x i16> %op1) #0 {
+; CHECK-LABEL: ucvtf_v2i16_v2f32:
+; CHECK: movi d1, #0x00ffff0000ffff
+; CHECK-NEXT: and v0.8b, v0.8b, v1.8b
+; CHECK-NEXT: ucvtf v0.2s, v0.2s
+; CHECK-NEXT: ret
+  %res = uitofp <2 x i16> %op1 to <2 x float>
+  ret <2 x float> %res
+}
+
+; Don't use SVE for 128-bit vectors.
+define <4 x float> @ucvtf_v4i16_v4f32(<4 x i16> %op1) #0 {
+; CHECK-LABEL: ucvtf_v4i16_v4f32:
+; CHECK: ucvtf v0.4s, v0.4s
+; CHECK-NEXT: ret
+  %res = uitofp <4 x i16> %op1 to <4 x float>
+  ret <4 x float> %res
+}
+
+define void @ucvtf_v8i16_v8f32(<8 x i16>* %a, <8 x float>* %b) #0 {
+; CHECK-LABEL: ucvtf_v8i16_v8f32:
+; CHECK: ldr q[[OP:[0-9]+]], [x0]
+; CHECK-NEXT: ptrue [[PG:p[0-9]+]].s, vl8
+; CHECK-NEXT: uunpklo [[UPK:z[0-9]+]].s, z[[OP]].h
+; CHECK-NEXT: ucvtf [[RES:z[0-9]+]].s, [[PG]]/m, [[UPK]].s
+; CHECK-NEXT: st1w { [[RES]].s }, [[PG]], [x1]
+; CHECK-NEXT: ret
+  %op1 = load <8 x i16>, <8 x i16>* %a
+  %res = uitofp <8 x i16> %op1 to <8 x float>
+  store <8 x float> %res, <8 x float>* %b
+  ret void
+}
+
+define void @ucvtf_v16i16_v16f32(<16 x i16>* %a, <16 x float>* %b) #0 {
+; CHECK-LABEL: ucvtf_v16i16_v16f32:
+; VBITS_GE_512: ptrue [[PG1:p[0-9]+]].h, vl16
+; VBITS_GE_512-NEXT: ld1h { [[OP:z[0-9]+]].h }, [[PG1]]/z, [x0]
+; VBITS_GE_512-NEXT: ptrue [[PG2:p[0-9]+]].s, vl16
+; VBITS_GE_512-NEXT: uunpklo [[UPK:z[0-9]+]].s, [[OP]].h
+; VBITS_GE_512-NEXT: ucvtf [[RES:z[0-9]+]].s, [[PG2]]/m, [[UPK]].s
+; VBITS_GE_512-NEXT: st1w { [[RES]].s }, [[PG1]], [x1]
+; VBITS_GE_512-NEXT: ret
+
+; Ensure sensible type legalisation - fixed type extract_subvector codegen is poor currently.
+; VBITS_EQ_256: ptrue [[PG1:p[0-9]+]].h, vl16
+; VBITS_EQ_256-DAG: ld1h { [[VEC:z[0-9]+]].h }, [[PG1]]/z, [x0]
+; VBITS_EQ_256-DAG: st1h { [[VEC:z[0-9]+]].h }, [[PG1]], [x8]
+; VBITS_EQ_256-DAG: ldp q[[LO:[0-9]+]], q[[HI:[0-9]+]], [sp]
+; VBITS_EQ_256-NEXT: ptrue [[PG2:p[0-9]+]].s, vl8
+; VBITS_EQ_256-NEXT: add x8, x1, #32
+; VBITS_EQ_256-NEXT: uunpklo [[UPK_LO:z[0-9]+]].s, z[[LO]].h
+; VBITS_EQ_256-NEXT: uunpklo [[UPK_HI:z[0-9]+]].s, z[[HI]].h
+; VBITS_EQ_256-NEXT: ucvtf [[RES_LO:z[0-9]+]].s, [[PG2]]/m, [[UPK_LO]].s
+; VBITS_EQ_256-NEXT: ucvtf [[RES_HI:z[0-9]+]].s, [[PG2]]/m, [[UPK_HI]].s
+; VBITS_EQ_256-NEXT: st1w { [[RES_HI]].s }, [[PG2]], [x8]
+; VBITS_EQ_256-NEXT: st1w { [[RES_LO]].s }, [[PG2]], [x1]
+  %op1 = load <16 x i16>, <16 x i16>* %a
+  %res = uitofp <16 x i16> %op1 to <16 x float>
+  store <16 x float> %res, <16 x float>* %b
+  ret void
+}
+
+define void @ucvtf_v32i16_v32f32(<32 x i16>* %a, <32 x float>* %b) #0 {
+; CHECK-LABEL: ucvtf_v32i16_v32f32:
+; VBITS_GE_1024: ptrue [[PG1:p[0-9]+]].h, vl32
+; VBITS_GE_1024-NEXT: ld1h { [[OP:z[0-9]+]].h }, [[PG1]]/z, [x0]
+; VBITS_GE_1024-NEXT: ptrue [[PG2:p[0-9]+]].s, vl32
+; VBITS_GE_1024-NEXT: uunpklo [[UPK:z[0-9]+]].s, [[OP]].h
+; VBITS_GE_1024-NEXT: ucvtf [[RES:z[0-9]+]].s, [[PG2]]/m, [[UPK]].s
+; VBITS_GE_1024-NEXT: st1w { [[RES]].s }, [[PG1]], [x1]
+; VBITS_GE_1024-NEXT: ret
+  %op1 = load <32 x i16>, <32 x i16>* %a
+  %res = uitofp <32 x i16> %op1 to <32 x float>
+  store <32 x float> %res, <32 x float>* %b
+  ret void
+}
+
+define void @ucvtf_v64i16_v64f32(<64 x i16>* %a, <64 x float>* %b) #0 {
+; CHECK-LABEL: ucvtf_v64i16_v64f32:
+; VBITS_GE_2048: ptrue [[PG1:p[0-9]+]].h, vl64
+; VBITS_GE_2048-NEXT: ld1h { [[OP:z[0-9]+]].h }, [[PG1]]/z, [x0]
+; VBITS_GE_2048-NEXT: ptrue [[PG2:p[0-9]+]].s, vl64
+; VBITS_GE_2048-NEXT: uunpklo [[UPK:z[0-9]+]].s, [[OP]].h
+; VBITS_GE_2048-NEXT: ucvtf [[RES:z[0-9]+]].s, [[PG2]]/m, [[UPK]].s
+; VBITS_GE_2048-NEXT: st1w { [[RES]].s }, [[PG1]], [x1]
+; VBITS_GE_2048-NEXT: ret
+  %op1 = load <64 x i16>, <64 x i16>* %a
+  %res = uitofp <64 x i16> %op1 to <64 x float>
+  store <64 x float> %res, <64 x float>* %b
+  ret void
+}
+
+;
+; UCVTF H -> D
+;
+
+; v1i16 is perfered to be widened to v4i16, which pushes the output into SVE types, so use SVE
+define <1 x double> @ucvtf_v1i16_v1f64(<1 x i16> %op1) #0 {
+; CHECK-LABEL: ucvtf_v1i16_v1f64:
+; CHECK: ptrue [[PG:p[0-9]+]].d, vl4
+; CHECK-NEXT: uunpklo [[UPK1:z[0-9]+]].s, z0.h
+; CHECK-NEXT: uunpklo [[UPK2:z[0-9]+]].d, [[UPK1]].s
+; CHECK-NEXT: ucvtf z0.d, [[PG]]/m, [[UPK2]].d
+; CHECK-NEXT: ret
+  %res = uitofp <1 x i16> %op1 to <1 x double>
+  ret <1 x double> %res
+}
+
+; Don't use SVE for 128-bit vectors.
+define <2 x double> @ucvtf_v2i16_v2f64(<2 x i16> %op1) #0 {
+; CHECK-LABEL: ucvtf_v2i16_v2f64:
+; CHECK: movi d1, #0x00ffff0000ffff
+; CHECK-NEXT: and v0.8b, v0.8b, v1.8b
+; CHECK-NEXT: ushll v0.2d, v0.2s, #0
+; CHECK-NEXT: ucvtf v0.2d, v0.2d
+; CHECK-NEXT: ret
+  %res = uitofp <2 x i16> %op1 to <2 x double>
+  ret <2 x double> %res
+}
+
+define void @ucvtf_v4i16_v4f64(<4 x i16>* %a, <4 x double>* %b) #0 {
+; CHECK-LABEL: ucvtf_v4i16_v4f64:
+; CHECK: ldr d[[OP:[0-9]+]], [x0]
+; CHECK-NEXT: ptrue [[PG:p[0-9]+]].d, vl4
+; CHECK-NEXT: uunpklo [[UPK1:z[0-9]+]].s, z[[OP]].h
+; CHECK-NEXT: uunpklo [[UPK2:z[0-9]+]].d, [[UPK1]].s
+; CHECK-NEXT: ucvtf [[RES:z[0-9]+]].d, [[PG]]/m, [[UPK2]].d
+; CHECK-NEXT: st1d { [[RES]].d }, [[PG]], [x1]
+; CHECK-NEXT: ret
+  %op1 = load <4 x i16>, <4 x i16>* %a
+  %res = uitofp <4 x i16> %op1 to <4 x double>
+  store <4 x double> %res, <4 x double>* %b
+  ret void
+}
+
+define void @ucvtf_v8i16_v8f64(<8 x i16>* %a, <8 x double>* %b) #0 {
+; CHECK-LABEL: ucvtf_v8i16_v8f64:
+; VBITS_GE_512: ldr q[[OP:[0-9]+]], [x0]
+; VBITS_GE_512-NEXT: ptrue [[PG:p[0-9]+]].d, vl8
+; VBITS_GE_512-NEXT: uunpklo [[UPK1:z[0-9]+]].s, z[[OP]].h
+; VBITS_GE_512-NEXT: uunpklo [[UPK2:z[0-9]+]].d, [[UPK1]].s
+; VBITS_GE_512-NEXT: ucvtf [[RES:z[0-9]+]].d, [[PG]]/m, [[UPK2]].d
+; VBITS_GE_512-NEXT: st1d { [[RES]].d }, [[PG]], [x1]
+; VBITS_GE_512-NEXT: ret
+
+; Ensure sensible type legalisation.
+; VBITS_EQ_256: ldr q[[OP:[0-9]+]], [x0]
+; VBITS_EQ_256-NEXT: ptrue [[PG1:p[0-9]+]].d, vl4
+; VBITS_EQ_256-NEXT: add x8, x1, #32
+; VBITS_EQ_256-NEXT: ext v[[HI:[0-9]+]].16b, v[[LO:[0-9]+]].16b, v[[OP]].16b, #8
+; VBITS_EQ_256-NEXT: uunpklo [[UPK1_LO:z[0-9]+]].s, z[[LO]].h
+; VBITS_EQ_256-NEXT: uunpklo [[UPK1_HI:z[0-9]+]].s, z[[HI]].h
+; VBITS_EQ_256-NEXT: uunpklo [[UPK2_LO:z[0-9]+]].d, [[UPK1_LO]].s
+; VBITS_EQ_256-NEXT: uunpklo [[UPK2_HI:z[0-9]+]].d, [[UPK1_HI]].s
+; VBITS_EQ_256-NEXT: ucvtf [[RES_LO:z[0-9]+]].d, [[PG2]]/m, [[UPK2_LO]].d
+; VBITS_EQ_256-NEXT: ucvtf [[RES_HI:z[0-9]+]].d, [[PG2]]/m, [[UPK2_HI]].d
+; VBITS_EQ_256-NEXT: st1d { [[RES_LO]].d }, [[PG2]], [x1]
+; VBITS_EQ_256-NEXT: st1d { [[RES_HI]].d }, [[PG2]], [x8]
+; VBITS_EQ_256-NEXT: ret
+  %op1 = load <8 x i16>, <8 x i16>* %a
+  %res = uitofp <8 x i16> %op1 to <8 x double>
+  store <8 x double> %res, <8 x double>* %b
+  ret void
+}
+
+define void @ucvtf_v16i16_v16f64(<16 x i16>* %a, <16 x double>* %b) #0 {
+; CHECK-LABEL: ucvtf_v16i16_v16f64:
+; VBITS_GE_1024: ptrue [[PG1:p[0-9]+]].h, vl16
+; VBITS_GE_1024-NEXT: ld1h { [[OP:z[0-9]+]].h }, [[PG1]]/z, [x0]
+; VBITS_GE_1024-NEXT: ptrue [[PG2:p[0-9]+]].d, vl16
+; VBITS_GE_1024-NEXT: uunpklo [[UPK1:z[0-9]+]].s, [[OP]].h
+; VBITS_GE_1024-NEXT: uunpklo [[UPK2:z[0-9]+]].d, [[UPK1]].s
+; VBITS_GE_1024-NEXT: ucvtf [[RES:z[0-9]+]].d, [[PG2]]/m, [[UPK2]].d
+; VBITS_GE_1024-NEXT: st1d { [[RES]].d }, [[PG1]], [x1]
+; VBITS_GE_1024-NEXT: ret
+  %op1 = load <16 x i16>, <16 x i16>* %a
+  %res = uitofp <16 x i16> %op1 to <16 x double>
+  store <16 x double> %res, <16 x double>* %b
+  ret void
+}
+
+define void @ucvtf_v32i16_v32f64(<32 x i16>* %a, <32 x double>* %b) #0 {
+; CHECK-LABEL: ucvtf_v32i16_v32f64:
+; VBITS_GE_2048: ptrue [[PG1:p[0-9]+]].h, vl32
+; VBITS_GE_2048-NEXT: ld1h { [[OP:z[0-9]+]].h }, [[PG1]]/z, [x0]
+; VBITS_GE_2048-NEXT: ptrue [[PG2:p[0-9]+]].d, vl32
+; VBITS_GE_2048-NEXT: uunpklo [[UPK1:z[0-9]+]].s, [[OP]].h
+; VBITS_GE_2048-NEXT: uunpklo [[UPK2:z[0-9]+]].d, [[UPK]].s
+; VBITS_GE_2048-NEXT: ucvtf [[RES:z[0-9]+]].d, [[PG2]]/m, [[UPK2]].d
+; VBITS_GE_2048-NEXT: st1d { [[RES]].d }, [[PG1]], [x1]
+; VBITS_GE_2048-NEXT: ret
+  %op1 = load <32 x i16>, <32 x i16>* %a
+  %res = uitofp <32 x i16> %op1 to <32 x double>
+  store <32 x double> %res, <32 x double>* %b
+  ret void
+}
+
+;
+; UCVTF S -> H
+;
+
+; Don't use SVE for 64-bit vectors.
+define <2 x half> @ucvtf_v2i32_v2f16(<2 x i32> %op1) #0 {
+; CHECK-LABEL: ucvtf_v2i32_v2f16:
+; CHECK: ucvtf v0.4s, v0.4s
+; CHECK-NEXT: fcvtn v0.4h, v0.4s
+; CHECK-NEXT: ret
+  %res = uitofp <2 x i32> %op1 to <2 x half>
+  ret <2 x half> %res
+}
+
+; Don't use SVE for 128-bit vectors.
+define <4 x half> @ucvtf_v4i32_v4f16(<4 x i32> %op1) #0 {
+; CHECK-LABEL: ucvtf_v4i32_v4f16:
+; CHECK: ucvtf v0.4s, v0.4s
+; CHECK-NEXT: fcvtn v0.4h, v0.4s
+; CHECK-NEXT: ret
+  %res = uitofp <4 x i32> %op1 to <4 x half>
+  ret <4 x half> %res
+}
+
+define <8 x half> @ucvtf_v8i32_v8f16(<8 x i32>* %a) #0 {
+; CHECK-LABEL: ucvtf_v8i32_v8f16:
+; CHECK: ptrue [[PG1:p[0-9]+]].s, vl8
+; CHECK-NEXT: ld1w { [[OP:z[0-9]+]].s }, [[PG1]]/z, [x0]
+; CHECK-NEXT: ptrue [[PG2:p[0-9]+]].s
+; CHECK-NEXT: ucvtf [[CVT:z[0-9]+]].h, [[PG2]]/m, [[OP]].s
+; CHECK-NEXT: uzp1 z0.h, [[CVT]].h, [[CVT]].h
+; CHECK-NEXT: ret
+  %op1 = load <8 x i32>, <8 x i32>* %a
+  %res = uitofp <8 x i32> %op1 to <8 x half>
+  ret <8 x half> %res
+}
+
+define void @ucvtf_v16i32_v16f16(<16 x i32>* %a, <16 x half>* %b) #0 {
+; CHECK-LABEL: ucvtf_v16i32_v16f16:
+; VBITS_GE_512: ptrue [[PG1:p[0-9]+]].s, vl16
+; VBITS_GE_512-NEXT: ld1w { [[OP:z[0-9]+]].s }, [[PG1]]/z, [x0]
+; VBITS_GE_512-NEXT: ptrue [[PG2:p[0-9]+]].s
+; VBITS_GE_512-NEXT: ucvtf [[CVT:z[0-9]+]].h, [[PG2]]/m, [[OP]].s
+; VBITS_GE_512-NEXT: uzp1 [[RES:z[0-9]+]].h, [[CVT]].h, [[CVT]].h
+; VBITS_GE_512-NEXT: ptrue [[PG3:p[0-9]+]].h, vl16
+; VBITS_GE_512-NEXT: st1h { [[RES]].h }, [[PG3]], [x1]
+; VBITS_GE_512-NEXT: ret
+
+; Ensure sensible type legalisation.
+; VBITS_EQ_256: add x8, x0, #32
+; VBITS_EQ_256-NEXT: ptrue [[PG1:p[0-9]+]].s, vl8
+; VBITS_EQ_256-NEXT: ld1w { [[HI:z[0-9]+]].s }, [[PG]]/z, [x8]
+; VBITS_EQ_256-NEXT: ld1w { [[LO:z[0-9]+]].s }, [[PG]]/z, [x0]
+; VBITS_EQ_256-NEXT: ptrue [[PG2:p[0-9]+]].s
+; VBITS_EQ_256-NEXT: ptrue [[PG3:p[0-9]+]].h, vl8
+; VBITS_EQ_256-NEXT: ucvtf [[CVT_HI:z[0-9]+]].h, [[PG2]]/m, [[HI]].s
+; VBITS_EQ_256-NEXT: ucvtf [[CVT_LO:z[0-9]+]].h, [[PG2]]/m, [[LO]].s
+; VBITS_EQ_256-NEXT: uzp1 [[RES_LO:z[0-9]+]].h, [[CVT_LO]].h, [[CVT_LO]].h
+; VBITS_EQ_256-NEXT: uzp1 [[RES_HI:z[0-9]+]].h, [[CVT_HI]].h, [[CVT_HI]].h
+; VBITS_EQ_256-NEXT: splice [[RES:z[0-9]+]].h, [[PG3]], [[RES_LO]].h, [[RES_HI]].h
+; VBITS_EQ_256-NEXT: ptrue [[PG4:p[0-9]+]].h, vl16
+; VBITS_EQ_256-NEXT: st1h { [[RES]].h }, [[PG4]], [x1]
+; VBITS_EQ_256-NEXT: ret
+  %op1 = load <16 x i32>, <16 x i32>* %a
+  %res = uitofp <16 x i32> %op1 to <16 x half>
+  store <16 x half> %res, <16 x half>* %b
+  ret void
+}
+
+define void @ucvtf_v32i32_v32f16(<32 x i32>* %a, <32 x half>* %b) #0 {
+; CHECK-LABEL: ucvtf_v32i32_v32f16:
+; VBITS_GE_1024: ptrue [[PG1:p[0-9]+]].s, vl32
+; VBITS_GE_1024-NEXT: ld1w { [[OP:z[0-9]+]].s }, [[PG1]]/z, [x0]
+; VBITS_GE_1024-NEXT: ptrue [[PG2:p[0-9]+]].s
+; VBITS_GE_1024-NEXT: ucvtf [[CVT:z[0-9]+]].h, [[PG2]]/m, [[OP]].s
+; VBITS_GE_1024-NEXT: uzp1 [[RES:z[0-9]+]].h, [[CVT]].h, [[CVT]].h
+; VBITS_GE_1024-NEXT: ptrue [[PG3:p[0-9]+]].h, vl32
+; VBITS_GE_1024-NEXT: st1h { [[RES]].h }, [[PG3]], [x1]
+; VBITS_GE_1024-NEXT: ret
+  %op1 = load <32 x i32>, <32 x i32>* %a
+  %res = uitofp <32 x i32> %op1 to <32 x half>
+  store <32 x half> %res, <32 x half>* %b
+  ret void
+}
+
+define void @ucvtf_v64i32_v64f16(<64 x i32>* %a, <64 x half>* %b) #0 {
+; CHECK-LABEL: ucvtf_v64i32_v64f16:
+; VBITS_GE_2048: ptrue [[PG1:p[0-9]+]].s, vl64
+; VBITS_GE_2048-NEXT: ld1w { [[OP:z[0-9]+]].s }, [[PG1]]/z, [x0]
+; VBITS_GE_2048-NEXT: ptrue [[PG2:p[0-9]+]].s
+; VBITS_GE_2048-NEXT: ucvtf [[RES:z[0-9]+]].h, [[PG2]]/m, [[UPK]].s
+; VBITS_GE_2048-NEXT: uzp1 [[RES:z[0-9]+]].h, [[CVT]].h, [[CVT]].h
+; VBITS_GE_2048-NEXT: ptrue [[PG3:p[0-9]+]].h, vl64
+; VBITS_GE_2048-NEXT: st1h { [[RES]].h }, [[PG3]], [x1]
+; VBITS_GE_2048-NEXT: ret
+  %op1 = load <64 x i32>, <64 x i32>* %a
+  %res = uitofp <64 x i32> %op1 to <64 x half>
+  store <64 x half> %res, <64 x half>* %b
+  ret void
+}
+
+;
+; UCVTF S -> S
+;
+
+; Don't use SVE for 64-bit vectors.
+define <2 x float> @ucvtf_v2i32_v2f32(<2 x i32> %op1) #0 {
+; CHECK-LABEL: ucvtf_v2i32_v2f32:
+; CHECK: ucvtf v0.2s, v0.2s
+; CHECK-NEXT: ret
+  %res = uitofp <2 x i32> %op1 to <2 x float>
+  ret <2 x float> %res
+}
+
+; Don't use SVE for 128-bit vectors.
+define <4 x float> @ucvtf_v4i32_v4f32(<4 x i32> %op1) #0 {
+; CHECK-LABEL: ucvtf_v4i32_v4f32:
+; CHECK: ucvtf v0.4s, v0.4s
+; CHECK-NEXT: ret
+  %res = uitofp <4 x i32> %op1 to <4 x float>
+  ret <4 x float> %res
+}
+
+define void @ucvtf_v8i32_v8f32(<8 x i32>* %a, <8 x float>* %b) #0 {
+; CHECK-LABEL: ucvtf_v8i32_v8f32:
+; CHECK: ptrue [[PG:p[0-9]+]].s, vl8
+; CHECK-NEXT: ld1w { [[OP:z[0-9]+]].s }, [[PG]]/z, [x0]
+; CHECK-NEXT: ucvtf [[RES:z[0-9]+]].s, [[PG]]/m, [[OP]].s
+; CHECK-NEXT: st1w { [[RES]].s }, [[PG]], [x1]
+; CHECK-NEXT: ret
+  %op1 = load <8 x i32>, <8 x i32>* %a
+  %res = uitofp <8 x i32> %op1 to <8 x float>
+  store <8 x float> %res, <8 x float>* %b
+  ret void
+}
+
+define void @ucvtf_v16i32_v16f32(<16 x i32>* %a, <16 x float>* %b) #0 {
+; CHECK-LABEL: ucvtf_v16i32_v16f32:
+; VBITS_GE_512: ptrue [[PG:p[0-9]+]].s, vl16
+; VBITS_GE_512-NEXT: ld1w { [[OP:z[0-9]+]].s }, [[PG]]/z, [x0]
+; VBITS_GE_512-NEXT: ucvtf [[RES:z[0-9]+]].s, [[PG]]/m, [[OP]].s
+; VBITS_GE_512-NEXT: st1w { [[RES]].s }, [[PG]], [x1]
+; VBITS_GE_512-NEXT: ret
+
+; Ensure sensible type legalisation.
+; VBITS_EQ_256: ptrue [[PG:p[0-9]+]].s, vl8
+; VBITS_EQ_256-NEXT: add x8, x0, #32
+; VBITS_EQ_256-NEXT: ld1w { [[LO:z[0-9]+]].s }, [[PG]]/z, [x0]
+; VBITS_EQ_256-NEXT: ld1w { [[HI:z[0-9]+]].s }, [[PG]]/z, [x8]
+; VBITS_EQ_256-NEXT: add x8, x1, #32
+; VBITS_EQ_256-NEXT: ucvtf [[RES_LO:z[0-9]+]].s, [[PG]]/m, [[LO]].s
+; VBITS_EQ_256-NEXT: ucvtf [[RES_HI:z[0-9]+]].s, [[PG]]/m, [[HI]].s
+; VBITS_EQ_256-NEXT: st1w { [[RES_LO]].s }, [[PG]], [x1]
+; VBITS_EQ_256-NEXT: st1w { [[RES_HI]].s }, [[PG]], [x8]
+; VBITS_EQ_256-NEXT: ret
+  %op1 = load <16 x i32>, <16 x i32>* %a
+  %res = uitofp <16 x i32> %op1 to <16 x float>
+  store <16 x float> %res, <16 x float>* %b
+  ret void
+}
+
+define void @ucvtf_v32i32_v32f32(<32 x i32>* %a, <32 x float>* %b) #0 {
+; CHECK-LABEL: ucvtf_v32i32_v32f32:
+; VBITS_GE_1024: ptrue [[PG:p[0-9]+]].s, vl32
+; VBITS_GE_1024-NEXT: ld1w { [[OP:z[0-9]+]].s }, [[PG]]/z, [x0]
+; VBITS_GE_1024-NEXT: ucvtf [[RES:z[0-9]+]].s, [[PG]]/m, [[OP]].s
+; VBITS_GE_1024-NEXT: st1w { [[RES]].s }, [[PG]], [x1]
+; VBITS_GE_1024-NEXT: ret
+  %op1 = load <32 x i32>, <32 x i32>* %a
+  %res = uitofp <32 x i32> %op1 to <32 x float>
+  store <32 x float> %res, <32 x float>* %b
+  ret void
+}
+
+define void @ucvtf_v64i32_v64f32(<64 x i32>* %a, <64 x float>* %b) #0 {
+; CHECK-LABEL: ucvtf_v64i32_v64f32:
+; VBITS_GE_2048: ptrue [[PG:p[0-9]+]].s, vl64
+; VBITS_GE_2048-NEXT: ld1w { [[OP:z[0-9]+]].s }, [[PG]]/z, [x0]
+; VBITS_GE_2048-NEXT: ucvtf [[RES:z[0-9]+]].s, [[PG]]/m, [[OP]].s
+; VBITS_GE_2048-NEXT: st1w { [[RES]].s }, [[PG]], [x1]
+; VBITS_GE_2048-NEXT: ret
+  %op1 = load <64 x i32>, <64 x i32>* %a
+  %res = uitofp <64 x i32> %op1 to <64 x float>
+  store <64 x float> %res, <64 x float>* %b
+  ret void
+}
+
+;
+; UCVTF S -> D
+;
+
+; Don't use SVE for 64-bit vectors.
+define <1 x double> @ucvtf_v1i32_v1f64(<1 x i32> %op1) #0 {
+; CHECK-LABEL: ucvtf_v1i32_v1f64:
+; CHECK: ushll v0.2d, v0.2s, #0
+; CHECK-NEXT: ucvtf v0.2d, v0.2d
+; CHECK-NEXT: ret
+  %res = uitofp <1 x i32> %op1 to <1 x double>
+  ret <1 x double> %res
+}
+
+; Don't use SVE for 128-bit vectors.
+define <2 x double> @ucvtf_v2i32_v2f64(<2 x i32> %op1) #0 {
+; CHECK-LABEL: ucvtf_v2i32_v2f64:
+; CHECK: ushll v0.2d, v0.2s, #0
+; CHECK-NEXT: ucvtf v0.2d, v0.2d
+; CHECK-NEXT: ret
+  %res = uitofp <2 x i32> %op1 to <2 x double>
+  ret <2 x double> %res
+}
+
+define void @ucvtf_v4i32_v4f64(<4 x i32>* %a, <4 x double>* %b) #0 {
+; CHECK-LABEL: ucvtf_v4i32_v4f64:
+; CHECK: ldr q[[OP:[0-9]+]], [x0]
+; CHECK-NEXT: ptrue [[PG:p[0-9]+]].d, vl4
+; CHECK-NEXT: uunpklo [[UPK:z[0-9]+]].d, z[[OP]].s
+; CHECK-NEXT: ucvtf [[RES:z[0-9]+]].d, [[PG]]/m, [[UPK]].d
+; CHECK-NEXT: st1d { [[RES]].d }, [[PG]], [x1]
+; CHECK-NEXT: ret
+  %op1 = load <4 x i32>, <4 x i32>* %a
+  %res = uitofp <4 x i32> %op1 to <4 x double>
+  store <4 x double> %res, <4 x double>* %b
+  ret void
+}
+
+define void @ucvtf_v8i32_v8f64(<8 x i32>* %a, <8 x double>* %b) #0 {
+; CHECK-LABEL: ucvtf_v8i32_v8f64:
+; VBITS_GE_512: ptrue [[PG1:p[0-9]+]].s, vl8
+; VBITS_GE_512-NEXT: ld1w { [[OP:z[0-9]+]].s }, [[PG1]]/z, [x0]
+; VBITS_GE_512-NEXT: ptrue [[PG:p[0-9]+]].d, vl8
+; VBITS_GE_512-NEXT: uunpklo [[UPK:z[0-9]+]].d, [[OP]].s
+; VBITS_GE_512-NEXT: ucvtf [[RES:z[0-9]+]].d, [[PG1]]/m, [[UPK]].d
+; VBITS_GE_512-NEXT: st1d { [[RES]].d }, [[PG1]], [x1]
+; VBITS_GE_512-NEXT: ret
+
+; Ensure sensible type legalisation - fixed type extract_subvector codegen is poor currently.
+; VBITS_EQ_256: ptrue [[PG1:p[0-9]+]].s, vl8
+; VBITS_EQ_256-DAG: ld1w { [[VEC:z[0-9]+]].s }, [[PG1]]/z, [x0]
+; VBITS_EQ_256-DAG: st1w { [[VEC:z[0-9]+]].s }, [[PG1]], [x8]
+; VBITS_EQ_256-DAG: ldp q[[LO:[0-9]+]], q[[HI:[0-9]+]], [sp]
+; VBITS_EQ_256-NEXT: ptrue [[PG2:p[0-9]+]].d, vl4
+; VBITS_EQ_256-NEXT: add x8, x1, #32
+; VBITS_EQ_256-NEXT: uunpklo [[UPK_LO:z[0-9]+]].d, z[[LO]].s
+; VBITS_EQ_256-NEXT: uunpklo [[UPK_HI:z[0-9]+]].d, z[[HI]].s
+; VBITS_EQ_256-NEXT: ucvtf [[RES_LO:z[0-9]+]].d, [[PG2]]/m, [[UPK_LO]].d
+; VBITS_EQ_256-NEXT: ucvtf [[RES_HI:z[0-9]+]].d, [[PG2]]/m, [[UPK_HI]].d
+; VBITS_EQ_256-NEXT: st1d { [[RES_HI]].d }, [[PG2]], [x8]
+; VBITS_EQ_256-NEXT: st1d { [[RES_LO]].d }, [[PG2]], [x1]
+  %op1 = load <8 x i32>, <8 x i32>* %a
+  %res = uitofp <8 x i32> %op1 to <8 x double>
+  store <8 x double> %res, <8 x double>* %b
+  ret void
+}
+
+define void @ucvtf_v16i32_v16f64(<16 x i32>* %a, <16 x double>* %b) #0 {
+; CHECK-LABEL: ucvtf_v16i32_v16f64:
+; VBITS_GE_1024: ptrue [[PG1:p[0-9]+]].s, vl16
+; VBITS_GE_1024-NEXT: ld1w { [[OP:z[0-9]+]].s }, [[PG1]]/z, [x0]
+; VBITS_GE_1024-NEXT: ptrue [[PG2:p[0-9]+]].d, vl16
+; VBITS_GE_1024-NEXT: uunpklo [[UPK:z[0-9]+]].d, [[OP]].s
+; VBITS_GE_1024-NEXT: ucvtf [[RES:z[0-9]+]].d, [[PG2]]/m, [[UPK]].d
+; VBITS_GE_1024-NEXT: st1d { [[RES]].d }, [[PG1]], [x1]
+; VBITS_GE_1024-NEXT: ret
+  %op1 = load <16 x i32>, <16 x i32>* %a
+  %res = uitofp <16 x i32> %op1 to <16 x double>
+  store <16 x double> %res, <16 x double>* %b
+  ret void
+}
+
+define void @ucvtf_v32i32_v32f64(<32 x i32>* %a, <32 x double>* %b) #0 {
+; CHECK-LABEL: ucvtf_v32i32_v32f64:
+; VBITS_GE_2048: ptrue [[PG1:p[0-9]+]].s, vl32
+; VBITS_GE_2048-NEXT: ld1w { [[OP:z[0-9]+]].s }, [[PG1]]/z, [x0]
+; VBITS_GE_2048-NEXT: ptrue [[PG2:p[0-9]+]].d, vl32
+; VBITS_GE_2048-NEXT: uunpklo [[UPK:z[0-9]+]].d, [[OP]].s
+; VBITS_GE_2048-NEXT: ucvtf [[RES:z[0-9]+]].d, [[PG2]]/m, [[UPK]].d
+; VBITS_GE_2048-NEXT: st1d { [[RES]].d }, [[PG1]], [x1]
+; VBITS_GE_2048-NEXT: ret
+  %op1 = load <32 x i32>, <32 x i32>* %a
+  %res = uitofp <32 x i32> %op1 to <32 x double>
+  store <32 x double> %res, <32 x double>* %b
+  ret void
+}
+
+
+;
+; UCVTF D -> H
+;
+
+; Don't use SVE for 64-bit vectors.
+define <1 x half> @ucvtf_v1i64_v1f16(<1 x i64> %op1) #0 {
+; CHECK-LABEL: ucvtf_v1i64_v1f16:
+; CHECK: fmov x8, d0
+; CHECK-NEXT: ucvtf h0, x8
+; CHECK-NEXT: ret
+  %res = uitofp <1 x i64> %op1 to <1 x half>
+  ret <1 x half> %res
+}
+
+; v2f16 is not legal for NEON, so use SVE
+define <2 x half> @ucvtf_v2i64_v2f16(<2 x i64> %op1) #0 {
+; CHECK-LABEL: ucvtf_v2i64_v2f16:
+; CHECK: ptrue [[PG:p[0-9]+]].d
+; CHECK-NEXT: ucvtf [[CVT:z[0-9]+]].h, [[PG]]/m, z0.d
+; CHECK-NEXT: uzp1 [[UZP:z[0-9]+]].s, [[CVT]].s, [[CVT]].s
+; CHECK-NEXT: uzp1 z0.h, [[UZP]].h, [[UZP]].h
+; CHECK-NEXT: ret
+  %res = uitofp <2 x i64> %op1 to <2 x half>
+  ret <2 x half> %res
+}
+
+define <4 x half> @ucvtf_v4i64_v4f16(<4 x i64>* %a) #0 {
+; CHECK-LABEL: ucvtf_v4i64_v4f16:
+; CHECK: ptrue [[PG1:p[0-9]+]].d, vl4
+; CHECK-NEXT: ld1d { [[OP:z[0-9]+]].d }, [[PG1]]/z, [x0]
+; CHECK-NEXT: ptrue [[PG2:p[0-9]+]].d
+; CHECK-NEXT: ucvtf [[CVT:z[0-9]+]].h, [[PG2]]/m, [[OP]].d
+; CHECK-NEXT: uzp1 [[UZP:z[0-9]+]].s, [[CVT]].s, [[CVT]].s
+; CHECK-NEXT: uzp1 z0.h, [[UZP]].h, [[UZP]].h
+; CHECK-NEXT: ret
+  %op1 = load <4 x i64>, <4 x i64>* %a
+  %res = uitofp <4 x i64> %op1 to <4 x half>
+  ret <4 x half> %res
+}
+
+define <8 x half> @ucvtf_v8i64_v8f16(<8 x i64>* %a) #0 {
+; CHECK-LABEL: ucvtf_v8i64_v8f16:
+; VBITS_GE_512: ptrue [[PG1:p[0-9]+]].d, vl8
+; VBITS_GE_512-NEXT: ld1d { [[OP:z[0-9]+]].d }, [[PG1]]/z, [x0]
+; VBITS_GE_512-NEXT: ptrue [[PG2:p[0-9]+]].d
+; VBITS_GE_512-NEXT: ucvtf [[CVT:z[0-9]+]].h, [[PG2]]/m, [[OP]].d
+; VBITS_GE_512-NEXT: uzp1 [[UZP:z[0-9]+]].s, [[CVT]].s, [[CVT]].s
+; VBITS_GE_512-NEXT: uzp1 z0.h, [[UZP]].h, [[UZP]].h
+; VBITS_GE_512-NEXT: ret
+
+; Ensure sensible type legalisation.
+; VBITS_EQ_256: add x8, x0, #32
+; VBITS_EQ_256-NEXT: ptrue [[PG1:p[0-9]+]].d, vl4
+; VBITS_EQ_256-NEXT: ld1d { [[HI:z[0-9]+]].d }, [[PG]]/z, [x8]
+; VBITS_EQ_256-NEXT: ld1d { [[LO:z[0-9]+]].d }, [[PG]]/z, [x0]
+; VBITS_EQ_256-NEXT: ptrue [[PG2:p[0-9]+]].d
+; VBITS_EQ_256-NEXT: ucvtf [[CVT_HI:z[0-9]+]].h, [[PG2]]/m, [[HI]].d
+; VBITS_EQ_256-NEXT: ucvtf [[CVT_LO:z[0-9]+]].h, [[PG2]]/m, [[LO]].d
+; VBITS_EQ_256-NEXT: uzp1 [[UZP_LO:z[0-9]+]].s, [[CVT_LO]].s, [[CVT_LO]].s
+; VBITS_EQ_256-NEXT: uzp1 [[UZP_HI:z[0-9]+]].s, [[CVT_HI]].s, [[CVT_HI]].s
+; VBITS_EQ_256-NEXT: uzp1 z[[RES_LO:[0-9]+]].h, [[UZP_LO]].h, [[UZP_LO]].h
+; VBITS_EQ_256-NEXT: uzp1 z[[RES_HI:[0-9]+]].h, [[UZP_HI]].h, [[UZP_HI]].h
+; VBITS_EQ_256-NEXT: mov v[[RES_LO]].d[1], v[[RES_HI]].d[0]
+; VBITS_EQ_256-NEXT: ret
+  %op1 = load <8 x i64>, <8 x i64>* %a
+  %res = uitofp <8 x i64> %op1 to <8 x half>
+  ret <8 x half> %res
+}
+
+define void @ucvtf_v16i64_v16f16(<16 x i64>* %a, <16 x half>* %b) #0 {
+; CHECK-LABEL: ucvtf_v16i64_v16f16:
+; VBITS_GE_1024: ptrue [[PG1:p[0-9]+]].d, vl16
+; VBITS_GE_1024-NEXT: ld1d { [[OP:z[0-9]+]].d }, [[PG1]]/z, [x0]
+; VBITS_GE_1024-NEXT: ptrue [[PG2:p[0-9]+]].d
+; VBITS_GE_1024-NEXT: ucvtf [[CVT:z[0-9]+]].h, [[PG2]]/m, [[OP]].d
+; VBITS_GE_1024-NEXT: uzp1 [[UZP:z[0-9]+]].s, [[CVT]].s, [[CVT]].s
+; VBITS_GE_1024-NEXT: uzp1 [[RES:z[0-9]+]].h, [[UZP]].h, [[UZP]].h
+; VBITS_GE_1024-NEXT: ptrue [[PG3:p[0-9]+]].h, vl16
+; VBITS_GE_1024-NEXT: st1h { [[RES]].h }, [[PG3]], [x1]
+; VBITS_GE_1024-NEXT: ret
+  %op1 = load <16 x i64>, <16 x i64>* %a
+  %res = uitofp <16 x i64> %op1 to <16 x half>
+  store <16 x half> %res, <16 x half>* %b
+  ret void
+}
+
+define void @ucvtf_v32i64_v32f16(<32 x i64>* %a, <32 x half>* %b) #0 {
+; CHECK-LABEL: ucvtf_v32i64_v32f16:
+; VBITS_GE_2048: ptrue [[PG1:p[0-9]+]].d, vl32
+; VBITS_GE_2048-NEXT: ld1d { [[OP:z[0-9]+]].d }, [[PG1]]/z, [x0]
+; VBITS_GE_2048-NEXT: ptrue [[PG2:p[0-9]+]].d
+; VBITS_GE_2048-NEXT: ucvtf [[CVT:z[0-9]+]].h, [[PG2]]/m, [[OP]].d
+; VBITS_GE_2048-NEXT: uzp1 [[UZP:z[0-9]+]].s, [[CVT]].s, [[CVT]].s
+; VBITS_GE_2048-NEXT: uzp1 [[RES:z[0-9]+]].h, [[UZP]].h, [[UZP]].h
+; VBITS_GE_2048-NEXT: ptrue [[PG3:p[0-9]+]].h, vl32
+; VBITS_GE_2048-NEXT: st1h { [[RES]].h }, [[PG3]], [x1]
+; VBITS_GE_2048-NEXT: ret
+  %op1 = load <32 x i64>, <32 x i64>* %a
+  %res = uitofp <32 x i64> %op1 to <32 x half>
+  store <32 x half> %res, <32 x half>* %b
+  ret void
+}
+
+;
+; UCVTF D -> S
+;
+
+; Don't use SVE for 64-bit vectors.
+define <1 x float> @ucvtf_v1i64_v1f32(<1 x i64> %op1) #0 {
+; CHECK-LABEL: ucvtf_v1i64_v1f32:
+; CHECK: ucvtf v0.2d, v0.2d
+; CHECK-NEXT: fcvtn v0.2s, v0.2d
+; CHECK-NEXT: ret
+  %res = uitofp <1 x i64> %op1 to <1 x float>
+  ret <1 x float> %res
+}
+
+; Don't use SVE for 128-bit vectors.
+define <2 x float> @ucvtf_v2i64_v2f32(<2 x i64> %op1) #0 {
+; CHECK-LABEL: ucvtf_v2i64_v2f32:
+; CHECK: ucvtf v0.2d, v0.2d
+; CHECK-NEXT: fcvtn v0.2s, v0.2d
+; CHECK-NEXT: ret
+  %res = uitofp <2 x i64> %op1 to <2 x float>
+  ret <2 x float> %res
+}
+
+define <4 x float> @ucvtf_v4i64_v4f32(<4 x i64>* %a) #0 {
+; CHECK-LABEL: ucvtf_v4i64_v4f32:
+; CHECK: ptrue [[PG1:p[0-9]+]].d, vl4
+; CHECK-NEXT: ld1d { [[OP:z[0-9]+]].d }, [[PG1]]/z, [x0]
+; CHECK-NEXT: ptrue [[PG2:p[0-9]+]].d
+; CHECK-NEXT: ucvtf [[CVT:z[0-9]+]].s, [[PG2]]/m, [[OP]].d
+; CHECK-NEXT: uzp1 z0.s, [[CVT]].s, [[CVT]].s
+; CHECK-NEXT: ret
+  %op1 = load <4 x i64>, <4 x i64>* %a
+  %res = uitofp <4 x i64> %op1 to <4 x float>
+  ret <4 x float> %res
+}
+
+define void @ucvtf_v8i64_v8f32(<8 x i64>* %a, <8 x float>* %b) #0 {
+; CHECK-LABEL: ucvtf_v8i64_v8f32:
+; VBITS_GE_512: ptrue [[PG1:p[0-9]+]].d, vl8
+; VBITS_GE_512-NEXT: ld1d { [[OP:z[0-9]+]].d }, [[PG1]]/z, [x0]
+; VBITS_GE_512-NEXT: ptrue [[PG2:p[0-9]+]].d
+; VBITS_GE_512-NEXT: ucvtf [[CVT:z[0-9]+]].s, [[PG2]]/m, [[OP]].d
+; VBITS_GE_512-NEXT: uzp1 [[RES:z[0-9]+]].s, [[CVT]].s, [[CVT]].s
+; VBITS_GE_512-NEXT: ptrue [[PG3:p[0-9]+]].s, vl8
+; VBITS_GE_512-NEXT: st1w { [[RES]].s }, [[PG3]], [x1]
+; VBITS_GE_512-NEXT: ret
+
+; Ensure sensible type legalisation.
+; VBITS_EQ_256: add x8, x0, #32
+; VBITS_EQ_256-NEXT: ptrue [[PG1:p[0-9]+]].d, vl4
+; VBITS_EQ_256-NEXT: ld1d { [[HI:z[0-9]+]].d }, [[PG]]/z, [x8]
+; VBITS_EQ_256-NEXT: ld1d { [[LO:z[0-9]+]].d }, [[PG]]/z, [x0]
+; VBITS_EQ_256-NEXT: ptrue [[PG2:p[0-9]+]].d
+; VBITS_EQ_256-NEXT: ptrue [[PG3:p[0-9]+]].s, vl4
+; VBITS_EQ_256-NEXT: ucvtf [[CVT_HI:z[0-9]+]].s, [[PG2]]/m, [[HI]].d
+; VBITS_EQ_256-NEXT: ucvtf [[CVT_LO:z[0-9]+]].s, [[PG2]]/m, [[LO]].d
+; VBITS_EQ_256-NEXT: uzp1 [[RES_LO:z[0-9]+]].s, [[CVT_LO]].s, [[CVT_LO]].s
+; VBITS_EQ_256-NEXT: uzp1 [[RES_HI:z[0-9]+]].s, [[CVT_HI]].s, [[CVT_HI]].s
+; VBITS_EQ_256-NEXT: splice [[RES:z[0-9]+]].s, [[PG3]], [[RES_LO]].s, [[RES_HI]].s
+; VBITS_EQ_256-NEXT: ptrue [[PG4:p[0-9]+]].s, vl8
+; VBITS_EQ_256-NEXT: st1w { [[RES]].s }, [[PG4]], [x1]
+; VBITS_EQ_256-NEXT: ret
+  %op1 = load <8 x i64>, <8 x i64>* %a
+  %res = uitofp <8 x i64> %op1 to <8 x float>
+  store <8 x float> %res, <8 x float>* %b
+  ret void
+}
+
+define void @ucvtf_v16i64_v16f32(<16 x i64>* %a, <16 x float>* %b) #0 {
+; CHECK-LABEL: ucvtf_v16i64_v16f32:
+; VBITS_GE_1024: ptrue [[PG1:p[0-9]+]].d, vl16
+; VBITS_GE_1024-NEXT: ld1d { [[OP:z[0-9]+]].d }, [[PG1]]/z, [x0]
+; VBITS_GE_1024-NEXT: ptrue [[PG2:p[0-9]+]].d
+; VBITS_GE_1024-NEXT: ucvtf [[CVT:z[0-9]+]].s, [[PG2]]/m, [[OP]].d
+; VBITS_GE_1024-NEXT: uzp1 [[RES:z[0-9]+]].s, [[CVT]].s, [[CVT]].s
+; VBITS_GE_1024-NEXT: ptrue [[PG3:p[0-9]+]].s, vl16
+; VBITS_GE_1024-NEXT: st1w { [[RES]].s }, [[PG3]], [x1]
+; VBITS_GE_1024-NEXT: ret
+  %op1 = load <16 x i64>, <16 x i64>* %a
+  %res = uitofp <16 x i64> %op1 to <16 x float>
+  store <16 x float> %res, <16 x float>* %b
+  ret void
+}
+
+define void @ucvtf_v32i64_v32f32(<32 x i64>* %a, <32 x float>* %b) #0 {
+; CHECK-LABEL: ucvtf_v32i64_v32f32:
+; VBITS_GE_2048: ptrue [[PG1:p[0-9]+]].d, vl32
+; VBITS_GE_2048-NEXT: ld1d { [[OP:z[0-9]+]].d }, [[PG1]]/z, [x0]
+; VBITS_GE_2048-NEXT: ptrue [[PG2:p[0-9]+]].d
+; VBITS_GE_2048-NEXT: ucvtf [[CVT:z[0-9]+]].s, [[PG2]]/m, [[OP]].d
+; VBITS_GE_2048-NEXT: uzp1 [[RES:z[0-9]+]].s, [[CVT]].s, [[CVT]].s
+; VBITS_GE_2048-NEXT: ptrue [[PG3:p[0-9]+]].s, vl32
+; VBITS_GE_2048-NEXT: st1w { [[RES]].s }, [[PG3]], [x1]
+; VBITS_GE_2048-NEXT: ret
+  %op1 = load <32 x i64>, <32 x i64>* %a
+  %res = uitofp <32 x i64> %op1 to <32 x float>
+  store <32 x float> %res, <32 x float>* %b
+  ret void
+}
+
+;
+; UCVTF D -> D
+;
+
+; Don't use SVE for 64-bit vectors.
+define <1 x double> @ucvtf_v1i64_v1f64(<1 x i64> %op1) #0 {
+; CHECK-LABEL: ucvtf_v1i64_v1f64:
+; CHECK: fmov x8, d0
+; CHECK-NEXT: ucvtf d0, x8
+; CHECK-NEXT: ret
+  %res = uitofp <1 x i64> %op1 to <1 x double>
+  ret <1 x double> %res
+}
+
+; Don't use SVE for 128-bit vectors.
+define <2 x double> @ucvtf_v2i64_v2f64(<2 x i64> %op1) #0 {
+; CHECK-LABEL: ucvtf_v2i64_v2f64:
+; CHECK: ucvtf v0.2d, v0.2d
+; CHECK-NEXT: ret
+  %res = uitofp <2 x i64> %op1 to <2 x double>
+  ret <2 x double> %res
+}
+
+define void @ucvtf_v4i64_v4f64(<4 x i64>* %a, <4 x double>* %b) #0 {
+; CHECK-LABEL: ucvtf_v4i64_v4f64:
+; CHECK: ptrue [[PG:p[0-9]+]].d, vl4
+; CHECK-NEXT: ld1d { [[OP:z[0-9]+]].d }, [[PG]]/z, [x0]
+; CHECK-NEXT: ucvtf [[RES:z[0-9]+]].d, [[PG]]/m, [[OP]].d
+; CHECK-NEXT: st1d { [[RES]].d }, [[PG]], [x1]
+; CHECK-NEXT: ret
+  %op1 = load <4 x i64>, <4 x i64>* %a
+  %res = uitofp <4 x i64> %op1 to <4 x double>
+  store <4 x double> %res, <4 x double>* %b
+  ret void
+}
+
+define void @ucvtf_v8i64_v8f64(<8 x i64>* %a, <8 x double>* %b) #0 {
+; CHECK-LABEL: ucvtf_v8i64_v8f64:
+; VBITS_GE_512: ptrue [[PG:p[0-9]+]].d, vl8
+; VBITS_GE_512-NEXT: ld1d { [[OP:z[0-9]+]].d }, [[PG]]/z, [x0]
+; VBITS_GE_512-NEXT: ucvtf [[RES:z[0-9]+]].d, [[PG]]/m, [[OP]].d
+; VBITS_GE_512-NEXT: st1d { [[RES]].d }, [[PG]], [x1]
+; VBITS_GE_512-NEXT: ret
+
+; Ensure sensible type legalisation.
+; VBITS_EQ_256: ptrue [[PG:p[0-9]+]].d, vl4
+; VBITS_EQ_256-NEXT: add x8, x0, #32
+; VBITS_EQ_256-NEXT: ld1d { [[LO:z[0-9]+]].d }, [[PG]]/z, [x0]
+; VBITS_EQ_256-NEXT: ld1d { [[HI:z[0-9]+]].d }, [[PG]]/z, [x8]
+; VBITS_EQ_256-NEXT: add x8, x1, #32
+; VBITS_EQ_256-NEXT: ucvtf [[RES_LO:z[0-9]+]].d, [[PG]]/m, [[LO]].d
+; VBITS_EQ_256-NEXT: ucvtf [[RES_HI:z[0-9]+]].d, [[PG]]/m, [[HI]].d
+; VBITS_EQ_256-NEXT: st1d { [[RES_LO]].d }, [[PG]], [x1]
+; VBITS_EQ_256-NEXT: st1d { [[RES_HI]].d }, [[PG]], [x8]
+; VBITS_EQ_256-NEXT: ret
+  %op1 = load <8 x i64>, <8 x i64>* %a
+  %res = uitofp <8 x i64> %op1 to <8 x double>
+  store <8 x double> %res, <8 x double>* %b
+  ret void
+}
+
+define void @ucvtf_v16i64_v16f64(<16 x i64>* %a, <16 x double>* %b) #0 {
+; CHECK-LABEL: ucvtf_v16i64_v16f64:
+; VBITS_GE_1024: ptrue [[PG:p[0-9]+]].d, vl16
+; VBITS_GE_1024-NEXT: ld1d { [[OP:z[0-9]+]].d }, [[PG]]/z, [x0]
+; VBITS_GE_1024-NEXT: ucvtf [[RES:z[0-9]+]].d, [[PG]]/m, [[OP]].d
+; VBITS_GE_1024-NEXT: st1d { [[RES]].d }, [[PG]], [x1]
+; VBITS_GE_1024-NEXT: ret
+  %op1 = load <16 x i64>, <16 x i64>* %a
+  %res = uitofp <16 x i64> %op1 to <16 x double>
+  store <16 x double> %res, <16 x double>* %b
+  ret void
+}
+
+define void @ucvtf_v32i64_v32f64(<32 x i64>* %a, <32 x double>* %b) #0 {
+; CHECK-LABEL: ucvtf_v32i64_v32f64:
+; VBITS_GE_2048: ptrue [[PG:p[0-9]+]].d, vl32
+; VBITS_GE_2048-NEXT: ld1d { [[OP:z[0-9]+]].d }, [[PG]]/z, [x0]
+; VBITS_GE_2048-NEXT: ucvtf [[RES:z[0-9]+]].d, [[PG]]/m, [[OP]].d
+; VBITS_GE_2048-NEXT: st1d { [[RES]].d }, [[PG]], [x1]
+; VBITS_GE_2048-NEXT: ret
+  %op1 = load <32 x i64>, <32 x i64>* %a
+  %res = uitofp <32 x i64> %op1 to <32 x double>
+  store <32 x double> %res, <32 x double>* %b
+  ret void
+}
+
+;
+; SCVTF H -> H
+;
+
+; Don't use SVE for 64-bit vectors.
+define <4 x half> @scvtf_v4i16_v4f16(<4 x i16> %op1) #0 {
+; CHECK-LABEL: scvtf_v4i16_v4f16:
+; CHECK: scvtf v0.4h, v0.4h
+; CHECK-NEXT: ret
+  %res = sitofp <4 x i16> %op1 to <4 x half>
+  ret <4 x half> %res
+}
+
+; Don't use SVE for 128-bit vectors.
+define void @scvtf_v8i16_v8f16(<8 x i16>* %a, <8 x half>* %b) #0 {
+; CHECK-LABEL: scvtf_v8i16_v8f16:
+; CHECK: ldr q0, [x0]
+; CHECK-NEXT: scvtf v0.8h, v0.8h
+; CHECK-NEXT: str q0, [x1]
+; CHECK-NEXT: ret
+  %op1 = load <8 x i16>, <8 x i16>* %a
+  %res = sitofp <8 x i16> %op1 to <8 x half>
+  store <8 x half> %res, <8 x half>* %b
+  ret void
+}
+
+define void @scvtf_v16i16_v16f16(<16 x i16>* %a, <16 x half>* %b) #0 {
+; CHECK-LABEL: scvtf_v16i16_v16f16:
+; CHECK: ptrue [[PG:p[0-9]+]].h, vl16
+; CHECK-NEXT: ld1h { [[OP:z[0-9]+]].h }, [[PG]]/z, [x0]
+; CHECK-NEXT: scvtf [[RES:z[0-9]+]].h, [[PG]]/m, [[OP]].h
+; CHECK-NEXT: st1h { [[RES]].h }, [[PG]], [x1]
+; CHECK-NEXT: ret
+  %op1 = load <16 x i16>, <16 x i16>* %a
+  %res = sitofp <16 x i16> %op1 to <16 x half>
+  store <16 x half> %res, <16 x half>* %b
+  ret void
+}
+
+define void @scvtf_v32i16_v32f16(<32 x i16>* %a, <32 x half>* %b) #0 {
+; CHECK-LABEL: scvtf_v32i16_v32f16:
+; VBITS_GE_512: ptrue [[PG:p[0-9]+]].h, vl32
+; VBITS_GE_512-NEXT: ld1h { [[OP:z[0-9]+]].h }, [[PG]]/z, [x0]
+; VBITS_GE_512-NEXT: scvtf [[RES:z[0-9]+]].h, [[PG]]/m, [[OP]].h
+; VBITS_GE_512-NEXT: st1h { [[RES]].h }, [[PG]], [x1]
+; VBITS_GE_512-NEXT: ret
+
+; Ensure sensible type legalisation.
+; VBITS_EQ_256: ptrue [[PG:p[0-9]+]].h, vl16
+; VBITS_EQ_256-NEXT: add x8, x0, #32
+; VBITS_EQ_256-NEXT: ld1h { [[LO:z[0-9]+]].h }, [[PG]]/z, [x0]
+; VBITS_EQ_256-NEXT: ld1h { [[HI:z[0-9]+]].h }, [[PG]]/z, [x8]
+; VBITS_EQ_256-NEXT: add x8, x1, #32
+; VBITS_EQ_256-NEXT: scvtf [[RES_LO:z[0-9]+]].h, [[PG]]/m, [[LO]].h
+; VBITS_EQ_256-NEXT: scvtf [[RES_HI:z[0-9]+]].h, [[PG]]/m, [[HI]].h
+; VBITS_EQ_256-NEXT: st1h { [[RES_LO]].h }, [[PG]], [x1]
+; VBITS_EQ_256-NEXT: st1h { [[RES_HI]].h }, [[PG]], [x8]
+; VBITS_EQ_256-NEXT: ret
+  %op1 = load <32 x i16>, <32 x i16>* %a
+  %res = sitofp <32 x i16> %op1 to <32 x half>
+  store <32 x half> %res, <32 x half>* %b
+  ret void
+}
+
+define void @scvtf_v64i16_v64f16(<64 x i16>* %a, <64 x half>* %b) #0 {
+; CHECK-LABEL: scvtf_v64i16_v64f16:
+; VBITS_GE_1024: ptrue [[PG:p[0-9]+]].h, vl64
+; VBITS_GE_1024-NEXT: ld1h { [[OP:z[0-9]+]].h }, [[PG]]/z, [x0]
+; VBITS_GE_1024-NEXT: scvtf [[RES:z[0-9]+]].h, [[PG]]/m, [[OP]].h
+; VBITS_GE_1024-NEXT: st1h { [[RES]].h }, [[PG]], [x1]
+; VBITS_GE_1024-NEXT: ret
+  %op1 = load <64 x i16>, <64 x i16>* %a
+  %res = sitofp <64 x i16> %op1 to <64 x half>
+  store <64 x half> %res, <64 x half>* %b
+  ret void
+}
+
+define void @scvtf_v128i16_v128f16(<128 x i16>* %a, <128 x half>* %b) #0 {
+; CHECK-LABEL: scvtf_v128i16_v128f16:
+; VBITS_GE_2048: ptrue [[PG:p[0-9]+]].h, vl128
+; VBITS_GE_2048-NEXT: ld1h { [[OP:z[0-9]+]].h }, [[PG]]/z, [x0]
+; VBITS_GE_2048-NEXT: scvtf [[RES:z[0-9]+]].h, [[PG]]/m, [[OP]].h
+; VBITS_GE_2048-NEXT: st1h { [[RES]].h }, [[PG]], [x1]
+; VBITS_GE_2048-NEXT: ret
+  %op1 = load <128 x i16>, <128 x i16>* %a
+  %res = sitofp <128 x i16> %op1 to <128 x half>
+  store <128 x half> %res, <128 x half>* %b
+  ret void
+}
+
+;
+; SCVTF H -> S
+;
+
+; Don't use SVE for 64-bit vectors.
+define <2 x float> @scvtf_v2i16_v2f32(<2 x i16> %op1) #0 {
+; CHECK-LABEL: scvtf_v2i16_v2f32:
+; CHECK: shl v0.2s, v0.2s, #16
+; CHECK-NEXT: sshr v0.2s, v0.2s, #16
+; CHECK-NEXT: scvtf v0.2s, v0.2s
+; CHECK-NEXT: ret
+  %res = sitofp <2 x i16> %op1 to <2 x float>
+  ret <2 x float> %res
+}
+
+; Don't use SVE for 128-bit vectors.
+define <4 x float> @scvtf_v4i16_v4f32(<4 x i16> %op1) #0 {
+; CHECK-LABEL: scvtf_v4i16_v4f32:
+; CHECK: scvtf v0.4s, v0.4s
+; CHECK-NEXT: ret
+  %res = sitofp <4 x i16> %op1 to <4 x float>
+  ret <4 x float> %res
+}
+
+define void @scvtf_v8i16_v8f32(<8 x i16>* %a, <8 x float>* %b) #0 {
+; CHECK-LABEL: scvtf_v8i16_v8f32:
+; CHECK: ldr q[[OP:[0-9]+]], [x0]
+; CHECK-NEXT: ptrue [[PG:p[0-9]+]].s, vl8
+; CHECK-NEXT: sunpklo [[UPK:z[0-9]+]].s, z[[OP]].h
+; CHECK-NEXT: scvtf [[RES:z[0-9]+]].s, [[PG]]/m, [[UPK]].s
+; CHECK-NEXT: st1w { [[RES]].s }, [[PG]], [x1]
+; CHECK-NEXT: ret
+  %op1 = load <8 x i16>, <8 x i16>* %a
+  %res = sitofp <8 x i16> %op1 to <8 x float>
+  store <8 x float> %res, <8 x float>* %b
+  ret void
+}
+
+define void @scvtf_v16i16_v16f32(<16 x i16>* %a, <16 x float>* %b) #0 {
+; CHECK-LABEL: scvtf_v16i16_v16f32:
+; VBITS_GE_512: ptrue [[PG1:p[0-9]+]].h, vl16
+; VBITS_GE_512-NEXT: ld1h { [[OP:z[0-9]+]].h }, [[PG1]]/z, [x0]
+; VBITS_GE_512-NEXT: ptrue [[PG2:p[0-9]+]].s, vl16
+; VBITS_GE_512-NEXT: sunpklo [[UPK:z[0-9]+]].s, [[OP]].h
+; VBITS_GE_512-NEXT: scvtf [[RES:z[0-9]+]].s, [[PG2]]/m, [[UPK]].s
+; VBITS_GE_512-NEXT: st1w { [[RES]].s }, [[PG1]], [x1]
+; VBITS_GE_512-NEXT: ret
+
+; Ensure sensible type legalisation - fixed type extract_subvector codegen is poor currently.
+; VBITS_EQ_256: ptrue [[PG1:p[0-9]+]].h, vl16
+; VBITS_EQ_256-DAG: ld1h { [[VEC:z[0-9]+]].h }, [[PG1]]/z, [x0]
+; VBITS_EQ_256-DAG: st1h { [[VEC:z[0-9]+]].h }, [[PG1]], [x8]
+; VBITS_EQ_256-DAG: ldp q[[LO:[0-9]+]], q[[HI:[0-9]+]], [sp]
+; VBITS_EQ_256-NEXT: ptrue [[PG2:p[0-9]+]].s, vl8
+; VBITS_EQ_256-NEXT: add x8, x1, #32
+; VBITS_EQ_256-NEXT: sunpklo [[UPK_LO:z[0-9]+]].s, z[[LO]].h
+; VBITS_EQ_256-NEXT: sunpklo [[UPK_HI:z[0-9]+]].s, z[[HI]].h
+; VBITS_EQ_256-NEXT: scvtf [[RES_LO:z[0-9]+]].s, [[PG2]]/m, [[UPK_LO]].s
+; VBITS_EQ_256-NEXT: scvtf [[RES_HI:z[0-9]+]].s, [[PG2]]/m, [[UPK_HI]].s
+; VBITS_EQ_256-NEXT: st1w { [[RES_HI]].s }, [[PG2]], [x8]
+; VBITS_EQ_256-NEXT: st1w { [[RES_LO]].s }, [[PG2]], [x1]
+  %op1 = load <16 x i16>, <16 x i16>* %a
+  %res = sitofp <16 x i16> %op1 to <16 x float>
+  store <16 x float> %res, <16 x float>* %b
+  ret void
+}
+
+define void @scvtf_v32i16_v32f32(<32 x i16>* %a, <32 x float>* %b) #0 {
+; CHECK-LABEL: scvtf_v32i16_v32f32:
+; VBITS_GE_1024: ptrue [[PG1:p[0-9]+]].h, vl32
+; VBITS_GE_1024-NEXT: ld1h { [[OP:z[0-9]+]].h }, [[PG1]]/z, [x0]
+; VBITS_GE_1024-NEXT: ptrue [[PG2:p[0-9]+]].s, vl32
+; VBITS_GE_1024-NEXT: sunpklo [[UPK:z[0-9]+]].s, [[OP]].h
+; VBITS_GE_1024-NEXT: scvtf [[RES:z[0-9]+]].s, [[PG2]]/m, [[UPK]].s
+; VBITS_GE_1024-NEXT: st1w { [[RES]].s }, [[PG1]], [x1]
+; VBITS_GE_1024-NEXT: ret
+  %op1 = load <32 x i16>, <32 x i16>* %a
+  %res = sitofp <32 x i16> %op1 to <32 x float>
+  store <32 x float> %res, <32 x float>* %b
+  ret void
+}
+
+define void @scvtf_v64i16_v64f32(<64 x i16>* %a, <64 x float>* %b) #0 {
+; CHECK-LABEL: scvtf_v64i16_v64f32:
+; VBITS_GE_2048: ptrue [[PG1:p[0-9]+]].h, vl64
+; VBITS_GE_2048-NEXT: ld1h { [[OP:z[0-9]+]].h }, [[PG1]]/z, [x0]
+; VBITS_GE_2048-NEXT: ptrue [[PG2:p[0-9]+]].s, vl64
+; VBITS_GE_2048-NEXT: sunpklo [[UPK:z[0-9]+]].s, [[OP]].h
+; VBITS_GE_2048-NEXT: scvtf [[RES:z[0-9]+]].s, [[PG2]]/m, [[UPK]].s
+; VBITS_GE_2048-NEXT: st1w { [[RES]].s }, [[PG1]], [x1]
+; VBITS_GE_2048-NEXT: ret
+  %op1 = load <64 x i16>, <64 x i16>* %a
+  %res = sitofp <64 x i16> %op1 to <64 x float>
+  store <64 x float> %res, <64 x float>* %b
+  ret void
+}
+
+;
+; SCVTF H -> D
+;
+
+; v1i16 is perfered to be widened to v4i16, which pushes the output into SVE types, so use SVE
+define <1 x double> @scvtf_v1i16_v1f64(<1 x i16> %op1) #0 {
+; CHECK-LABEL: scvtf_v1i16_v1f64:
+; CHECK: ptrue [[PG:p[0-9]+]].d, vl4
+; CHECK-NEXT: sunpklo [[UPK1:z[0-9]+]].s, z0.h
+; CHECK-NEXT: sunpklo [[UPK2:z[0-9]+]].d, [[UPK1]].s
+; CHECK-NEXT: scvtf z0.d, [[PG]]/m, [[UPK2]].d
+; CHECK-NEXT: ret
+  %res = sitofp <1 x i16> %op1 to <1 x double>
+  ret <1 x double> %res
+}
+
+; Don't use SVE for 128-bit vectors.
+define <2 x double> @scvtf_v2i16_v2f64(<2 x i16> %op1) #0 {
+; CHECK-LABEL: scvtf_v2i16_v2f64:
+; CHECK: shl v0.2s, v0.2s, #16
+; CHECK-NEXT: sshr v0.2s, v0.2s, #16
+; CHECK-NEXT: sshll v0.2d, v0.2s, #0
+; CHECK-NEXT: scvtf v0.2d, v0.2d
+; CHECK-NEXT: ret
+  %res = sitofp <2 x i16> %op1 to <2 x double>
+  ret <2 x double> %res
+}
+
+define void @scvtf_v4i16_v4f64(<4 x i16>* %a, <4 x double>* %b) #0 {
+; CHECK-LABEL: scvtf_v4i16_v4f64:
+; CHECK: ldr d[[OP:[0-9]+]], [x0]
+; CHECK-NEXT: ptrue [[PG:p[0-9]+]].d, vl4
+; CHECK-NEXT: sunpklo [[UPK1:z[0-9]+]].s, z[[OP]].h
+; CHECK-NEXT: sunpklo [[UPK2:z[0-9]+]].d, [[UPK1]].s
+; CHECK-NEXT: scvtf [[RES:z[0-9]+]].d, [[PG]]/m, [[UPK2]].d
+; CHECK-NEXT: st1d { [[RES]].d }, [[PG]], [x1]
+; CHECK-NEXT: ret
+  %op1 = load <4 x i16>, <4 x i16>* %a
+  %res = sitofp <4 x i16> %op1 to <4 x double>
+  store <4 x double> %res, <4 x double>* %b
+  ret void
+}
+
+define void @scvtf_v8i16_v8f64(<8 x i16>* %a, <8 x double>* %b) #0 {
+; CHECK-LABEL: scvtf_v8i16_v8f64:
+; VBITS_GE_512: ldr q[[OP:[0-9]+]], [x0]
+; VBITS_GE_512-NEXT: ptrue [[PG:p[0-9]+]].d, vl8
+; VBITS_GE_512-NEXT: sunpklo [[UPK1:z[0-9]+]].s, z[[OP]].h
+; VBITS_GE_512-NEXT: sunpklo [[UPK2:z[0-9]+]].d, [[UPK1]].s
+; VBITS_GE_512-NEXT: scvtf [[RES:z[0-9]+]].d, [[PG]]/m, [[UPK2]].d
+; VBITS_GE_512-NEXT: st1d { [[RES]].d }, [[PG]], [x1]
+; VBITS_GE_512-NEXT: ret
+
+; Ensure sensible type legalisation.
+; VBITS_EQ_256: ldr q[[OP:[0-9]+]], [x0]
+; VBITS_EQ_256-NEXT: ptrue [[PG1:p[0-9]+]].d, vl4
+; VBITS_EQ_256-NEXT: add x8, x1, #32
+; VBITS_EQ_256-NEXT: ext v[[HI:[0-9]+]].16b, v[[LO:[0-9]+]].16b, v[[OP]].16b, #8
+; VBITS_EQ_256-NEXT: sunpklo [[UPK1_LO:z[0-9]+]].s, z[[LO]].h
+; VBITS_EQ_256-NEXT: sunpklo [[UPK1_HI:z[0-9]+]].s, z[[HI]].h
+; VBITS_EQ_256-NEXT: sunpklo [[UPK2_LO:z[0-9]+]].d, [[UPK1_LO]].s
+; VBITS_EQ_256-NEXT: sunpklo [[UPK2_HI:z[0-9]+]].d, [[UPK1_HI]].s
+; VBITS_EQ_256-NEXT: scvtf [[RES_LO:z[0-9]+]].d, [[PG2]]/m, [[UPK2_LO]].d
+; VBITS_EQ_256-NEXT: scvtf [[RES_HI:z[0-9]+]].d, [[PG2]]/m, [[UPK2_HI]].d
+; VBITS_EQ_256-NEXT: st1d { [[RES_LO]].d }, [[PG2]], [x1]
+; VBITS_EQ_256-NEXT: st1d { [[RES_HI]].d }, [[PG2]], [x8]
+; VBITS_EQ_256-NEXT: ret
+  %op1 = load <8 x i16>, <8 x i16>* %a
+  %res = sitofp <8 x i16> %op1 to <8 x double>
+  store <8 x double> %res, <8 x double>* %b
+  ret void
+}
+
+define void @scvtf_v16i16_v16f64(<16 x i16>* %a, <16 x double>* %b) #0 {
+; CHECK-LABEL: scvtf_v16i16_v16f64:
+; VBITS_GE_1024: ptrue [[PG1:p[0-9]+]].h, vl16
+; VBITS_GE_1024-NEXT: ld1h { [[OP:z[0-9]+]].h }, [[PG1]]/z, [x0]
+; VBITS_GE_1024-NEXT: ptrue [[PG2:p[0-9]+]].d, vl16
+; VBITS_GE_1024-NEXT: sunpklo [[UPK1:z[0-9]+]].s, [[OP]].h
+; VBITS_GE_1024-NEXT: sunpklo [[UPK2:z[0-9]+]].d, [[UPK1]].s
+; VBITS_GE_1024-NEXT: scvtf [[RES:z[0-9]+]].d, [[PG2]]/m, [[UPK2]].d
+; VBITS_GE_1024-NEXT: st1d { [[RES]].d }, [[PG1]], [x1]
+; VBITS_GE_1024-NEXT: ret
+  %op1 = load <16 x i16>, <16 x i16>* %a
+  %res = sitofp <16 x i16> %op1 to <16 x double>
+  store <16 x double> %res, <16 x double>* %b
+  ret void
+}
+
+define void @scvtf_v32i16_v32f64(<32 x i16>* %a, <32 x double>* %b) #0 {
+; CHECK-LABEL: scvtf_v32i16_v32f64:
+; VBITS_GE_2048: ptrue [[PG1:p[0-9]+]].h, vl32
+; VBITS_GE_2048-NEXT: ld1h { [[OP:z[0-9]+]].h }, [[PG1]]/z, [x0]
+; VBITS_GE_2048-NEXT: ptrue [[PG2:p[0-9]+]].d, vl32
+; VBITS_GE_2048-NEXT: sunpklo [[UPK1:z[0-9]+]].s, [[OP]].h
+; VBITS_GE_2048-NEXT: sunpklo [[UPK2:z[0-9]+]].d, [[UPK]].s
+; VBITS_GE_2048-NEXT: scvtf [[RES:z[0-9]+]].d, [[PG2]]/m, [[UPK2]].d
+; VBITS_GE_2048-NEXT: st1d { [[RES]].d }, [[PG1]], [x1]
+; VBITS_GE_2048-NEXT: ret
+  %op1 = load <32 x i16>, <32 x i16>* %a
+  %res = sitofp <32 x i16> %op1 to <32 x double>
+  store <32 x double> %res, <32 x double>* %b
+  ret void
+}
+
+;
+; SCVTF S -> H
+;
+
+; Don't use SVE for 64-bit vectors.
+define <2 x half> @scvtf_v2i32_v2f16(<2 x i32> %op1) #0 {
+; CHECK-LABEL: scvtf_v2i32_v2f16:
+; CHECK: scvtf v0.4s, v0.4s
+; CHECK-NEXT: fcvtn v0.4h, v0.4s
+; CHECK-NEXT: ret
+  %res = sitofp <2 x i32> %op1 to <2 x half>
+  ret <2 x half> %res
+}
+
+; Don't use SVE for 128-bit vectors.
+define <4 x half> @scvtf_v4i32_v4f16(<4 x i32> %op1) #0 {
+; CHECK-LABEL: scvtf_v4i32_v4f16:
+; CHECK: scvtf v0.4s, v0.4s
+; CHECK-NEXT: fcvtn v0.4h, v0.4s
+; CHECK-NEXT: ret
+  %res = sitofp <4 x i32> %op1 to <4 x half>
+  ret <4 x half> %res
+}
+
+define <8 x half> @scvtf_v8i32_v8f16(<8 x i32>* %a) #0 {
+; CHECK-LABEL: scvtf_v8i32_v8f16:
+; CHECK: ptrue [[PG1:p[0-9]+]].s, vl8
+; CHECK-NEXT: ld1w { [[OP:z[0-9]+]].s }, [[PG1]]/z, [x0]
+; CHECK-NEXT: ptrue [[PG2:p[0-9]+]].s
+; CHECK-NEXT: scvtf [[CVT:z[0-9]+]].h, [[PG2]]/m, [[OP]].s
+; CHECK-NEXT: uzp1 z0.h, [[CVT]].h, [[CVT]].h
+; CHECK-NEXT: ret
+  %op1 = load <8 x i32>, <8 x i32>* %a
+  %res = sitofp <8 x i32> %op1 to <8 x half>
+  ret <8 x half> %res
+}
+
+define void @scvtf_v16i32_v16f16(<16 x i32>* %a, <16 x half>* %b) #0 {
+; CHECK-LABEL: scvtf_v16i32_v16f16:
+; VBITS_GE_512: ptrue [[PG1:p[0-9]+]].s, vl16
+; VBITS_GE_512-NEXT: ld1w { [[OP:z[0-9]+]].s }, [[PG1]]/z, [x0]
+; VBITS_GE_512-NEXT: ptrue [[PG2:p[0-9]+]].s
+; VBITS_GE_512-NEXT: scvtf [[CVT:z[0-9]+]].h, [[PG2]]/m, [[OP]].s
+; VBITS_GE_512-NEXT: uzp1 [[RES:z[0-9]+]].h, [[CVT]].h, [[CVT]].h
+; VBITS_GE_512-NEXT: ptrue [[PG3:p[0-9]+]].h, vl16
+; VBITS_GE_512-NEXT: st1h { [[RES]].h }, [[PG3]], [x1]
+; VBITS_GE_512-NEXT: ret
+
+; Ensure sensible type legalisation.
+; VBITS_EQ_256: add x8, x0, #32
+; VBITS_EQ_256-NEXT: ptrue [[PG1:p[0-9]+]].s, vl8
+; VBITS_EQ_256-NEXT: ld1w { [[HI:z[0-9]+]].s }, [[PG]]/z, [x8]
+; VBITS_EQ_256-NEXT: ld1w { [[LO:z[0-9]+]].s }, [[PG]]/z, [x0]
+; VBITS_EQ_256-NEXT: ptrue [[PG2:p[0-9]+]].s
+; VBITS_EQ_256-NEXT: ptrue [[PG3:p[0-9]+]].h, vl8
+; VBITS_EQ_256-NEXT: scvtf [[CVT_HI:z[0-9]+]].h, [[PG2]]/m, [[HI]].s
+; VBITS_EQ_256-NEXT: scvtf [[CVT_LO:z[0-9]+]].h, [[PG2]]/m, [[LO]].s
+; VBITS_EQ_256-NEXT: uzp1 [[RES_LO:z[0-9]+]].h, [[CVT_LO]].h, [[CVT_LO]].h
+; VBITS_EQ_256-NEXT: uzp1 [[RES_HI:z[0-9]+]].h, [[CVT_HI]].h, [[CVT_HI]].h
+; VBITS_EQ_256-NEXT: splice [[RES:z[0-9]+]].h, [[PG3]], [[RES_LO]].h, [[RES_HI]].h
+; VBITS_EQ_256-NEXT: ptrue [[PG4:p[0-9]+]].h, vl16
+; VBITS_EQ_256-NEXT: st1h { [[RES]].h }, [[PG4]], [x1]
+; VBITS_EQ_256-NEXT: ret
+  %op1 = load <16 x i32>, <16 x i32>* %a
+  %res = sitofp <16 x i32> %op1 to <16 x half>
+  store <16 x half> %res, <16 x half>* %b
+  ret void
+}
+
+define void @scvtf_v32i32_v32f16(<32 x i32>* %a, <32 x half>* %b) #0 {
+; CHECK-LABEL: scvtf_v32i32_v32f16:
+; VBITS_GE_1024: ptrue [[PG1:p[0-9]+]].s, vl32
+; VBITS_GE_1024-NEXT: ld1w { [[OP:z[0-9]+]].s }, [[PG1]]/z, [x0]
+; VBITS_GE_1024-NEXT: ptrue [[PG2:p[0-9]+]].s
+; VBITS_GE_1024-NEXT: scvtf [[CVT:z[0-9]+]].h, [[PG2]]/m, [[OP]].s
+; VBITS_GE_1024-NEXT: uzp1 [[RES:z[0-9]+]].h, [[CVT]].h, [[CVT]].h
+; VBITS_GE_1024-NEXT: ptrue [[PG3:p[0-9]+]].h, vl32
+; VBITS_GE_1024-NEXT: st1h { [[RES]].h }, [[PG3]], [x1]
+; VBITS_GE_1024-NEXT: ret
+  %op1 = load <32 x i32>, <32 x i32>* %a
+  %res = sitofp <32 x i32> %op1 to <32 x half>
+  store <32 x half> %res, <32 x half>* %b
+  ret void
+}
+
+define void @scvtf_v64i32_v64f16(<64 x i32>* %a, <64 x half>* %b) #0 {
+; CHECK-LABEL: scvtf_v64i32_v64f16:
+; VBITS_GE_2048: ptrue [[PG1:p[0-9]+]].s, vl64
+; VBITS_GE_2048-NEXT: ld1w { [[OP:z[0-9]+]].s }, [[PG1]]/z, [x0]
+; VBITS_GE_2048-NEXT: ptrue [[PG2:p[0-9]+]].s
+; VBITS_GE_2048-NEXT: scvtf [[RES:z[0-9]+]].h, [[PG2]]/m, [[UPK]].s
+; VBITS_GE_2048-NEXT: uzp1 [[RES:z[0-9]+]].h, [[CVT]].h, [[CVT]].h
+; VBITS_GE_2048-NEXT: ptrue [[PG3:p[0-9]+]].h, vl64
+; VBITS_GE_2048-NEXT: st1h { [[RES]].h }, [[PG3]], [x1]
+; VBITS_GE_2048-NEXT: ret
+  %op1 = load <64 x i32>, <64 x i32>* %a
+  %res = sitofp <64 x i32> %op1 to <64 x half>
+  store <64 x half> %res, <64 x half>* %b
+  ret void
+}
+
+;
+; SCVTF S -> S
+;
+
+; Don't use SVE for 64-bit vectors.
+define <2 x float> @scvtf_v2i32_v2f32(<2 x i32> %op1) #0 {
+; CHECK-LABEL: scvtf_v2i32_v2f32:
+; CHECK: scvtf v0.2s, v0.2s
+; CHECK-NEXT: ret
+  %res = sitofp <2 x i32> %op1 to <2 x float>
+  ret <2 x float> %res
+}
+
+; Don't use SVE for 128-bit vectors.
+define <4 x float> @scvtf_v4i32_v4f32(<4 x i32> %op1) #0 {
+; CHECK-LABEL: scvtf_v4i32_v4f32:
+; CHECK: scvtf v0.4s, v0.4s
+; CHECK-NEXT: ret
+  %res = sitofp <4 x i32> %op1 to <4 x float>
+  ret <4 x float> %res
+}
+
+define void @scvtf_v8i32_v8f32(<8 x i32>* %a, <8 x float>* %b) #0 {
+; CHECK-LABEL: scvtf_v8i32_v8f32:
+; CHECK: ptrue [[PG:p[0-9]+]].s, vl8
+; CHECK-NEXT: ld1w { [[OP:z[0-9]+]].s }, [[PG]]/z, [x0]
+; CHECK-NEXT: scvtf [[RES:z[0-9]+]].s, [[PG]]/m, [[OP]].s
+; CHECK-NEXT: st1w { [[RES]].s }, [[PG]], [x1]
+; CHECK-NEXT: ret
+  %op1 = load <8 x i32>, <8 x i32>* %a
+  %res = sitofp <8 x i32> %op1 to <8 x float>
+  store <8 x float> %res, <8 x float>* %b
+  ret void
+}
+
+define void @scvtf_v16i32_v16f32(<16 x i32>* %a, <16 x float>* %b) #0 {
+; CHECK-LABEL: scvtf_v16i32_v16f32:
+; VBITS_GE_512: ptrue [[PG:p[0-9]+]].s, vl16
+; VBITS_GE_512-NEXT: ld1w { [[OP:z[0-9]+]].s }, [[PG]]/z, [x0]
+; VBITS_GE_512-NEXT: scvtf [[RES:z[0-9]+]].s, [[PG]]/m, [[OP]].s
+; VBITS_GE_512-NEXT: st1w { [[RES]].s }, [[PG]], [x1]
+; VBITS_GE_512-NEXT: ret
+
+; Ensure sensible type legalisation.
+; VBITS_EQ_256: ptrue [[PG:p[0-9]+]].s, vl8
+; VBITS_EQ_256-NEXT: add x8, x0, #32
+; VBITS_EQ_256-NEXT: ld1w { [[LO:z[0-9]+]].s }, [[PG]]/z, [x0]
+; VBITS_EQ_256-NEXT: ld1w { [[HI:z[0-9]+]].s }, [[PG]]/z, [x8]
+; VBITS_EQ_256-NEXT: add x8, x1, #32
+; VBITS_EQ_256-NEXT: scvtf [[RES_LO:z[0-9]+]].s, [[PG]]/m, [[LO]].s
+; VBITS_EQ_256-NEXT: scvtf [[RES_HI:z[0-9]+]].s, [[PG]]/m, [[HI]].s
+; VBITS_EQ_256-NEXT: st1w { [[RES_LO]].s }, [[PG]], [x1]
+; VBITS_EQ_256-NEXT: st1w { [[RES_HI]].s }, [[PG]], [x8]
+; VBITS_EQ_256-NEXT: ret
+  %op1 = load <16 x i32>, <16 x i32>* %a
+  %res = sitofp <16 x i32> %op1 to <16 x float>
+  store <16 x float> %res, <16 x float>* %b
+  ret void
+}
+
+define void @scvtf_v32i32_v32f32(<32 x i32>* %a, <32 x float>* %b) #0 {
+; CHECK-LABEL: scvtf_v32i32_v32f32:
+; VBITS_GE_1024: ptrue [[PG:p[0-9]+]].s, vl32
+; VBITS_GE_1024-NEXT: ld1w { [[OP:z[0-9]+]].s }, [[PG]]/z, [x0]
+; VBITS_GE_1024-NEXT: scvtf [[RES:z[0-9]+]].s, [[PG]]/m, [[OP]].s
+; VBITS_GE_1024-NEXT: st1w { [[RES]].s }, [[PG]], [x1]
+; VBITS_GE_1024-NEXT: ret
+  %op1 = load <32 x i32>, <32 x i32>* %a
+  %res = sitofp <32 x i32> %op1 to <32 x float>
+  store <32 x float> %res, <32 x float>* %b
+  ret void
+}
+
+define void @scvtf_v64i32_v64f32(<64 x i32>* %a, <64 x float>* %b) #0 {
+; CHECK-LABEL: scvtf_v64i32_v64f32:
+; VBITS_GE_2048: ptrue [[PG:p[0-9]+]].s, vl64
+; VBITS_GE_2048-NEXT: ld1w { [[OP:z[0-9]+]].s }, [[PG]]/z, [x0]
+; VBITS_GE_2048-NEXT: scvtf [[RES:z[0-9]+]].s, [[PG]]/m, [[OP]].s
+; VBITS_GE_2048-NEXT: st1w { [[RES]].s }, [[PG]], [x1]
+; VBITS_GE_2048-NEXT: ret
+  %op1 = load <64 x i32>, <64 x i32>* %a
+  %res = sitofp <64 x i32> %op1 to <64 x float>
+  store <64 x float> %res, <64 x float>* %b
+  ret void
+}
+
+;
+; SCVTF S -> D
+;
+
+; Don't use SVE for 64-bit vectors.
+define <1 x double> @scvtf_v1i32_v1f64(<1 x i32> %op1) #0 {
+; CHECK-LABEL: scvtf_v1i32_v1f64:
+; CHECK: sshll v0.2d, v0.2s, #0
+; CHECK-NEXT: scvtf v0.2d, v0.2d
+; CHECK-NEXT: ret
+  %res = sitofp <1 x i32> %op1 to <1 x double>
+  ret <1 x double> %res
+}
+
+; Don't use SVE for 128-bit vectors.
+define <2 x double> @scvtf_v2i32_v2f64(<2 x i32> %op1) #0 {
+; CHECK-LABEL: scvtf_v2i32_v2f64:
+; CHECK: sshll v0.2d, v0.2s, #0
+; CHECK-NEXT: scvtf v0.2d, v0.2d
+; CHECK-NEXT: ret
+  %res = sitofp <2 x i32> %op1 to <2 x double>
+  ret <2 x double> %res
+}
+
+define void @scvtf_v4i32_v4f64(<4 x i32>* %a, <4 x double>* %b) #0 {
+; CHECK-LABEL: scvtf_v4i32_v4f64:
+; CHECK: ldr q[[OP:[0-9]+]], [x0]
+; CHECK-NEXT: ptrue [[PG:p[0-9]+]].d, vl4
+; CHECK-NEXT: sunpklo [[UPK:z[0-9]+]].d, z[[OP]].s
+; CHECK-NEXT: scvtf [[RES:z[0-9]+]].d, [[PG]]/m, [[UPK]].d
+; CHECK-NEXT: st1d { [[RES]].d }, [[PG]], [x1]
+; CHECK-NEXT: ret
+  %op1 = load <4 x i32>, <4 x i32>* %a
+  %res = sitofp <4 x i32> %op1 to <4 x double>
+  store <4 x double> %res, <4 x double>* %b
+  ret void
+}
+
+define void @scvtf_v8i32_v8f64(<8 x i32>* %a, <8 x double>* %b) #0 {
+; CHECK-LABEL: scvtf_v8i32_v8f64:
+; VBITS_GE_512: ptrue [[PG1:p[0-9]+]].s, vl8
+; VBITS_GE_512-NEXT: ld1w { [[OP:z[0-9]+]].s }, [[PG1]]/z, [x0]
+; VBITS_GE_512-NEXT: ptrue [[PG:p[0-9]+]].d, vl8
+; VBITS_GE_512-NEXT: sunpklo [[UPK:z[0-9]+]].d, [[OP]].s
+; VBITS_GE_512-NEXT: scvtf [[RES:z[0-9]+]].d, [[PG1]]/m, [[UPK]].d
+; VBITS_GE_512-NEXT: st1d { [[RES]].d }, [[PG1]], [x1]
+; VBITS_GE_512-NEXT: ret
+
+; Ensure sensible type legalisation - fixed type extract_subvector codegen is poor currently.
+; VBITS_EQ_256: ptrue [[PG1:p[0-9]+]].s, vl8
+; VBITS_EQ_256-DAG: ld1w { [[VEC:z[0-9]+]].s }, [[PG1]]/z, [x0]
+; VBITS_EQ_256-DAG: st1w { [[VEC:z[0-9]+]].s }, [[PG1]], [x8]
+; VBITS_EQ_256-DAG: ldp q[[LO:[0-9]+]], q[[HI:[0-9]+]], [sp]
+; VBITS_EQ_256-NEXT: ptrue [[PG2:p[0-9]+]].d, vl4
+; VBITS_EQ_256-NEXT: add x8, x1, #32
+; VBITS_EQ_256-NEXT: sunpklo [[UPK_LO:z[0-9]+]].d, z[[LO]].s
+; VBITS_EQ_256-NEXT: sunpklo [[UPK_HI:z[0-9]+]].d, z[[HI]].s
+; VBITS_EQ_256-NEXT: scvtf [[RES_LO:z[0-9]+]].d, [[PG2]]/m, [[UPK_LO]].d
+; VBITS_EQ_256-NEXT: scvtf [[RES_HI:z[0-9]+]].d, [[PG2]]/m, [[UPK_HI]].d
+; VBITS_EQ_256-NEXT: st1d { [[RES_HI]].d }, [[PG2]], [x8]
+; VBITS_EQ_256-NEXT: st1d { [[RES_LO]].d }, [[PG2]], [x1]
+  %op1 = load <8 x i32>, <8 x i32>* %a
+  %res = sitofp <8 x i32> %op1 to <8 x double>
+  store <8 x double> %res, <8 x double>* %b
+  ret void
+}
+
+define void @scvtf_v16i32_v16f64(<16 x i32>* %a, <16 x double>* %b) #0 {
+; CHECK-LABEL: scvtf_v16i32_v16f64:
+; VBITS_GE_1024: ptrue [[PG1:p[0-9]+]].s, vl16
+; VBITS_GE_1024-NEXT: ld1w { [[OP:z[0-9]+]].s }, [[PG1]]/z, [x0]
+; VBITS_GE_1024-NEXT: ptrue [[PG2:p[0-9]+]].d, vl16
+; VBITS_GE_1024-NEXT: sunpklo [[UPK:z[0-9]+]].d, [[OP]].s
+; VBITS_GE_1024-NEXT: scvtf [[RES:z[0-9]+]].d, [[PG2]]/m, [[UPK]].d
+; VBITS_GE_1024-NEXT: st1d { [[RES]].d }, [[PG1]], [x1]
+; VBITS_GE_1024-NEXT: ret
+  %op1 = load <16 x i32>, <16 x i32>* %a
+  %res = sitofp <16 x i32> %op1 to <16 x double>
+  store <16 x double> %res, <16 x double>* %b
+  ret void
+}
+
+define void @scvtf_v32i32_v32f64(<32 x i32>* %a, <32 x double>* %b) #0 {
+; CHECK-LABEL: scvtf_v32i32_v32f64:
+; VBITS_GE_2048: ptrue [[PG1:p[0-9]+]].s, vl32
+; VBITS_GE_2048-NEXT: ld1w { [[OP:z[0-9]+]].s }, [[PG1]]/z, [x0]
+; VBITS_GE_2048-NEXT: ptrue [[PG2:p[0-9]+]].d, vl32
+; VBITS_GE_2048-NEXT: sunpklo [[UPK:z[0-9]+]].d, [[OP]].s
+; VBITS_GE_2048-NEXT: scvtf [[RES:z[0-9]+]].d, [[PG2]]/m, [[UPK]].d
+; VBITS_GE_2048-NEXT: st1d { [[RES]].d }, [[PG1]], [x1]
+; VBITS_GE_2048-NEXT: ret
+  %op1 = load <32 x i32>, <32 x i32>* %a
+  %res = sitofp <32 x i32> %op1 to <32 x double>
+  store <32 x double> %res, <32 x double>* %b
+  ret void
+}
+
+
+;
+; SCVTF D -> H
+;
+
+; Don't use SVE for 64-bit vectors.
+define <1 x half> @scvtf_v1i64_v1f16(<1 x i64> %op1) #0 {
+; CHECK-LABEL: scvtf_v1i64_v1f16:
+; CHECK: fmov x8, d0
+; CHECK-NEXT: scvtf h0, x8
+; CHECK-NEXT: ret
+  %res = sitofp <1 x i64> %op1 to <1 x half>
+  ret <1 x half> %res
+}
+
+; v2f16 is not legal for NEON, so use SVE
+define <2 x half> @scvtf_v2i64_v2f16(<2 x i64> %op1) #0 {
+; CHECK-LABEL: scvtf_v2i64_v2f16:
+; CHECK: ptrue [[PG:p[0-9]+]].d
+; CHECK-NEXT: scvtf [[CVT:z[0-9]+]].h, [[PG]]/m, z0.d
+; CHECK-NEXT: uzp1 [[UZP:z[0-9]+]].s, [[CVT]].s, [[CVT]].s
+; CHECK-NEXT: uzp1 z0.h, [[UZP]].h, [[UZP]].h
+; CHECK-NEXT: ret
+  %res = sitofp <2 x i64> %op1 to <2 x half>
+  ret <2 x half> %res
+}
+
+define <4 x half> @scvtf_v4i64_v4f16(<4 x i64>* %a) #0 {
+; CHECK-LABEL: scvtf_v4i64_v4f16:
+; CHECK: ptrue [[PG1:p[0-9]+]].d, vl4
+; CHECK-NEXT: ld1d { [[OP:z[0-9]+]].d }, [[PG1]]/z, [x0]
+; CHECK-NEXT: ptrue [[PG2:p[0-9]+]].d
+; CHECK-NEXT: scvtf [[CVT:z[0-9]+]].h, [[PG2]]/m, [[OP]].d
+; CHECK-NEXT: uzp1 [[UZP:z[0-9]+]].s, [[CVT]].s, [[CVT]].s
+; CHECK-NEXT: uzp1 z0.h, [[UZP]].h, [[UZP]].h
+; CHECK-NEXT: ret
+  %op1 = load <4 x i64>, <4 x i64>* %a
+  %res = sitofp <4 x i64> %op1 to <4 x half>
+  ret <4 x half> %res
+}
+
+define <8 x half> @scvtf_v8i64_v8f16(<8 x i64>* %a) #0 {
+; CHECK-LABEL: scvtf_v8i64_v8f16:
+; VBITS_GE_512: ptrue [[PG1:p[0-9]+]].d, vl8
+; VBITS_GE_512-NEXT: ld1d { [[OP:z[0-9]+]].d }, [[PG1]]/z, [x0]
+; VBITS_GE_512-NEXT: ptrue [[PG2:p[0-9]+]].d
+; VBITS_GE_512-NEXT: scvtf [[CVT:z[0-9]+]].h, [[PG2]]/m, [[OP]].d
+; VBITS_GE_512-NEXT: uzp1 [[UZP:z[0-9]+]].s, [[CVT]].s, [[CVT]].s
+; VBITS_GE_512-NEXT: uzp1 z0.h, [[UZP]].h, [[UZP]].h
+; VBITS_GE_512-NEXT: ret
+
+; Ensure sensible type legalisation.
+; VBITS_EQ_256: add x8, x0, #32
+; VBITS_EQ_256-NEXT: ptrue [[PG1:p[0-9]+]].d, vl4
+; VBITS_EQ_256-NEXT: ld1d { [[HI:z[0-9]+]].d }, [[PG]]/z, [x8]
+; VBITS_EQ_256-NEXT: ld1d { [[LO:z[0-9]+]].d }, [[PG]]/z, [x0]
+; VBITS_EQ_256-NEXT: ptrue [[PG2:p[0-9]+]].d
+; VBITS_EQ_256-NEXT: scvtf [[CVT_HI:z[0-9]+]].h, [[PG2]]/m, [[HI]].d
+; VBITS_EQ_256-NEXT: scvtf [[CVT_LO:z[0-9]+]].h, [[PG2]]/m, [[LO]].d
+; VBITS_EQ_256-NEXT: uzp1 [[UZP_LO:z[0-9]+]].s, [[CVT_LO]].s, [[CVT_LO]].s
+; VBITS_EQ_256-NEXT: uzp1 [[UZP_HI:z[0-9]+]].s, [[CVT_HI]].s, [[CVT_HI]].s
+; VBITS_EQ_256-NEXT: uzp1 z[[RES_LO:[0-9]+]].h, [[UZP_LO]].h, [[UZP_LO]].h
+; VBITS_EQ_256-NEXT: uzp1 z[[RES_HI:[0-9]+]].h, [[UZP_HI]].h, [[UZP_HI]].h
+; VBITS_EQ_256-NEXT: mov v[[RES_LO]].d[1], v[[RES_HI]].d[0]
+; VBITS_EQ_256-NEXT: ret
+  %op1 = load <8 x i64>, <8 x i64>* %a
+  %res = sitofp <8 x i64> %op1 to <8 x half>
+  ret <8 x half> %res
+}
+
+define void @scvtf_v16i64_v16f16(<16 x i64>* %a, <16 x half>* %b) #0 {
+; CHECK-LABEL: scvtf_v16i64_v16f16:
+; VBITS_GE_1024: ptrue [[PG1:p[0-9]+]].d, vl16
+; VBITS_GE_1024-NEXT: ld1d { [[OP:z[0-9]+]].d }, [[PG1]]/z, [x0]
+; VBITS_GE_1024-NEXT: ptrue [[PG2:p[0-9]+]].d
+; VBITS_GE_1024-NEXT: scvtf [[CVT:z[0-9]+]].h, [[PG2]]/m, [[OP]].d
+; VBITS_GE_1024-NEXT: uzp1 [[UZP:z[0-9]+]].s, [[CVT]].s, [[CVT]].s
+; VBITS_GE_1024-NEXT: uzp1 [[RES:z[0-9]+]].h, [[UZP]].h, [[UZP]].h
+; VBITS_GE_1024-NEXT: ptrue [[PG3:p[0-9]+]].h, vl16
+; VBITS_GE_1024-NEXT: st1h { [[RES]].h }, [[PG3]], [x1]
+; VBITS_GE_1024-NEXT: ret
+  %op1 = load <16 x i64>, <16 x i64>* %a
+  %res = sitofp <16 x i64> %op1 to <16 x half>
+  store <16 x half> %res, <16 x half>* %b
+  ret void
+}
+
+define void @scvtf_v32i64_v32f16(<32 x i64>* %a, <32 x half>* %b) #0 {
+; CHECK-LABEL: scvtf_v32i64_v32f16:
+; VBITS_GE_2048: ptrue [[PG1:p[0-9]+]].d, vl32
+; VBITS_GE_2048-NEXT: ld1d { [[OP:z[0-9]+]].d }, [[PG1]]/z, [x0]
+; VBITS_GE_2048-NEXT: ptrue [[PG2:p[0-9]+]].d
+; VBITS_GE_2048-NEXT: scvtf [[CVT:z[0-9]+]].h, [[PG2]]/m, [[OP]].d
+; VBITS_GE_2048-NEXT: uzp1 [[UZP:z[0-9]+]].s, [[CVT]].s, [[CVT]].s
+; VBITS_GE_2048-NEXT: uzp1 [[RES:z[0-9]+]].h, [[UZP]].h, [[UZP]].h
+; VBITS_GE_2048-NEXT: ptrue [[PG3:p[0-9]+]].h, vl32
+; VBITS_GE_2048-NEXT: st1h { [[RES]].h }, [[PG3]], [x1]
+; VBITS_GE_2048-NEXT: ret
+  %op1 = load <32 x i64>, <32 x i64>* %a
+  %res = sitofp <32 x i64> %op1 to <32 x half>
+  store <32 x half> %res, <32 x half>* %b
+  ret void
+}
+
+;
+; SCVTF D -> S
+;
+
+; Don't use SVE for 64-bit vectors.
+define <1 x float> @scvtf_v1i64_v1f32(<1 x i64> %op1) #0 {
+; CHECK-LABEL: scvtf_v1i64_v1f32:
+; CHECK: scvtf v0.2d, v0.2d
+; CHECK-NEXT: fcvtn v0.2s, v0.2d
+; CHECK-NEXT: ret
+  %res = sitofp <1 x i64> %op1 to <1 x float>
+  ret <1 x float> %res
+}
+
+; Don't use SVE for 128-bit vectors.
+define <2 x float> @scvtf_v2i64_v2f32(<2 x i64> %op1) #0 {
+; CHECK-LABEL: scvtf_v2i64_v2f32:
+; CHECK: scvtf v0.2d, v0.2d
+; CHECK-NEXT: fcvtn v0.2s, v0.2d
+; CHECK-NEXT: ret
+  %res = sitofp <2 x i64> %op1 to <2 x float>
+  ret <2 x float> %res
+}
+
+define <4 x float> @scvtf_v4i64_v4f32(<4 x i64>* %a) #0 {
+; CHECK-LABEL: scvtf_v4i64_v4f32:
+; CHECK: ptrue [[PG1:p[0-9]+]].d, vl4
+; CHECK-NEXT: ld1d { [[OP:z[0-9]+]].d }, [[PG1]]/z, [x0]
+; CHECK-NEXT: ptrue [[PG2:p[0-9]+]].d
+; CHECK-NEXT: scvtf [[CVT:z[0-9]+]].s, [[PG2]]/m, [[OP]].d
+; CHECK-NEXT: uzp1 z0.s, [[CVT]].s, [[CVT]].s
+; CHECK-NEXT: ret
+  %op1 = load <4 x i64>, <4 x i64>* %a
+  %res = sitofp <4 x i64> %op1 to <4 x float>
+  ret <4 x float> %res
+}
+
+define void @scvtf_v8i64_v8f32(<8 x i64>* %a, <8 x float>* %b) #0 {
+; CHECK-LABEL: scvtf_v8i64_v8f32:
+; VBITS_GE_512: ptrue [[PG1:p[0-9]+]].d, vl8
+; VBITS_GE_512-NEXT: ld1d { [[OP:z[0-9]+]].d }, [[PG1]]/z, [x0]
+; VBITS_GE_512-NEXT: ptrue [[PG2:p[0-9]+]].d
+; VBITS_GE_512-NEXT: scvtf [[CVT:z[0-9]+]].s, [[PG2]]/m, [[OP]].d
+; VBITS_GE_512-NEXT: uzp1 [[RES:z[0-9]+]].s, [[CVT]].s, [[CVT]].s
+; VBITS_GE_512-NEXT: ptrue [[PG3:p[0-9]+]].s, vl8
+; VBITS_GE_512-NEXT: st1w { [[RES]].s }, [[PG3]], [x1]
+; VBITS_GE_512-NEXT: ret
+
+; Ensure sensible type legalisation.
+; VBITS_EQ_256: add x8, x0, #32
+; VBITS_EQ_256-NEXT: ptrue [[PG1:p[0-9]+]].d, vl4
+; VBITS_EQ_256-NEXT: ld1d { [[HI:z[0-9]+]].d }, [[PG]]/z, [x8]
+; VBITS_EQ_256-NEXT: ld1d { [[LO:z[0-9]+]].d }, [[PG]]/z, [x0]
+; VBITS_EQ_256-NEXT: ptrue [[PG2:p[0-9]+]].d
+; VBITS_EQ_256-NEXT: ptrue [[PG3:p[0-9]+]].s, vl4
+; VBITS_EQ_256-NEXT: scvtf [[CVT_HI:z[0-9]+]].s, [[PG2]]/m, [[HI]].d
+; VBITS_EQ_256-NEXT: scvtf [[CVT_LO:z[0-9]+]].s, [[PG2]]/m, [[LO]].d
+; VBITS_EQ_256-NEXT: uzp1 [[RES_LO:z[0-9]+]].s, [[CVT_LO]].s, [[CVT_LO]].s
+; VBITS_EQ_256-NEXT: uzp1 [[RES_HI:z[0-9]+]].s, [[CVT_HI]].s, [[CVT_HI]].s
+; VBITS_EQ_256-NEXT: splice [[RES:z[0-9]+]].s, [[PG3]], [[RES_LO]].s, [[RES_HI]].s
+; VBITS_EQ_256-NEXT: ptrue [[PG4:p[0-9]+]].s, vl8
+; VBITS_EQ_256-NEXT: st1w { [[RES]].s }, [[PG4]], [x1]
+; VBITS_EQ_256-NEXT: ret
+  %op1 = load <8 x i64>, <8 x i64>* %a
+  %res = sitofp <8 x i64> %op1 to <8 x float>
+  store <8 x float> %res, <8 x float>* %b
+  ret void
+}
+
+define void @scvtf_v16i64_v16f32(<16 x i64>* %a, <16 x float>* %b) #0 {
+; CHECK-LABEL: scvtf_v16i64_v16f32:
+; VBITS_GE_1024: ptrue [[PG1:p[0-9]+]].d, vl16
+; VBITS_GE_1024-NEXT: ld1d { [[OP:z[0-9]+]].d }, [[PG1]]/z, [x0]
+; VBITS_GE_1024-NEXT: ptrue [[PG2:p[0-9]+]].d
+; VBITS_GE_1024-NEXT: scvtf [[CVT:z[0-9]+]].s, [[PG2]]/m, [[OP]].d
+; VBITS_GE_1024-NEXT: uzp1 [[RES:z[0-9]+]].s, [[CVT]].s, [[CVT]].s
+; VBITS_GE_1024-NEXT: ptrue [[PG3:p[0-9]+]].s, vl16
+; VBITS_GE_1024-NEXT: st1w { [[RES]].s }, [[PG3]], [x1]
+; VBITS_GE_1024-NEXT: ret
+  %op1 = load <16 x i64>, <16 x i64>* %a
+  %res = sitofp <16 x i64> %op1 to <16 x float>
+  store <16 x float> %res, <16 x float>* %b
+  ret void
+}
+
+define void @scvtf_v32i64_v32f32(<32 x i64>* %a, <32 x float>* %b) #0 {
+; CHECK-LABEL: scvtf_v32i64_v32f32:
+; VBITS_GE_2048: ptrue [[PG1:p[0-9]+]].d, vl32
+; VBITS_GE_2048-NEXT: ld1d { [[OP:z[0-9]+]].d }, [[PG1]]/z, [x0]
+; VBITS_GE_2048-NEXT: ptrue [[PG2:p[0-9]+]].d
+; VBITS_GE_2048-NEXT: scvtf [[CVT:z[0-9]+]].s, [[PG2]]/m, [[OP]].d
+; VBITS_GE_2048-NEXT: uzp1 [[RES:z[0-9]+]].s, [[CVT]].s, [[CVT]].s
+; VBITS_GE_2048-NEXT: ptrue [[PG3:p[0-9]+]].s, vl32
+; VBITS_GE_2048-NEXT: st1w { [[RES]].s }, [[PG3]], [x1]
+; VBITS_GE_2048-NEXT: ret
+  %op1 = load <32 x i64>, <32 x i64>* %a
+  %res = sitofp <32 x i64> %op1 to <32 x float>
+  store <32 x float> %res, <32 x float>* %b
+  ret void
+}
+
+;
+; SCVTF D -> D
+;
+
+; Don't use SVE for 64-bit vectors.
+define <1 x double> @scvtf_v1i64_v1f64(<1 x i64> %op1) #0 {
+; CHECK-LABEL: scvtf_v1i64_v1f64:
+; CHECK: fmov x8, d0
+; CHECK-NEXT: scvtf d0, x8
+; CHECK-NEXT: ret
+  %res = sitofp <1 x i64> %op1 to <1 x double>
+  ret <1 x double> %res
+}
+
+; Don't use SVE for 128-bit vectors.
+define <2 x double> @scvtf_v2i64_v2f64(<2 x i64> %op1) #0 {
+; CHECK-LABEL: scvtf_v2i64_v2f64:
+; CHECK: scvtf v0.2d, v0.2d
+; CHECK-NEXT: ret
+  %res = sitofp <2 x i64> %op1 to <2 x double>
+  ret <2 x double> %res
+}
+
+define void @scvtf_v4i64_v4f64(<4 x i64>* %a, <4 x double>* %b) #0 {
+; CHECK-LABEL: scvtf_v4i64_v4f64:
+; CHECK: ptrue [[PG:p[0-9]+]].d, vl4
+; CHECK-NEXT: ld1d { [[OP:z[0-9]+]].d }, [[PG]]/z, [x0]
+; CHECK-NEXT: scvtf [[RES:z[0-9]+]].d, [[PG]]/m, [[OP]].d
+; CHECK-NEXT: st1d { [[RES]].d }, [[PG]], [x1]
+; CHECK-NEXT: ret
+  %op1 = load <4 x i64>, <4 x i64>* %a
+  %res = sitofp <4 x i64> %op1 to <4 x double>
+  store <4 x double> %res, <4 x double>* %b
+  ret void
+}
+
+define void @scvtf_v8i64_v8f64(<8 x i64>* %a, <8 x double>* %b) #0 {
+; CHECK-LABEL: scvtf_v8i64_v8f64:
+; VBITS_GE_512: ptrue [[PG:p[0-9]+]].d, vl8
+; VBITS_GE_512-NEXT: ld1d { [[OP:z[0-9]+]].d }, [[PG]]/z, [x0]
+; VBITS_GE_512-NEXT: scvtf [[RES:z[0-9]+]].d, [[PG]]/m, [[OP]].d
+; VBITS_GE_512-NEXT: st1d { [[RES]].d }, [[PG]], [x1]
+; VBITS_GE_512-NEXT: ret
+
+; Ensure sensible type legalisation.
+; VBITS_EQ_256: ptrue [[PG:p[0-9]+]].d, vl4
+; VBITS_EQ_256-NEXT: add x8, x0, #32
+; VBITS_EQ_256-NEXT: ld1d { [[LO:z[0-9]+]].d }, [[PG]]/z, [x0]
+; VBITS_EQ_256-NEXT: ld1d { [[HI:z[0-9]+]].d }, [[PG]]/z, [x8]
+; VBITS_EQ_256-NEXT: add x8, x1, #32
+; VBITS_EQ_256-NEXT: scvtf [[RES_LO:z[0-9]+]].d, [[PG]]/m, [[LO]].d
+; VBITS_EQ_256-NEXT: scvtf [[RES_HI:z[0-9]+]].d, [[PG]]/m, [[HI]].d
+; VBITS_EQ_256-NEXT: st1d { [[RES_LO]].d }, [[PG]], [x1]
+; VBITS_EQ_256-NEXT: st1d { [[RES_HI]].d }, [[PG]], [x8]
+; VBITS_EQ_256-NEXT: ret
+  %op1 = load <8 x i64>, <8 x i64>* %a
+  %res = sitofp <8 x i64> %op1 to <8 x double>
+  store <8 x double> %res, <8 x double>* %b
+  ret void
+}
+
+define void @scvtf_v16i64_v16f64(<16 x i64>* %a, <16 x double>* %b) #0 {
+; CHECK-LABEL: scvtf_v16i64_v16f64:
+; VBITS_GE_1024: ptrue [[PG:p[0-9]+]].d, vl16
+; VBITS_GE_1024-NEXT: ld1d { [[OP:z[0-9]+]].d }, [[PG]]/z, [x0]
+; VBITS_GE_1024-NEXT: scvtf [[RES:z[0-9]+]].d, [[PG]]/m, [[OP]].d
+; VBITS_GE_1024-NEXT: st1d { [[RES]].d }, [[PG]], [x1]
+; VBITS_GE_1024-NEXT: ret
+  %op1 = load <16 x i64>, <16 x i64>* %a
+  %res = sitofp <16 x i64> %op1 to <16 x double>
+  store <16 x double> %res, <16 x double>* %b
+  ret void
+}
+
+define void @scvtf_v32i64_v32f64(<32 x i64>* %a, <32 x double>* %b) #0 {
+; CHECK-LABEL: scvtf_v32i64_v32f64:
+; VBITS_GE_2048: ptrue [[PG:p[0-9]+]].d, vl32
+; VBITS_GE_2048-NEXT: ld1d { [[OP:z[0-9]+]].d }, [[PG]]/z, [x0]
+; VBITS_GE_2048-NEXT: scvtf [[RES:z[0-9]+]].d, [[PG]]/m, [[OP]].d
+; VBITS_GE_2048-NEXT: st1d { [[RES]].d }, [[PG]], [x1]
+; VBITS_GE_2048-NEXT: ret
+  %op1 = load <32 x i64>, <32 x i64>* %a
+  %res = sitofp <32 x i64> %op1 to <32 x double>
+  store <32 x double> %res, <32 x double>* %b
+  ret void
+}
+
+attributes #0 = { "target-features"="+sve" }


        


More information about the llvm-commits mailing list