[llvm] [DAG] Support saturated truncate (PR #99418)
David Green via llvm-commits
llvm-commits at lists.llvm.org
Tue Jul 30 11:32:22 PDT 2024
================
@@ -14915,6 +14920,166 @@ SDValue DAGCombiner::visitEXTEND_VECTOR_INREG(SDNode *N) {
return SDValue();
}
+SDValue DAGCombiner::visitTRUNCATE_USAT(SDNode *N) {
+ EVT VT = N->getValueType(0);
+ SDValue N0 = N->getOperand(0);
+
+ auto MatchFPTOINT = [&](SDValue Val) -> SDValue {
+ if (Val.getOpcode() == ISD::FP_TO_SINT ||
+ Val.getOpcode() == ISD::FP_TO_UINT)
+ return Val;
+ return SDValue();
+ };
+
+ SDValue FPInstr;
+ if (N0.getOpcode() == ISD::SMAX) {
+ FPInstr = MatchFPTOINT(N0.getOperand(0));
+ if (!FPInstr)
+ FPInstr = MatchFPTOINT(N0.getOperand(1));
+ } else
+ FPInstr = MatchFPTOINT(N0);
+
+ if (FPInstr) {
+ EVT FPVT = FPInstr.getOperand(0).getValueType();
+ if (!DAG.getTargetLoweringInfo().shouldConvertFpToSat(ISD::FP_TO_UINT_SAT,
+ FPVT, VT))
+ return SDValue();
+ return DAG.getNode(ISD::FP_TO_UINT_SAT, SDLoc(FPInstr), VT,
+ FPInstr.getOperand(0),
+ DAG.getValueType(VT.getScalarType()));
+ }
+
+ return SDValue();
+}
+
+// Match min/max and return limit value as a parameter.
+static SDValue matchMinMax(SDValue V, unsigned Opcode, APInt &Limit,
+ bool Signed) {
+ if (V.getOpcode() == Opcode) {
+ if (Signed) {
+ APInt C;
+ if (ISD::isConstantSplatVector(V.getOperand(1).getNode(), C) &&
+ C == Limit)
+ return V.getOperand(0);
+ } else if (ISD::isConstantSplatVector(V.getOperand(1).getNode(), Limit))
+ return V.getOperand(0);
+ }
+ return SDValue();
+}
+
+/// Detect patterns of truncation with unsigned saturation:
+///
+/// (truncate (umin (x, unsigned_max_of_dest_type)) to dest_type).
+/// Return the source value x to be truncated or SDValue() if the pattern was
+/// not matched.
+///
+static SDValue detectUSatUPattern(SDValue In, EVT VT) {
+ EVT InVT = In.getValueType();
+
+ // Saturation with truncation. We truncate from InVT to VT.
+ assert(InVT.getScalarSizeInBits() > VT.getScalarSizeInBits() &&
+ "Unexpected types for truncate operation");
+
+ APInt C1, C2;
+ if (SDValue UMin = matchMinMax(In, ISD::UMIN, C2, /*Signed*/ false)) {
+ // C2 should be equal to UINT32_MAX / UINT16_MAX / UINT8_MAX according
+ // the element size of the destination type.
+ if (C2.isMask(VT.getScalarSizeInBits())) {
+ // (truncate (umin (smax (x, C1), C2)))
+ // where C1 == 0, C2 is unsigned max of destination type.
+ if (SDValue SMax = matchMinMax(UMin, ISD::SMAX, C1, /*Signed*/ false)) {
----------------
davemgreen wrote:
I think this logic should be in detectSSatUPattern.
https://github.com/llvm/llvm-project/pull/99418
More information about the llvm-commits
mailing list