[llvm] [X86] Merge BT with a matching BTR/BTS/BTC (PR #193612)

Simon Pilgrim via llvm-commits llvm-commits at lists.llvm.org
Thu May 7 03:27:31 PDT 2026


================
@@ -56676,6 +56672,111 @@ static SDValue combineAndnp(SDNode *N, SelectionDAG &DAG,
   return SDValue();
 }
 
+// Strip TRUNCATE/ZERO_EXTEND/ANY_EXTEND wrappers and `and x, C` where C
+// preserves the low log2(BW) bits — these are transparent to BT/BTR/BTS/BTC,
+// which implicitly mask the bit index to log2(BW) bits.
+static SDValue peekThroughBitPosExtTrunc(SDValue V, unsigned BW) {
+  APInt LowBits =
+      APInt::getLowBitsSet(V.getScalarValueSizeInBits(), Log2_32(BW));
+  for (;;) {
+    unsigned Op = V.getOpcode();
+    if (Op == ISD::TRUNCATE || Op == ISD::ZERO_EXTEND ||
+        Op == ISD::ANY_EXTEND) {
+      V = V.getOperand(0);
+      LowBits = LowBits.zextOrTrunc(V.getScalarValueSizeInBits());
+      continue;
+    }
+    if (Op == ISD::AND) {
+      auto *C = dyn_cast<ConstantSDNode>(V.getOperand(1));
+      if (C && LowBits.isSubsetOf(C->getAPIntValue())) {
+        V = V.getOperand(0);
+        continue;
+      }
+    }
+    return V;
+  }
+}
+
+// Try to merge a (X86ISD::BT Src, BitNo) with a sibling bit-modifying op on
+// Src — AND(Src, rotl -2, X), OR(Src, shl 1, X), XOR(Src, shl 1, X) — into a
+// single flag-producing X86ISD::{BTR,BTS,BTC} node. Both BT and BTR/BTS/BTC
+// set CF from the pre-op bit value, so one instruction subsumes the other.
+// Fixes llvm#165291.
+static SDValue combineBTToBitOpFlag(SDNode *N, SelectionDAG &DAG) {
+  SDValue Src = N->getOperand(0);
+  SDValue BitNo = N->getOperand(1);
+  EVT VT = Src.getValueType();
+  SDLoc DL(N);
+
+  // BT is only emitted for legal integer widths (16/32/64); match those.
+  if (VT != MVT::i16 && VT != MVT::i32 && VT != MVT::i64)
+    return SDValue();
+
+  unsigned BW = VT.getScalarSizeInBits();
+  SDValue PeeledBitNo = peekThroughBitPosExtTrunc(BitNo, BW);
+
+  for (SDNode *User : Src->users()) {
+    if (User == N)
+      continue;
+    unsigned UOpc = User->getOpcode();
+    if (UOpc != ISD::AND && UOpc != ISD::OR && UOpc != ISD::XOR)
+      continue;
+    if (User->getValueType(0) != VT)
+      continue;
+
+    // Identify which operand of User is Src; the other is the mask.
+    SDValue UOp0 = User->getOperand(0);
+    SDValue UOp1 = User->getOperand(1);
+    SDValue Mask;
+    if (UOp0 == SDValue(Src.getNode(), Src.getResNo()))
----------------
RKSimon wrote:

Isn't that UOp0 == Src?

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


More information about the llvm-commits mailing list