@@ -5192,13 +5192,14 @@ AArch64TargetLowering::LowerVectorFP_TO_INT_SAT(SDValue Op,
51925192 // AArch64 FP-to-int conversions saturate to the destination element size, so
51935193 // we can lower common saturating conversions to simple instructions.
51945194 SDValue SrcVal = Op.getOperand(0);
5195- EVT SrcVT = SrcVal.getValueType();
5196- EVT DstVT = Op.getValueType();
5197- EVT SatVT = cast<VTSDNode>(Op.getOperand(1))->getVT();
5198-
5199- uint64_t SrcElementWidth = SrcVT.getScalarSizeInBits();
5200- uint64_t DstElementWidth = DstVT.getScalarSizeInBits();
5201- uint64_t SatWidth = SatVT.getScalarSizeInBits();
5195+ const EVT SrcVT = SrcVal.getValueType();
5196+ const EVT DstVT = Op.getValueType();
5197+ const EVT DstElementVT = DstVT.getVectorElementType();
5198+ const EVT SatVT = cast<VTSDNode>(Op.getOperand(1))->getVT();
5199+
5200+ const uint64_t SrcElementWidth = SrcVT.getScalarSizeInBits();
5201+ const uint64_t DstElementWidth = DstVT.getScalarSizeInBits();
5202+ const uint64_t SatWidth = SatVT.getScalarSizeInBits();
52025203 assert(SatWidth <= DstElementWidth &&
52035204 "Saturation width cannot exceed result width");
52045205
@@ -5208,54 +5209,76 @@ AArch64TargetLowering::LowerVectorFP_TO_INT_SAT(SDValue Op,
52085209 if (DstVT.isScalableVector())
52095210 return SDValue();
52105211
5211- EVT SrcElementVT = SrcVT.getVectorElementType();
5212+ const EVT SrcElementVT = SrcVT.getVectorElementType();
5213+ if (SrcElementVT != MVT::f64 && SrcElementVT != MVT::f32 &&
5214+ SrcElementVT != MVT::f16 && SrcElementVT != MVT::bf16)
5215+ return SDValue();
5216+
5217+ // Returns true if the operation can be matched by an isel pattern directly.
5218+ auto CanHandleNatively = [&DstVT, &SatWidth](EVT SrcVT) -> bool {
5219+ return SrcVT.getScalarSizeInBits() == DstVT.getScalarSizeInBits() &&
5220+ SrcVT.getScalarSizeInBits() == SatWidth;
5221+ };
5222+
5223+ // Returns true if the operation is best expanded.
5224+ auto Expand = [&SatWidth, &CanHandleNatively](EVT SrcVT) -> bool {
5225+ return !CanHandleNatively(SrcVT) &&
5226+ (SrcVT.getScalarSizeInBits() < SatWidth ||
5227+ // NEON has no vector MIN/MAX for i64, so it's simpler to scalarize
5228+ // (at least until sqxtn is selected).
5229+ SrcVT.getVectorElementType() == MVT::f64);
5230+ };
5231+
5232+ // Try to promote the operation to a wider type if SrcVT < DstVT,
5233+ // or if type is bf16 or if the target has no +fullfp16.
5234+ std::optional<EVT> PromVT;
5235+ switch (SrcElementVT.getSimpleVT().SimpleTy) {
5236+ case MVT::f16:
5237+ case MVT::bf16:
5238+ if (DstElementVT == MVT::i32 || SrcElementVT == MVT::bf16 ||
5239+ !Subtarget->hasFullFP16()) {
5240+ PromVT = MVT::getVectorVT(MVT::f32, SrcVT.getVectorElementCount());
5241+ break;
5242+ }
5243+ [[fallthrough]];
5244+ case MVT::f32:
5245+ // Promote to f64
5246+ if (DstElementVT == MVT::i64) {
5247+ PromVT = MVT::getVectorVT(MVT::f64, SrcVT.getVectorElementCount());
5248+ break;
5249+ }
5250+ [[fallthrough]];
5251+ default:
5252+ break;
5253+ }
52125254
5213- // In the absence of FP16 support, promote f16 to f32 and saturate the result.
5214- // Note that SatWidth stays unchanged.
52155255 SDLoc DL(Op);
52165256 unsigned Opc = Op.getOpcode();
5217- if ((SrcElementVT == MVT::f16 &&
5218- (!Subtarget->hasFullFP16() || DstElementWidth > 16)) ||
5219- SrcElementVT == MVT::bf16) {
5220- MVT F32VT = MVT::getVectorVT(MVT::f32, SrcVT.getVectorNumElements());
5221- SrcVal = DAG.getNode(ISD::FP_EXTEND, DL, F32VT, SrcVal);
5222- // If we are extending to a v8f32, split into two v4f32 to produce legal
5223- // types.
5224- if (F32VT == MVT::v8f32) {
5225- auto [SrcValLo, SrcValHi] = DAG.SplitVector(SrcVal, DL);
5226- SDValue Lo = DAG.getNode(Opc, DL, MVT::v4i32, SrcValLo, Op.getOperand(1));
5227- SDValue Hi = DAG.getNode(Opc, DL, MVT::v4i32, SrcValHi, Op.getOperand(1));
5228- Lo = DAG.getNode(ISD::TRUNCATE, DL, MVT::v4i16, Lo);
5229- Hi = DAG.getNode(ISD::TRUNCATE, DL, MVT::v4i16, Hi);
5230- return DAG.getNode(ISD::CONCAT_VECTORS, DL, DstVT, Lo, Hi);
5231- }
5232- SrcVT = F32VT;
5233- SrcElementVT = MVT::f32;
5234- SrcElementWidth = 32;
5235- } else if (SrcElementVT != MVT::f64 && SrcElementVT != MVT::f32 &&
5236- SrcElementVT != MVT::f16 && SrcElementVT != MVT::bf16)
5237- return SDValue();
5238-
5239- // Expand to f64 if we are saturating to i64, to help keep the lanes the same
5240- // width and produce a fcvtzu. Note that SatWidth stays unchanged.
5241- if (SatWidth == 64 && SrcElementWidth < 64) {
5242- MVT F64VT = MVT::getVectorVT(MVT::f64, SrcVT.getVectorNumElements());
5243- SrcVal = DAG.getNode(ISD::FP_EXTEND, DL, F64VT, SrcVal);
5244- SrcVT = F64VT;
5245- SrcElementVT = MVT::f64;
5246- SrcElementWidth = 64;
5257+ if (PromVT && !Expand(*PromVT)) {
5258+ // When promoting the input type, SatWidth stays unchanged.
5259+ SrcVal = DAG.getNode(ISD::FP_EXTEND, DL, *PromVT, SrcVal);
5260+ if (*PromVT != MVT::v8f32)
5261+ return DAG.getNode(Op.getOpcode(), DL, DstVT, SrcVal, Op.getOperand(1));
5262+
5263+ // If we are extending to a wider type (e.g. v8f16 -> v8f32) due to lack
5264+ // of fp16 support, then it's more efficient to split the operation
5265+ // into two v4f32 to produce legal types.
5266+ auto [SrcValLo, SrcValHi] = DAG.SplitVector(SrcVal, DL);
5267+ SDValue Lo = DAG.getNode(Opc, DL, MVT::v4i32, SrcValLo, Op.getOperand(1));
5268+ SDValue Hi = DAG.getNode(Opc, DL, MVT::v4i32, SrcValHi, Op.getOperand(1));
5269+ Lo = DAG.getNode(ISD::TRUNCATE, DL, MVT::v4i16, Lo);
5270+ Hi = DAG.getNode(ISD::TRUNCATE, DL, MVT::v4i16, Hi);
5271+ return DAG.getNode(ISD::CONCAT_VECTORS, DL, DstVT, Lo, Hi);
52475272 }
5273+
52485274 // Cases that we can emit directly.
5249- if (SrcElementWidth == DstElementWidth && SrcElementWidth == SatWidth)
5275+ if (CanHandleNatively(SrcVT)) {
5276+ assert(isTypeLegal(SrcVT) && "Expected SrcVT to be a legal type");
52505277 return DAG.getNode(Opc, DL, DstVT, SrcVal,
52515278 DAG.getValueType(DstVT.getScalarType()));
5252-
5253- // Otherwise we emit a cvt that saturates to a higher BW, and saturate the
5254- // result. This is only valid if the legal cvt is larger than the saturate
5255- // width. For double, as we don't have MIN/MAX, it can be simpler to scalarize
5256- // (at least until sqxtn is selected).
5257- if (SrcElementWidth < SatWidth || SrcElementVT == MVT::f64)
5279+ } else if (Expand(SrcVT)) {
52585280 return SDValue();
5281+ }
52595282
52605283 assert((SrcElementWidth > DstElementWidth) ||
52615284 (SrcElementWidth == DstElementWidth && SatWidth < DstElementWidth));
0 commit comments