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

Paweł Bylica via llvm-commits llvm-commits at lists.llvm.org
Thu Apr 23 01:26:43 PDT 2026


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

>From 005f6084e799062e77fcda728458187eefad346b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pawe=C5=82=20Bylica?= <pawel at hepcolgum.band>
Date: Thu, 23 Apr 2026 00:22:07 +0200
Subject: [PATCH] [X86] Merge BT with a matching BTR/BTS/BTC

BTR/BTS/BTC set CF from the pre-operation bit value, so a subsequent BT
on the same source and bit index produces redundant EFLAGS. We were
emitting both, e.g. for `(and ld, ~bit) | (and ld, bit) != 0` we got:

    btrl %esi, %ecx
    btl  %esi, %eax
    setae %al

Introduce three flag-producing DAG nodes X86ISD::BTR/BTS/BTC that model
the register-register BTR/BTS/BTC as `(res, EFLAGS) = op src, bitno`
(the atomic locked variants live under X86ISD::LBTR/LBTS/LBTC already),
pattern-match them to the existing BTR/BTS/BTC encodings, and add a DAG
combine in combineBT that fuses an X86ISD::BT with a sibling
AND(Src, rotl -2, X) / OR(Src, shl 1, X) / XOR(Src, shl 1, X) on the
same source into a single flag-producing node. The bit-position operand
can differ from BT's by trunc/zext/and-with-mask that preserves the low
log2(BW) bits (BT already masks those implicitly), so peek through
those wrappers when matching.

After the fix the example lowers to:

    btrl %esi, %ecx
    setae %al

Fixes llvm#165291.
---
 llvm/lib/Target/X86/X86ISelLowering.cpp      | 108 +++++++
 llvm/lib/Target/X86/X86InstrCompiler.td      |  17 ++
 llvm/lib/Target/X86/X86InstrFragments.td     |   8 +
 llvm/test/CodeGen/X86/bittest-big-integer.ll | 306 +++++++------------
 4 files changed, 247 insertions(+), 192 deletions(-)

diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp
index 5ed2eed2a0e8d..8b54fbdad0e03 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.cpp
+++ b/llvm/lib/Target/X86/X86ISelLowering.cpp
@@ -56672,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()))
+      Mask = UOp1;
+    else if (UOp1 == SDValue(Src.getNode(), Src.getResNo()))
+      Mask = UOp0;
+    else
+      continue;
+    // We will replace the mask's consumer (User); require the mask to have no
+    // other live uses so we can drop it.
+    if (!Mask.hasOneUse())
+      continue;
+
+    unsigned FlagOp = 0;
+    SDValue ShAmt;
+    if (UOpc == ISD::AND && Mask.getOpcode() == ISD::ROTL) {
+      // (and Src, (rotl -2, X)) — clears bit X.
+      if (auto *C = dyn_cast<ConstantSDNode>(Mask.getOperand(0)))
+        if (C->getAPIntValue() == APInt::getAllOnes(BW) - 1) {
+          FlagOp = X86ISD::BTR;
+          ShAmt = Mask.getOperand(1);
+        }
+    } else if ((UOpc == ISD::OR || UOpc == ISD::XOR) &&
+               Mask.getOpcode() == ISD::SHL) {
+      // (or/xor Src, (shl 1, X)) — sets / flips bit X.
+      if (auto *C = dyn_cast<ConstantSDNode>(Mask.getOperand(0)))
+        if (C->getAPIntValue() == 1) {
+          FlagOp = UOpc == ISD::OR ? X86ISD::BTS : X86ISD::BTC;
+          ShAmt = Mask.getOperand(1);
+        }
+    }
+    if (!FlagOp)
+      continue;
+
+    // The BT and the bit-op must address the same bit. They can differ only
+    // by truncation/extension or an AND that preserves the low log2(BW) bits.
+    if (peekThroughBitPosExtTrunc(ShAmt, BW) != PeeledBitNo)
+      continue;
+
+    // BTR/BTS/BTC *rr take the bit index in a register of the same width as
+    // the source. Extend or truncate to VT to match the instruction signature.
+    SDValue BN = DAG.getZExtOrTrunc(BitNo, DL, VT);
+    SDValue New = DAG.getNode(FlagOp, DL, DAG.getVTList(VT, MVT::i32), Src, BN);
+    // Reroute the value output through User's consumers.
+    DAG.ReplaceAllUsesOfValueWith(SDValue(User, 0), New.getValue(0));
+    // Return the flags output so combineBT installs it as N's replacement.
+    return New.getValue(1);
+  }
+  return SDValue();
+}
+
 static SDValue combineBT(SDNode *N, SelectionDAG &DAG,
                          TargetLowering::DAGCombinerInfo &DCI) {
   SDValue N1 = N->getOperand(1);
@@ -56685,6 +56790,9 @@ static SDValue combineBT(SDNode *N, SelectionDAG &DAG,
     return SDValue(N, 0);
   }
 
+  if (SDValue V = combineBTToBitOpFlag(N, DAG))
+    return V;
+
   return SDValue();
 }
 
diff --git a/llvm/lib/Target/X86/X86InstrCompiler.td b/llvm/lib/Target/X86/X86InstrCompiler.td
index ebbfa48d2660c..735bc57e8eaba 100644
--- a/llvm/lib/Target/X86/X86InstrCompiler.td
+++ b/llvm/lib/Target/X86/X86InstrCompiler.td
@@ -2072,6 +2072,23 @@ defm : OneBitPats<GR16, i16, BTR16rr, BTS16rr, BTC16rr, shiftMask16>;
 defm : OneBitPats<GR32, i32, BTR32rr, BTS32rr, BTC32rr, shiftMask32>;
 defm : OneBitPats<GR64, i64, BTR64rr, BTS64rr, BTC64rr, shiftMask64>;
 
+// Flag-producing variants: reuse the BTR/BTS/BTC encodings so CF can replace
+// a separate X86ISD::BT. Emitted by a DAG combine in combineBT.
+multiclass OneBitFlagPats<RegisterClass rc, Instruction btr, Instruction bts,
+                          Instruction btc, SDNode btr_flag, SDNode bts_flag,
+                          SDNode btc_flag> {
+  def : Pat<(btr_flag rc:$src1, rc:$src2), (btr rc:$src1, rc:$src2)>;
+  def : Pat<(bts_flag rc:$src1, rc:$src2), (bts rc:$src1, rc:$src2)>;
+  def : Pat<(btc_flag rc:$src1, rc:$src2), (btc rc:$src1, rc:$src2)>;
+}
+
+defm : OneBitFlagPats<GR16, BTR16rr, BTS16rr, BTC16rr,
+                      X86btr_flag, X86bts_flag, X86btc_flag>;
+defm : OneBitFlagPats<GR32, BTR32rr, BTS32rr, BTC32rr,
+                      X86btr_flag, X86bts_flag, X86btc_flag>;
+defm : OneBitFlagPats<GR64, BTR64rr, BTS64rr, BTC64rr,
+                      X86btr_flag, X86bts_flag, X86btc_flag>;
+
 //===----------------------------------------------------------------------===//
 // EFLAGS-defining Patterns
 //===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Target/X86/X86InstrFragments.td b/llvm/lib/Target/X86/X86InstrFragments.td
index bae1211e51330..e096aa1d074fa 100644
--- a/llvm/lib/Target/X86/X86InstrFragments.td
+++ b/llvm/lib/Target/X86/X86InstrFragments.td
@@ -165,6 +165,14 @@ let IsStrictFP = true in {
 // X86 bit-test instructions.
 def X86bt      : SDNode<"X86ISD::BT",       SDTX86CmpTest>;
 
+// X86 bit-test-and-modify instructions: res, EFLAGS = op src, bitno.
+// CF is set from the pre-operation bit value; BT on the same operands is
+// therefore redundant after one of these nodes. The atomic (locked) variants
+// live under X86ISD::LBTR/LBTS/LBTC.
+def X86btr_flag : SDNode<"X86ISD::BTR", SDTBinaryArithWithFlags>;
+def X86bts_flag : SDNode<"X86ISD::BTS", SDTBinaryArithWithFlags>;
+def X86btc_flag : SDNode<"X86ISD::BTC", SDTBinaryArithWithFlags>;
+
 // Conditional compare instructions
 def X86ccmp    : SDNode<"X86ISD::CCMP",     SDTX86Ccmp>;
 def X86ctest   : SDNode<"X86ISD::CTEST",    SDTX86Ccmp>;
diff --git a/llvm/test/CodeGen/X86/bittest-big-integer.ll b/llvm/test/CodeGen/X86/bittest-big-integer.ll
index 96ccc7b0f7527..6767cc45a2c5e 100644
--- a/llvm/test/CodeGen/X86/bittest-big-integer.ll
+++ b/llvm/test/CodeGen/X86/bittest-big-integer.ll
@@ -38,24 +38,18 @@ define i1 @test_eq_i32(ptr %word, i32 %position) nounwind {
 define i1 @complement_ne_i32(ptr %word, i32 %position) nounwind {
 ; X86-LABEL: complement_ne_i32:
 ; X86:       # %bb.0:
-; X86-NEXT:    pushl %esi
-; X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
 ; X86-NEXT:    movl {{[0-9]+}}(%esp), %ecx
 ; X86-NEXT:    movl (%ecx), %edx
-; X86-NEXT:    movl %edx, %esi
-; X86-NEXT:    btcl %eax, %esi
-; X86-NEXT:    btl %eax, %edx
+; X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
+; X86-NEXT:    btcl %eax, %edx
 ; X86-NEXT:    setb %al
-; X86-NEXT:    movl %esi, (%ecx)
-; X86-NEXT:    popl %esi
+; X86-NEXT:    movl %edx, (%ecx)
 ; X86-NEXT:    retl
 ;
 ; X64-LABEL: complement_ne_i32:
 ; X64:       # %bb.0:
-; X64-NEXT:    movl (%rdi), %eax
-; X64-NEXT:    movl %eax, %ecx
+; X64-NEXT:    movl (%rdi), %ecx
 ; X64-NEXT:    btcl %esi, %ecx
-; X64-NEXT:    btl %esi, %eax
 ; X64-NEXT:    setb %al
 ; X64-NEXT:    movl %ecx, (%rdi)
 ; X64-NEXT:    retq
@@ -72,24 +66,18 @@ define i1 @complement_ne_i32(ptr %word, i32 %position) nounwind {
 define i1 @reset_eq_i32(ptr %word, i32 %position) nounwind {
 ; X86-LABEL: reset_eq_i32:
 ; X86:       # %bb.0:
-; X86-NEXT:    pushl %esi
-; X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
 ; X86-NEXT:    movl {{[0-9]+}}(%esp), %ecx
 ; X86-NEXT:    movl (%ecx), %edx
-; X86-NEXT:    movl %edx, %esi
-; X86-NEXT:    btrl %eax, %esi
-; X86-NEXT:    btl %eax, %edx
+; X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
+; X86-NEXT:    btrl %eax, %edx
 ; X86-NEXT:    setae %al
-; X86-NEXT:    movl %esi, (%ecx)
-; X86-NEXT:    popl %esi
+; X86-NEXT:    movl %edx, (%ecx)
 ; X86-NEXT:    retl
 ;
 ; X64-LABEL: reset_eq_i32:
 ; X64:       # %bb.0:
-; X64-NEXT:    movl (%rdi), %eax
-; X64-NEXT:    movl %eax, %ecx
+; X64-NEXT:    movl (%rdi), %ecx
 ; X64-NEXT:    btrl %esi, %ecx
-; X64-NEXT:    btl %esi, %eax
 ; X64-NEXT:    setae %al
 ; X64-NEXT:    movl %ecx, (%rdi)
 ; X64-NEXT:    retq
@@ -107,24 +95,18 @@ define i1 @reset_eq_i32(ptr %word, i32 %position) nounwind {
 define i1 @set_ne_i32(ptr %word, i32 %position) nounwind {
 ; X86-LABEL: set_ne_i32:
 ; X86:       # %bb.0:
-; X86-NEXT:    pushl %esi
-; X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
 ; X86-NEXT:    movl {{[0-9]+}}(%esp), %ecx
 ; X86-NEXT:    movl (%ecx), %edx
-; X86-NEXT:    movl %edx, %esi
-; X86-NEXT:    btsl %eax, %esi
-; X86-NEXT:    btl %eax, %edx
+; X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
+; X86-NEXT:    btsl %eax, %edx
 ; X86-NEXT:    setb %al
-; X86-NEXT:    movl %esi, (%ecx)
-; X86-NEXT:    popl %esi
+; X86-NEXT:    movl %edx, (%ecx)
 ; X86-NEXT:    retl
 ;
 ; X64-LABEL: set_ne_i32:
 ; X64:       # %bb.0:
-; X64-NEXT:    movl (%rdi), %eax
-; X64-NEXT:    movl %eax, %ecx
+; X64-NEXT:    movl (%rdi), %ecx
 ; X64-NEXT:    btsl %esi, %ecx
-; X64-NEXT:    btl %esi, %eax
 ; X64-NEXT:    setb %al
 ; X64-NEXT:    movl %ecx, (%rdi)
 ; X64-NEXT:    retq
@@ -145,14 +127,12 @@ define i1 @init_eq_i32(ptr %word, i32 %position, i1 zeroext %value) nounwind {
 ; X86-NEXT:    pushl %esi
 ; X86-NEXT:    movl {{[0-9]+}}(%esp), %ecx
 ; X86-NEXT:    movl {{[0-9]+}}(%esp), %edx
-; X86-NEXT:    movzbl {{[0-9]+}}(%esp), %eax
-; X86-NEXT:    shll %cl, %eax
-; X86-NEXT:    movl (%edx), %esi
-; X86-NEXT:    movl %esi, %edi
+; X86-NEXT:    movzbl {{[0-9]+}}(%esp), %esi
+; X86-NEXT:    shll %cl, %esi
+; X86-NEXT:    movl (%edx), %edi
 ; X86-NEXT:    btrl %ecx, %edi
-; X86-NEXT:    orl %eax, %edi
-; X86-NEXT:    btl %ecx, %esi
 ; X86-NEXT:    setae %al
+; X86-NEXT:    orl %esi, %edi
 ; X86-NEXT:    movl %edi, (%edx)
 ; X86-NEXT:    popl %esi
 ; X86-NEXT:    popl %edi
@@ -162,24 +142,20 @@ define i1 @init_eq_i32(ptr %word, i32 %position, i1 zeroext %value) nounwind {
 ; SSE:       # %bb.0:
 ; SSE-NEXT:    movl %esi, %ecx
 ; SSE-NEXT:    shll %cl, %edx
-; SSE-NEXT:    movl (%rdi), %eax
-; SSE-NEXT:    movl %eax, %esi
+; SSE-NEXT:    movl (%rdi), %esi
 ; SSE-NEXT:    btrl %ecx, %esi
-; SSE-NEXT:    orl %edx, %esi
-; SSE-NEXT:    btl %ecx, %eax
 ; SSE-NEXT:    setae %al
+; SSE-NEXT:    orl %edx, %esi
 ; SSE-NEXT:    movl %esi, (%rdi)
 ; SSE-NEXT:    retq
 ;
 ; AVX-LABEL: init_eq_i32:
 ; AVX:       # %bb.0:
-; AVX-NEXT:    shlxl %esi, %edx, %eax
-; AVX-NEXT:    movl (%rdi), %ecx
-; AVX-NEXT:    movl %ecx, %edx
+; AVX-NEXT:    shlxl %esi, %edx, %ecx
+; AVX-NEXT:    movl (%rdi), %edx
 ; AVX-NEXT:    btrl %esi, %edx
-; AVX-NEXT:    orl %eax, %edx
-; AVX-NEXT:    btl %esi, %ecx
 ; AVX-NEXT:    setae %al
+; AVX-NEXT:    orl %ecx, %edx
 ; AVX-NEXT:    movl %edx, (%rdi)
 ; AVX-NEXT:    retq
   %ofs = and i32 %position, 31
@@ -232,29 +208,24 @@ define i1 @test_ne_i64(ptr %word, i32 %position) nounwind {
 define i1 @complement_ne_i64(ptr %word, i32 %position) nounwind {
 ; X86-LABEL: complement_ne_i64:
 ; X86:       # %bb.0:
-; X86-NEXT:    pushl %edi
 ; X86-NEXT:    pushl %esi
 ; X86-NEXT:    movl {{[0-9]+}}(%esp), %ecx
-; X86-NEXT:    movl {{[0-9]+}}(%esp), %edx
-; X86-NEXT:    movl %edx, %esi
-; X86-NEXT:    andl $32, %esi
-; X86-NEXT:    shrl $3, %esi
-; X86-NEXT:    movl (%ecx,%esi), %edi
-; X86-NEXT:    btl %edx, %edi
+; X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
+; X86-NEXT:    movl %eax, %edx
+; X86-NEXT:    andl $32, %edx
+; X86-NEXT:    shrl $3, %edx
+; X86-NEXT:    movl (%ecx,%edx), %esi
+; X86-NEXT:    btcl %eax, %esi
 ; X86-NEXT:    setb %al
-; X86-NEXT:    btcl %edx, %edi
-; X86-NEXT:    movl %edi, (%ecx,%esi)
+; X86-NEXT:    movl %esi, (%ecx,%edx)
 ; X86-NEXT:    popl %esi
-; X86-NEXT:    popl %edi
 ; X86-NEXT:    retl
 ;
 ; X64-LABEL: complement_ne_i64:
 ; X64:       # %bb.0:
 ; X64-NEXT:    # kill: def $esi killed $esi def $rsi
-; X64-NEXT:    movq (%rdi), %rax
-; X64-NEXT:    movq %rax, %rcx
+; X64-NEXT:    movq (%rdi), %rcx
 ; X64-NEXT:    btcq %rsi, %rcx
-; X64-NEXT:    btq %rsi, %rax
 ; X64-NEXT:    setb %al
 ; X64-NEXT:    movq %rcx, (%rdi)
 ; X64-NEXT:    retq
@@ -272,29 +243,24 @@ define i1 @complement_ne_i64(ptr %word, i32 %position) nounwind {
 define i1 @reset_eq_i64(ptr %word, i32 %position) nounwind {
 ; X86-LABEL: reset_eq_i64:
 ; X86:       # %bb.0:
-; X86-NEXT:    pushl %edi
 ; X86-NEXT:    pushl %esi
 ; X86-NEXT:    movl {{[0-9]+}}(%esp), %ecx
-; X86-NEXT:    movl {{[0-9]+}}(%esp), %edx
-; X86-NEXT:    movl %edx, %esi
-; X86-NEXT:    andl $32, %esi
-; X86-NEXT:    shrl $3, %esi
-; X86-NEXT:    movl (%ecx,%esi), %edi
-; X86-NEXT:    btl %edx, %edi
+; X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
+; X86-NEXT:    movl %eax, %edx
+; X86-NEXT:    andl $32, %edx
+; X86-NEXT:    shrl $3, %edx
+; X86-NEXT:    movl (%ecx,%edx), %esi
+; X86-NEXT:    btrl %eax, %esi
 ; X86-NEXT:    setae %al
-; X86-NEXT:    btrl %edx, %edi
-; X86-NEXT:    movl %edi, (%ecx,%esi)
+; X86-NEXT:    movl %esi, (%ecx,%edx)
 ; X86-NEXT:    popl %esi
-; X86-NEXT:    popl %edi
 ; X86-NEXT:    retl
 ;
 ; X64-LABEL: reset_eq_i64:
 ; X64:       # %bb.0:
 ; X64-NEXT:    # kill: def $esi killed $esi def $rsi
-; X64-NEXT:    movq (%rdi), %rax
-; X64-NEXT:    movq %rax, %rcx
+; X64-NEXT:    movq (%rdi), %rcx
 ; X64-NEXT:    btrq %rsi, %rcx
-; X64-NEXT:    btq %rsi, %rax
 ; X64-NEXT:    setae %al
 ; X64-NEXT:    movq %rcx, (%rdi)
 ; X64-NEXT:    retq
@@ -313,29 +279,24 @@ define i1 @reset_eq_i64(ptr %word, i32 %position) nounwind {
 define i1 @set_ne_i64(ptr %word, i32 %position) nounwind {
 ; X86-LABEL: set_ne_i64:
 ; X86:       # %bb.0:
-; X86-NEXT:    pushl %edi
 ; X86-NEXT:    pushl %esi
 ; X86-NEXT:    movl {{[0-9]+}}(%esp), %ecx
-; X86-NEXT:    movl {{[0-9]+}}(%esp), %edx
-; X86-NEXT:    movl %edx, %esi
-; X86-NEXT:    andl $32, %esi
-; X86-NEXT:    shrl $3, %esi
-; X86-NEXT:    movl (%ecx,%esi), %edi
-; X86-NEXT:    btl %edx, %edi
+; X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
+; X86-NEXT:    movl %eax, %edx
+; X86-NEXT:    andl $32, %edx
+; X86-NEXT:    shrl $3, %edx
+; X86-NEXT:    movl (%ecx,%edx), %esi
+; X86-NEXT:    btsl %eax, %esi
 ; X86-NEXT:    setb %al
-; X86-NEXT:    btsl %edx, %edi
-; X86-NEXT:    movl %edi, (%ecx,%esi)
+; X86-NEXT:    movl %esi, (%ecx,%edx)
 ; X86-NEXT:    popl %esi
-; X86-NEXT:    popl %edi
 ; X86-NEXT:    retl
 ;
 ; X64-LABEL: set_ne_i64:
 ; X64:       # %bb.0:
 ; X64-NEXT:    # kill: def $esi killed $esi def $rsi
-; X64-NEXT:    movq (%rdi), %rax
-; X64-NEXT:    movq %rax, %rcx
+; X64-NEXT:    movq (%rdi), %rcx
 ; X64-NEXT:    btsq %rsi, %rcx
-; X64-NEXT:    btq %rsi, %rax
 ; X64-NEXT:    setb %al
 ; X64-NEXT:    movq %rcx, (%rdi)
 ; X64-NEXT:    retq
@@ -362,9 +323,8 @@ define i1 @init_eq_i64(ptr %word, i32 %position, i1 zeroext %value) nounwind {
 ; X86-NEXT:    andl $32, %esi
 ; X86-NEXT:    shrl $3, %esi
 ; X86-NEXT:    movl (%edx,%esi), %edi
-; X86-NEXT:    btl %ecx, %edi
-; X86-NEXT:    setae %al
 ; X86-NEXT:    btrl %ecx, %edi
+; X86-NEXT:    setae %al
 ; X86-NEXT:    movzbl {{[0-9]+}}(%esp), %ebx
 ; X86-NEXT:    # kill: def $cl killed $cl killed $ecx
 ; X86-NEXT:    shll %cl, %ebx
@@ -378,14 +338,12 @@ define i1 @init_eq_i64(ptr %word, i32 %position, i1 zeroext %value) nounwind {
 ; SSE-LABEL: init_eq_i64:
 ; SSE:       # %bb.0:
 ; SSE-NEXT:    movl %esi, %ecx
-; SSE-NEXT:    movl %edx, %eax
-; SSE-NEXT:    shlq %cl, %rax
-; SSE-NEXT:    movq (%rdi), %rdx
-; SSE-NEXT:    movq %rdx, %rsi
+; SSE-NEXT:    movl %edx, %edx
+; SSE-NEXT:    shlq %cl, %rdx
+; SSE-NEXT:    movq (%rdi), %rsi
 ; SSE-NEXT:    btrq %rcx, %rsi
-; SSE-NEXT:    orq %rax, %rsi
-; SSE-NEXT:    btq %rcx, %rdx
 ; SSE-NEXT:    setae %al
+; SSE-NEXT:    orq %rdx, %rsi
 ; SSE-NEXT:    movq %rsi, (%rdi)
 ; SSE-NEXT:    retq
 ;
@@ -393,13 +351,11 @@ define i1 @init_eq_i64(ptr %word, i32 %position, i1 zeroext %value) nounwind {
 ; AVX:       # %bb.0:
 ; AVX-NEXT:    # kill: def $esi killed $esi def $rsi
 ; AVX-NEXT:    movl %edx, %eax
-; AVX-NEXT:    shlxq %rsi, %rax, %rax
-; AVX-NEXT:    movq (%rdi), %rcx
-; AVX-NEXT:    movq %rcx, %rdx
+; AVX-NEXT:    shlxq %rsi, %rax, %rcx
+; AVX-NEXT:    movq (%rdi), %rdx
 ; AVX-NEXT:    btrq %rsi, %rdx
-; AVX-NEXT:    orq %rax, %rdx
-; AVX-NEXT:    btq %rsi, %rcx
 ; AVX-NEXT:    setae %al
+; AVX-NEXT:    orq %rcx, %rdx
 ; AVX-NEXT:    movq %rdx, (%rdi)
 ; AVX-NEXT:    retq
   %rem = and i32 %position, 63
@@ -455,20 +411,17 @@ define i1 @test_ne_i128(ptr %word, i32 %position) nounwind {
 define i1 @complement_ne_i128(ptr %word, i32 %position) nounwind {
 ; X86-LABEL: complement_ne_i128:
 ; X86:       # %bb.0:
-; X86-NEXT:    pushl %edi
 ; X86-NEXT:    pushl %esi
 ; X86-NEXT:    movl {{[0-9]+}}(%esp), %ecx
-; X86-NEXT:    movl {{[0-9]+}}(%esp), %edx
-; X86-NEXT:    movl %edx, %esi
-; X86-NEXT:    andl $96, %esi
-; X86-NEXT:    shrl $3, %esi
-; X86-NEXT:    movl (%ecx,%esi), %edi
-; X86-NEXT:    btl %edx, %edi
+; X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
+; X86-NEXT:    movl %eax, %edx
+; X86-NEXT:    andl $96, %edx
+; X86-NEXT:    shrl $3, %edx
+; X86-NEXT:    movl (%ecx,%edx), %esi
+; X86-NEXT:    btcl %eax, %esi
 ; X86-NEXT:    setb %al
-; X86-NEXT:    btcl %edx, %edi
-; X86-NEXT:    movl %edi, (%ecx,%esi)
+; X86-NEXT:    movl %esi, (%ecx,%edx)
 ; X86-NEXT:    popl %esi
-; X86-NEXT:    popl %edi
 ; X86-NEXT:    retl
 ;
 ; X64-LABEL: complement_ne_i128:
@@ -477,9 +430,8 @@ define i1 @complement_ne_i128(ptr %word, i32 %position) nounwind {
 ; X64-NEXT:    andl $96, %ecx
 ; X64-NEXT:    shrl $3, %ecx
 ; X64-NEXT:    movl (%rdi,%rcx), %edx
-; X64-NEXT:    btl %esi, %edx
-; X64-NEXT:    setb %al
 ; X64-NEXT:    btcl %esi, %edx
+; X64-NEXT:    setb %al
 ; X64-NEXT:    movl %edx, (%rdi,%rcx)
 ; X64-NEXT:    retq
   %rem = and i32 %position, 127
@@ -496,20 +448,17 @@ define i1 @complement_ne_i128(ptr %word, i32 %position) nounwind {
 define i1 @reset_eq_i128(ptr %word, i32 %position) nounwind {
 ; X86-LABEL: reset_eq_i128:
 ; X86:       # %bb.0:
-; X86-NEXT:    pushl %edi
 ; X86-NEXT:    pushl %esi
 ; X86-NEXT:    movl {{[0-9]+}}(%esp), %ecx
-; X86-NEXT:    movl {{[0-9]+}}(%esp), %edx
-; X86-NEXT:    movl %edx, %esi
-; X86-NEXT:    andl $96, %esi
-; X86-NEXT:    shrl $3, %esi
-; X86-NEXT:    movl (%ecx,%esi), %edi
-; X86-NEXT:    btl %edx, %edi
+; X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
+; X86-NEXT:    movl %eax, %edx
+; X86-NEXT:    andl $96, %edx
+; X86-NEXT:    shrl $3, %edx
+; X86-NEXT:    movl (%ecx,%edx), %esi
+; X86-NEXT:    btrl %eax, %esi
 ; X86-NEXT:    setae %al
-; X86-NEXT:    btrl %edx, %edi
-; X86-NEXT:    movl %edi, (%ecx,%esi)
+; X86-NEXT:    movl %esi, (%ecx,%edx)
 ; X86-NEXT:    popl %esi
-; X86-NEXT:    popl %edi
 ; X86-NEXT:    retl
 ;
 ; X64-LABEL: reset_eq_i128:
@@ -518,9 +467,8 @@ define i1 @reset_eq_i128(ptr %word, i32 %position) nounwind {
 ; X64-NEXT:    andl $96, %ecx
 ; X64-NEXT:    shrl $3, %ecx
 ; X64-NEXT:    movl (%rdi,%rcx), %edx
-; X64-NEXT:    btl %esi, %edx
-; X64-NEXT:    setae %al
 ; X64-NEXT:    btrl %esi, %edx
+; X64-NEXT:    setae %al
 ; X64-NEXT:    movl %edx, (%rdi,%rcx)
 ; X64-NEXT:    retq
   %rem = and i32 %position, 127
@@ -538,20 +486,17 @@ define i1 @reset_eq_i128(ptr %word, i32 %position) nounwind {
 define i1 @set_ne_i128(ptr %word, i32 %position) nounwind {
 ; X86-LABEL: set_ne_i128:
 ; X86:       # %bb.0:
-; X86-NEXT:    pushl %edi
 ; X86-NEXT:    pushl %esi
 ; X86-NEXT:    movl {{[0-9]+}}(%esp), %ecx
-; X86-NEXT:    movl {{[0-9]+}}(%esp), %edx
-; X86-NEXT:    movl %edx, %esi
-; X86-NEXT:    andl $96, %esi
-; X86-NEXT:    shrl $3, %esi
-; X86-NEXT:    movl (%ecx,%esi), %edi
-; X86-NEXT:    btl %edx, %edi
+; X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
+; X86-NEXT:    movl %eax, %edx
+; X86-NEXT:    andl $96, %edx
+; X86-NEXT:    shrl $3, %edx
+; X86-NEXT:    movl (%ecx,%edx), %esi
+; X86-NEXT:    btsl %eax, %esi
 ; X86-NEXT:    setb %al
-; X86-NEXT:    btsl %edx, %edi
-; X86-NEXT:    movl %edi, (%ecx,%esi)
+; X86-NEXT:    movl %esi, (%ecx,%edx)
 ; X86-NEXT:    popl %esi
-; X86-NEXT:    popl %edi
 ; X86-NEXT:    retl
 ;
 ; X64-LABEL: set_ne_i128:
@@ -560,9 +505,8 @@ define i1 @set_ne_i128(ptr %word, i32 %position) nounwind {
 ; X64-NEXT:    andl $96, %ecx
 ; X64-NEXT:    shrl $3, %ecx
 ; X64-NEXT:    movl (%rdi,%rcx), %edx
-; X64-NEXT:    btl %esi, %edx
-; X64-NEXT:    setb %al
 ; X64-NEXT:    btsl %esi, %edx
+; X64-NEXT:    setb %al
 ; X64-NEXT:    movl %edx, (%rdi,%rcx)
 ; X64-NEXT:    retq
   %rem = and i32 %position, 127
@@ -588,9 +532,8 @@ define i1 @init_eq_i128(ptr %word, i32 %position, i1 zeroext %value) nounwind {
 ; X86-NEXT:    andl $96, %esi
 ; X86-NEXT:    shrl $3, %esi
 ; X86-NEXT:    movl (%edx,%esi), %edi
-; X86-NEXT:    btl %ecx, %edi
-; X86-NEXT:    setae %al
 ; X86-NEXT:    btrl %ecx, %edi
+; X86-NEXT:    setae %al
 ; X86-NEXT:    movzbl {{[0-9]+}}(%esp), %ebx
 ; X86-NEXT:    # kill: def $cl killed $cl killed $ecx
 ; X86-NEXT:    shll %cl, %ebx
@@ -607,10 +550,10 @@ define i1 @init_eq_i128(ptr %word, i32 %position, i1 zeroext %value) nounwind {
 ; SSE-NEXT:    andl $96, %esi
 ; SSE-NEXT:    shrl $3, %esi
 ; SSE-NEXT:    movl (%rdi,%rsi), %r8d
-; SSE-NEXT:    btl %ecx, %r8d
+; SSE-NEXT:    btrl %ecx, %r8d
 ; SSE-NEXT:    setae %al
+; SSE-NEXT:    # kill: def $cl killed $cl killed $ecx
 ; SSE-NEXT:    shll %cl, %edx
-; SSE-NEXT:    btrl %ecx, %r8d
 ; SSE-NEXT:    orl %r8d, %edx
 ; SSE-NEXT:    movl %edx, (%rdi,%rsi)
 ; SSE-NEXT:    retq
@@ -621,9 +564,8 @@ define i1 @init_eq_i128(ptr %word, i32 %position, i1 zeroext %value) nounwind {
 ; AVX-NEXT:    andl $96, %ecx
 ; AVX-NEXT:    shrl $3, %ecx
 ; AVX-NEXT:    movl (%rdi,%rcx), %r8d
-; AVX-NEXT:    btl %esi, %r8d
-; AVX-NEXT:    setae %al
 ; AVX-NEXT:    btrl %esi, %r8d
+; AVX-NEXT:    setae %al
 ; AVX-NEXT:    shlxl %esi, %edx, %edx
 ; AVX-NEXT:    orl %r8d, %edx
 ; AVX-NEXT:    movl %edx, (%rdi,%rcx)
@@ -679,20 +621,17 @@ define i1 @test_ne_i512(ptr %word, i32 %position) nounwind {
 define i1 @complement_ne_i512(ptr %word, i32 %position) nounwind {
 ; X86-LABEL: complement_ne_i512:
 ; X86:       # %bb.0:
-; X86-NEXT:    pushl %edi
 ; X86-NEXT:    pushl %esi
 ; X86-NEXT:    movl {{[0-9]+}}(%esp), %ecx
-; X86-NEXT:    movl {{[0-9]+}}(%esp), %edx
-; X86-NEXT:    movl %edx, %esi
-; X86-NEXT:    shrl $3, %esi
-; X86-NEXT:    andl $60, %esi
-; X86-NEXT:    movl (%ecx,%esi), %edi
-; X86-NEXT:    btl %edx, %edi
+; X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
+; X86-NEXT:    movl %eax, %edx
+; X86-NEXT:    shrl $3, %edx
+; X86-NEXT:    andl $60, %edx
+; X86-NEXT:    movl (%ecx,%edx), %esi
+; X86-NEXT:    btcl %eax, %esi
 ; X86-NEXT:    setb %al
-; X86-NEXT:    btcl %edx, %edi
-; X86-NEXT:    movl %edi, (%ecx,%esi)
+; X86-NEXT:    movl %esi, (%ecx,%edx)
 ; X86-NEXT:    popl %esi
-; X86-NEXT:    popl %edi
 ; X86-NEXT:    retl
 ;
 ; X64-LABEL: complement_ne_i512:
@@ -701,9 +640,8 @@ define i1 @complement_ne_i512(ptr %word, i32 %position) nounwind {
 ; X64-NEXT:    shrl $3, %ecx
 ; X64-NEXT:    andl $60, %ecx
 ; X64-NEXT:    movl (%rdi,%rcx), %edx
-; X64-NEXT:    btl %esi, %edx
-; X64-NEXT:    setb %al
 ; X64-NEXT:    btcl %esi, %edx
+; X64-NEXT:    setb %al
 ; X64-NEXT:    movl %edx, (%rdi,%rcx)
 ; X64-NEXT:    retq
   %rem = and i32 %position, 511
@@ -720,20 +658,17 @@ define i1 @complement_ne_i512(ptr %word, i32 %position) nounwind {
 define i1 @reset_eq_i512(ptr %word, i32 %position) nounwind {
 ; X86-LABEL: reset_eq_i512:
 ; X86:       # %bb.0:
-; X86-NEXT:    pushl %edi
 ; X86-NEXT:    pushl %esi
 ; X86-NEXT:    movl {{[0-9]+}}(%esp), %ecx
-; X86-NEXT:    movl {{[0-9]+}}(%esp), %edx
-; X86-NEXT:    movl %edx, %esi
-; X86-NEXT:    shrl $3, %esi
-; X86-NEXT:    andl $60, %esi
-; X86-NEXT:    movl (%ecx,%esi), %edi
-; X86-NEXT:    btl %edx, %edi
+; X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
+; X86-NEXT:    movl %eax, %edx
+; X86-NEXT:    shrl $3, %edx
+; X86-NEXT:    andl $60, %edx
+; X86-NEXT:    movl (%ecx,%edx), %esi
+; X86-NEXT:    btrl %eax, %esi
 ; X86-NEXT:    setae %al
-; X86-NEXT:    btrl %edx, %edi
-; X86-NEXT:    movl %edi, (%ecx,%esi)
+; X86-NEXT:    movl %esi, (%ecx,%edx)
 ; X86-NEXT:    popl %esi
-; X86-NEXT:    popl %edi
 ; X86-NEXT:    retl
 ;
 ; X64-LABEL: reset_eq_i512:
@@ -742,9 +677,8 @@ define i1 @reset_eq_i512(ptr %word, i32 %position) nounwind {
 ; X64-NEXT:    shrl $3, %ecx
 ; X64-NEXT:    andl $60, %ecx
 ; X64-NEXT:    movl (%rdi,%rcx), %edx
-; X64-NEXT:    btl %esi, %edx
-; X64-NEXT:    setae %al
 ; X64-NEXT:    btrl %esi, %edx
+; X64-NEXT:    setae %al
 ; X64-NEXT:    movl %edx, (%rdi,%rcx)
 ; X64-NEXT:    retq
   %rem = and i32 %position, 511
@@ -762,20 +696,17 @@ define i1 @reset_eq_i512(ptr %word, i32 %position) nounwind {
 define i1 @set_ne_i512(ptr %word, i32 %position) nounwind {
 ; X86-LABEL: set_ne_i512:
 ; X86:       # %bb.0:
-; X86-NEXT:    pushl %edi
 ; X86-NEXT:    pushl %esi
 ; X86-NEXT:    movl {{[0-9]+}}(%esp), %ecx
-; X86-NEXT:    movl {{[0-9]+}}(%esp), %edx
-; X86-NEXT:    movl %edx, %esi
-; X86-NEXT:    shrl $3, %esi
-; X86-NEXT:    andl $60, %esi
-; X86-NEXT:    movl (%ecx,%esi), %edi
-; X86-NEXT:    btl %edx, %edi
+; X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
+; X86-NEXT:    movl %eax, %edx
+; X86-NEXT:    shrl $3, %edx
+; X86-NEXT:    andl $60, %edx
+; X86-NEXT:    movl (%ecx,%edx), %esi
+; X86-NEXT:    btsl %eax, %esi
 ; X86-NEXT:    setb %al
-; X86-NEXT:    btsl %edx, %edi
-; X86-NEXT:    movl %edi, (%ecx,%esi)
+; X86-NEXT:    movl %esi, (%ecx,%edx)
 ; X86-NEXT:    popl %esi
-; X86-NEXT:    popl %edi
 ; X86-NEXT:    retl
 ;
 ; X64-LABEL: set_ne_i512:
@@ -784,9 +715,8 @@ define i1 @set_ne_i512(ptr %word, i32 %position) nounwind {
 ; X64-NEXT:    shrl $3, %ecx
 ; X64-NEXT:    andl $60, %ecx
 ; X64-NEXT:    movl (%rdi,%rcx), %edx
-; X64-NEXT:    btl %esi, %edx
-; X64-NEXT:    setb %al
 ; X64-NEXT:    btsl %esi, %edx
+; X64-NEXT:    setb %al
 ; X64-NEXT:    movl %edx, (%rdi,%rcx)
 ; X64-NEXT:    retq
   %rem = and i32 %position, 511
@@ -812,9 +742,8 @@ define i1 @init_eq_i512(ptr %word, i32 %position, i1 zeroext %value) nounwind {
 ; X86-NEXT:    shrl $3, %esi
 ; X86-NEXT:    andl $60, %esi
 ; X86-NEXT:    movl (%edx,%esi), %edi
-; X86-NEXT:    btl %ecx, %edi
-; X86-NEXT:    setae %al
 ; X86-NEXT:    btrl %ecx, %edi
+; X86-NEXT:    setae %al
 ; X86-NEXT:    movzbl {{[0-9]+}}(%esp), %ebx
 ; X86-NEXT:    # kill: def $cl killed $cl killed $ecx
 ; X86-NEXT:    shll %cl, %ebx
@@ -831,10 +760,10 @@ define i1 @init_eq_i512(ptr %word, i32 %position, i1 zeroext %value) nounwind {
 ; SSE-NEXT:    shrl $3, %esi
 ; SSE-NEXT:    andl $60, %esi
 ; SSE-NEXT:    movl (%rdi,%rsi), %r8d
-; SSE-NEXT:    btl %ecx, %r8d
+; SSE-NEXT:    btrl %ecx, %r8d
 ; SSE-NEXT:    setae %al
+; SSE-NEXT:    # kill: def $cl killed $cl killed $ecx
 ; SSE-NEXT:    shll %cl, %edx
-; SSE-NEXT:    btrl %ecx, %r8d
 ; SSE-NEXT:    orl %r8d, %edx
 ; SSE-NEXT:    movl %edx, (%rdi,%rsi)
 ; SSE-NEXT:    retq
@@ -845,9 +774,8 @@ define i1 @init_eq_i512(ptr %word, i32 %position, i1 zeroext %value) nounwind {
 ; AVX-NEXT:    shrl $3, %ecx
 ; AVX-NEXT:    andl $60, %ecx
 ; AVX-NEXT:    movl (%rdi,%rcx), %r8d
-; AVX-NEXT:    btl %esi, %r8d
-; AVX-NEXT:    setae %al
 ; AVX-NEXT:    btrl %esi, %r8d
+; AVX-NEXT:    setae %al
 ; AVX-NEXT:    shlxl %esi, %edx, %edx
 ; AVX-NEXT:    orl %r8d, %edx
 ; AVX-NEXT:    movl %edx, (%rdi,%rcx)
@@ -1103,28 +1031,24 @@ define <8 x i16> @complement_ne_i128_bitcast(ptr %word, i32 %position) nounwind
 define i32 @reset_multiload_i128(ptr %word, i32 %position, ptr %p) nounwind {
 ; X86-LABEL: reset_multiload_i128:
 ; X86:       # %bb.0:
-; X86-NEXT:    pushl %ebx
 ; X86-NEXT:    pushl %edi
 ; X86-NEXT:    pushl %esi
 ; X86-NEXT:    movl {{[0-9]+}}(%esp), %ecx
-; X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
 ; X86-NEXT:    movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
 ; X86-NEXT:    movl (%eax), %eax
 ; X86-NEXT:    movl %edx, %esi
 ; X86-NEXT:    andl $96, %esi
 ; X86-NEXT:    shrl $3, %esi
 ; X86-NEXT:    movl (%ecx,%esi), %edi
-; X86-NEXT:    movl %edi, %ebx
-; X86-NEXT:    btrl %edx, %ebx
-; X86-NEXT:    btl %edx, %edi
-; X86-NEXT:    movl %ebx, (%ecx,%esi)
+; X86-NEXT:    btrl %edx, %edi
+; X86-NEXT:    movl %edi, (%ecx,%esi)
 ; X86-NEXT:    jae .LBB23_2
 ; X86-NEXT:  # %bb.1:
 ; X86-NEXT:    xorl %eax, %eax
 ; X86-NEXT:  .LBB23_2:
 ; X86-NEXT:    popl %esi
 ; X86-NEXT:    popl %edi
-; X86-NEXT:    popl %ebx
 ; X86-NEXT:    retl
 ;
 ; X64-LABEL: reset_multiload_i128:
@@ -1132,11 +1056,9 @@ define i32 @reset_multiload_i128(ptr %word, i32 %position, ptr %p) nounwind {
 ; X64-NEXT:    movl %esi, %ecx
 ; X64-NEXT:    andl $96, %ecx
 ; X64-NEXT:    shrl $3, %ecx
-; X64-NEXT:    movl (%rdi,%rcx), %r9d
-; X64-NEXT:    movl %r9d, %r8d
-; X64-NEXT:    btrl %esi, %r8d
+; X64-NEXT:    movl (%rdi,%rcx), %r8d
 ; X64-NEXT:    xorl %eax, %eax
-; X64-NEXT:    btl %esi, %r9d
+; X64-NEXT:    btrl %esi, %r8d
 ; X64-NEXT:    jb .LBB23_2
 ; X64-NEXT:  # %bb.1:
 ; X64-NEXT:    movl (%rdx), %eax



More information about the llvm-commits mailing list