[llvm] [X86] Prefer SIMD min/max/abs for scalars when staying in XMM domain (PR #210654)

Simon Pilgrim via llvm-commits llvm-commits at lists.llvm.org
Thu Aug 13 11:06:48 PDT 2026


================
@@ -54617,6 +54617,97 @@ static SDValue narrowBitOpRMW(StoreSDNode *St, const SDLoc &DL,
   return NewStore;
 }
 
+/// Fold store(abs/min/max(load…)) of scalar i16/i32/i64 into SIMD
+/// PABS/PMIN/PMAX to keep memory-bound sort2/abs in the XMM domain.
+static SDValue combineScalarMinMaxAbsStore(StoreSDNode *St, const SDLoc &DL,
+                                           SelectionDAG &DAG,
+                                           const X86Subtarget &Subtarget) {
+  if (!ISD::isNormalStore(St))
+    return SDValue();
+
+  SDValue StoredVal = St->getValue();
+  unsigned Opc = StoredVal.getOpcode();
+  bool IsAbs = Opc == ISD::ABS;
+  if ((!IsAbs && !ISD::isMinMaxOpcode(Opc)) || !StoredVal.hasOneUse())
+    return SDValue();
+
+  EVT VT = StoredVal.getValueType();
+  const Function &F = DAG.getMachineFunction().getFunction();
+  if (F.hasFnAttribute(Attribute::NoImplicitFloat) ||
+      Subtarget.useSoftFloat() || F.hasOptSize())
+    return SDValue();
+
+  const TargetLowering &TLI = DAG.getTargetLoweringInfo();
+
+  // Pick the widened vector type; require a legal vector op and that
+  // SCALAR_TO_VECTOR can fold the scalar load into XMM (i32/i64: SSE2
+  // movd/movq; i16: FP16 vmovw). i64 also needs VLX to avoid zmm widen +
+  // vzeroupper.
+  auto getVecVT = [&]() -> std::optional<MVT> {
+    MVT VecVT;
+    if (VT == MVT::i32)
+      VecVT = MVT::v4i32;
+    else if (VT == MVT::i64)
+      VecVT = MVT::v2i64;
+    else if (VT == MVT::i16)
+      VecVT = MVT::v8i16;
+    else
+      return std::nullopt;
+
+    if (VT == MVT::i16 ? !Subtarget.hasFP16() : !Subtarget.hasSSE2())
+      return std::nullopt;
+    if (VT == MVT::i64 && !Subtarget.hasVLX())
+      return std::nullopt;
+    if (!TLI.isOperationLegal(Opc, VecVT))
+      return std::nullopt;
+    return VecVT;
+  };
----------------
RKSimon wrote:

This should be all you need:
```
  auto getVecVT = [&]() -> std::optional<MVT> {
    MVT VecVT;
    if (VT == MVT::i32 && Subtarget.hasSSE2())
      VecVT = MVT::v4i32;
    else if (VT == MVT::i64 && Subtarget.hasSSE2())
      VecVT = MVT::v2i64;
    else if (VT == MVT::i16 && Subtarget.hasFP16())
      VecVT = MVT::v8i16;
    else
      return std::nullopt;

    if (!DAG.getTargetLoweringInfo().isOperationLegal(Opc, VecVT))
      return std::nullopt;
    return VecVT;
  };
```

https://github.com/llvm/llvm-project/pull/210654


More information about the llvm-commits mailing list