diff options
| author | David Majnemer <david.majnemer@gmail.com> | 2024-03-07 19:35:38 +0000 |
|---|---|---|
| committer | David Majnemer <david.majnemer@gmail.com> | 2024-03-08 19:52:53 +0000 |
| commit | 5f935e91810eb28854611faf13bb7d07a8dbf470 (patch) | |
| tree | f29c2d1d0aa03f1fe3ca0f930872c0eb0e037e74 /llvm/lib | |
| parent | e963d0740e64fc70b4018f39325469d204f6217a (diff) | |
[AArch64] Optimize fp64 <-> fp16 SIMD conversions
Legalization would result in needless scalarization. Add some
DAGCombines to fix this up.
Diffstat (limited to 'llvm/lib')
| -rw-r--r-- | llvm/lib/Target/AArch64/AArch64ISelLowering.cpp | 95 | ||||
| -rw-r--r-- | llvm/lib/Target/AArch64/AArch64InstrFormats.td | 4 | ||||
| -rw-r--r-- | llvm/lib/Target/AArch64/AArch64InstrInfo.td | 11 |
3 files changed, 102 insertions, 8 deletions
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp index 2290223a06f8..89b697b2d515 100644 --- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp +++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp @@ -4507,13 +4507,16 @@ SDValue AArch64TargetLowering::LowerINT_TO_FP(SDValue Op, }; if (Op.getValueType() == MVT::bf16) { + unsigned MaxWidth = IsSigned + ? DAG.ComputeMaxSignificantBits(SrcVal) + : DAG.computeKnownBits(SrcVal).countMaxActiveBits(); // bf16 conversions are promoted to f32 when converting from i16. - if (DAG.ComputeMaxSignificantBits(SrcVal) <= 24) { + if (MaxWidth <= 24) { return IntToFpViaPromotion(MVT::f32); } // bf16 conversions are promoted to f64 when converting from i32. - if (DAG.ComputeMaxSignificantBits(SrcVal) <= 53) { + if (MaxWidth <= 53) { return IntToFpViaPromotion(MVT::f64); } @@ -19376,6 +19379,94 @@ static SDValue performBuildVectorCombine(SDNode *N, SDLoc DL(N); EVT VT = N->getValueType(0); + if (VT == MVT::v4f16 || VT == MVT::v4bf16) { + SDValue Elt0 = N->getOperand(0), Elt1 = N->getOperand(1), + Elt2 = N->getOperand(2), Elt3 = N->getOperand(3); + if (Elt0->getOpcode() == ISD::FP_ROUND && + Elt1->getOpcode() == ISD::FP_ROUND && + isa<ConstantSDNode>(Elt0->getOperand(1)) && + isa<ConstantSDNode>(Elt1->getOperand(1)) && + Elt0->getConstantOperandVal(1) == Elt1->getConstantOperandVal(1) && + Elt0->getOperand(0)->getOpcode() == ISD::EXTRACT_VECTOR_ELT && + Elt1->getOperand(0)->getOpcode() == ISD::EXTRACT_VECTOR_ELT && + // Constant index. + isa<ConstantSDNode>(Elt0->getOperand(0)->getOperand(1)) && + isa<ConstantSDNode>(Elt1->getOperand(0)->getOperand(1)) && + Elt0->getOperand(0)->getOperand(0) == + Elt1->getOperand(0)->getOperand(0) && + Elt0->getOperand(0)->getConstantOperandVal(1) == 0 && + Elt1->getOperand(0)->getConstantOperandVal(1) == 1) { + SDValue LowLanesSrcVec = Elt0->getOperand(0)->getOperand(0); + if (LowLanesSrcVec.getValueType() == MVT::v2f64) { + SDValue HighLanes; + if (Elt2->getOpcode() == ISD::UNDEF && + Elt3->getOpcode() == ISD::UNDEF) { + HighLanes = DAG.getUNDEF(MVT::v2f32); + } else if (Elt2->getOpcode() == ISD::FP_ROUND && + Elt3->getOpcode() == ISD::FP_ROUND && + isa<ConstantSDNode>(Elt2->getOperand(1)) && + isa<ConstantSDNode>(Elt3->getOperand(1)) && + Elt2->getConstantOperandVal(1) == + Elt3->getConstantOperandVal(1) && + Elt2->getOperand(0)->getOpcode() == + ISD::EXTRACT_VECTOR_ELT && + Elt3->getOperand(0)->getOpcode() == + ISD::EXTRACT_VECTOR_ELT && + // Constant index. + isa<ConstantSDNode>(Elt2->getOperand(0)->getOperand(1)) && + isa<ConstantSDNode>(Elt3->getOperand(0)->getOperand(1)) && + Elt2->getOperand(0)->getOperand(0) == + Elt3->getOperand(0)->getOperand(0) && + Elt2->getOperand(0)->getConstantOperandVal(1) == 0 && + Elt3->getOperand(0)->getConstantOperandVal(1) == 1) { + SDValue HighLanesSrcVec = Elt2->getOperand(0)->getOperand(0); + HighLanes = + DAG.getNode(AArch64ISD::FCVTXN, DL, MVT::v2f32, HighLanesSrcVec); + } + if (HighLanes) { + SDValue DoubleToSingleSticky = + DAG.getNode(AArch64ISD::FCVTXN, DL, MVT::v2f32, LowLanesSrcVec); + SDValue Concat = DAG.getNode(ISD::CONCAT_VECTORS, DL, MVT::v4f32, + DoubleToSingleSticky, HighLanes); + return DAG.getNode(ISD::FP_ROUND, DL, VT, Concat, + Elt0->getOperand(1)); + } + } + } + } + + if (VT == MVT::v2f64) { + SDValue Elt0 = N->getOperand(0), Elt1 = N->getOperand(1); + if (Elt0->getOpcode() == ISD::FP_EXTEND && + Elt1->getOpcode() == ISD::FP_EXTEND && + Elt0->getOperand(0)->getOpcode() == ISD::EXTRACT_VECTOR_ELT && + Elt1->getOperand(0)->getOpcode() == ISD::EXTRACT_VECTOR_ELT && + Elt0->getOperand(0)->getOperand(0) == + Elt1->getOperand(0)->getOperand(0) && + // Constant index. + isa<ConstantSDNode>(Elt0->getOperand(0)->getOperand(1)) && + isa<ConstantSDNode>(Elt1->getOperand(0)->getOperand(1)) && + Elt0->getOperand(0)->getConstantOperandVal(1) + 1 == + Elt1->getOperand(0)->getConstantOperandVal(1) && + // EXTRACT_SUBVECTOR requires that Idx be a constant multiple of + // ResultType's known minimum vector length. + Elt0->getOperand(0)->getConstantOperandVal(1) % + VT.getVectorMinNumElements() == + 0) { + SDValue SrcVec = Elt0->getOperand(0)->getOperand(0); + if (SrcVec.getValueType() == MVT::v4f16 || + SrcVec.getValueType() == MVT::v4bf16) { + SDValue HalfToSingle = + DAG.getNode(ISD::FP_EXTEND, DL, MVT::v4f32, SrcVec); + SDValue SubvectorIdx = Elt0->getOperand(0)->getOperand(1); + SDValue Extract = DAG.getNode( + ISD::EXTRACT_SUBVECTOR, DL, VT.changeVectorElementType(MVT::f32), + HalfToSingle, SubvectorIdx); + return DAG.getNode(ISD::FP_EXTEND, DL, VT, Extract); + } + } + } + // A build vector of two extracted elements is equivalent to an // extract subvector where the inner vector is any-extended to the // extract_vector_elt VT. diff --git a/llvm/lib/Target/AArch64/AArch64InstrFormats.td b/llvm/lib/Target/AArch64/AArch64InstrFormats.td index 091db559a337..8360bef8e2f8 100644 --- a/llvm/lib/Target/AArch64/AArch64InstrFormats.td +++ b/llvm/lib/Target/AArch64/AArch64InstrFormats.td @@ -6832,7 +6832,7 @@ multiclass SIMDFPNarrowTwoVector<bit U, bit S, bits<5> opc, string asm> { } multiclass SIMDFPInexactCvtTwoVector<bit U, bit S, bits<5> opc, string asm, - Intrinsic OpNode> { + SDPatternOperator OpNode> { def v2f32 : BaseSIMDFPCvtTwoVector<0, U, {S,1}, opc, V64, V128, asm, ".2s", ".2d", [(set (v2f32 V64:$Rd), (OpNode (v2f64 V128:$Rn)))]>; @@ -7547,7 +7547,7 @@ class BaseSIMDCmpTwoScalar<bit U, bits<2> size, bits<2> size2, bits<5> opcode, let mayRaiseFPException = 1, Uses = [FPCR] in class SIMDInexactCvtTwoScalar<bits<5> opcode, string asm> : I<(outs FPR32:$Rd), (ins FPR64:$Rn), asm, "\t$Rd, $Rn", "", - [(set (f32 FPR32:$Rd), (AArch64fcvtxn (f64 FPR64:$Rn)))]>, + [(set (f32 FPR32:$Rd), (AArch64fcvtxnsdr (f64 FPR64:$Rn)))]>, Sched<[WriteVd]> { bits<5> Rd; bits<5> Rn; diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td index f8c6d9019ef6..3c67f616c1b9 100644 --- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td +++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td @@ -757,9 +757,12 @@ def AArch64fcmlez: SDNode<"AArch64ISD::FCMLEz", SDT_AArch64fcmpz>; def AArch64fcmltz: SDNode<"AArch64ISD::FCMLTz", SDT_AArch64fcmpz>; def AArch64fcvtxn_n: SDNode<"AArch64ISD::FCVTXN", SDTFPRoundOp>; -def AArch64fcvtxn: PatFrags<(ops node:$Rn), - [(f32 (int_aarch64_sisd_fcvtxn (f64 node:$Rn))), - (f32 (AArch64fcvtxn_n (f64 node:$Rn)))]>; +def AArch64fcvtxnsdr: PatFrags<(ops node:$Rn), + [(f32 (int_aarch64_sisd_fcvtxn (f64 node:$Rn))), + (f32 (AArch64fcvtxn_n (f64 node:$Rn)))]>; +def AArch64fcvtxnv: PatFrags<(ops node:$Rn), + [(int_aarch64_neon_fcvtxn node:$Rn), + (AArch64fcvtxn_n node:$Rn)]>; def AArch64bici: SDNode<"AArch64ISD::BICi", SDT_AArch64vecimm>; def AArch64orri: SDNode<"AArch64ISD::ORRi", SDT_AArch64vecimm>; @@ -5042,7 +5045,7 @@ def : Pat<(concat_vectors V64:$Rd, (v4f16 (any_fpround (v4f32 V128:$Rn)))), defm FCVTPS : SIMDTwoVectorFPToInt<0,1,0b11010, "fcvtps",int_aarch64_neon_fcvtps>; defm FCVTPU : SIMDTwoVectorFPToInt<1,1,0b11010, "fcvtpu",int_aarch64_neon_fcvtpu>; defm FCVTXN : SIMDFPInexactCvtTwoVector<1, 0, 0b10110, "fcvtxn", - int_aarch64_neon_fcvtxn>; + AArch64fcvtxnv>; defm FCVTZS : SIMDTwoVectorFPToInt<0, 1, 0b11011, "fcvtzs", any_fp_to_sint>; defm FCVTZU : SIMDTwoVectorFPToInt<1, 1, 0b11011, "fcvtzu", any_fp_to_uint>; |
