[llvm] [X86] Fold chained i32 CLMUL operands (PR #202250)

Simon Pilgrim via llvm-commits llvm-commits at lists.llvm.org
Mon Jul 20 07:59:35 PDT 2026


================
@@ -45461,6 +45461,71 @@ bool X86TargetLowering::SimplifyDemandedBitsForTargetNode(
     }
     break;
   }
+  case X86ISD::PCLMULQDQ: {
+    // Carry-less product bit i only depends on source bits [0, i], so a
+    // low-qword extract+narrow+scalar_to_vector round-trip on an operand can be
+    // replaced by its source vector when only those low result bits are wanted.
+    unsigned NumElts = VT.getVectorNumElements();
+    APInt HighElts = APInt::getSplat(NumElts, APInt(2, 0b10));
+    unsigned DemandedLoBits = OriginalDemandedBits.getActiveBits();
+    if (!(OriginalDemandedElts & HighElts).isZero() || DemandedLoBits == 0 ||
+        DemandedLoBits >= BitWidth)
+      break;
+
+    uint64_t Imm = Op.getConstantOperandVal(2);
+    uint64_t M0 = Imm & 0x01, M1 = (Imm & 0x10) >> 4;
+    APInt LoElts = APInt::getSplat(NumElts, APInt(2, 0b01));
+    APInt SrcBits = APInt::getLowBitsSet(BitWidth, DemandedLoBits);
+    KnownBits KnownLHS, KnownRHS;
+    if (SimplifyDemandedBits(Op.getOperand(0), SrcBits, M0 ? HighElts : LoElts,
+                             KnownLHS, TLO, Depth + 1))
+      return true;
+    if (SimplifyDemandedBits(Op.getOperand(1), SrcBits, M1 ? HighElts : LoElts,
+                             KnownRHS, TLO, Depth + 1))
+      return true;
+
+    auto PeelToVector = [&](SDValue Operand, uint64_t M) -> SDValue {
+      // scalar_to_vector only defines the low qword, so the imm must select it.
+      if (M != 0)
+        return SDValue();
+
+      SDValue S2V = peekThroughBitcasts(Operand);
+      if (S2V.getOpcode() != ISD::SCALAR_TO_VECTOR ||
+          S2V.getValueSizeInBits() != VT.getSizeInBits())
+        return SDValue();
+
+      uint64_t MinScalarBits = S2V.getScalarValueSizeInBits();
+      SDValue Inner = S2V.getOperand(0);
+      while (Inner.getOpcode() == ISD::ANY_EXTEND ||
+             Inner.getOpcode() == ISD::TRUNCATE) {
+        MinScalarBits =
+            std::min(MinScalarBits, Inner.getScalarValueSizeInBits());
+        Inner = Inner.getOperand(0);
+      }
+      MinScalarBits = std::min(MinScalarBits, Inner.getScalarValueSizeInBits());
+
+      if (Inner.getOpcode() != ISD::EXTRACT_VECTOR_ELT ||
+          !isNullConstant(Inner.getOperand(1)) ||
+          DemandedLoBits > MinScalarBits)
+        return SDValue();
+
+      SDValue Src = Inner.getOperand(0);
+      if (!Src.getValueType().isVector() ||
+          Src.getValueSizeInBits() != VT.getSizeInBits())
+        return SDValue();
+      return TLO.DAG.getBitcast(VT, Src);
+    };
+
+    SDValue NewLHS = PeelToVector(Op.getOperand(0), M0);
+    SDValue NewRHS = PeelToVector(Op.getOperand(1), M1);
----------------
RKSimon wrote:

why do you need this PeelToVector work? The recursive SimplifyDemandedBits should be handling this for us with the correct DemandedElts mask - you might want to consider a SimplifyMultipleUseDemandedBits call in some circumstances.

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


More information about the llvm-commits mailing list