[llvm] [DAGCombiner] Port custom DAG combine for `rem` from NVPTX (PR #210344)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Jul 17 07:15:04 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-selectiondag
Author: Ayaan (def3r)
<details>
<summary>Changes</summary>
Part of #<!-- -->116695
Supersedes #<!-- -->167147
Port NVPTX combine for `rem` to DAGCombine. Folds `Num % Den -> Num - (Num / Den) * Den` if `DIVREM` is not supported by the backend.
---
Full diff: https://github.com/llvm/llvm-project/pull/210344.diff
4 Files Affected:
- (modified) llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp (+36)
- (modified) llvm/lib/Target/NVPTX/NVPTXISelLowering.cpp (+3-34)
- (modified) llvm/test/CodeGen/X86/divide-by-constant.ll (+22-37)
- (modified) llvm/test/CodeGen/X86/divrem.ll (+44-32)
``````````diff
diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index 2f2d5cb709642..f5388a2982bde 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -444,6 +444,7 @@ namespace {
SDValue visitSSUBO_CARRY(SDNode *N);
SDValue visitMUL(SDNode *N);
SDValue visitMULFIX(SDNode *N);
+ SDValue performREMCombine(SDNode *N);
SDValue useDivRem(SDNode *N);
SDValue visitSDIV(SDNode *N);
SDValue visitSDIVLike(SDValue N0, SDValue N1, SDNode *N);
@@ -5093,6 +5094,38 @@ static bool isDivRemLibcallAvailable(SDNode *Node, bool isSigned,
return DAG.getLibcalls().getLibcallImpl(LC) != RTLIB::Unsupported;
}
+// Fold Num % Den -> Num - (Num / Den) * Den, if (Num / Den) is already
+// computed
+SDValue DAGCombiner::performREMCombine(SDNode *N) {
+ assert(N->getOpcode() == ISD::SREM || N->getOpcode() == ISD::UREM);
+
+ // Don't do anything at less than -O2.
+ if (OptLevel < CodeGenOptLevel::Default)
+ return SDValue();
+
+ SDLoc DL(N);
+ EVT VT = N->getValueType(0);
+ bool IsSigned = N->getOpcode() == ISD::SREM;
+ unsigned DivOpc = IsSigned ? ISD::SDIV : ISD::UDIV;
+ unsigned DivRemOpc = IsSigned ? ISD::SDIVREM : ISD::UDIVREM;
+
+ // If DIVREM is available, do not fold
+ if (TLI.isOperationLegalOrCustom(DivRemOpc, VT.getScalarType()))
+ return SDValue();
+
+ const SDValue &Num = N->getOperand(0);
+ const SDValue &Den = N->getOperand(1);
+ for (const SDNode *U : Num->users()) {
+ if (U->getOpcode() == DivOpc && U->getOperand(0) == Num &&
+ U->getOperand(1) == Den) {
+ SDValue Div = DAG.getNode(DivOpc, DL, VT, Num, Den);
+ SDValue Mul = DAG.getNode(ISD::MUL, DL, VT, Div, Den);
+ return DAG.getNode(ISD::SUB, DL, VT, Num, Mul);
+ }
+ }
+ return SDValue();
+}
+
/// Issue divrem if both quotient and remainder are needed.
SDValue DAGCombiner::useDivRem(SDNode *Node) {
if (Node->use_empty())
@@ -5563,6 +5596,9 @@ SDValue DAGCombiner::visitREM(SDNode *N) {
}
}
+ if (SDValue V = performREMCombine(N))
+ return V;
+
// sdiv, srem -> sdivrem
if (SDValue DivRem = useDivRem(N))
return DivRem.getValue(1);
diff --git a/llvm/lib/Target/NVPTX/NVPTXISelLowering.cpp b/llvm/lib/Target/NVPTX/NVPTXISelLowering.cpp
index 1c5caf124c17e..522620d88227f 100644
--- a/llvm/lib/Target/NVPTX/NVPTXISelLowering.cpp
+++ b/llvm/lib/Target/NVPTX/NVPTXISelLowering.cpp
@@ -687,6 +687,9 @@ NVPTXTargetLowering::NVPTXTargetLowering(const NVPTXTargetMachine &TM,
setOperationAction(ISD::BR_CC, VT, Expand);
}
+ setOperationAction(ISD::SDIVREM, {MVT::i32, MVT::i64}, Expand);
+ setOperationAction(ISD::UDIVREM, {MVT::i32, MVT::i64}, Expand);
+
// We don't want ops like FMINIMUM or UMAX to be lowered to SETCC+VSELECT.
setOperationAction(ISD::VSELECT, {MVT::v2f32, MVT::v2i32}, Expand);
@@ -6281,37 +6284,6 @@ static SDValue PerformFMinMaxCombine(SDNode *N,
return SDValue();
}
-static SDValue PerformREMCombine(SDNode *N,
- TargetLowering::DAGCombinerInfo &DCI,
- CodeGenOptLevel OptLevel) {
- assert(N->getOpcode() == ISD::SREM || N->getOpcode() == ISD::UREM);
-
- // Don't do anything at less than -O2.
- if (OptLevel < CodeGenOptLevel::Default)
- return SDValue();
-
- SelectionDAG &DAG = DCI.DAG;
- SDLoc DL(N);
- EVT VT = N->getValueType(0);
- bool IsSigned = N->getOpcode() == ISD::SREM;
- unsigned DivOpc = IsSigned ? ISD::SDIV : ISD::UDIV;
-
- const SDValue &Num = N->getOperand(0);
- const SDValue &Den = N->getOperand(1);
-
- for (const SDNode *U : Num->users()) {
- if (U->getOpcode() == DivOpc && U->getOperand(0) == Num &&
- U->getOperand(1) == Den) {
- // Num % Den -> Num - (Num / Den) * Den
- return DAG.getNode(ISD::SUB, DL, VT, Num,
- DAG.getNode(ISD::MUL, DL, VT,
- DAG.getNode(DivOpc, DL, VT, Num, Den),
- Den));
- }
- }
- return SDValue();
-}
-
// sext (mul.iN nsw x, y) => mul.wide.sN x, y
// zext (mul.iN nuw x, y) => mul.wide.uN x, y
// sext (shl.iN nsw x, const) => mul.wide.sN x, (1 << const)
@@ -7121,9 +7093,6 @@ SDValue NVPTXTargetLowering::PerformDAGCombine(SDNode *N,
return PerformSETCCCombine(N, DCI, STI.getSmVersion());
case ISD::SHL:
return PerformSHLCombine(N, DCI, OptLevel);
- case ISD::SREM:
- case ISD::UREM:
- return PerformREMCombine(N, DCI, OptLevel);
case ISD::STORE:
case NVPTXISD::StoreV2:
case NVPTXISD::StoreV4:
diff --git a/llvm/test/CodeGen/X86/divide-by-constant.ll b/llvm/test/CodeGen/X86/divide-by-constant.ll
index d9e19df39f6b6..4dee2fdc872c7 100644
--- a/llvm/test/CodeGen/X86/divide-by-constant.ll
+++ b/llvm/test/CodeGen/X86/divide-by-constant.ll
@@ -410,40 +410,40 @@ define { i64, i32 } @PR38622(i64) nounwind {
; X86-NEXT: pushl %esi
; X86-NEXT: pushl %eax
; X86-NEXT: movl {{[0-9]+}}(%esp), %ecx
-; X86-NEXT: movl {{[0-9]+}}(%esp), %edi
-; X86-NEXT: movl %ecx, %ebx
-; X86-NEXT: shrdl $11, %edi, %ebx
+; X86-NEXT: movl {{[0-9]+}}(%esp), %ebx
+; X86-NEXT: movl %ecx, %edi
+; X86-NEXT: shrdl $11, %ebx, %edi
; X86-NEXT: movl $1125899, %edx # imm = 0x112E0B
-; X86-NEXT: movl %ebx, %eax
+; X86-NEXT: movl %edi, %eax
; X86-NEXT: mull %edx
; X86-NEXT: movl %eax, (%esp) # 4-byte Spill
; X86-NEXT: movl %edx, %esi
; X86-NEXT: movl $-400107883, %edx # imm = 0xE826D695
-; X86-NEXT: movl %ebx, %eax
+; X86-NEXT: movl %edi, %eax
; X86-NEXT: mull %edx
; X86-NEXT: movl %edx, %ebp
; X86-NEXT: addl (%esp), %ebp # 4-byte Folded Reload
; X86-NEXT: adcl $0, %esi
-; X86-NEXT: shrl $11, %edi
-; X86-NEXT: movl %edi, %eax
+; X86-NEXT: shrl $11, %ebx
+; X86-NEXT: movl %ebx, %eax
; X86-NEXT: movl $1125899, %edx # imm = 0x112E0B
; X86-NEXT: mull %edx
-; X86-NEXT: movl %edx, %ebx
+; X86-NEXT: movl %edx, %edi
; X86-NEXT: movl %eax, (%esp) # 4-byte Spill
-; X86-NEXT: movl %edi, %eax
+; X86-NEXT: movl %ebx, %eax
; X86-NEXT: movl $-400107883, %edx # imm = 0xE826D695
; X86-NEXT: mull %edx
; X86-NEXT: addl %ebp, %eax
; X86-NEXT: adcl %edx, %esi
-; X86-NEXT: adcl $0, %ebx
+; X86-NEXT: adcl $0, %edi
; X86-NEXT: addl (%esp), %esi # 4-byte Folded Reload
-; X86-NEXT: adcl $0, %ebx
-; X86-NEXT: shrdl $9, %ebx, %esi
+; X86-NEXT: adcl $0, %edi
+; X86-NEXT: shrdl $9, %edi, %esi
; X86-NEXT: imull $-294967296, %esi, %eax # imm = 0xEE6B2800
; X86-NEXT: subl %eax, %ecx
-; X86-NEXT: shrl $9, %ebx
+; X86-NEXT: shrl $9, %edi
; X86-NEXT: movl %esi, %eax
-; X86-NEXT: movl %ebx, %edx
+; X86-NEXT: movl %edi, %edx
; X86-NEXT: addl $4, %esp
; X86-NEXT: popl %esi
; X86-NEXT: popl %edi
@@ -474,35 +474,20 @@ define { i64, i32 } @PR38622(i64) nounwind {
define { i64, i32 } @PR38622_signed(i64) nounwind {
; X86-LABEL: PR38622_signed:
; X86: # %bb.0:
-; X86-NEXT: pushl %ebp
-; X86-NEXT: pushl %ebx
-; X86-NEXT: pushl %edi
; X86-NEXT: pushl %esi
-; X86-NEXT: subl $12, %esp
-; X86-NEXT: movl {{[0-9]+}}(%esp), %ebx
-; X86-NEXT: movl {{[0-9]+}}(%esp), %ebp
+; X86-NEXT: subl $8, %esp
+; X86-NEXT: movl {{[0-9]+}}(%esp), %esi
; X86-NEXT: pushl $0
; X86-NEXT: pushl $-294967296 # imm = 0xEE6B2800
-; X86-NEXT: pushl %ebp
-; X86-NEXT: pushl %ebx
+; X86-NEXT: pushl {{[0-9]+}}(%esp)
+; X86-NEXT: pushl %esi
; X86-NEXT: calll __divdi3
; X86-NEXT: addl $16, %esp
-; X86-NEXT: movl %eax, %esi
-; X86-NEXT: movl %edx, %edi
-; X86-NEXT: pushl $0
-; X86-NEXT: pushl $-294967296 # imm = 0xEE6B2800
-; X86-NEXT: pushl %ebp
-; X86-NEXT: pushl %ebx
-; X86-NEXT: calll __moddi3
-; X86-NEXT: addl $16, %esp
-; X86-NEXT: movl %eax, %ecx
-; X86-NEXT: movl %esi, %eax
-; X86-NEXT: movl %edi, %edx
-; X86-NEXT: addl $12, %esp
+; X86-NEXT: imull $-294967296, %eax, %ecx # imm = 0xEE6B2800
+; X86-NEXT: subl %ecx, %esi
+; X86-NEXT: movl %esi, %ecx
+; X86-NEXT: addl $8, %esp
; X86-NEXT: popl %esi
-; X86-NEXT: popl %edi
-; X86-NEXT: popl %ebx
-; X86-NEXT: popl %ebp
; X86-NEXT: retl
;
; X64-LABEL: PR38622_signed:
diff --git a/llvm/test/CodeGen/X86/divrem.ll b/llvm/test/CodeGen/X86/divrem.ll
index ba777b4954611..8e21e75b3f3d8 100644
--- a/llvm/test/CodeGen/X86/divrem.ll
+++ b/llvm/test/CodeGen/X86/divrem.ll
@@ -9,28 +9,34 @@ define void @si64(i64 %x, i64 %y, ptr %p, ptr %q) nounwind {
; X86-NEXT: pushl %ebx
; X86-NEXT: pushl %edi
; X86-NEXT: pushl %esi
+; X86-NEXT: pushl %eax
; X86-NEXT: movl {{[0-9]+}}(%esp), %ebx
; X86-NEXT: movl {{[0-9]+}}(%esp), %ebp
+; X86-NEXT: movl {{[0-9]+}}(%esp), %esi
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edi
+; X86-NEXT: pushl %edi
+; X86-NEXT: pushl %esi
; X86-NEXT: pushl %ebp
; X86-NEXT: pushl %ebx
-; X86-NEXT: pushl {{[0-9]+}}(%esp)
-; X86-NEXT: pushl {{[0-9]+}}(%esp)
; X86-NEXT: calll __divdi3
; X86-NEXT: addl $16, %esp
-; X86-NEXT: movl %eax, %esi
-; X86-NEXT: movl %edx, %edi
-; X86-NEXT: pushl %ebp
-; X86-NEXT: pushl %ebx
-; X86-NEXT: pushl {{[0-9]+}}(%esp)
-; X86-NEXT: pushl {{[0-9]+}}(%esp)
-; X86-NEXT: calll __moddi3
-; X86-NEXT: addl $16, %esp
-; X86-NEXT: movl {{[0-9]+}}(%esp), %ecx
-; X86-NEXT: movl %edi, 4(%ecx)
-; X86-NEXT: movl %esi, (%ecx)
-; X86-NEXT: movl {{[0-9]+}}(%esp), %ecx
-; X86-NEXT: movl %edx, 4(%ecx)
-; X86-NEXT: movl %eax, (%ecx)
+; X86-NEXT: movl %eax, %ecx
+; X86-NEXT: movl %edx, (%esp) # 4-byte Spill
+; X86-NEXT: imull %eax, %edi
+; X86-NEXT: mull %esi
+; X86-NEXT: addl %edi, %edx
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edi
+; X86-NEXT: movl %ecx, (%edi)
+; X86-NEXT: movl (%esp), %ecx # 4-byte Reload
+; X86-NEXT: movl %ecx, 4(%edi)
+; X86-NEXT: imull %ecx, %esi
+; X86-NEXT: addl %edx, %esi
+; X86-NEXT: subl %eax, %ebx
+; X86-NEXT: sbbl %esi, %ebp
+; X86-NEXT: movl {{[0-9]+}}(%esp), %eax
+; X86-NEXT: movl %ebx, (%eax)
+; X86-NEXT: movl %ebp, 4(%eax)
+; X86-NEXT: addl $4, %esp
; X86-NEXT: popl %esi
; X86-NEXT: popl %edi
; X86-NEXT: popl %ebx
@@ -150,28 +156,34 @@ define void @ui64(i64 %x, i64 %y, ptr %p, ptr %q) nounwind {
; X86-NEXT: pushl %ebx
; X86-NEXT: pushl %edi
; X86-NEXT: pushl %esi
+; X86-NEXT: pushl %eax
; X86-NEXT: movl {{[0-9]+}}(%esp), %ebx
; X86-NEXT: movl {{[0-9]+}}(%esp), %ebp
+; X86-NEXT: movl {{[0-9]+}}(%esp), %esi
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edi
+; X86-NEXT: pushl %edi
+; X86-NEXT: pushl %esi
; X86-NEXT: pushl %ebp
; X86-NEXT: pushl %ebx
-; X86-NEXT: pushl {{[0-9]+}}(%esp)
-; X86-NEXT: pushl {{[0-9]+}}(%esp)
; X86-NEXT: calll __udivdi3
; X86-NEXT: addl $16, %esp
-; X86-NEXT: movl %eax, %esi
-; X86-NEXT: movl %edx, %edi
-; X86-NEXT: pushl %ebp
-; X86-NEXT: pushl %ebx
-; X86-NEXT: pushl {{[0-9]+}}(%esp)
-; X86-NEXT: pushl {{[0-9]+}}(%esp)
-; X86-NEXT: calll __umoddi3
-; X86-NEXT: addl $16, %esp
-; X86-NEXT: movl {{[0-9]+}}(%esp), %ecx
-; X86-NEXT: movl %edi, 4(%ecx)
-; X86-NEXT: movl %esi, (%ecx)
-; X86-NEXT: movl {{[0-9]+}}(%esp), %ecx
-; X86-NEXT: movl %edx, 4(%ecx)
-; X86-NEXT: movl %eax, (%ecx)
+; X86-NEXT: movl %eax, %ecx
+; X86-NEXT: movl %edx, (%esp) # 4-byte Spill
+; X86-NEXT: imull %eax, %edi
+; X86-NEXT: mull %esi
+; X86-NEXT: addl %edi, %edx
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edi
+; X86-NEXT: movl %ecx, (%edi)
+; X86-NEXT: movl (%esp), %ecx # 4-byte Reload
+; X86-NEXT: movl %ecx, 4(%edi)
+; X86-NEXT: imull %ecx, %esi
+; X86-NEXT: addl %edx, %esi
+; X86-NEXT: subl %eax, %ebx
+; X86-NEXT: sbbl %esi, %ebp
+; X86-NEXT: movl {{[0-9]+}}(%esp), %eax
+; X86-NEXT: movl %ebx, (%eax)
+; X86-NEXT: movl %ebp, 4(%eax)
+; X86-NEXT: addl $4, %esp
; X86-NEXT: popl %esi
; X86-NEXT: popl %edi
; X86-NEXT: popl %ebx
``````````
</details>
https://github.com/llvm/llvm-project/pull/210344
More information about the llvm-commits
mailing list