summaryrefslogtreecommitdiff
path: root/llvm/lib
diff options
context:
space:
mode:
authorDavid Majnemer <david.majnemer@gmail.com>2024-03-07 19:35:38 +0000
committerDavid Majnemer <david.majnemer@gmail.com>2024-03-08 19:52:53 +0000
commit5f935e91810eb28854611faf13bb7d07a8dbf470 (patch)
treef29c2d1d0aa03f1fe3ca0f930872c0eb0e037e74 /llvm/lib
parente963d0740e64fc70b4018f39325469d204f6217a (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.cpp95
-rw-r--r--llvm/lib/Target/AArch64/AArch64InstrFormats.td4
-rw-r--r--llvm/lib/Target/AArch64/AArch64InstrInfo.td11
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>;