diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp index 7bea2dcec5891..23328ed57fb36 100644 --- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp +++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp @@ -4935,6 +4935,18 @@ SDValue AArch64TargetLowering::LowerFP_TO_INT_SAT(SDValue Op, if (DstWidth < SatWidth) return SDValue(); + if (SrcVT == MVT::f16 && SatVT == MVT::i16 && DstVT == MVT::i32) { + if (Op.getOpcode() == ISD::FP_TO_SINT_SAT) { + SDValue CVTf32 = + DAG.getNode(AArch64ISD::FCVTZS_HALF, DL, MVT::f32, SrcVal); + SDValue Bitcast = DAG.getBitcast(DstVT, CVTf32); + return DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, DstVT, Bitcast, + DAG.getValueType(SatVT)); + } + SDValue CVTf32 = DAG.getNode(AArch64ISD::FCVTZU_HALF, DL, MVT::f32, SrcVal); + return DAG.getBitcast(DstVT, CVTf32); + } + SDValue NativeCvt = DAG.getNode(Op.getOpcode(), DL, DstVT, SrcVal, DAG.getValueType(DstVT)); SDValue Sat; diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td index ad8556b824cda..07c07008c0e05 100644 --- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td +++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td @@ -989,6 +989,9 @@ def AArch64fcvtxnv: PatFrags<(ops node:$Rn), [(int_aarch64_neon_fcvtxn node:$Rn), (AArch64fcvtxn_n node:$Rn)]>; +def AArch64fcvtzs_half : SDNode<"AArch64ISD::FCVTZS_HALF", SDTFPExtendOp>; +def AArch64fcvtzu_half : SDNode<"AArch64ISD::FCVTZU_HALF", SDTFPExtendOp>; + //def Aarch64softf32tobf16v8: SDNode<"AArch64ISD::", SDTFPRoundOp>; // Vector immediate ops @@ -6539,6 +6542,16 @@ defm USQADD : SIMDTwoScalarBHSDTied< 1, 0b00011, "usqadd", def : Pat<(v1i64 (AArch64vashr (v1i64 V64:$Rn), (i32 63))), (CMLTv1i64rz V64:$Rn)>; +// f16 -> i16 conversions leave the bit pattern in a f32 +class F16ToI16ScalarPat + : Pat<(f32 (cvt_isd (f16 FPR16:$Rn))), + (f32 (SUBREG_TO_REG (i64 0), (instr FPR16:$Rn), hsub))>; + +let Predicates = [HasFullFP16] in { +def : F16ToI16ScalarPat; +def : F16ToI16ScalarPat; +} + // Round FP64 to BF16. let Predicates = [HasNEONandIsStreamingSafe, HasBF16] in def : Pat<(bf16 (any_fpround (f64 FPR64:$Rn))), diff --git a/llvm/test/CodeGen/AArch64/fptosi-sat-scalar.ll b/llvm/test/CodeGen/AArch64/fptosi-sat-scalar.ll index e3aef487890f9..83a1893cdbc75 100644 --- a/llvm/test/CodeGen/AArch64/fptosi-sat-scalar.ll +++ b/llvm/test/CodeGen/AArch64/fptosi-sat-scalar.ll @@ -670,13 +670,9 @@ define i16 @test_signed_i16_f16(half %f) nounwind { ; ; CHECK-SD-FP16-LABEL: test_signed_i16_f16: ; CHECK-SD-FP16: // %bb.0: -; CHECK-SD-FP16-NEXT: fcvtzs w8, h0 -; CHECK-SD-FP16-NEXT: mov w9, #32767 // =0x7fff -; CHECK-SD-FP16-NEXT: cmp w8, w9 -; CHECK-SD-FP16-NEXT: csel w8, w8, w9, lt -; CHECK-SD-FP16-NEXT: mov w9, #-32768 // =0xffff8000 -; CHECK-SD-FP16-NEXT: cmn w8, #8, lsl #12 // =32768 -; CHECK-SD-FP16-NEXT: csel w0, w8, w9, gt +; CHECK-SD-FP16-NEXT: fcvtzs h0, h0 +; CHECK-SD-FP16-NEXT: fmov w8, s0 +; CHECK-SD-FP16-NEXT: sxth w0, w8 ; CHECK-SD-FP16-NEXT: ret ; ; CHECK-GI-CVT-LABEL: test_signed_i16_f16: diff --git a/llvm/test/CodeGen/AArch64/fptoui-sat-scalar.ll b/llvm/test/CodeGen/AArch64/fptoui-sat-scalar.ll index 07e49e331415e..2613f8337a918 100644 --- a/llvm/test/CodeGen/AArch64/fptoui-sat-scalar.ll +++ b/llvm/test/CodeGen/AArch64/fptoui-sat-scalar.ll @@ -531,10 +531,8 @@ define i16 @test_unsigned_i16_f16(half %f) nounwind { ; ; CHECK-SD-FP16-LABEL: test_unsigned_i16_f16: ; CHECK-SD-FP16: // %bb.0: -; CHECK-SD-FP16-NEXT: fcvtzu w8, h0 -; CHECK-SD-FP16-NEXT: mov w9, #65535 // =0xffff -; CHECK-SD-FP16-NEXT: cmp w8, w9 -; CHECK-SD-FP16-NEXT: csel w0, w8, w9, lo +; CHECK-SD-FP16-NEXT: fcvtzu h0, h0 +; CHECK-SD-FP16-NEXT: fmov w0, s0 ; CHECK-SD-FP16-NEXT: ret ; ; CHECK-GI-CVT-LABEL: test_unsigned_i16_f16: