[llvm] [InstCombine] Split div/rem by a select of constants with a variable dividend (PR #216908)

Adam Scott via llvm-commits llvm-commits at lists.llvm.org
Tue Aug 25 21:46:10 PDT 2026


https://github.com/as4230 updated https://github.com/llvm/llvm-project/pull/216908

>From f9f97f7007726f9a8d17ca2c8f0cf97ae6b3bcee Mon Sep 17 00:00:00 2001
From: Adam Scott <adamscott200322 at gmail.com>
Date: Tue, 18 Aug 2026 02:53:35 +0000
Subject: [PATCH 1/3] Add tests for div/rem by a select of constants

---
 llvm/test/CodeGen/X86/divrem-by-select.ll |  49 ++++++-
 llvm/test/Transforms/InstCombine/div.ll   | 155 +++++++++++++++++++++-
 llvm/test/Transforms/InstCombine/rem.ll   |  31 ++++-
 3 files changed, 229 insertions(+), 6 deletions(-)

diff --git a/llvm/test/CodeGen/X86/divrem-by-select.ll b/llvm/test/CodeGen/X86/divrem-by-select.ll
index b80531881fa65..d29d65e521e8e 100644
--- a/llvm/test/CodeGen/X86/divrem-by-select.ll
+++ b/llvm/test/CodeGen/X86/divrem-by-select.ll
@@ -518,5 +518,50 @@ define <2 x i64> @sdivrem_identity_const(<2 x i1> %c, <2 x i64> %x) {
   %r = add <2 x i64> %div, %rem
   ret <2 x i64> %r
 }
-;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
-; CHECK-X64: {{.*}}
+
+define i32 @sdiv_select_of_constants(i32 %x, i1 %c) {
+; CHECK-X64-LABEL: sdiv_select_of_constants:
+; CHECK-X64:       # %bb.0:
+; CHECK-X64-NEXT:    movl %edi, %eax
+; CHECK-X64-NEXT:    andl $1, %esi
+; CHECK-X64-NEXT:    xorl $5, %esi
+; CHECK-X64-NEXT:    cltd
+; CHECK-X64-NEXT:    idivl %esi
+; CHECK-X64-NEXT:    retq
+  %a = sdiv i32 %x, 4
+  %b = sdiv i32 %x, 5
+  %r = select i1 %c, i32 %a, i32 %b
+  ret i32 %r
+}
+
+define i32 @urem_select_of_constants(i32 %x, i1 %c) {
+; CHECK-X64-LABEL: urem_select_of_constants:
+; CHECK-X64:       # %bb.0:
+; CHECK-X64-NEXT:    movl %edi, %eax
+; CHECK-X64-NEXT:    andl $1, %esi
+; CHECK-X64-NEXT:    xorl $7, %esi
+; CHECK-X64-NEXT:    xorl %edx, %edx
+; CHECK-X64-NEXT:    divl %esi
+; CHECK-X64-NEXT:    movl %edx, %eax
+; CHECK-X64-NEXT:    retq
+  %a = urem i32 %x, 6
+  %b = urem i32 %x, 7
+  %r = select i1 %c, i32 %a, i32 %b
+  ret i32 %r
+}
+
+define i32 @sdiv_select_of_constants_minsize(i32 %x, i1 %c) minsize {
+; CHECK-X64-LABEL: sdiv_select_of_constants_minsize:
+; CHECK-X64:       # %bb.0:
+; CHECK-X64-NEXT:    movl %edi, %eax
+; CHECK-X64-NEXT:    andl $1, %esi
+; CHECK-X64-NEXT:    xorl $5, %esi
+; CHECK-X64-NEXT:    cltd
+; CHECK-X64-NEXT:    idivl %esi
+; CHECK-X64-NEXT:    retq
+  %a = sdiv i32 %x, 4
+  %b = sdiv i32 %x, 5
+  %r = select i1 %c, i32 %a, i32 %b
+  ret i32 %r
+}
+
diff --git a/llvm/test/Transforms/InstCombine/div.ll b/llvm/test/Transforms/InstCombine/div.ll
index 75a6c897e6133..153a6a60adef3 100644
--- a/llvm/test/Transforms/InstCombine/div.ll
+++ b/llvm/test/Transforms/InstCombine/div.ll
@@ -1180,7 +1180,7 @@ define <2 x i8> @sdiv_constant_dividend_select_of_constants_divisor_vec_ub2(i1 %
   ret <2 x i8> %r
 }
 
-; negative test - must have constant dividend
+; a variable dividend splits into a constant division per arm
 
 define i32 @sdiv_select_of_constants_divisor(i1 %b, i32 %x) {
 ; CHECK-LABEL: @sdiv_select_of_constants_divisor(
@@ -1193,6 +1193,28 @@ define i32 @sdiv_select_of_constants_divisor(i1 %b, i32 %x) {
   ret i32 %r
 }
 
+define i32 @sdiv_select_of_constants_divisor_exact(i1 %b, i32 %x) {
+; CHECK-LABEL: @sdiv_select_of_constants_divisor_exact(
+; CHECK-NEXT:    [[S:%.*]] = select i1 [[B:%.*]], i32 4, i32 5
+; CHECK-NEXT:    [[R:%.*]] = sdiv exact i32 [[X:%.*]], [[S]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %s = select i1 %b, i32 4, i32 5
+  %r = sdiv exact i32 %x, %s
+  ret i32 %r
+}
+
+define i32 @sdiv_select_of_constants_divisor_minus_one_arm(i1 %b, i32 %x) {
+; CHECK-LABEL: @sdiv_select_of_constants_divisor_minus_one_arm(
+; CHECK-NEXT:    [[S:%.*]] = select i1 [[B:%.*]], i32 -2, i32 -1
+; CHECK-NEXT:    [[R:%.*]] = sdiv i32 [[X:%.*]], [[S]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %s = select i1 %b, i32 -2, i32 -1
+  %r = sdiv i32 %x, %s
+  ret i32 %r
+}
+
 define i32 @udiv_constant_dividend_select_of_constants_divisor(i1 %b) {
 ; CHECK-LABEL: @udiv_constant_dividend_select_of_constants_divisor(
 ; CHECK-NEXT:    [[R:%.*]] = select i1 [[B:%.*]], i32 3, i32 0
@@ -1287,7 +1309,7 @@ define <2 x i8> @udiv_constant_dividend_select_of_constants_divisor_vec_ub2(i1 %
   ret <2 x i8> %r
 }
 
-; negative test - must have constant dividend
+; a variable dividend splits into a constant division per arm
 
 define i32 @udiv_select_of_constants_divisor(i1 %b, i32 %x) {
 ; CHECK-LABEL: @udiv_select_of_constants_divisor(
@@ -1300,6 +1322,133 @@ define i32 @udiv_select_of_constants_divisor(i1 %b, i32 %x) {
   ret i32 %r
 }
 
+define i32 @udiv_select_of_constants_divisor_pow2_arm(i1 %b, i32 %x) {
+; CHECK-LABEL: @udiv_select_of_constants_divisor_pow2_arm(
+; CHECK-NEXT:    [[S:%.*]] = select i1 [[B:%.*]], i32 4, i32 5
+; CHECK-NEXT:    [[R:%.*]] = udiv i32 [[X:%.*]], [[S]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %s = select i1 %b, i32 4, i32 5
+  %r = udiv i32 %x, %s
+  ret i32 %r
+}
+
+define i32 @udiv_select_of_constants_divisor_from_zext_add(i1 %b, i32 %x) {
+; CHECK-LABEL: @udiv_select_of_constants_divisor_from_zext_add(
+; CHECK-NEXT:    [[S:%.*]] = select i1 [[B:%.*]], i32 5, i32 4
+; CHECK-NEXT:    [[R:%.*]] = udiv i32 [[X:%.*]], [[S]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %z = zext i1 %b to i32
+  %s = add i32 %z, 4
+  %r = udiv i32 %x, %s
+  ret i32 %r
+}
+
+define i32 @udiv_select_of_constants_divisor_both_pow2(i1 %b, i32 %x) {
+; CHECK-LABEL: @udiv_select_of_constants_divisor_both_pow2(
+; CHECK-NEXT:    [[R_V:%.*]] = select i1 [[B:%.*]], i32 2, i32 3
+; CHECK-NEXT:    [[R:%.*]] = lshr i32 [[X:%.*]], [[R_V]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %s = select i1 %b, i32 4, i32 8
+  %r = udiv i32 %x, %s
+  ret i32 %r
+}
+
+
+define i32 @udiv_select_of_constants_divisor_exact(i1 %b, i32 %x) {
+; CHECK-LABEL: @udiv_select_of_constants_divisor_exact(
+; CHECK-NEXT:    [[S:%.*]] = select i1 [[B:%.*]], i32 4, i32 5
+; CHECK-NEXT:    [[R:%.*]] = udiv exact i32 [[X:%.*]], [[S]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %s = select i1 %b, i32 4, i32 5
+  %r = udiv exact i32 %x, %s
+  ret i32 %r
+}
+
+define i32 @udiv_select_of_constants_divisor_minus_one_arm(i1 %b, i32 %x) {
+; CHECK-LABEL: @udiv_select_of_constants_divisor_minus_one_arm(
+; CHECK-NEXT:    [[S:%.*]] = select i1 [[B:%.*]], i32 -2, i32 -1
+; CHECK-NEXT:    [[R_V:%.*]] = icmp uge i32 [[X:%.*]], [[S]]
+; CHECK-NEXT:    [[R:%.*]] = zext i1 [[R_V]] to i32
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %s = select i1 %b, i32 -2, i32 -1
+  %r = udiv i32 %x, %s
+  ret i32 %r
+}
+
+define <2 x i32> @udiv_select_of_constants_divisor_splat(i1 %b, <2 x i32> %x) {
+; CHECK-LABEL: @udiv_select_of_constants_divisor_splat(
+; CHECK-NEXT:    [[S:%.*]] = select i1 [[B:%.*]], <2 x i32> splat (i32 4), <2 x i32> splat (i32 5)
+; CHECK-NEXT:    [[R:%.*]] = udiv <2 x i32> [[X:%.*]], [[S]]
+; CHECK-NEXT:    ret <2 x i32> [[R]]
+;
+  %s = select i1 %b, <2 x i32> splat (i32 4), <2 x i32> splat (i32 5)
+  %r = udiv <2 x i32> %x, %s
+  ret <2 x i32> %r
+}
+
+define <2 x i32> @udiv_select_of_constants_divisor_splat_poison(i1 %b, <2 x i32> %x) {
+; CHECK-LABEL: @udiv_select_of_constants_divisor_splat_poison(
+; CHECK-NEXT:    [[S:%.*]] = select i1 [[B:%.*]], <2 x i32> <i32 4, i32 poison>, <2 x i32> <i32 5, i32 poison>
+; CHECK-NEXT:    [[R:%.*]] = udiv <2 x i32> [[X:%.*]], [[S]]
+; CHECK-NEXT:    ret <2 x i32> [[R]]
+;
+  %s = select i1 %b, <2 x i32> <i32 4, i32 poison>, <2 x i32> <i32 5, i32 poison>
+  %r = udiv <2 x i32> %x, %s
+  ret <2 x i32> %r
+}
+
+define <2 x i32> @udiv_select_of_constants_divisor_non_splat(i1 %b, <2 x i32> %x) {
+; CHECK-LABEL: @udiv_select_of_constants_divisor_non_splat(
+; CHECK-NEXT:    [[S:%.*]] = select i1 [[B:%.*]], <2 x i32> <i32 4, i32 8>, <2 x i32> <i32 5, i32 9>
+; CHECK-NEXT:    [[R:%.*]] = udiv <2 x i32> [[X:%.*]], [[S]]
+; CHECK-NEXT:    ret <2 x i32> [[R]]
+;
+  %s = select i1 %b, <2 x i32> <i32 4, i32 8>, <2 x i32> <i32 5, i32 9>
+  %r = udiv <2 x i32> %x, %s
+  ret <2 x i32> %r
+}
+
+define i32 @udiv_select_of_constants_divisor_minsize(i1 %b, i32 %x) minsize {
+; CHECK-LABEL: @udiv_select_of_constants_divisor_minsize(
+; CHECK-NEXT:    [[S:%.*]] = select i1 [[B:%.*]], i32 4, i32 5
+; CHECK-NEXT:    [[R:%.*]] = udiv i32 [[X:%.*]], [[S]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %s = select i1 %b, i32 4, i32 5
+  %r = udiv i32 %x, %s
+  ret i32 %r
+}
+
+
+define i32 @udiv_select_of_constants_divisor_variable_arm(i1 %b, i32 %x, i32 %y) {
+; CHECK-LABEL: @udiv_select_of_constants_divisor_variable_arm(
+; CHECK-NEXT:    [[S:%.*]] = select i1 [[B:%.*]], i32 [[Y:%.*]], i32 4
+; CHECK-NEXT:    [[R:%.*]] = udiv i32 [[X:%.*]], [[S]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %s = select i1 %b, i32 %y, i32 4
+  %r = udiv i32 %x, %s
+  ret i32 %r
+}
+
+define i32 @udiv_select_of_constants_divisor_multi_use(i1 %b, i32 %x) {
+; CHECK-LABEL: @udiv_select_of_constants_divisor_multi_use(
+; CHECK-NEXT:    [[S:%.*]] = select i1 [[B:%.*]], i32 4, i32 5
+; CHECK-NEXT:    call void @use(i32 [[S]])
+; CHECK-NEXT:    [[R:%.*]] = udiv i32 [[X:%.*]], [[S]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %s = select i1 %b, i32 4, i32 5
+  call void @use(i32 %s)
+  %r = udiv i32 %x, %s
+  ret i32 %r
+}
+
 ; PR34063
 ; 1 / X !=/== -1
 
@@ -2359,6 +2508,8 @@ define <2 x i8> @udiv_udiv_vec(<2 x i8> %a, <2 x i8> %b, <2 x i8> %c) {
 
 !0 = !{!"function_entry_count", i64 1000}
 ;.
+; CHECK: attributes #[[ATTR0:[0-9]+]] = { minsize }
+;.
 ; CHECK: [[META0:![0-9]+]] = !{!"function_entry_count", i64 1000}
 ; CHECK: [[PROF1]] = !{!"unknown", !"instcombine"}
 ;.
diff --git a/llvm/test/Transforms/InstCombine/rem.ll b/llvm/test/Transforms/InstCombine/rem.ll
index d0730cc4ecce7..3042f905313dd 100644
--- a/llvm/test/Transforms/InstCombine/rem.ll
+++ b/llvm/test/Transforms/InstCombine/rem.ll
@@ -914,7 +914,7 @@ define <2 x i8> @srem_constant_dividend_select_of_constants_divisor_vec_ub2(i1 %
   ret <2 x i8> %r
 }
 
-; negative test - must have constant dividend
+; a variable dividend splits into a constant division per arm
 
 define i32 @srem_select_of_constants_divisor(i1 %b, i32 %x) {
 ; CHECK-LABEL: @srem_select_of_constants_divisor(
@@ -927,6 +927,29 @@ define i32 @srem_select_of_constants_divisor(i1 %b, i32 %x) {
   ret i32 %r
 }
 
+
+define i32 @srem_select_of_constants_divisor_minus_one_arm(i1 %b, i32 %x) {
+; CHECK-LABEL: @srem_select_of_constants_divisor_minus_one_arm(
+; CHECK-NEXT:    [[S:%.*]] = select i1 [[B:%.*]], i32 -2, i32 -1
+; CHECK-NEXT:    [[R:%.*]] = srem i32 [[X:%.*]], [[S]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %s = select i1 %b, i32 -2, i32 -1
+  %r = srem i32 %x, %s
+  ret i32 %r
+}
+
+define i32 @urem_select_of_constants_divisor_high_bits(i1 %b, i32 %x) {
+; CHECK-LABEL: @urem_select_of_constants_divisor_high_bits(
+; CHECK-NEXT:    [[S:%.*]] = select i1 [[B:%.*]], i32 -2, i32 -1
+; CHECK-NEXT:    [[R:%.*]] = urem i32 [[X:%.*]], [[S]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %s = select i1 %b, i32 -2, i32 -1
+  %r = urem i32 %x, %s
+  ret i32 %r
+}
+
 define i32 @urem_constant_dividend_select_of_constants_divisor(i1 %b) {
 ; CHECK-LABEL: @urem_constant_dividend_select_of_constants_divisor(
 ; CHECK-NEXT:    [[R:%.*]] = select i1 [[B:%.*]], i32 6, i32 42
@@ -1021,7 +1044,7 @@ define <2 x i8> @urem_constant_dividend_select_of_constants_divisor_vec_ub2(i1 %
   ret <2 x i8> %r
 }
 
-; negative test - must have constant dividend
+; a variable dividend splits into a constant division per arm
 
 define i32 @urem_select_of_constants_divisor(i1 %b, i32 %x) {
 ; CHECK-LABEL: @urem_select_of_constants_divisor(
@@ -1034,6 +1057,10 @@ define i32 @urem_select_of_constants_divisor(i1 %b, i32 %x) {
   ret i32 %r
 }
 
+
+
+
+
 ; https://alive2.llvm.org/ce/z/bh2KHm
 define <2 x i32> @PR62401(<2 x i1> %x, <2 x i32> %y) {
 ; CHECK-LABEL: @PR62401(

>From 3da6fa727d62c7262ed325df4dff79111f47f7d2 Mon Sep 17 00:00:00 2001
From: Adam Scott <adamscott200322 at gmail.com>
Date: Tue, 18 Aug 2026 02:54:26 +0000
Subject: [PATCH 2/3] Split div/rem by a select of constants with a variable
 dividend

---
 llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 10 +++
 .../InstCombine/InstCombineInternal.h         |  3 +-
 .../InstCombine/InstCombineMulDivRem.cpp      | 46 ++++++++++++++
 .../InstCombine/InstCombineSelect.cpp         |  6 ++
 .../InstCombine/InstructionCombining.cpp      |  5 +-
 llvm/test/CodeGen/X86/divrem-by-select.ll     | 63 ++++++++++++++-----
 llvm/test/Transforms/InstCombine/div.ll       | 43 ++++++++-----
 llvm/test/Transforms/InstCombine/rem.ll       | 26 +++++---
 8 files changed, 161 insertions(+), 41 deletions(-)

diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index 863d99e61a4aa..b7acd76c6399c 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -31099,6 +31099,16 @@ SDValue DAGCombiner::foldSelectOfBinops(SDNode *N) {
   if (N1.getOperand(0) == N2.getOperand(0)) {
     SDValue N11 = N1.getOperand(1);
     SDValue N21 = N2.getOperand(1);
+    // Two constant divisors would become one variable divisor, which needs a
+    // hardware divide that neither arm needed. Targets that would rather have
+    // the divider can say so through isIntDivCheap.
+    if ((BinOpc == ISD::SDIV || BinOpc == ISD::UDIV || BinOpc == ISD::SREM ||
+         BinOpc == ISD::UREM) &&
+        isConstantOrConstantVector(N11) && isConstantOrConstantVector(N21) &&
+        !TLI.isIntDivCheap(
+            N->getValueType(0),
+            DAG.getMachineFunction().getFunction().getAttributes()))
+      return SDValue();
     // Second op VT might be different (e.g. shift amount type)
     if (N11.getValueType() == N21.getValueType()) {
       SDValue NewSel = DAG.getSelect(DL, N11.getValueType(), N0, N11, N21);
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
index 8b759e701da60..5365a33d90188 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
+++ b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
@@ -677,7 +677,8 @@ class LLVM_LIBRARY_VISIBILITY InstCombinerImpl final
   /// second operand.
   Instruction *FoldOpIntoSelect(Instruction &Op, SelectInst *SI,
                                 bool FoldWithMultiUse = false,
-                                bool SimplifyBothArms = false);
+                                bool SimplifyBothArms = false,
+                                bool AllowNoArmSimplification = false);
 
   Instruction *foldBinOpSelectBinOp(BinaryOperator &Op);
 
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
index 4e1aa36230550..87e026fbeb022 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
@@ -1318,6 +1318,42 @@ static Value *foldIDivShl(BinaryOperator &I, InstCombiner::BuilderTy &Builder) {
   return nullptr;
 }
 
+/// True if the divisor selects between two constants, so that splitting the
+/// division leaves a constant divisor on either arm.
+static bool isSplittableSelectDivisor(BinaryOperator &I) {
+  const APInt *C1, *C2;
+  if (!match(I.getOperand(1), m_Select(m_Value(), m_APInt(C1), m_APInt(C2))))
+    return false;
+
+  // Both arms are evaluated after the split, so neither may divide by zero.
+  if (C1->isZero() || C2->isZero())
+    return false;
+
+  // A sibling div/rem on this divisor would leave four divisions where one
+  // hardware divide already computes both results.
+  auto *SI = cast<SelectInst>(I.getOperand(1));
+  for (User *U : SI->users()) {
+    auto *UI = dyn_cast<Instruction>(U);
+    if (UI && UI != &I && UI->isIntDivRem() && UI->getOperand(1) == SI)
+      return false;
+  }
+
+  // Signed division of INT_MIN by -1 overflows so an arm dividing by -1 would
+  // be undefined on a path that previously chose the other arm.
+  bool IsSigned = I.getOpcode() == Instruction::SDiv ||
+                  I.getOpcode() == Instruction::SRem;
+  if (IsSigned && (C1->isAllOnes() || C2->isAllOnes()))
+    return false;
+
+  // An unsigned divisor with the high bit set leaves a quotient of zero or
+  // one which folds to a compare against the select without a split.
+  if (I.getOpcode() == Instruction::UDiv && C1->isNegative() &&
+      C2->isNegative())
+    return false;
+
+  return true;
+}
+
 /// Common integer divide/remainder transforms
 Instruction *InstCombinerImpl::commonIDivRemTransforms(BinaryOperator &I) {
   assert(I.isIntDivRem() && "Unexpected instruction");
@@ -1352,6 +1388,16 @@ Instruction *InstCombinerImpl::commonIDivRemTransforms(BinaryOperator &I) {
       return R;
   }
 
+  // X div/rem (select C, C1, C2) --> select C, (X div/rem C1), (X div/rem C2)
+  // This increases instruction count but it's okay since a constant divisor
+  // does not need the hardware divider.
+  if (!MinimizeSize && isSplittableSelectDivisor(I))
+    if (Instruction *R = FoldOpIntoSelect(I, cast<SelectInst>(Op1),
+                                          /*FoldWithMultiUse=*/true,
+                                          /*SimplifyBothArms=*/false,
+                                          /*AllowNoArmSimplification=*/true))
+      return R;
+
   return nullptr;
 }
 
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index 558ad2ebccc37..20df1a09100fe 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -460,6 +460,12 @@ Instruction *InstCombinerImpl::foldSelectOpOp(SelectInst &SI, Instruction *TI,
   if (!MatchOp)
     return nullptr;
 
+  // Two constant divisors would become one variable divisor, which needs a
+  // hardware divide that neither of them needed.
+  if (TI->isIntDivRem() && MatchIsOpZero && isa<Constant>(OtherOpT) &&
+      isa<Constant>(OtherOpF))
+    return nullptr;
+
   // If the select condition is a vector, the operands of the original select's
   // operands also must be vectors. This may not be the case for getelementptr
   // for example.
diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
index 1fd813fb856ad..cedef12727c53 100644
--- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
@@ -1781,7 +1781,8 @@ static Value *foldOperationIntoSelectOperand(Instruction &I, SelectInst *SI,
 
 Instruction *InstCombinerImpl::FoldOpIntoSelect(Instruction &Op, SelectInst *SI,
                                                 bool FoldWithMultiUse,
-                                                bool SimplifyBothArms) {
+                                                bool SimplifyBothArms,
+                                                bool AllowNoArmSimplification) {
   // Don't modify shared select instructions unless set FoldWithMultiUse
   if (!SI->hasOneUser() && !FoldWithMultiUse)
     return nullptr;
@@ -1822,7 +1823,7 @@ Instruction *InstCombinerImpl::FoldOpIntoSelect(Instruction &Op, SelectInst *SI,
   Value *NewTV = simplifyOperationIntoSelectOperand(Op, SI, /*IsTrueArm=*/true);
   Value *NewFV =
       simplifyOperationIntoSelectOperand(Op, SI, /*IsTrueArm=*/false);
-  if (!NewTV && !NewFV)
+  if (!NewTV && !NewFV && !AllowNoArmSimplification)
     return nullptr;
 
   if (SimplifyBothArms && !(NewTV && NewFV))
diff --git a/llvm/test/CodeGen/X86/divrem-by-select.ll b/llvm/test/CodeGen/X86/divrem-by-select.ll
index d29d65e521e8e..c8dbe7dbeaf27 100644
--- a/llvm/test/CodeGen/X86/divrem-by-select.ll
+++ b/llvm/test/CodeGen/X86/divrem-by-select.ll
@@ -522,11 +522,20 @@ define <2 x i64> @sdivrem_identity_const(<2 x i1> %c, <2 x i64> %x) {
 define i32 @sdiv_select_of_constants(i32 %x, i1 %c) {
 ; CHECK-X64-LABEL: sdiv_select_of_constants:
 ; CHECK-X64:       # %bb.0:
-; CHECK-X64-NEXT:    movl %edi, %eax
-; CHECK-X64-NEXT:    andl $1, %esi
-; CHECK-X64-NEXT:    xorl $5, %esi
-; CHECK-X64-NEXT:    cltd
-; CHECK-X64-NEXT:    idivl %esi
+; CHECK-X64-NEXT:    # kill: def $edi killed $edi def $rdi
+; CHECK-X64-NEXT:    leal 3(%rdi), %ecx
+; CHECK-X64-NEXT:    testl %edi, %edi
+; CHECK-X64-NEXT:    cmovnsl %edi, %ecx
+; CHECK-X64-NEXT:    sarl $2, %ecx
+; CHECK-X64-NEXT:    movslq %edi, %rax
+; CHECK-X64-NEXT:    imulq $1717986919, %rax, %rax # imm = 0x66666667
+; CHECK-X64-NEXT:    movq %rax, %rdx
+; CHECK-X64-NEXT:    shrq $63, %rdx
+; CHECK-X64-NEXT:    sarq $33, %rax
+; CHECK-X64-NEXT:    addl %edx, %eax
+; CHECK-X64-NEXT:    testb $1, %sil
+; CHECK-X64-NEXT:    cmovnel %ecx, %eax
+; CHECK-X64-NEXT:    # kill: def $eax killed $eax killed $rax
 ; CHECK-X64-NEXT:    retq
   %a = sdiv i32 %x, 4
   %b = sdiv i32 %x, 5
@@ -535,15 +544,41 @@ define i32 @sdiv_select_of_constants(i32 %x, i1 %c) {
 }
 
 define i32 @urem_select_of_constants(i32 %x, i1 %c) {
-; CHECK-X64-LABEL: urem_select_of_constants:
-; CHECK-X64:       # %bb.0:
-; CHECK-X64-NEXT:    movl %edi, %eax
-; CHECK-X64-NEXT:    andl $1, %esi
-; CHECK-X64-NEXT:    xorl $7, %esi
-; CHECK-X64-NEXT:    xorl %edx, %edx
-; CHECK-X64-NEXT:    divl %esi
-; CHECK-X64-NEXT:    movl %edx, %eax
-; CHECK-X64-NEXT:    retq
+; CHECK-X64-V3-LABEL: urem_select_of_constants:
+; CHECK-X64-V3:       # %bb.0:
+; CHECK-X64-V3-NEXT:    movl %edi, %eax
+; CHECK-X64-V3-NEXT:    movl %edi, %edx
+; CHECK-X64-V3-NEXT:    movl $2863311531, %ecx # imm = 0xAAAAAAAB
+; CHECK-X64-V3-NEXT:    imulq %rdx, %rcx
+; CHECK-X64-V3-NEXT:    shrq $34, %rcx
+; CHECK-X64-V3-NEXT:    addl %ecx, %ecx
+; CHECK-X64-V3-NEXT:    leal (%rcx,%rcx,2), %ecx
+; CHECK-X64-V3-NEXT:    movabsq $2635249153617166336, %rdi # imm = 0x24924924A0000000
+; CHECK-X64-V3-NEXT:    mulxq %rdi, %rdx, %rdx
+; CHECK-X64-V3-NEXT:    leal (,%rdx,8), %edi
+; CHECK-X64-V3-NEXT:    subl %edx, %edi
+; CHECK-X64-V3-NEXT:    testb $1, %sil
+; CHECK-X64-V3-NEXT:    cmovnel %ecx, %edi
+; CHECK-X64-V3-NEXT:    subl %edi, %eax
+; CHECK-X64-V3-NEXT:    retq
+;
+; CHECK-X64-V4-LABEL: urem_select_of_constants:
+; CHECK-X64-V4:       # %bb.0:
+; CHECK-X64-V4-NEXT:    movl %edi, %eax
+; CHECK-X64-V4-NEXT:    movl %edi, %edx
+; CHECK-X64-V4-NEXT:    movl $2863311531, %ecx # imm = 0xAAAAAAAB
+; CHECK-X64-V4-NEXT:    imulq %rdx, %rcx
+; CHECK-X64-V4-NEXT:    shrq $34, %rcx
+; CHECK-X64-V4-NEXT:    addl %ecx, %ecx
+; CHECK-X64-V4-NEXT:    movabsq $2635249153617166336, %rdi # imm = 0x24924924A0000000
+; CHECK-X64-V4-NEXT:    mulxq %rdi, %rdx, %rdx
+; CHECK-X64-V4-NEXT:    leal (%rcx,%rcx,2), %ecx
+; CHECK-X64-V4-NEXT:    leal (,%rdx,8), %edi
+; CHECK-X64-V4-NEXT:    subl %edx, %edi
+; CHECK-X64-V4-NEXT:    testb $1, %sil
+; CHECK-X64-V4-NEXT:    cmovnel %ecx, %edi
+; CHECK-X64-V4-NEXT:    subl %edi, %eax
+; CHECK-X64-V4-NEXT:    retq
   %a = urem i32 %x, 6
   %b = urem i32 %x, 7
   %r = select i1 %c, i32 %a, i32 %b
diff --git a/llvm/test/Transforms/InstCombine/div.ll b/llvm/test/Transforms/InstCombine/div.ll
index 153a6a60adef3..13c421eb9d75a 100644
--- a/llvm/test/Transforms/InstCombine/div.ll
+++ b/llvm/test/Transforms/InstCombine/div.ll
@@ -1184,8 +1184,9 @@ define <2 x i8> @sdiv_constant_dividend_select_of_constants_divisor_vec_ub2(i1 %
 
 define i32 @sdiv_select_of_constants_divisor(i1 %b, i32 %x) {
 ; CHECK-LABEL: @sdiv_select_of_constants_divisor(
-; CHECK-NEXT:    [[S:%.*]] = select i1 [[B:%.*]], i32 12, i32 -3
-; CHECK-NEXT:    [[R:%.*]] = sdiv i32 [[X:%.*]], [[S]]
+; CHECK-NEXT:    [[TMP1:%.*]] = sdiv i32 [[X:%.*]], 12
+; CHECK-NEXT:    [[TMP2:%.*]] = sdiv i32 [[X]], -3
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[B:%.*]], i32 [[TMP1]], i32 [[TMP2]]
 ; CHECK-NEXT:    ret i32 [[R]]
 ;
   %s = select i1 %b, i32 12, i32 -3
@@ -1195,8 +1196,9 @@ define i32 @sdiv_select_of_constants_divisor(i1 %b, i32 %x) {
 
 define i32 @sdiv_select_of_constants_divisor_exact(i1 %b, i32 %x) {
 ; CHECK-LABEL: @sdiv_select_of_constants_divisor_exact(
-; CHECK-NEXT:    [[S:%.*]] = select i1 [[B:%.*]], i32 4, i32 5
-; CHECK-NEXT:    [[R:%.*]] = sdiv exact i32 [[X:%.*]], [[S]]
+; CHECK-NEXT:    [[TMP1:%.*]] = ashr exact i32 [[X:%.*]], 2
+; CHECK-NEXT:    [[TMP2:%.*]] = sdiv exact i32 [[X]], 5
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[B:%.*]], i32 [[TMP1]], i32 [[TMP2]]
 ; CHECK-NEXT:    ret i32 [[R]]
 ;
   %s = select i1 %b, i32 4, i32 5
@@ -1313,8 +1315,10 @@ define <2 x i8> @udiv_constant_dividend_select_of_constants_divisor_vec_ub2(i1 %
 
 define i32 @udiv_select_of_constants_divisor(i1 %b, i32 %x) {
 ; CHECK-LABEL: @udiv_select_of_constants_divisor(
-; CHECK-NEXT:    [[S:%.*]] = select i1 [[B:%.*]], i32 12, i32 -3
-; CHECK-NEXT:    [[R:%.*]] = udiv i32 [[X:%.*]], [[S]]
+; CHECK-NEXT:    [[TMP1:%.*]] = udiv i32 [[X:%.*]], 12
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp ugt i32 [[X]], -4
+; CHECK-NEXT:    [[TMP3:%.*]] = zext i1 [[TMP2]] to i32
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[B:%.*]], i32 [[TMP1]], i32 [[TMP3]]
 ; CHECK-NEXT:    ret i32 [[R]]
 ;
   %s = select i1 %b, i32 12, i32 -3
@@ -1324,8 +1328,9 @@ define i32 @udiv_select_of_constants_divisor(i1 %b, i32 %x) {
 
 define i32 @udiv_select_of_constants_divisor_pow2_arm(i1 %b, i32 %x) {
 ; CHECK-LABEL: @udiv_select_of_constants_divisor_pow2_arm(
-; CHECK-NEXT:    [[S:%.*]] = select i1 [[B:%.*]], i32 4, i32 5
-; CHECK-NEXT:    [[R:%.*]] = udiv i32 [[X:%.*]], [[S]]
+; CHECK-NEXT:    [[TMP1:%.*]] = lshr i32 [[X:%.*]], 2
+; CHECK-NEXT:    [[TMP2:%.*]] = udiv i32 [[X]], 5
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[B:%.*]], i32 [[TMP1]], i32 [[TMP2]]
 ; CHECK-NEXT:    ret i32 [[R]]
 ;
   %s = select i1 %b, i32 4, i32 5
@@ -1335,8 +1340,9 @@ define i32 @udiv_select_of_constants_divisor_pow2_arm(i1 %b, i32 %x) {
 
 define i32 @udiv_select_of_constants_divisor_from_zext_add(i1 %b, i32 %x) {
 ; CHECK-LABEL: @udiv_select_of_constants_divisor_from_zext_add(
-; CHECK-NEXT:    [[S:%.*]] = select i1 [[B:%.*]], i32 5, i32 4
-; CHECK-NEXT:    [[R:%.*]] = udiv i32 [[X:%.*]], [[S]]
+; CHECK-NEXT:    [[TMP1:%.*]] = udiv i32 [[X:%.*]], 5
+; CHECK-NEXT:    [[TMP2:%.*]] = lshr i32 [[X]], 2
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[B:%.*]], i32 [[TMP1]], i32 [[TMP2]]
 ; CHECK-NEXT:    ret i32 [[R]]
 ;
   %z = zext i1 %b to i32
@@ -1359,8 +1365,9 @@ define i32 @udiv_select_of_constants_divisor_both_pow2(i1 %b, i32 %x) {
 
 define i32 @udiv_select_of_constants_divisor_exact(i1 %b, i32 %x) {
 ; CHECK-LABEL: @udiv_select_of_constants_divisor_exact(
-; CHECK-NEXT:    [[S:%.*]] = select i1 [[B:%.*]], i32 4, i32 5
-; CHECK-NEXT:    [[R:%.*]] = udiv exact i32 [[X:%.*]], [[S]]
+; CHECK-NEXT:    [[TMP1:%.*]] = lshr exact i32 [[X:%.*]], 2
+; CHECK-NEXT:    [[TMP2:%.*]] = udiv exact i32 [[X]], 5
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[B:%.*]], i32 [[TMP1]], i32 [[TMP2]]
 ; CHECK-NEXT:    ret i32 [[R]]
 ;
   %s = select i1 %b, i32 4, i32 5
@@ -1382,8 +1389,9 @@ define i32 @udiv_select_of_constants_divisor_minus_one_arm(i1 %b, i32 %x) {
 
 define <2 x i32> @udiv_select_of_constants_divisor_splat(i1 %b, <2 x i32> %x) {
 ; CHECK-LABEL: @udiv_select_of_constants_divisor_splat(
-; CHECK-NEXT:    [[S:%.*]] = select i1 [[B:%.*]], <2 x i32> splat (i32 4), <2 x i32> splat (i32 5)
-; CHECK-NEXT:    [[R:%.*]] = udiv <2 x i32> [[X:%.*]], [[S]]
+; CHECK-NEXT:    [[TMP1:%.*]] = lshr <2 x i32> [[X:%.*]], splat (i32 2)
+; CHECK-NEXT:    [[TMP2:%.*]] = udiv <2 x i32> [[X]], splat (i32 5)
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[B:%.*]], <2 x i32> [[TMP1]], <2 x i32> [[TMP2]]
 ; CHECK-NEXT:    ret <2 x i32> [[R]]
 ;
   %s = select i1 %b, <2 x i32> splat (i32 4), <2 x i32> splat (i32 5)
@@ -1440,7 +1448,9 @@ define i32 @udiv_select_of_constants_divisor_multi_use(i1 %b, i32 %x) {
 ; CHECK-LABEL: @udiv_select_of_constants_divisor_multi_use(
 ; CHECK-NEXT:    [[S:%.*]] = select i1 [[B:%.*]], i32 4, i32 5
 ; CHECK-NEXT:    call void @use(i32 [[S]])
-; CHECK-NEXT:    [[R:%.*]] = udiv i32 [[X:%.*]], [[S]]
+; CHECK-NEXT:    [[TMP1:%.*]] = lshr i32 [[X:%.*]], 2
+; CHECK-NEXT:    [[TMP2:%.*]] = udiv i32 [[X]], 5
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[B]], i32 [[TMP1]], i32 [[TMP2]]
 ; CHECK-NEXT:    ret i32 [[R]]
 ;
   %s = select i1 %b, i32 4, i32 5
@@ -2093,7 +2103,8 @@ define i32 @sdiv_select_one_multiuse(i32 %a, i1 %b) {
 ; CHECK-LABEL: @sdiv_select_one_multiuse(
 ; CHECK-NEXT:    [[SUB:%.*]] = select i1 [[B:%.*]], i32 1, i32 2
 ; CHECK-NEXT:    call void @use(i32 [[SUB]])
-; CHECK-NEXT:    [[DIV:%.*]] = sdiv i32 [[A:%.*]], [[SUB]]
+; CHECK-NEXT:    [[TMP1:%.*]] = sdiv i32 [[A:%.*]], 2
+; CHECK-NEXT:    [[DIV:%.*]] = select i1 [[B]], i32 [[A]], i32 [[TMP1]]
 ; CHECK-NEXT:    ret i32 [[DIV]]
 ;
   %sub = select i1 %b, i32 1, i32 2
diff --git a/llvm/test/Transforms/InstCombine/rem.ll b/llvm/test/Transforms/InstCombine/rem.ll
index 3042f905313dd..1c9a2ab9eb1db 100644
--- a/llvm/test/Transforms/InstCombine/rem.ll
+++ b/llvm/test/Transforms/InstCombine/rem.ll
@@ -242,8 +242,8 @@ define <2 x i1> @test3a_vec(<2 x i32> %A) {
 
 define i32 @test4(i32 %X, i1 %C) {
 ; CHECK-LABEL: @test4(
-; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[C:%.*]], i32 0, i32 7
-; CHECK-NEXT:    [[R:%.*]] = and i32 [[X:%.*]], [[TMP1]]
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[X:%.*]], 7
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[C:%.*]], i32 0, i32 [[TMP1]]
 ; CHECK-NEXT:    ret i32 [[R]]
 ;
   %V = select i1 %C, i32 1, i32 8
@@ -918,8 +918,9 @@ define <2 x i8> @srem_constant_dividend_select_of_constants_divisor_vec_ub2(i1 %
 
 define i32 @srem_select_of_constants_divisor(i1 %b, i32 %x) {
 ; CHECK-LABEL: @srem_select_of_constants_divisor(
-; CHECK-NEXT:    [[S:%.*]] = select i1 [[B:%.*]], i32 12, i32 -3
-; CHECK-NEXT:    [[R:%.*]] = srem i32 [[X:%.*]], [[S]]
+; CHECK-NEXT:    [[TMP1:%.*]] = srem i32 [[X:%.*]], 12
+; CHECK-NEXT:    [[TMP2:%.*]] = srem i32 [[X]], 3
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[B:%.*]], i32 [[TMP1]], i32 [[TMP2]]
 ; CHECK-NEXT:    ret i32 [[R]]
 ;
   %s = select i1 %b, i32 12, i32 -3
@@ -941,8 +942,13 @@ define i32 @srem_select_of_constants_divisor_minus_one_arm(i1 %b, i32 %x) {
 
 define i32 @urem_select_of_constants_divisor_high_bits(i1 %b, i32 %x) {
 ; CHECK-LABEL: @urem_select_of_constants_divisor_high_bits(
-; CHECK-NEXT:    [[S:%.*]] = select i1 [[B:%.*]], i32 -2, i32 -1
-; CHECK-NEXT:    [[R:%.*]] = urem i32 [[X:%.*]], [[S]]
+; CHECK-NEXT:    [[X_FR:%.*]] = freeze i32 [[X:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ult i32 [[X_FR]], -2
+; CHECK-NEXT:    [[TMP2:%.*]] = add i32 [[X_FR]], 2
+; CHECK-NEXT:    [[TMP3:%.*]] = select i1 [[TMP1]], i32 [[X_FR]], i32 [[TMP2]]
+; CHECK-NEXT:    [[DOTNOT:%.*]] = icmp eq i32 [[X_FR]], -1
+; CHECK-NEXT:    [[TMP4:%.*]] = select i1 [[DOTNOT]], i32 0, i32 [[X_FR]]
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[B:%.*]], i32 [[TMP3]], i32 [[TMP4]]
 ; CHECK-NEXT:    ret i32 [[R]]
 ;
   %s = select i1 %b, i32 -2, i32 -1
@@ -1048,8 +1054,12 @@ define <2 x i8> @urem_constant_dividend_select_of_constants_divisor_vec_ub2(i1 %
 
 define i32 @urem_select_of_constants_divisor(i1 %b, i32 %x) {
 ; CHECK-LABEL: @urem_select_of_constants_divisor(
-; CHECK-NEXT:    [[S:%.*]] = select i1 [[B:%.*]], i32 12, i32 -3
-; CHECK-NEXT:    [[R:%.*]] = urem i32 [[X:%.*]], [[S]]
+; CHECK-NEXT:    [[X_FR:%.*]] = freeze i32 [[X:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = urem i32 [[X_FR]], 12
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp ult i32 [[X_FR]], -3
+; CHECK-NEXT:    [[TMP3:%.*]] = add i32 [[X_FR]], 3
+; CHECK-NEXT:    [[TMP4:%.*]] = select i1 [[TMP2]], i32 [[X_FR]], i32 [[TMP3]]
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[B:%.*]], i32 [[TMP1]], i32 [[TMP4]]
 ; CHECK-NEXT:    ret i32 [[R]]
 ;
   %s = select i1 %b, i32 12, i32 -3

>From 9dd8a0aab575e10c7e8e148f972cd22b753be6b3 Mon Sep 17 00:00:00 2001
From: Adam Scott <adamscott200322 at gmail.com>
Date: Wed, 26 Aug 2026 02:26:34 +0000
Subject: [PATCH 3/3] Narrow to InstCombine only

---
 llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 10 ---
 .../InstCombine/InstCombineMulDivRem.cpp      | 13 +--
 llvm/test/CodeGen/X86/divrem-by-select.ll     | 84 +------------------
 llvm/test/Transforms/InstCombine/div.ll       | 20 ++++-
 llvm/test/Transforms/InstCombine/rem.ll       |  5 --
 5 files changed, 22 insertions(+), 110 deletions(-)

diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index b7acd76c6399c..863d99e61a4aa 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -31099,16 +31099,6 @@ SDValue DAGCombiner::foldSelectOfBinops(SDNode *N) {
   if (N1.getOperand(0) == N2.getOperand(0)) {
     SDValue N11 = N1.getOperand(1);
     SDValue N21 = N2.getOperand(1);
-    // Two constant divisors would become one variable divisor, which needs a
-    // hardware divide that neither arm needed. Targets that would rather have
-    // the divider can say so through isIntDivCheap.
-    if ((BinOpc == ISD::SDIV || BinOpc == ISD::UDIV || BinOpc == ISD::SREM ||
-         BinOpc == ISD::UREM) &&
-        isConstantOrConstantVector(N11) && isConstantOrConstantVector(N21) &&
-        !TLI.isIntDivCheap(
-            N->getValueType(0),
-            DAG.getMachineFunction().getFunction().getAttributes()))
-      return SDValue();
     // Second op VT might be different (e.g. shift amount type)
     if (N11.getValueType() == N21.getValueType()) {
       SDValue NewSel = DAG.getSelect(DL, N11.getValueType(), N0, N11, N21);
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
index 87e026fbeb022..4a6ba445a39bb 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
@@ -1329,19 +1329,10 @@ static bool isSplittableSelectDivisor(BinaryOperator &I) {
   if (C1->isZero() || C2->isZero())
     return false;
 
-  // A sibling div/rem on this divisor would leave four divisions where one
-  // hardware divide already computes both results.
-  auto *SI = cast<SelectInst>(I.getOperand(1));
-  for (User *U : SI->users()) {
-    auto *UI = dyn_cast<Instruction>(U);
-    if (UI && UI != &I && UI->isIntDivRem() && UI->getOperand(1) == SI)
-      return false;
-  }
-
   // Signed division of INT_MIN by -1 overflows so an arm dividing by -1 would
   // be undefined on a path that previously chose the other arm.
-  bool IsSigned = I.getOpcode() == Instruction::SDiv ||
-                  I.getOpcode() == Instruction::SRem;
+  bool IsSigned =
+      I.getOpcode() == Instruction::SDiv || I.getOpcode() == Instruction::SRem;
   if (IsSigned && (C1->isAllOnes() || C2->isAllOnes()))
     return false;
 
diff --git a/llvm/test/CodeGen/X86/divrem-by-select.ll b/llvm/test/CodeGen/X86/divrem-by-select.ll
index c8dbe7dbeaf27..b80531881fa65 100644
--- a/llvm/test/CodeGen/X86/divrem-by-select.ll
+++ b/llvm/test/CodeGen/X86/divrem-by-select.ll
@@ -518,85 +518,5 @@ define <2 x i64> @sdivrem_identity_const(<2 x i1> %c, <2 x i64> %x) {
   %r = add <2 x i64> %div, %rem
   ret <2 x i64> %r
 }
-
-define i32 @sdiv_select_of_constants(i32 %x, i1 %c) {
-; CHECK-X64-LABEL: sdiv_select_of_constants:
-; CHECK-X64:       # %bb.0:
-; CHECK-X64-NEXT:    # kill: def $edi killed $edi def $rdi
-; CHECK-X64-NEXT:    leal 3(%rdi), %ecx
-; CHECK-X64-NEXT:    testl %edi, %edi
-; CHECK-X64-NEXT:    cmovnsl %edi, %ecx
-; CHECK-X64-NEXT:    sarl $2, %ecx
-; CHECK-X64-NEXT:    movslq %edi, %rax
-; CHECK-X64-NEXT:    imulq $1717986919, %rax, %rax # imm = 0x66666667
-; CHECK-X64-NEXT:    movq %rax, %rdx
-; CHECK-X64-NEXT:    shrq $63, %rdx
-; CHECK-X64-NEXT:    sarq $33, %rax
-; CHECK-X64-NEXT:    addl %edx, %eax
-; CHECK-X64-NEXT:    testb $1, %sil
-; CHECK-X64-NEXT:    cmovnel %ecx, %eax
-; CHECK-X64-NEXT:    # kill: def $eax killed $eax killed $rax
-; CHECK-X64-NEXT:    retq
-  %a = sdiv i32 %x, 4
-  %b = sdiv i32 %x, 5
-  %r = select i1 %c, i32 %a, i32 %b
-  ret i32 %r
-}
-
-define i32 @urem_select_of_constants(i32 %x, i1 %c) {
-; CHECK-X64-V3-LABEL: urem_select_of_constants:
-; CHECK-X64-V3:       # %bb.0:
-; CHECK-X64-V3-NEXT:    movl %edi, %eax
-; CHECK-X64-V3-NEXT:    movl %edi, %edx
-; CHECK-X64-V3-NEXT:    movl $2863311531, %ecx # imm = 0xAAAAAAAB
-; CHECK-X64-V3-NEXT:    imulq %rdx, %rcx
-; CHECK-X64-V3-NEXT:    shrq $34, %rcx
-; CHECK-X64-V3-NEXT:    addl %ecx, %ecx
-; CHECK-X64-V3-NEXT:    leal (%rcx,%rcx,2), %ecx
-; CHECK-X64-V3-NEXT:    movabsq $2635249153617166336, %rdi # imm = 0x24924924A0000000
-; CHECK-X64-V3-NEXT:    mulxq %rdi, %rdx, %rdx
-; CHECK-X64-V3-NEXT:    leal (,%rdx,8), %edi
-; CHECK-X64-V3-NEXT:    subl %edx, %edi
-; CHECK-X64-V3-NEXT:    testb $1, %sil
-; CHECK-X64-V3-NEXT:    cmovnel %ecx, %edi
-; CHECK-X64-V3-NEXT:    subl %edi, %eax
-; CHECK-X64-V3-NEXT:    retq
-;
-; CHECK-X64-V4-LABEL: urem_select_of_constants:
-; CHECK-X64-V4:       # %bb.0:
-; CHECK-X64-V4-NEXT:    movl %edi, %eax
-; CHECK-X64-V4-NEXT:    movl %edi, %edx
-; CHECK-X64-V4-NEXT:    movl $2863311531, %ecx # imm = 0xAAAAAAAB
-; CHECK-X64-V4-NEXT:    imulq %rdx, %rcx
-; CHECK-X64-V4-NEXT:    shrq $34, %rcx
-; CHECK-X64-V4-NEXT:    addl %ecx, %ecx
-; CHECK-X64-V4-NEXT:    movabsq $2635249153617166336, %rdi # imm = 0x24924924A0000000
-; CHECK-X64-V4-NEXT:    mulxq %rdi, %rdx, %rdx
-; CHECK-X64-V4-NEXT:    leal (%rcx,%rcx,2), %ecx
-; CHECK-X64-V4-NEXT:    leal (,%rdx,8), %edi
-; CHECK-X64-V4-NEXT:    subl %edx, %edi
-; CHECK-X64-V4-NEXT:    testb $1, %sil
-; CHECK-X64-V4-NEXT:    cmovnel %ecx, %edi
-; CHECK-X64-V4-NEXT:    subl %edi, %eax
-; CHECK-X64-V4-NEXT:    retq
-  %a = urem i32 %x, 6
-  %b = urem i32 %x, 7
-  %r = select i1 %c, i32 %a, i32 %b
-  ret i32 %r
-}
-
-define i32 @sdiv_select_of_constants_minsize(i32 %x, i1 %c) minsize {
-; CHECK-X64-LABEL: sdiv_select_of_constants_minsize:
-; CHECK-X64:       # %bb.0:
-; CHECK-X64-NEXT:    movl %edi, %eax
-; CHECK-X64-NEXT:    andl $1, %esi
-; CHECK-X64-NEXT:    xorl $5, %esi
-; CHECK-X64-NEXT:    cltd
-; CHECK-X64-NEXT:    idivl %esi
-; CHECK-X64-NEXT:    retq
-  %a = sdiv i32 %x, 4
-  %b = sdiv i32 %x, 5
-  %r = select i1 %c, i32 %a, i32 %b
-  ret i32 %r
-}
-
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; CHECK-X64: {{.*}}
diff --git a/llvm/test/Transforms/InstCombine/div.ll b/llvm/test/Transforms/InstCombine/div.ll
index 13c421eb9d75a..933d41c93d685 100644
--- a/llvm/test/Transforms/InstCombine/div.ll
+++ b/llvm/test/Transforms/InstCombine/div.ll
@@ -1362,7 +1362,6 @@ define i32 @udiv_select_of_constants_divisor_both_pow2(i1 %b, i32 %x) {
   ret i32 %r
 }
 
-
 define i32 @udiv_select_of_constants_divisor_exact(i1 %b, i32 %x) {
 ; CHECK-LABEL: @udiv_select_of_constants_divisor_exact(
 ; CHECK-NEXT:    [[TMP1:%.*]] = lshr exact i32 [[X:%.*]], 2
@@ -1432,7 +1431,6 @@ define i32 @udiv_select_of_constants_divisor_minsize(i1 %b, i32 %x) minsize {
   ret i32 %r
 }
 
-
 define i32 @udiv_select_of_constants_divisor_variable_arm(i1 %b, i32 %x, i32 %y) {
 ; CHECK-LABEL: @udiv_select_of_constants_divisor_variable_arm(
 ; CHECK-NEXT:    [[S:%.*]] = select i1 [[B:%.*]], i32 [[Y:%.*]], i32 4
@@ -1444,6 +1442,24 @@ define i32 @udiv_select_of_constants_divisor_variable_arm(i1 %b, i32 %x, i32 %y)
   ret i32 %r
 }
 
+define i32 @udiv_urem_select_of_constants_divisor(i1 %b, i32 %x) {
+; CHECK-LABEL: @udiv_urem_select_of_constants_divisor(
+; CHECK-NEXT:    [[TMP1:%.*]] = lshr i32 [[X:%.*]], 2
+; CHECK-NEXT:    [[TMP2:%.*]] = udiv i32 [[X]], 5
+; CHECK-NEXT:    [[D:%.*]] = select i1 [[B:%.*]], i32 [[TMP1]], i32 [[TMP2]]
+; CHECK-NEXT:    [[TMP3:%.*]] = and i32 [[X]], 3
+; CHECK-NEXT:    [[TMP4:%.*]] = urem i32 [[X]], 5
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[B]], i32 [[TMP3]], i32 [[TMP4]]
+; CHECK-NEXT:    [[A:%.*]] = add nuw nsw i32 [[D]], [[R]]
+; CHECK-NEXT:    ret i32 [[A]]
+;
+  %s = select i1 %b, i32 4, i32 5
+  %d = udiv i32 %x, %s
+  %r = urem i32 %x, %s
+  %a = add i32 %d, %r
+  ret i32 %a
+}
+
 define i32 @udiv_select_of_constants_divisor_multi_use(i1 %b, i32 %x) {
 ; CHECK-LABEL: @udiv_select_of_constants_divisor_multi_use(
 ; CHECK-NEXT:    [[S:%.*]] = select i1 [[B:%.*]], i32 4, i32 5
diff --git a/llvm/test/Transforms/InstCombine/rem.ll b/llvm/test/Transforms/InstCombine/rem.ll
index 1c9a2ab9eb1db..94904a36b10a0 100644
--- a/llvm/test/Transforms/InstCombine/rem.ll
+++ b/llvm/test/Transforms/InstCombine/rem.ll
@@ -928,7 +928,6 @@ define i32 @srem_select_of_constants_divisor(i1 %b, i32 %x) {
   ret i32 %r
 }
 
-
 define i32 @srem_select_of_constants_divisor_minus_one_arm(i1 %b, i32 %x) {
 ; CHECK-LABEL: @srem_select_of_constants_divisor_minus_one_arm(
 ; CHECK-NEXT:    [[S:%.*]] = select i1 [[B:%.*]], i32 -2, i32 -1
@@ -1067,10 +1066,6 @@ define i32 @urem_select_of_constants_divisor(i1 %b, i32 %x) {
   ret i32 %r
 }
 
-
-
-
-
 ; https://alive2.llvm.org/ce/z/bh2KHm
 define <2 x i32> @PR62401(<2 x i1> %x, <2 x i32> %y) {
 ; CHECK-LABEL: @PR62401(



More information about the llvm-commits mailing list