[llvm] [X86] Use BSR passthrough behaviour to fold (CMOV (BSR ?, X), Y, (X == 0)) -> (BSR Y, X) (PR #143662)

Simon Pilgrim via llvm-commits llvm-commits at lists.llvm.org
Wed Jun 11 00:43:43 PDT 2025


https://github.com/RKSimon created https://github.com/llvm/llvm-project/pull/143662

Make use of targets that support BSR "pass through behaviour" on a zero input to remove a CMOV thats performing the same function

BSF will be a trickier patch as we need to make sure it works with the "REP BSF" hack in X86MCInstLower

>From 319bc9517920c3ef9b5b2731762c8a099d8a8357 Mon Sep 17 00:00:00 2001
From: Simon Pilgrim <llvm-dev at redking.me.uk>
Date: Wed, 11 Jun 2025 08:42:29 +0100
Subject: [PATCH] [X86] Use BSR passthrough behaviour to fold (CMOV (BSR ?, X),
 Y, (X == 0)) -> (BSR Y, X)

Make use of targets that support BSR "pass through behaviour" on a zero input to remove a CMOV thats performing the same function

BSF will be a trickier patch as we need to make sure it works with the "REP BSF" hack in X86MCInstLower
---
 llvm/lib/Target/X86/X86ISelLowering.cpp | 10 ++++++++++
 llvm/test/CodeGen/X86/bsr.ll            | 10 ++++------
 llvm/test/CodeGen/X86/pr40090.ll        | 11 ++++-------
 3 files changed, 18 insertions(+), 13 deletions(-)

diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp
index 8bcd8670879a9..91636dce814e8 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.cpp
+++ b/llvm/lib/Target/X86/X86ISelLowering.cpp
@@ -49392,6 +49392,8 @@ static SDValue combineCMov(SDNode *N, SelectionDAG &DAG,
   //      (ADD (CMOV C1-C2, (CTTZ X), (X != 0)), C2)
   // Or (CMOV (ADD (CTTZ X), C2), C1, (X == 0)) ->
   //    (ADD (CMOV (CTTZ X), C1-C2, (X == 0)), C2)
+  // Or (CMOV (BSR ?, X), Y, (X == 0)) -> (BSR Y, X)
+  // TODO: Or (CMOV (BSF ?, X), Y, (X == 0)) -> (BSF Y, X)
   if ((CC == X86::COND_NE || CC == X86::COND_E) &&
       Cond.getOpcode() == X86ISD::CMP && isNullConstant(Cond.getOperand(1))) {
     SDValue Add = TrueOp;
@@ -49400,6 +49402,14 @@ static SDValue combineCMov(SDNode *N, SelectionDAG &DAG,
     if (CC == X86::COND_E)
       std::swap(Add, Const);
 
+    // TODO: ADD BSF support, but requires changes to the "REP BSF" CTTZ hack.
+    if (Subtarget.hasBitScanPassThrough() && Add.getOpcode() == X86ISD::BSR &&
+        Add.getResNo() == 0 && Add.hasOneUse() &&
+        Add.getOperand(1) == Cond.getOperand(0)) {
+      return DAG.getNode(Add.getOpcode(), DL, Add->getVTList(), Const,
+                         Add.getOperand(1));
+    }
+
     // We might have replaced the constant in the cmov with the LHS of the
     // compare. If so change it to the RHS of the compare.
     if (Const == Cond.getOperand(0))
diff --git a/llvm/test/CodeGen/X86/bsr.ll b/llvm/test/CodeGen/X86/bsr.ll
index 1247b3ec59324..fbca4af425eac 100644
--- a/llvm/test/CodeGen/X86/bsr.ll
+++ b/llvm/test/CodeGen/X86/bsr.ll
@@ -162,9 +162,8 @@ define i32 @cmov_bsr32(i32 %x, i32 %y) nounwind {
 ;
 ; X64-LABEL: cmov_bsr32:
 ; X64:       # %bb.0:
-; X64-NEXT:    movl $63, %eax
+; X64-NEXT:    movl %esi, %eax
 ; X64-NEXT:    bsrl %edi, %eax
-; X64-NEXT:    cmovel %esi, %eax
 ; X64-NEXT:    retq
   %1 = tail call i32 @llvm.ctlz.i32(i32 %x, i1 false)
   %2 = xor i32 %1, 31
@@ -188,8 +187,8 @@ define i32 @cmov_bsr32_undef(i32 %x, i32 %y) nounwind {
 ;
 ; X64-LABEL: cmov_bsr32_undef:
 ; X64:       # %bb.0:
+; X64-NEXT:    movl %esi, %eax
 ; X64-NEXT:    bsrl %edi, %eax
-; X64-NEXT:    cmovel %esi, %eax
 ; X64-NEXT:    retq
   %1 = tail call i32 @llvm.ctlz.i32(i32 %x, i1 true)
   %2 = xor i32 %1, 31
@@ -239,9 +238,8 @@ define i64 @cmov_bsr64(i64 %x, i64 %y) nounwind {
 ;
 ; X64-LABEL: cmov_bsr64:
 ; X64:       # %bb.0:
-; X64-NEXT:    movl $127, %eax
+; X64-NEXT:    movq %rsi, %rax
 ; X64-NEXT:    bsrq %rdi, %rax
-; X64-NEXT:    cmoveq %rsi, %rax
 ; X64-NEXT:    retq
   %1 = tail call i64 @llvm.ctlz.i64(i64 %x, i1 false)
   %2 = xor i64 %1, 63
@@ -279,8 +277,8 @@ define i64 @cmov_bsr64_undef(i64 %x, i64 %y) nounwind {
 ;
 ; X64-LABEL: cmov_bsr64_undef:
 ; X64:       # %bb.0:
+; X64-NEXT:    movq %rsi, %rax
 ; X64-NEXT:    bsrq %rdi, %rax
-; X64-NEXT:    cmoveq %rsi, %rax
 ; X64-NEXT:    retq
   %1 = tail call i64 @llvm.ctlz.i64(i64 %x, i1 true)
   %2 = xor i64 %1, 63
diff --git a/llvm/test/CodeGen/X86/pr40090.ll b/llvm/test/CodeGen/X86/pr40090.ll
index 24e957ac59f52..af933c950e111 100644
--- a/llvm/test/CodeGen/X86/pr40090.ll
+++ b/llvm/test/CodeGen/X86/pr40090.ll
@@ -4,10 +4,9 @@
 define i64 @foo(i64 %x, i64 %y) {
 ; CHECK-LABEL: foo:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    bsrq %rdi, %rax
-; CHECK-NEXT:    orq $64, %rax
+; CHECK-NEXT:    bsrq %rdi, %rcx
+; CHECK-NEXT:    orq $64, %rcx
 ; CHECK-NEXT:    bsrq %rsi, %rcx
-; CHECK-NEXT:    cmoveq %rax, %rcx
 ; CHECK-NEXT:    movl $63, %eax
 ; CHECK-NEXT:    subq %rcx, %rax
 ; CHECK-NEXT:    retq
@@ -25,11 +24,9 @@ define i64 @bar(i64 %x, i64 %y) {
 ; CHECK-LABEL: bar:
 ; CHECK:       # %bb.0:
 ; CHECK-NEXT:    movl $127, %ecx
-; CHECK-NEXT:    movl $127, %eax
-; CHECK-NEXT:    bsrq %rdi, %rax
-; CHECK-NEXT:    xorq $64, %rax
+; CHECK-NEXT:    bsrq %rdi, %rcx
+; CHECK-NEXT:    xorq $64, %rcx
 ; CHECK-NEXT:    bsrq %rsi, %rcx
-; CHECK-NEXT:    cmoveq %rax, %rcx
 ; CHECK-NEXT:    movl $63, %eax
 ; CHECK-NEXT:    subq %rcx, %rax
 ; CHECK-NEXT:    retq



More information about the llvm-commits mailing list