[llvm] [SelectionDAG] Use Magic Algorithm for Splitting UDIV/UREM by Constant (PR #154968)

Marius Kamp via llvm-commits llvm-commits at lists.llvm.org
Fri May 1 09:42:59 PDT 2026


https://github.com/mskamp updated https://github.com/llvm/llvm-project/pull/154968

>From 78da376499947e7a7a58f5affdeac4c8b927fcca Mon Sep 17 00:00:00 2001
From: Marius Kamp <msk at posteo.org>
Date: Tue, 12 Aug 2025 18:05:50 +0200
Subject: [PATCH 1/5] [SelectionDAG] Add Tests for Large UDIV/UREM by Constant;
 NFC

---
 llvm/test/CodeGen/X86/divide-by-constant.ll | 167 ++++++++++++++
 llvm/test/CodeGen/X86/divmod128.ll          | 244 ++++++++++++++++++++
 2 files changed, 411 insertions(+)

diff --git a/llvm/test/CodeGen/X86/divide-by-constant.ll b/llvm/test/CodeGen/X86/divide-by-constant.ll
index e0bff50e2e2dd..3558da9ac9879 100644
--- a/llvm/test/CodeGen/X86/divide-by-constant.ll
+++ b/llvm/test/CodeGen/X86/divide-by-constant.ll
@@ -1190,6 +1190,173 @@ entry:
   ret i64 %rem
 }
 
+; PR137514
+define i64 @udiv_i64_magic_large_postshift(i64 %x) nounwind {
+; X86-LABEL: udiv_i64_magic_large_postshift:
+; X86:       # %bb.0:
+; X86-NEXT:    subl $12, %esp
+; X86-NEXT:    pushl $-1073741825 # imm = 0xBFFFFFFF
+; X86-NEXT:    pushl $-2
+; X86-NEXT:    pushl {{[0-9]+}}(%esp)
+; X86-NEXT:    pushl {{[0-9]+}}(%esp)
+; X86-NEXT:    calll __udivdi3
+; X86-NEXT:    addl $28, %esp
+; X86-NEXT:    retl
+;
+; X64-LABEL: udiv_i64_magic_large_postshift:
+; X64:       # %bb.0:
+; X64-NEXT:    movq %rdi, %rax
+; X64-NEXT:    movabsq $-6148914691236517203, %rcx # imm = 0xAAAAAAAAAAAAAAAD
+; X64-NEXT:    mulq %rcx
+; X64-NEXT:    movq %rdx, %rax
+; X64-NEXT:    shrq $63, %rax
+; X64-NEXT:    retq
+  %ret = udiv i64 %x, 13835058055282163710 ; = 3 * 2^62 - 2
+  ret i64 %ret
+}
+
+; PR137514
+define i64 @urem_i64_magic_large_postshift(i64 %x) nounwind {
+; X86-LABEL: urem_i64_magic_large_postshift:
+; X86:       # %bb.0:
+; X86-NEXT:    subl $12, %esp
+; X86-NEXT:    pushl $-1073741825 # imm = 0xBFFFFFFF
+; X86-NEXT:    pushl $-2
+; X86-NEXT:    pushl {{[0-9]+}}(%esp)
+; X86-NEXT:    pushl {{[0-9]+}}(%esp)
+; X86-NEXT:    calll __umoddi3
+; X86-NEXT:    addl $28, %esp
+; X86-NEXT:    retl
+;
+; X64-LABEL: urem_i64_magic_large_postshift:
+; X64:       # %bb.0:
+; X64-NEXT:    movabsq $-6148914691236517203, %rcx # imm = 0xAAAAAAAAAAAAAAAD
+; X64-NEXT:    movq %rdi, %rax
+; X64-NEXT:    mulq %rcx
+; X64-NEXT:    shrq $63, %rdx
+; X64-NEXT:    movabsq $-4611686018427387906, %rax # imm = 0xBFFFFFFFFFFFFFFE
+; X64-NEXT:    imulq %rdx, %rax
+; X64-NEXT:    subq %rax, %rdi
+; X64-NEXT:    movq %rdi, %rax
+; X64-NEXT:    retq
+  %ret = urem i64 %x, 13835058055282163710 ; = 3 * 2^62 - 2
+  ret i64 %ret
+}
+
+; PR137514
+define i64 @udiv_i64_magic_large_preshift(i64 %x) nounwind {
+; X86-LABEL: udiv_i64_magic_large_preshift:
+; X86:       # %bb.0:
+; X86-NEXT:    subl $12, %esp
+; X86-NEXT:    pushl $13
+; X86-NEXT:    pushl $-2
+; X86-NEXT:    pushl {{[0-9]+}}(%esp)
+; X86-NEXT:    pushl {{[0-9]+}}(%esp)
+; X86-NEXT:    calll __udivdi3
+; X86-NEXT:    addl $28, %esp
+; X86-NEXT:    retl
+;
+; X64-LABEL: udiv_i64_magic_large_preshift:
+; X64:       # %bb.0:
+; X64-NEXT:    movq %rdi, %rax
+; X64-NEXT:    shrq %rax
+; X64-NEXT:    movabsq $-7905747459810626831, %rcx # imm = 0x924924925E0A72F1
+; X64-NEXT:    mulq %rcx
+; X64-NEXT:    movq %rdx, %rax
+; X64-NEXT:    shrq $34, %rax
+; X64-NEXT:    retq
+  %ret = udiv i64 %x, 60129542142 ; = 14 * 2^32 - 2
+  ret i64 %ret
+}
+
+; PR137514
+define i64 @urem_i64_magic_large_preshift(i64 %x) nounwind {
+; X86-LABEL: urem_i64_magic_large_preshift:
+; X86:       # %bb.0:
+; X86-NEXT:    subl $12, %esp
+; X86-NEXT:    pushl $13
+; X86-NEXT:    pushl $-2
+; X86-NEXT:    pushl {{[0-9]+}}(%esp)
+; X86-NEXT:    pushl {{[0-9]+}}(%esp)
+; X86-NEXT:    calll __umoddi3
+; X86-NEXT:    addl $28, %esp
+; X86-NEXT:    retl
+;
+; X64-LABEL: urem_i64_magic_large_preshift:
+; X64:       # %bb.0:
+; X64-NEXT:    movq %rdi, %rax
+; X64-NEXT:    shrq %rax
+; X64-NEXT:    movabsq $-7905747459810626831, %rcx # imm = 0x924924925E0A72F1
+; X64-NEXT:    mulq %rcx
+; X64-NEXT:    shrq $34, %rdx
+; X64-NEXT:    movabsq $60129542142, %rax # imm = 0xDFFFFFFFE
+; X64-NEXT:    imulq %rdx, %rax
+; X64-NEXT:    subq %rax, %rdi
+; X64-NEXT:    movq %rdi, %rax
+; X64-NEXT:    retq
+  %ret = urem i64 %x, 60129542142 ; = 14 * 2^32 - 2
+  ret i64 %ret
+}
+
+; PR137514
+define i64 @udiv_i64_magic_is_add(i64 %x) nounwind {
+; X86-LABEL: udiv_i64_magic_is_add:
+; X86:       # %bb.0:
+; X86-NEXT:    subl $12, %esp
+; X86-NEXT:    pushl $196608 # imm = 0x30000
+; X86-NEXT:    pushl $-1
+; X86-NEXT:    pushl {{[0-9]+}}(%esp)
+; X86-NEXT:    pushl {{[0-9]+}}(%esp)
+; X86-NEXT:    calll __udivdi3
+; X86-NEXT:    addl $28, %esp
+; X86-NEXT:    retl
+;
+; X64-LABEL: udiv_i64_magic_is_add:
+; X64:       # %bb.0:
+; X64-NEXT:    movabsq $6148789591883185367, %rcx # imm = 0x5554E38E5ED0FCD7
+; X64-NEXT:    movq %rdi, %rax
+; X64-NEXT:    mulq %rcx
+; X64-NEXT:    subq %rdx, %rdi
+; X64-NEXT:    shrq %rdi
+; X64-NEXT:    leaq (%rdi,%rdx), %rax
+; X64-NEXT:    shrq $49, %rax
+; X64-NEXT:    retq
+  %ret = udiv i64 %x, 844429225099263 ; = 3 * 2^48 + 2^32 - 1
+  ret i64 %ret
+}
+
+; PR137514
+define i64 @urem_i64_magic_is_add(i64 %x) nounwind {
+; X86-LABEL: urem_i64_magic_is_add:
+; X86:       # %bb.0:
+; X86-NEXT:    subl $12, %esp
+; X86-NEXT:    pushl $196608 # imm = 0x30000
+; X86-NEXT:    pushl $-1
+; X86-NEXT:    pushl {{[0-9]+}}(%esp)
+; X86-NEXT:    pushl {{[0-9]+}}(%esp)
+; X86-NEXT:    calll __umoddi3
+; X86-NEXT:    addl $28, %esp
+; X86-NEXT:    retl
+;
+; X64-LABEL: urem_i64_magic_is_add:
+; X64:       # %bb.0:
+; X64-NEXT:    movabsq $6148789591883185367, %rcx # imm = 0x5554E38E5ED0FCD7
+; X64-NEXT:    movq %rdi, %rax
+; X64-NEXT:    mulq %rcx
+; X64-NEXT:    movq %rdi, %rax
+; X64-NEXT:    subq %rdx, %rax
+; X64-NEXT:    shrq %rax
+; X64-NEXT:    addq %rdx, %rax
+; X64-NEXT:    shrq $49, %rax
+; X64-NEXT:    movabsq $844429225099263, %rcx # imm = 0x30000FFFFFFFF
+; X64-NEXT:    imulq %rax, %rcx
+; X64-NEXT:    subq %rcx, %rdi
+; X64-NEXT:    movq %rdi, %rax
+; X64-NEXT:    retq
+  %ret = urem i64 %x, 844429225099263 ; = 3 * 2^48 + 2^32 - 1
+  ret i64 %ret
+}
+
 ; Make sure we don't inline expand for optsize.
 define i64 @urem_i64_3_optsize(i64 %x) nounwind optsize {
 ; X86-LABEL: urem_i64_3_optsize:
diff --git a/llvm/test/CodeGen/X86/divmod128.ll b/llvm/test/CodeGen/X86/divmod128.ll
index 54022d242ab50..ee9bca86d6ea8 100644
--- a/llvm/test/CodeGen/X86/divmod128.ll
+++ b/llvm/test/CodeGen/X86/divmod128.ll
@@ -1168,3 +1168,247 @@ entry:
   %rem = udiv i128 %x, 13
   ret i128 %rem
 }
+
+; PR137514
+define i128 @udiv_magic_preshift_and_postshift(i128 %x) nounwind {
+; X86-64-LABEL: udiv_magic_preshift_and_postshift:
+; X86-64:       # %bb.0:
+; X86-64-NEXT:    pushq %rax
+; X86-64-NEXT:    movl $358, %edx # imm = 0x166
+; X86-64-NEXT:    xorl %ecx, %ecx
+; X86-64-NEXT:    callq __udivti3 at PLT
+; X86-64-NEXT:    popq %rcx
+; X86-64-NEXT:    retq
+;
+; WIN64-LABEL: udiv_magic_preshift_and_postshift:
+; WIN64:       # %bb.0:
+; WIN64-NEXT:    subq $72, %rsp
+; WIN64-NEXT:    movq %rdx, {{[0-9]+}}(%rsp)
+; WIN64-NEXT:    movq %rcx, {{[0-9]+}}(%rsp)
+; WIN64-NEXT:    movq $358, {{[0-9]+}}(%rsp) # imm = 0x166
+; WIN64-NEXT:    movq $0, {{[0-9]+}}(%rsp)
+; WIN64-NEXT:    leaq {{[0-9]+}}(%rsp), %rcx
+; WIN64-NEXT:    leaq {{[0-9]+}}(%rsp), %rdx
+; WIN64-NEXT:    callq __udivti3
+; WIN64-NEXT:    movq %xmm0, %rax
+; WIN64-NEXT:    pshufd {{.*#+}} xmm0 = xmm0[2,3,2,3]
+; WIN64-NEXT:    movq %xmm0, %rdx
+; WIN64-NEXT:    addq $72, %rsp
+; WIN64-NEXT:    retq
+  %ret = udiv i128 %x, 358
+  ret i128 %ret
+}
+
+; PR137514
+define i128 @urem_magic_preshift_and_postshift(i128 %x) nounwind {
+; X86-64-LABEL: urem_magic_preshift_and_postshift:
+; X86-64:       # %bb.0:
+; X86-64-NEXT:    pushq %rax
+; X86-64-NEXT:    movl $358, %edx # imm = 0x166
+; X86-64-NEXT:    xorl %ecx, %ecx
+; X86-64-NEXT:    callq __umodti3 at PLT
+; X86-64-NEXT:    popq %rcx
+; X86-64-NEXT:    retq
+;
+; WIN64-LABEL: urem_magic_preshift_and_postshift:
+; WIN64:       # %bb.0:
+; WIN64-NEXT:    subq $72, %rsp
+; WIN64-NEXT:    movq %rdx, {{[0-9]+}}(%rsp)
+; WIN64-NEXT:    movq %rcx, {{[0-9]+}}(%rsp)
+; WIN64-NEXT:    movq $358, {{[0-9]+}}(%rsp) # imm = 0x166
+; WIN64-NEXT:    movq $0, {{[0-9]+}}(%rsp)
+; WIN64-NEXT:    leaq {{[0-9]+}}(%rsp), %rcx
+; WIN64-NEXT:    leaq {{[0-9]+}}(%rsp), %rdx
+; WIN64-NEXT:    callq __umodti3
+; WIN64-NEXT:    movq %xmm0, %rax
+; WIN64-NEXT:    pshufd {{.*#+}} xmm0 = xmm0[2,3,2,3]
+; WIN64-NEXT:    movq %xmm0, %rdx
+; WIN64-NEXT:    addq $72, %rsp
+; WIN64-NEXT:    retq
+  %ret = urem i128 %x, 358
+  ret i128 %ret
+}
+
+; PR137514
+define i128 @udiv_magic_large_preshift(i128 %x) nounwind {
+; X86-64-LABEL: udiv_magic_large_preshift:
+; X86-64:       # %bb.0:
+; X86-64-NEXT:    pushq %rax
+; X86-64-NEXT:    movabsq $12300786335744, %rcx # imm = 0xB3000000000
+; X86-64-NEXT:    xorl %edx, %edx
+; X86-64-NEXT:    callq __udivti3 at PLT
+; X86-64-NEXT:    popq %rcx
+; X86-64-NEXT:    retq
+;
+; WIN64-LABEL: udiv_magic_large_preshift:
+; WIN64:       # %bb.0:
+; WIN64-NEXT:    subq $72, %rsp
+; WIN64-NEXT:    movq %rdx, {{[0-9]+}}(%rsp)
+; WIN64-NEXT:    movq %rcx, {{[0-9]+}}(%rsp)
+; WIN64-NEXT:    movabsq $12300786335744, %rax # imm = 0xB3000000000
+; WIN64-NEXT:    movq %rax, {{[0-9]+}}(%rsp)
+; WIN64-NEXT:    movq $0, {{[0-9]+}}(%rsp)
+; WIN64-NEXT:    leaq {{[0-9]+}}(%rsp), %rcx
+; WIN64-NEXT:    leaq {{[0-9]+}}(%rsp), %rdx
+; WIN64-NEXT:    callq __udivti3
+; WIN64-NEXT:    movq %xmm0, %rax
+; WIN64-NEXT:    pshufd {{.*#+}} xmm0 = xmm0[2,3,2,3]
+; WIN64-NEXT:    movq %xmm0, %rdx
+; WIN64-NEXT:    addq $72, %rsp
+; WIN64-NEXT:    retq
+  %ret = udiv i128 %x, 226909457440853062867909873762304 ; = 179 * 2^100
+  ret i128 %ret
+}
+
+; PR137514
+define i128 @urem_magic_large_preshift(i128 %x) nounwind {
+; X86-64-LABEL: urem_magic_large_preshift:
+; X86-64:       # %bb.0:
+; X86-64-NEXT:    pushq %rax
+; X86-64-NEXT:    movabsq $12300786335744, %rcx # imm = 0xB3000000000
+; X86-64-NEXT:    xorl %edx, %edx
+; X86-64-NEXT:    callq __umodti3 at PLT
+; X86-64-NEXT:    popq %rcx
+; X86-64-NEXT:    retq
+;
+; WIN64-LABEL: urem_magic_large_preshift:
+; WIN64:       # %bb.0:
+; WIN64-NEXT:    subq $72, %rsp
+; WIN64-NEXT:    movq %rdx, {{[0-9]+}}(%rsp)
+; WIN64-NEXT:    movq %rcx, {{[0-9]+}}(%rsp)
+; WIN64-NEXT:    movabsq $12300786335744, %rax # imm = 0xB3000000000
+; WIN64-NEXT:    movq %rax, {{[0-9]+}}(%rsp)
+; WIN64-NEXT:    movq $0, {{[0-9]+}}(%rsp)
+; WIN64-NEXT:    leaq {{[0-9]+}}(%rsp), %rcx
+; WIN64-NEXT:    leaq {{[0-9]+}}(%rsp), %rdx
+; WIN64-NEXT:    callq __umodti3
+; WIN64-NEXT:    movq %xmm0, %rax
+; WIN64-NEXT:    pshufd {{.*#+}} xmm0 = xmm0[2,3,2,3]
+; WIN64-NEXT:    movq %xmm0, %rdx
+; WIN64-NEXT:    addq $72, %rsp
+; WIN64-NEXT:    retq
+  %ret = urem i128 %x, 226909457440853062867909873762304 ; = 179 * 2^100
+  ret i128 %ret
+}
+
+; PR137514
+define i128 @udiv_magic_large_postshift(i128 %x) nounwind {
+; X86-64-LABEL: udiv_magic_large_postshift:
+; X86-64:       # %bb.0:
+; X86-64-NEXT:    pushq %rax
+; X86-64-NEXT:    movl $1, %edx
+; X86-64-NEXT:    movl $1, %ecx
+; X86-64-NEXT:    callq __udivti3 at PLT
+; X86-64-NEXT:    popq %rcx
+; X86-64-NEXT:    retq
+;
+; WIN64-LABEL: udiv_magic_large_postshift:
+; WIN64:       # %bb.0:
+; WIN64-NEXT:    subq $72, %rsp
+; WIN64-NEXT:    movq %rdx, {{[0-9]+}}(%rsp)
+; WIN64-NEXT:    movq %rcx, {{[0-9]+}}(%rsp)
+; WIN64-NEXT:    movq $1, {{[0-9]+}}(%rsp)
+; WIN64-NEXT:    movq $1, {{[0-9]+}}(%rsp)
+; WIN64-NEXT:    leaq {{[0-9]+}}(%rsp), %rcx
+; WIN64-NEXT:    leaq {{[0-9]+}}(%rsp), %rdx
+; WIN64-NEXT:    callq __udivti3
+; WIN64-NEXT:    movq %xmm0, %rax
+; WIN64-NEXT:    pshufd {{.*#+}} xmm0 = xmm0[2,3,2,3]
+; WIN64-NEXT:    movq %xmm0, %rdx
+; WIN64-NEXT:    addq $72, %rsp
+; WIN64-NEXT:    retq
+  %ret = udiv i128 %x, 18446744073709551617 ; = 2^64 + 1
+  ret i128 %ret
+}
+
+; PR137514
+define i128 @urem_magic_large_postshift(i128 %x) nounwind {
+; X86-64-LABEL: urem_magic_large_postshift:
+; X86-64:       # %bb.0:
+; X86-64-NEXT:    pushq %rax
+; X86-64-NEXT:    movl $1, %edx
+; X86-64-NEXT:    movl $1, %ecx
+; X86-64-NEXT:    callq __umodti3 at PLT
+; X86-64-NEXT:    popq %rcx
+; X86-64-NEXT:    retq
+;
+; WIN64-LABEL: urem_magic_large_postshift:
+; WIN64:       # %bb.0:
+; WIN64-NEXT:    subq $72, %rsp
+; WIN64-NEXT:    movq %rdx, {{[0-9]+}}(%rsp)
+; WIN64-NEXT:    movq %rcx, {{[0-9]+}}(%rsp)
+; WIN64-NEXT:    movq $1, {{[0-9]+}}(%rsp)
+; WIN64-NEXT:    movq $1, {{[0-9]+}}(%rsp)
+; WIN64-NEXT:    leaq {{[0-9]+}}(%rsp), %rcx
+; WIN64-NEXT:    leaq {{[0-9]+}}(%rsp), %rdx
+; WIN64-NEXT:    callq __umodti3
+; WIN64-NEXT:    movq %xmm0, %rax
+; WIN64-NEXT:    pshufd {{.*#+}} xmm0 = xmm0[2,3,2,3]
+; WIN64-NEXT:    movq %xmm0, %rdx
+; WIN64-NEXT:    addq $72, %rsp
+; WIN64-NEXT:    retq
+  %ret = urem i128 %x, 18446744073709551617 ; = 2^64 + 1
+  ret i128 %ret
+}
+
+; PR137514
+define i128 @udiv_magic_is_add(i128 %x) nounwind {
+; X86-64-LABEL: udiv_magic_is_add:
+; X86-64:       # %bb.0:
+; X86-64-NEXT:    pushq %rax
+; X86-64-NEXT:    movabsq $-9223372036854775808, %rcx # imm = 0x8000000000000000
+; X86-64-NEXT:    movl $1, %edx
+; X86-64-NEXT:    callq __udivti3 at PLT
+; X86-64-NEXT:    popq %rcx
+; X86-64-NEXT:    retq
+;
+; WIN64-LABEL: udiv_magic_is_add:
+; WIN64:       # %bb.0:
+; WIN64-NEXT:    subq $72, %rsp
+; WIN64-NEXT:    movq %rdx, {{[0-9]+}}(%rsp)
+; WIN64-NEXT:    movq %rcx, {{[0-9]+}}(%rsp)
+; WIN64-NEXT:    movabsq $-9223372036854775808, %rax # imm = 0x8000000000000000
+; WIN64-NEXT:    movq %rax, {{[0-9]+}}(%rsp)
+; WIN64-NEXT:    movq $1, {{[0-9]+}}(%rsp)
+; WIN64-NEXT:    leaq {{[0-9]+}}(%rsp), %rcx
+; WIN64-NEXT:    leaq {{[0-9]+}}(%rsp), %rdx
+; WIN64-NEXT:    callq __udivti3
+; WIN64-NEXT:    movq %xmm0, %rax
+; WIN64-NEXT:    pshufd {{.*#+}} xmm0 = xmm0[2,3,2,3]
+; WIN64-NEXT:    movq %xmm0, %rdx
+; WIN64-NEXT:    addq $72, %rsp
+; WIN64-NEXT:    retq
+  %ret = udiv i128 %x, 170141183460469231731687303715884105729 ; = 2^127 + 1
+  ret i128 %ret
+}
+
+; PR137514
+define i128 @urem_magic_is_add(i128 %x) nounwind {
+; X86-64-LABEL: urem_magic_is_add:
+; X86-64:       # %bb.0:
+; X86-64-NEXT:    pushq %rax
+; X86-64-NEXT:    movabsq $-9223372036854775808, %rcx # imm = 0x8000000000000000
+; X86-64-NEXT:    movl $1, %edx
+; X86-64-NEXT:    callq __umodti3 at PLT
+; X86-64-NEXT:    popq %rcx
+; X86-64-NEXT:    retq
+;
+; WIN64-LABEL: urem_magic_is_add:
+; WIN64:       # %bb.0:
+; WIN64-NEXT:    subq $72, %rsp
+; WIN64-NEXT:    movq %rdx, {{[0-9]+}}(%rsp)
+; WIN64-NEXT:    movq %rcx, {{[0-9]+}}(%rsp)
+; WIN64-NEXT:    movabsq $-9223372036854775808, %rax # imm = 0x8000000000000000
+; WIN64-NEXT:    movq %rax, {{[0-9]+}}(%rsp)
+; WIN64-NEXT:    movq $1, {{[0-9]+}}(%rsp)
+; WIN64-NEXT:    leaq {{[0-9]+}}(%rsp), %rcx
+; WIN64-NEXT:    leaq {{[0-9]+}}(%rsp), %rdx
+; WIN64-NEXT:    callq __umodti3
+; WIN64-NEXT:    movq %xmm0, %rax
+; WIN64-NEXT:    pshufd {{.*#+}} xmm0 = xmm0[2,3,2,3]
+; WIN64-NEXT:    movq %xmm0, %rdx
+; WIN64-NEXT:    addq $72, %rsp
+; WIN64-NEXT:    retq
+  %ret = urem i128 %x, 170141183460469231731687303715884105729 ; = 2^127 + 1
+  ret i128 %ret
+}

>From 82b6a31b2b7c8715a6f5f83e8550e4768d394285 Mon Sep 17 00:00:00 2001
From: Marius Kamp <msk at posteo.org>
Date: Tue, 19 Aug 2025 05:39:58 +0200
Subject: [PATCH 2/5] [SelectionDAG] Adjust Existing Test; NFC

Rename a test that will be folded after a subsequent commit.
---
 llvm/test/CodeGen/RISCV/urem-vector-lkk.ll | 11 +++++------
 1 file changed, 5 insertions(+), 6 deletions(-)

diff --git a/llvm/test/CodeGen/RISCV/urem-vector-lkk.ll b/llvm/test/CodeGen/RISCV/urem-vector-lkk.ll
index 180fa6fd2b2f6..ce3e2c1a4f7be 100644
--- a/llvm/test/CodeGen/RISCV/urem-vector-lkk.ll
+++ b/llvm/test/CodeGen/RISCV/urem-vector-lkk.ll
@@ -778,9 +778,8 @@ define <4 x i16> @dont_fold_urem_i16_smax(<4 x i16> %x) nounwind {
   ret <4 x i16> %1
 }
 
-; Don't fold i64 urem.
-define <4 x i64> @dont_fold_urem_i64(<4 x i64> %x) nounwind {
-; RV32I-LABEL: dont_fold_urem_i64:
+define <4 x i64> @fold_urem_i64(<4 x i64> %x) nounwind {
+; RV32I-LABEL: fold_urem_i64:
 ; RV32I:       # %bb.0:
 ; RV32I-NEXT:    addi sp, sp, -48
 ; RV32I-NEXT:    sw ra, 44(sp) # 4-byte Folded Spill
@@ -850,7 +849,7 @@ define <4 x i64> @dont_fold_urem_i64(<4 x i64> %x) nounwind {
 ; RV32I-NEXT:    addi sp, sp, 48
 ; RV32I-NEXT:    ret
 ;
-; RV32IM-LABEL: dont_fold_urem_i64:
+; RV32IM-LABEL: fold_urem_i64:
 ; RV32IM:       # %bb.0:
 ; RV32IM-NEXT:    addi sp, sp, -48
 ; RV32IM-NEXT:    sw ra, 44(sp) # 4-byte Folded Spill
@@ -926,7 +925,7 @@ define <4 x i64> @dont_fold_urem_i64(<4 x i64> %x) nounwind {
 ; RV32IM-NEXT:    addi sp, sp, 48
 ; RV32IM-NEXT:    ret
 ;
-; RV64I-LABEL: dont_fold_urem_i64:
+; RV64I-LABEL: fold_urem_i64:
 ; RV64I:       # %bb.0:
 ; RV64I-NEXT:    addi sp, sp, -48
 ; RV64I-NEXT:    sd ra, 40(sp) # 8-byte Folded Spill
@@ -962,7 +961,7 @@ define <4 x i64> @dont_fold_urem_i64(<4 x i64> %x) nounwind {
 ; RV64I-NEXT:    addi sp, sp, 48
 ; RV64I-NEXT:    ret
 ;
-; RV64IM-LABEL: dont_fold_urem_i64:
+; RV64IM-LABEL: fold_urem_i64:
 ; RV64IM:       # %bb.0:
 ; RV64IM-NEXT:    ld a2, 8(a1)
 ; RV64IM-NEXT:    ld a3, 16(a1)

>From 36787767825d37dec0a90ffa7f000809cf70b543 Mon Sep 17 00:00:00 2001
From: Marius Kamp <msk at posteo.org>
Date: Tue, 15 Jul 2025 16:21:25 +0200
Subject: [PATCH 3/5] [SelectionDAG] Move UREM Decomposition to Own Function;
 NFC

---
 llvm/include/llvm/CodeGen/TargetLowering.h    |  4 +
 .../CodeGen/SelectionDAG/TargetLowering.cpp   | 73 +++++++++++--------
 2 files changed, 47 insertions(+), 30 deletions(-)

diff --git a/llvm/include/llvm/CodeGen/TargetLowering.h b/llvm/include/llvm/CodeGen/TargetLowering.h
index 59a0f2d2e0c2a..430c01f82d736 100644
--- a/llvm/include/llvm/CodeGen/TargetLowering.h
+++ b/llvm/include/llvm/CodeGen/TargetLowering.h
@@ -6025,6 +6025,10 @@ class LLVM_ABI TargetLowering : public TargetLoweringBase {
   SDValue buildSREMEqFold(EVT SETCCVT, SDValue REMNode, SDValue CompTargetNode,
                           ISD::CondCode Cond, DAGCombinerInfo &DCI,
                           const SDLoc &DL) const;
+
+  bool expandUDIVREMByConstantViaUREMDecomposition(
+      SDNode *N, APInt Divisor, SmallVectorImpl<SDValue> &Result, EVT HiLoVT,
+      SelectionDAG &DAG, SDValue LL, SDValue LH) const;
 };
 
 /// Given an LLVM IR type and return type attributes, compute the return value
diff --git a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
index e6aa222425d13..c7700923a0dc5 100644
--- a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
@@ -8106,44 +8106,17 @@ bool TargetLowering::expandMUL(SDNode *N, SDValue &Lo, SDValue &Hi, EVT HiLoVT,
 // dividend and multiply by the multiplicative inverse of the shifted divisor.
 // If we want the remainder, we shift the value left by the number of trailing
 // zeros and add the bits that were shifted out of the dividend.
-bool TargetLowering::expandDIVREMByConstant(SDNode *N,
-                                            SmallVectorImpl<SDValue> &Result,
-                                            EVT HiLoVT, SelectionDAG &DAG,
-                                            SDValue LL, SDValue LH) const {
+bool TargetLowering::expandUDIVREMByConstantViaUREMDecomposition(
+    SDNode *N, APInt Divisor, SmallVectorImpl<SDValue> &Result, EVT HiLoVT,
+    SelectionDAG &DAG, SDValue LL, SDValue LH) const {
   unsigned Opcode = N->getOpcode();
   EVT VT = N->getValueType(0);
 
-  // TODO: Support signed division/remainder.
-  if (Opcode == ISD::SREM || Opcode == ISD::SDIV || Opcode == ISD::SDIVREM)
-    return false;
-  assert(
-      (Opcode == ISD::UREM || Opcode == ISD::UDIV || Opcode == ISD::UDIVREM) &&
-      "Unexpected opcode");
-
-  auto *CN = dyn_cast<ConstantSDNode>(N->getOperand(1));
-  if (!CN)
-    return false;
-
-  APInt Divisor = CN->getAPIntValue();
   unsigned BitWidth = Divisor.getBitWidth();
   unsigned HBitWidth = BitWidth / 2;
   assert(VT.getScalarSizeInBits() == BitWidth &&
          HiLoVT.getScalarSizeInBits() == HBitWidth && "Unexpected VTs");
 
-  // We depend on the UREM by constant optimization in DAGCombiner that requires
-  // high multiply.
-  if (!isOperationLegalOrCustom(ISD::MULHU, HiLoVT) &&
-      !isOperationLegalOrCustom(ISD::UMUL_LOHI, HiLoVT))
-    return false;
-
-  // Don't expand if optimizing for size.
-  if (DAG.shouldOptForSize())
-    return false;
-
-  // Early out for 0 or 1 divisors.
-  if (Divisor.ule(1))
-    return false;
-
   // If the divisor is even, shift it until it becomes odd.
   unsigned TrailingZeros = 0;
   if (!Divisor[0]) {
@@ -8398,6 +8371,46 @@ bool TargetLowering::expandDIVREMByConstant(SDNode *N,
   return true;
 }
 
+bool TargetLowering::expandDIVREMByConstant(SDNode *N,
+                                            SmallVectorImpl<SDValue> &Result,
+                                            EVT HiLoVT, SelectionDAG &DAG,
+                                            SDValue LL, SDValue LH) const {
+  unsigned Opcode = N->getOpcode();
+
+  // TODO: Support signed division/remainder.
+  if (Opcode == ISD::SREM || Opcode == ISD::SDIV || Opcode == ISD::SDIVREM)
+    return false;
+  assert(
+      (Opcode == ISD::UREM || Opcode == ISD::UDIV || Opcode == ISD::UDIVREM) &&
+      "Unexpected opcode");
+
+  auto *CN = dyn_cast<ConstantSDNode>(N->getOperand(1));
+  if (!CN)
+    return false;
+
+  APInt Divisor = CN->getAPIntValue();
+
+  // We depend on the UREM by constant optimization in DAGCombiner that requires
+  // high multiply.
+  if (!isOperationLegalOrCustom(ISD::MULHU, HiLoVT) &&
+      !isOperationLegalOrCustom(ISD::UMUL_LOHI, HiLoVT))
+    return false;
+
+  // Don't expand if optimizing for size.
+  if (DAG.shouldOptForSize())
+    return false;
+
+  // Early out for 0 or 1 divisors.
+  if (Divisor.ule(1))
+    return false;
+
+  if (expandUDIVREMByConstantViaUREMDecomposition(N, Divisor, Result, HiLoVT,
+                                                  DAG, LL, LH))
+    return true;
+
+  return false;
+}
+
 // Check that (every element of) Z is undef or not an exact multiple of BW.
 static bool isNonZeroModBitWidthOrUndef(SDValue Z, unsigned BW) {
   return ISD::matchUnaryPredicate(

>From 8887864cd33f68f3f9f6c35271e7efa2ed431c9a Mon Sep 17 00:00:00 2001
From: Marius Kamp <msk at posteo.org>
Date: Tue, 12 Aug 2025 16:49:49 +0200
Subject: [PATCH 4/5] [SelectionDAG] Use Magic Algorithm for Splitting
 UDIV/UREM by Constant

For integer types twice as large as a legal type, we have previously
generated a library call if another splitting technique was not
applicable.

With this change, we use an adaption of the Magic algorithm. This
algorithm is also used for UDIV/UREM by constants on legal types. The
implementation introduced here is a simple port of the already existing
implementation to types twice the size of a legal type. The core idea of
this algorithm is to replace (udiv x c) for a constant c with the bits
higher or equal to the s-th bit of the multiplication of x by (2^s + o)/c
for some s and o. More details are available in Henry S. Warren, Jr.:
"Hacker's Delight", chapter 10.

An efficient handling of UDIV/UREM by constants on types twice as large
as a legal type is mostly relevant for 32-bit platforms. But some
projects may also benefit on 64-bit platforms. For example, the `fmt`
library for C++ uses 128-bit unsigned divisions by 100 and 10000, which
have not been covered by the previously existing optimizations.

Closes #137514.
---
 llvm/include/llvm/CodeGen/TargetLowering.h    |   5 +
 .../CodeGen/SelectionDAG/TargetLowering.cpp   | 112 ++++
 llvm/test/CodeGen/RISCV/urem-vector-lkk.ll    | 194 ++++---
 llvm/test/CodeGen/X86/divide-by-constant.ll   | 422 +++++++++++---
 llvm/test/CodeGen/X86/divmod128.ll            | 545 +++++++++++++-----
 llvm/test/CodeGen/X86/i128-udiv.ll            |  30 +-
 6 files changed, 1030 insertions(+), 278 deletions(-)

diff --git a/llvm/include/llvm/CodeGen/TargetLowering.h b/llvm/include/llvm/CodeGen/TargetLowering.h
index 430c01f82d736..429cf94f18469 100644
--- a/llvm/include/llvm/CodeGen/TargetLowering.h
+++ b/llvm/include/llvm/CodeGen/TargetLowering.h
@@ -6029,6 +6029,11 @@ class LLVM_ABI TargetLowering : public TargetLoweringBase {
   bool expandUDIVREMByConstantViaUREMDecomposition(
       SDNode *N, APInt Divisor, SmallVectorImpl<SDValue> &Result, EVT HiLoVT,
       SelectionDAG &DAG, SDValue LL, SDValue LH) const;
+
+  bool expandUDIVREMByConstantViaUMulHiMagic(SDNode *N, const APInt &Divisor,
+                                             SmallVectorImpl<SDValue> &Result,
+                                             EVT HiLoVT, SelectionDAG &DAG,
+                                             SDValue LL, SDValue LH) const;
 };
 
 /// Given an LLVM IR type and return type attributes, compute the return value
diff --git a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
index c7700923a0dc5..ae67aa93effbc 100644
--- a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
@@ -8371,6 +8371,114 @@ bool TargetLowering::expandUDIVREMByConstantViaUREMDecomposition(
   return true;
 }
 
+bool TargetLowering::expandUDIVREMByConstantViaUMulHiMagic(
+    SDNode *N, const APInt &Divisor, SmallVectorImpl<SDValue> &Result,
+    EVT HiLoVT, SelectionDAG &DAG, SDValue LL, SDValue LH) const {
+
+  SDValue N0 = N->getOperand(0);
+  EVT VT = N0->getValueType(0);
+  SDLoc DL{N};
+
+  assert(!Divisor.isOne() && "Magic algorithm does not work for division by 1");
+
+  // This helper creates a MUL_LOHI of the pair (LL, LH) by a constant.
+  auto MakeMUL_LOHIByConst = [&](unsigned Opc, SDValue LL, SDValue LH,
+                                 const APInt &Const,
+                                 SmallVectorImpl<SDValue> &Result) {
+    SDValue LHS = DAG.getNode(ISD::BUILD_PAIR, DL, VT, LL, LH);
+    SDValue RHS = DAG.getConstant(Const, DL, VT);
+    auto [RL, RH] = DAG.SplitScalar(RHS, DL, HiLoVT, HiLoVT);
+    return expandMUL_LOHI(Opc, VT, DL, LHS, RHS, Result, HiLoVT, DAG,
+                          TargetLowering::MulExpansionKind::OnlyLegalOrCustom,
+                          LL, LH, RL, RH);
+  };
+
+  // This helper creates an ADD/SUB of the pairs (LL, LH) and (RL, RH).
+  auto MakeAddSubLong = [&](unsigned Opc, SDValue LL, SDValue LH, SDValue RL,
+                            SDValue RH) {
+    SDValue AddSubNode =
+        DAG.getNode(Opc == ISD::ADD ? ISD::UADDO : ISD::USUBO, DL,
+                    DAG.getVTList(HiLoVT, MVT::i1), LL, RL);
+    SDValue OutL = AddSubNode.getValue(0);
+    SDValue Overflow = AddSubNode.getValue(1);
+    SDValue AddSubWithOverflow =
+        DAG.getNode(Opc == ISD::ADD ? ISD::UADDO_CARRY : ISD::USUBO_CARRY, DL,
+                    DAG.getVTList(HiLoVT, MVT::i1), LH, RH, Overflow);
+    SDValue OutH = AddSubWithOverflow.getValue(0);
+    return std::make_pair(OutL, OutH);
+  };
+
+  // This helper creates a SRL of the pair (LL, LH) by Shift.
+  auto MakeSRLLong = [&](SDValue LL, SDValue LH, unsigned Shift) {
+    unsigned HBitWidth = HiLoVT.getScalarSizeInBits();
+    if (Shift < HBitWidth) {
+      SDValue ShAmt = DAG.getShiftAmountConstant(Shift, HiLoVT, DL);
+      SDValue ResL = DAG.getNode(ISD::FSHR, DL, HiLoVT, LH, LL, ShAmt);
+      SDValue ResH = DAG.getNode(ISD::SRL, DL, HiLoVT, LH, ShAmt);
+      return std::make_pair(ResL, ResH);
+    }
+    SDValue Zero = DAG.getConstant(0, DL, HiLoVT);
+    if (Shift == HBitWidth)
+      return std::make_pair(LH, Zero);
+    assert(Shift - HBitWidth < HBitWidth &&
+           "We shouldn't generate an undefined shift");
+    SDValue ShAmt = DAG.getShiftAmountConstant(Shift - HBitWidth, HiLoVT, DL);
+    return std::make_pair(DAG.getNode(ISD::SRL, DL, HiLoVT, LH, ShAmt), Zero);
+  };
+
+  // Knowledge of leading zeros may help to reduce the multiplier.
+  unsigned KnownLeadingZeros = DAG.computeKnownBits(N0).countMinLeadingZeros();
+
+  UnsignedDivisionByConstantInfo Magics = UnsignedDivisionByConstantInfo::get(
+      Divisor, std::min(KnownLeadingZeros, Divisor.countl_zero()));
+
+  assert(!LL == !LH && "Expected both input halves or no input halves!");
+  if (!LL)
+    std::tie(LL, LH) = DAG.SplitScalar(N0, DL, HiLoVT, HiLoVT);
+  SDValue QL = LL;
+  SDValue QH = LH;
+  if (Magics.PreShift != 0)
+    std::tie(QL, QH) = MakeSRLLong(QL, QH, Magics.PreShift);
+
+  SmallVector<SDValue, 4> UMulResult;
+  if (!MakeMUL_LOHIByConst(ISD::UMUL_LOHI, QL, QH, Magics.Magic, UMulResult))
+    return false;
+
+  QL = UMulResult[2];
+  QH = UMulResult[3];
+
+  if (Magics.IsAdd) {
+    auto [NPQL, NPQH] = MakeAddSubLong(ISD::SUB, LL, LH, QL, QH);
+    std::tie(NPQL, NPQH) = MakeSRLLong(NPQL, NPQH, 1);
+    std::tie(QL, QH) = MakeAddSubLong(ISD::ADD, NPQL, NPQH, QL, QH);
+  }
+
+  if (Magics.PostShift != 0)
+    std::tie(QL, QH) = MakeSRLLong(QL, QH, Magics.PostShift);
+
+  unsigned Opcode = N->getOpcode();
+  if (Opcode != ISD::UREM) {
+    Result.push_back(QL);
+    Result.push_back(QH);
+  }
+
+  if (Opcode != ISD::UDIV) {
+    SmallVector<SDValue, 2> MulResult;
+    if (!MakeMUL_LOHIByConst(ISD::MUL, QL, QH, Divisor, MulResult))
+      return false;
+
+    assert(MulResult.size() == 2);
+
+    auto [RemL, RemH] =
+        MakeAddSubLong(ISD::SUB, LL, LH, MulResult[0], MulResult[1]);
+
+    Result.push_back(RemL);
+    Result.push_back(RemH);
+  }
+
+  return true;
+}
+
 bool TargetLowering::expandDIVREMByConstant(SDNode *N,
                                             SmallVectorImpl<SDValue> &Result,
                                             EVT HiLoVT, SelectionDAG &DAG,
@@ -8408,6 +8516,10 @@ bool TargetLowering::expandDIVREMByConstant(SDNode *N,
                                                   DAG, LL, LH))
     return true;
 
+  if (expandUDIVREMByConstantViaUMulHiMagic(N, Divisor, Result, HiLoVT, DAG, LL,
+                                            LH))
+    return true;
+
   return false;
 }
 
diff --git a/llvm/test/CodeGen/RISCV/urem-vector-lkk.ll b/llvm/test/CodeGen/RISCV/urem-vector-lkk.ll
index ce3e2c1a4f7be..bb28336c15c3b 100644
--- a/llvm/test/CodeGen/RISCV/urem-vector-lkk.ll
+++ b/llvm/test/CodeGen/RISCV/urem-vector-lkk.ll
@@ -851,78 +851,142 @@ define <4 x i64> @fold_urem_i64(<4 x i64> %x) nounwind {
 ;
 ; RV32IM-LABEL: fold_urem_i64:
 ; RV32IM:       # %bb.0:
-; RV32IM-NEXT:    addi sp, sp, -48
-; RV32IM-NEXT:    sw ra, 44(sp) # 4-byte Folded Spill
-; RV32IM-NEXT:    sw s0, 40(sp) # 4-byte Folded Spill
-; RV32IM-NEXT:    sw s1, 36(sp) # 4-byte Folded Spill
-; RV32IM-NEXT:    sw s2, 32(sp) # 4-byte Folded Spill
-; RV32IM-NEXT:    sw s3, 28(sp) # 4-byte Folded Spill
-; RV32IM-NEXT:    sw s4, 24(sp) # 4-byte Folded Spill
-; RV32IM-NEXT:    sw s5, 20(sp) # 4-byte Folded Spill
-; RV32IM-NEXT:    sw s6, 16(sp) # 4-byte Folded Spill
-; RV32IM-NEXT:    sw s7, 12(sp) # 4-byte Folded Spill
+; RV32IM-NEXT:    addi sp, sp, -32
+; RV32IM-NEXT:    sw ra, 28(sp) # 4-byte Folded Spill
+; RV32IM-NEXT:    sw s0, 24(sp) # 4-byte Folded Spill
+; RV32IM-NEXT:    sw s1, 20(sp) # 4-byte Folded Spill
+; RV32IM-NEXT:    sw s2, 16(sp) # 4-byte Folded Spill
+; RV32IM-NEXT:    sw s3, 12(sp) # 4-byte Folded Spill
+; RV32IM-NEXT:    sw s4, 8(sp) # 4-byte Folded Spill
+; RV32IM-NEXT:    sw s5, 4(sp) # 4-byte Folded Spill
+; RV32IM-NEXT:    mv a2, a1
 ; RV32IM-NEXT:    mv s0, a0
-; RV32IM-NEXT:    lw a2, 16(a1)
-; RV32IM-NEXT:    lw a4, 20(a1)
-; RV32IM-NEXT:    lw s1, 24(a1)
-; RV32IM-NEXT:    lw s2, 28(a1)
+; RV32IM-NEXT:    lw a7, 16(a1)
+; RV32IM-NEXT:    lw a6, 20(a1)
+; RV32IM-NEXT:    lw a3, 24(a1)
+; RV32IM-NEXT:    lw a5, 28(a1)
 ; RV32IM-NEXT:    lw a0, 0(a1)
-; RV32IM-NEXT:    lw a3, 4(a1)
-; RV32IM-NEXT:    lw s3, 8(a1)
-; RV32IM-NEXT:    lw s4, 12(a1)
-; RV32IM-NEXT:    lui a1, 1024
-; RV32IM-NEXT:    slli a5, a4, 10
-; RV32IM-NEXT:    srli a6, a2, 22
-; RV32IM-NEXT:    or a5, a6, a5
-; RV32IM-NEXT:    lui a6, 45590
-; RV32IM-NEXT:    addi a1, a1, -1
-; RV32IM-NEXT:    addi a6, a6, 1069
-; RV32IM-NEXT:    and a2, a2, a1
-; RV32IM-NEXT:    srli a4, a4, 12
-; RV32IM-NEXT:    add a2, a2, a4
-; RV32IM-NEXT:    and a1, a5, a1
-; RV32IM-NEXT:    add a1, a2, a1
-; RV32IM-NEXT:    mulhu a2, a1, a6
-; RV32IM-NEXT:    li a4, 23
-; RV32IM-NEXT:    mul a2, a2, a4
-; RV32IM-NEXT:    sub s7, a1, a2
+; RV32IM-NEXT:    lw a1, 4(a1)
+; RV32IM-NEXT:    lw a4, 8(a2)
+; RV32IM-NEXT:    lw a2, 12(a2)
+; RV32IM-NEXT:    lui t0, 410452
+; RV32IM-NEXT:    lui t1, 25653
+; RV32IM-NEXT:    lui t2, 791991
+; RV32IM-NEXT:    lui t3, 834723
+; RV32IM-NEXT:    lui t4, 1024
+; RV32IM-NEXT:    addi t0, t0, -952
+; RV32IM-NEXT:    addi t1, t1, 965
+; RV32IM-NEXT:    addi t2, t2, 77
+; RV32IM-NEXT:    addi t3, t3, -179
+; RV32IM-NEXT:    addi t4, t4, -1
+; RV32IM-NEXT:    srli t5, a4, 1
+; RV32IM-NEXT:    slli t6, a2, 31
+; RV32IM-NEXT:    srli s1, a2, 1
+; RV32IM-NEXT:    mul s2, a3, t2
+; RV32IM-NEXT:    and s3, a7, t4
+; RV32IM-NEXT:    slli s4, a6, 10
+; RV32IM-NEXT:    srli a7, a7, 22
+; RV32IM-NEXT:    srli a6, a6, 12
+; RV32IM-NEXT:    or t5, t6, t5
+; RV32IM-NEXT:    mul t6, s1, t1
+; RV32IM-NEXT:    mulhu s5, s1, t1
+; RV32IM-NEXT:    or a7, a7, s4
+; RV32IM-NEXT:    mul s4, s1, t0
+; RV32IM-NEXT:    mulhu s1, s1, t0
+; RV32IM-NEXT:    add a6, s3, a6
+; RV32IM-NEXT:    mul s3, t5, t0
+; RV32IM-NEXT:    mulhu t1, t5, t1
+; RV32IM-NEXT:    mulhu t0, t5, t0
+; RV32IM-NEXT:    mulhu t5, a3, t3
+; RV32IM-NEXT:    and a7, a7, t4
+; RV32IM-NEXT:    mul t4, a5, t3
+; RV32IM-NEXT:    add s2, t5, s2
+; RV32IM-NEXT:    add t4, s2, t4
+; RV32IM-NEXT:    sltu t5, s2, t5
+; RV32IM-NEXT:    sltu t4, t4, s2
+; RV32IM-NEXT:    mulhu s2, a3, t2
+; RV32IM-NEXT:    add t5, s2, t5
+; RV32IM-NEXT:    add a6, a6, a7
+; RV32IM-NEXT:    add s3, t1, s3
+; RV32IM-NEXT:    add t6, s3, t6
+; RV32IM-NEXT:    sltu a7, s3, t1
+; RV32IM-NEXT:    sltu t1, t6, s3
+; RV32IM-NEXT:    lui t6, 45590
+; RV32IM-NEXT:    add a7, t0, a7
+; RV32IM-NEXT:    li t0, 23
+; RV32IM-NEXT:    addi t6, t6, 1069
+; RV32IM-NEXT:    mulhu t3, a5, t3
+; RV32IM-NEXT:    add t3, t5, t3
+; RV32IM-NEXT:    mulhu t6, a6, t6
+; RV32IM-NEXT:    sltu t5, t3, t5
+; RV32IM-NEXT:    add t3, t3, t4
+; RV32IM-NEXT:    mul t0, t6, t0
+; RV32IM-NEXT:    seqz t6, t3
+; RV32IM-NEXT:    and t4, t6, t4
+; RV32IM-NEXT:    or t4, t5, t4
+; RV32IM-NEXT:    mul t5, a5, t2
+; RV32IM-NEXT:    mulhu t2, a5, t2
+; RV32IM-NEXT:    add s5, a7, s5
+; RV32IM-NEXT:    add t5, t3, t5
+; RV32IM-NEXT:    sltu a7, s5, a7
+; RV32IM-NEXT:    add s5, s5, t1
+; RV32IM-NEXT:    sltu t3, t5, t3
+; RV32IM-NEXT:    add t2, t3, t2
+; RV32IM-NEXT:    seqz t3, s5
+; RV32IM-NEXT:    and t1, t3, t1
+; RV32IM-NEXT:    add t2, t2, t4
+; RV32IM-NEXT:    or a7, a7, t1
+; RV32IM-NEXT:    li t1, 654
+; RV32IM-NEXT:    add s4, s5, s4
+; RV32IM-NEXT:    sltu t3, s4, s5
+; RV32IM-NEXT:    add t3, t3, s1
+; RV32IM-NEXT:    lui t4, 1
+; RV32IM-NEXT:    addi t4, t4, 1327
+; RV32IM-NEXT:    srli t5, t5, 12
+; RV32IM-NEXT:    srli t6, s4, 7
+; RV32IM-NEXT:    add a7, t3, a7
+; RV32IM-NEXT:    srli t3, t2, 12
+; RV32IM-NEXT:    slli t2, t2, 20
+; RV32IM-NEXT:    mul t3, t3, t4
+; RV32IM-NEXT:    or t2, t2, t5
+; RV32IM-NEXT:    srli t5, a7, 7
+; RV32IM-NEXT:    slli a7, a7, 25
+; RV32IM-NEXT:    sub a5, a5, t3
+; RV32IM-NEXT:    mulhu t3, t2, t4
+; RV32IM-NEXT:    mul t2, t2, t4
+; RV32IM-NEXT:    mul t4, t5, t1
+; RV32IM-NEXT:    or a7, a7, t6
+; RV32IM-NEXT:    sub a5, a5, t3
+; RV32IM-NEXT:    sub s1, a3, t2
+; RV32IM-NEXT:    mulhu t2, a7, t1
+; RV32IM-NEXT:    sub a2, a2, t4
+; RV32IM-NEXT:    mul a7, a7, t1
+; RV32IM-NEXT:    sltu a3, a3, s1
+; RV32IM-NEXT:    sub a2, a2, t2
+; RV32IM-NEXT:    sub s2, a4, a7
+; RV32IM-NEXT:    sub s3, a5, a3
+; RV32IM-NEXT:    sltu a3, a4, s2
+; RV32IM-NEXT:    sub s4, a2, a3
+; RV32IM-NEXT:    sub s5, a6, t0
 ; RV32IM-NEXT:    li a2, 1
-; RV32IM-NEXT:    mv a1, a3
-; RV32IM-NEXT:    li a3, 0
-; RV32IM-NEXT:    call __umoddi3
-; RV32IM-NEXT:    mv s5, a0
-; RV32IM-NEXT:    mv s6, a1
-; RV32IM-NEXT:    li a2, 654
-; RV32IM-NEXT:    mv a0, s3
-; RV32IM-NEXT:    mv a1, s4
-; RV32IM-NEXT:    li a3, 0
-; RV32IM-NEXT:    call __umoddi3
-; RV32IM-NEXT:    mv s3, a0
-; RV32IM-NEXT:    mv s4, a1
-; RV32IM-NEXT:    lui a2, 1
-; RV32IM-NEXT:    addi a2, a2, 1327
-; RV32IM-NEXT:    mv a0, s1
-; RV32IM-NEXT:    mv a1, s2
 ; RV32IM-NEXT:    li a3, 0
 ; RV32IM-NEXT:    call __umoddi3
-; RV32IM-NEXT:    sw s7, 16(s0)
+; RV32IM-NEXT:    sw s5, 16(s0)
 ; RV32IM-NEXT:    sw zero, 20(s0)
-; RV32IM-NEXT:    sw a0, 24(s0)
-; RV32IM-NEXT:    sw a1, 28(s0)
-; RV32IM-NEXT:    sw s5, 0(s0)
-; RV32IM-NEXT:    sw s6, 4(s0)
-; RV32IM-NEXT:    sw s3, 8(s0)
+; RV32IM-NEXT:    sw s1, 24(s0)
+; RV32IM-NEXT:    sw s3, 28(s0)
+; RV32IM-NEXT:    sw a0, 0(s0)
+; RV32IM-NEXT:    sw a1, 4(s0)
+; RV32IM-NEXT:    sw s2, 8(s0)
 ; RV32IM-NEXT:    sw s4, 12(s0)
-; RV32IM-NEXT:    lw ra, 44(sp) # 4-byte Folded Reload
-; RV32IM-NEXT:    lw s0, 40(sp) # 4-byte Folded Reload
-; RV32IM-NEXT:    lw s1, 36(sp) # 4-byte Folded Reload
-; RV32IM-NEXT:    lw s2, 32(sp) # 4-byte Folded Reload
-; RV32IM-NEXT:    lw s3, 28(sp) # 4-byte Folded Reload
-; RV32IM-NEXT:    lw s4, 24(sp) # 4-byte Folded Reload
-; RV32IM-NEXT:    lw s5, 20(sp) # 4-byte Folded Reload
-; RV32IM-NEXT:    lw s6, 16(sp) # 4-byte Folded Reload
-; RV32IM-NEXT:    lw s7, 12(sp) # 4-byte Folded Reload
-; RV32IM-NEXT:    addi sp, sp, 48
+; RV32IM-NEXT:    lw ra, 28(sp) # 4-byte Folded Reload
+; RV32IM-NEXT:    lw s0, 24(sp) # 4-byte Folded Reload
+; RV32IM-NEXT:    lw s1, 20(sp) # 4-byte Folded Reload
+; RV32IM-NEXT:    lw s2, 16(sp) # 4-byte Folded Reload
+; RV32IM-NEXT:    lw s3, 12(sp) # 4-byte Folded Reload
+; RV32IM-NEXT:    lw s4, 8(sp) # 4-byte Folded Reload
+; RV32IM-NEXT:    lw s5, 4(sp) # 4-byte Folded Reload
+; RV32IM-NEXT:    addi sp, sp, 32
 ; RV32IM-NEXT:    ret
 ;
 ; RV64I-LABEL: fold_urem_i64:
diff --git a/llvm/test/CodeGen/X86/divide-by-constant.ll b/llvm/test/CodeGen/X86/divide-by-constant.ll
index 3558da9ac9879..d9e19df39f6b6 100644
--- a/llvm/test/CodeGen/X86/divide-by-constant.ll
+++ b/llvm/test/CodeGen/X86/divide-by-constant.ll
@@ -294,25 +294,55 @@ entry:
 define i64 @PR23590(i64 %x) nounwind {
 ; X86-LABEL: PR23590:
 ; X86:       # %bb.0: # %entry
+; X86-NEXT:    pushl %ebp
+; X86-NEXT:    pushl %ebx
 ; X86-NEXT:    pushl %edi
 ; X86-NEXT:    pushl %esi
 ; X86-NEXT:    pushl %eax
-; X86-NEXT:    pushl $0
-; X86-NEXT:    pushl $12345 # imm = 0x3039
-; X86-NEXT:    pushl {{[0-9]+}}(%esp)
-; X86-NEXT:    pushl {{[0-9]+}}(%esp)
-; X86-NEXT:    calll __umoddi3
-; X86-NEXT:    addl $16, %esp
-; X86-NEXT:    movl %eax, %esi
-; X86-NEXT:    movl %edx, %ecx
+; X86-NEXT:    movl {{[0-9]+}}(%esp), %esi
+; X86-NEXT:    movl {{[0-9]+}}(%esp), %ecx
+; X86-NEXT:    movl $1425045447, %edx # imm = 0x54F077C7
+; X86-NEXT:    movl %esi, %eax
+; X86-NEXT:    mull %edx
+; X86-NEXT:    movl %eax, %ebx
+; X86-NEXT:    movl %edx, %edi
+; X86-NEXT:    movl $417841695, %edx # imm = 0x18E7C21F
+; X86-NEXT:    movl %esi, %eax
+; X86-NEXT:    mull %edx
+; X86-NEXT:    movl %edx, %ebp
+; X86-NEXT:    addl %ebx, %ebp
+; X86-NEXT:    adcl $0, %edi
+; X86-NEXT:    movl %ecx, %eax
+; X86-NEXT:    movl $1425045447, %edx # imm = 0x54F077C7
+; X86-NEXT:    mull %edx
+; X86-NEXT:    movl %edx, %ebx
+; X86-NEXT:    movl %eax, (%esp) # 4-byte Spill
+; X86-NEXT:    movl %ecx, %eax
+; X86-NEXT:    movl $417841695, %edx # imm = 0x18E7C21F
+; X86-NEXT:    mull %edx
+; X86-NEXT:    addl %ebp, %eax
+; X86-NEXT:    adcl %edx, %edi
+; X86-NEXT:    adcl $0, %ebx
+; X86-NEXT:    addl (%esp), %edi # 4-byte Folded Reload
+; X86-NEXT:    adcl $0, %ebx
+; X86-NEXT:    shrdl $12, %ebx, %edi
+; X86-NEXT:    movl $12345, %edx # imm = 0x3039
+; X86-NEXT:    movl %edi, %eax
+; X86-NEXT:    mull %edx
+; X86-NEXT:    shrl $12, %ebx
+; X86-NEXT:    imull $12345, %ebx, %edi # imm = 0x3039
+; X86-NEXT:    addl %edx, %edi
+; X86-NEXT:    subl %eax, %esi
+; X86-NEXT:    sbbl %edi, %ecx
+; X86-NEXT:    movl %esi, %eax
+; X86-NEXT:    shrdl $30, %ecx, %eax
 ; X86-NEXT:    andl $1073741823, %eax # imm = 0x3FFFFFFF
 ; X86-NEXT:    movl %esi, %edx
-; X86-NEXT:    shrdl $30, %ecx, %edx
 ; X86-NEXT:    andl $1073741823, %edx # imm = 0x3FFFFFFF
 ; X86-NEXT:    movl %ecx, %edi
 ; X86-NEXT:    shrl $28, %edi
-; X86-NEXT:    addl %eax, %edi
 ; X86-NEXT:    addl %edx, %edi
+; X86-NEXT:    addl %eax, %edi
 ; X86-NEXT:    movl $613566757, %edx # imm = 0x24924925
 ; X86-NEXT:    movl %edi, %eax
 ; X86-NEXT:    mull %edx
@@ -336,6 +366,8 @@ define i64 @PR23590(i64 %x) nounwind {
 ; X86-NEXT:    addl $4, %esp
 ; X86-NEXT:    popl %esi
 ; X86-NEXT:    popl %edi
+; X86-NEXT:    popl %ebx
+; X86-NEXT:    popl %ebp
 ; X86-NEXT:    retl
 ;
 ; X64-FAST-LABEL: PR23590:
@@ -376,27 +408,43 @@ define { i64, i32 } @PR38622(i64) nounwind {
 ; 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:    pushl $0
-; X86-NEXT:    pushl $-294967296 # imm = 0xEE6B2800
-; X86-NEXT:    pushl %ebp
-; X86-NEXT:    pushl %ebx
-; X86-NEXT:    calll __udivdi3
-; 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 __umoddi3
-; X86-NEXT:    addl $16, %esp
-; X86-NEXT:    movl %eax, %ecx
+; 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 $1125899, %edx # imm = 0x112E0B
+; X86-NEXT:    movl %ebx, %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:    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:    movl $1125899, %edx # imm = 0x112E0B
+; X86-NEXT:    mull %edx
+; X86-NEXT:    movl %edx, %ebx
+; X86-NEXT:    movl %eax, (%esp) # 4-byte Spill
+; X86-NEXT:    movl %edi, %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:    addl (%esp), %esi # 4-byte Folded Reload
+; X86-NEXT:    adcl $0, %ebx
+; X86-NEXT:    shrdl $9, %ebx, %esi
+; X86-NEXT:    imull $-294967296, %esi, %eax # imm = 0xEE6B2800
+; X86-NEXT:    subl %eax, %ecx
+; X86-NEXT:    shrl $9, %ebx
 ; X86-NEXT:    movl %esi, %eax
-; X86-NEXT:    movl %edi, %edx
-; X86-NEXT:    addl $12, %esp
+; X86-NEXT:    movl %ebx, %edx
+; X86-NEXT:    addl $4, %esp
 ; X86-NEXT:    popl %esi
 ; X86-NEXT:    popl %edi
 ; X86-NEXT:    popl %ebx
@@ -1194,13 +1242,41 @@ entry:
 define i64 @udiv_i64_magic_large_postshift(i64 %x) nounwind {
 ; X86-LABEL: udiv_i64_magic_large_postshift:
 ; X86:       # %bb.0:
-; X86-NEXT:    subl $12, %esp
-; X86-NEXT:    pushl $-1073741825 # imm = 0xBFFFFFFF
-; X86-NEXT:    pushl $-2
-; X86-NEXT:    pushl {{[0-9]+}}(%esp)
-; X86-NEXT:    pushl {{[0-9]+}}(%esp)
-; X86-NEXT:    calll __udivdi3
-; X86-NEXT:    addl $28, %esp
+; X86-NEXT:    pushl %ebp
+; X86-NEXT:    pushl %ebx
+; X86-NEXT:    pushl %edi
+; X86-NEXT:    pushl %esi
+; X86-NEXT:    movl {{[0-9]+}}(%esp), %edi
+; X86-NEXT:    movl $-1431655766, %ecx # imm = 0xAAAAAAAA
+; X86-NEXT:    movl %edi, %eax
+; X86-NEXT:    mull %ecx
+; X86-NEXT:    movl %eax, %ebp
+; X86-NEXT:    movl %edx, %ecx
+; X86-NEXT:    movl $-1431655763, %esi # imm = 0xAAAAAAAD
+; X86-NEXT:    movl %edi, %eax
+; X86-NEXT:    mull %esi
+; X86-NEXT:    movl %edx, %ebx
+; X86-NEXT:    addl %ebp, %ebx
+; X86-NEXT:    adcl $0, %ecx
+; X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
+; X86-NEXT:    movl $-1431655766, %edx # imm = 0xAAAAAAAA
+; X86-NEXT:    mull %edx
+; X86-NEXT:    movl %edx, %edi
+; X86-NEXT:    movl %eax, %ebp
+; X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
+; X86-NEXT:    mull %esi
+; X86-NEXT:    addl %ebx, %eax
+; X86-NEXT:    adcl %ecx, %edx
+; X86-NEXT:    adcl $0, %edi
+; X86-NEXT:    addl %ebp, %edx
+; X86-NEXT:    adcl $0, %edi
+; X86-NEXT:    shrl $31, %edi
+; X86-NEXT:    movl %edi, %eax
+; X86-NEXT:    xorl %edx, %edx
+; X86-NEXT:    popl %esi
+; X86-NEXT:    popl %edi
+; X86-NEXT:    popl %ebx
+; X86-NEXT:    popl %ebp
 ; X86-NEXT:    retl
 ;
 ; X64-LABEL: udiv_i64_magic_large_postshift:
@@ -1219,13 +1295,53 @@ define i64 @udiv_i64_magic_large_postshift(i64 %x) nounwind {
 define i64 @urem_i64_magic_large_postshift(i64 %x) nounwind {
 ; X86-LABEL: urem_i64_magic_large_postshift:
 ; X86:       # %bb.0:
-; X86-NEXT:    subl $12, %esp
-; X86-NEXT:    pushl $-1073741825 # imm = 0xBFFFFFFF
-; X86-NEXT:    pushl $-2
-; X86-NEXT:    pushl {{[0-9]+}}(%esp)
-; X86-NEXT:    pushl {{[0-9]+}}(%esp)
-; X86-NEXT:    calll __umoddi3
-; X86-NEXT:    addl $28, %esp
+; X86-NEXT:    pushl %ebp
+; X86-NEXT:    pushl %ebx
+; X86-NEXT:    pushl %edi
+; X86-NEXT:    pushl %esi
+; X86-NEXT:    pushl %eax
+; X86-NEXT:    movl {{[0-9]+}}(%esp), %ecx
+; X86-NEXT:    movl {{[0-9]+}}(%esp), %esi
+; X86-NEXT:    movl $-1431655766, %edx # imm = 0xAAAAAAAA
+; X86-NEXT:    movl %ecx, %eax
+; X86-NEXT:    mull %edx
+; X86-NEXT:    movl %eax, %edi
+; X86-NEXT:    movl %edx, %ebx
+; X86-NEXT:    movl $-1431655763, %edx # imm = 0xAAAAAAAD
+; X86-NEXT:    movl %ecx, %eax
+; X86-NEXT:    mull %edx
+; X86-NEXT:    movl %edx, %ebp
+; X86-NEXT:    addl %edi, %ebp
+; X86-NEXT:    adcl $0, %ebx
+; X86-NEXT:    movl %esi, %eax
+; X86-NEXT:    movl $-1431655766, %edx # imm = 0xAAAAAAAA
+; X86-NEXT:    mull %edx
+; X86-NEXT:    movl %edx, %edi
+; X86-NEXT:    movl %eax, (%esp) # 4-byte Spill
+; X86-NEXT:    movl %esi, %eax
+; X86-NEXT:    movl $-1431655763, %edx # imm = 0xAAAAAAAD
+; X86-NEXT:    mull %edx
+; X86-NEXT:    addl %ebp, %eax
+; X86-NEXT:    adcl %ebx, %edx
+; X86-NEXT:    adcl $0, %edi
+; X86-NEXT:    addl (%esp), %edx # 4-byte Folded Reload
+; X86-NEXT:    adcl $0, %edi
+; X86-NEXT:    shrl $31, %edi
+; X86-NEXT:    movl %edi, %eax
+; X86-NEXT:    shll $30, %eax
+; X86-NEXT:    orl %edi, %eax
+; X86-NEXT:    negl %eax
+; X86-NEXT:    addl %edi, %edi
+; X86-NEXT:    negl %edi
+; X86-NEXT:    subl %edi, %ecx
+; X86-NEXT:    sbbl %eax, %esi
+; X86-NEXT:    movl %ecx, %eax
+; X86-NEXT:    movl %esi, %edx
+; X86-NEXT:    addl $4, %esp
+; X86-NEXT:    popl %esi
+; X86-NEXT:    popl %edi
+; X86-NEXT:    popl %ebx
+; X86-NEXT:    popl %ebp
 ; X86-NEXT:    retl
 ;
 ; X64-LABEL: urem_i64_magic_large_postshift:
@@ -1247,13 +1363,45 @@ define i64 @urem_i64_magic_large_postshift(i64 %x) nounwind {
 define i64 @udiv_i64_magic_large_preshift(i64 %x) nounwind {
 ; X86-LABEL: udiv_i64_magic_large_preshift:
 ; X86:       # %bb.0:
-; X86-NEXT:    subl $12, %esp
-; X86-NEXT:    pushl $13
-; X86-NEXT:    pushl $-2
-; X86-NEXT:    pushl {{[0-9]+}}(%esp)
-; X86-NEXT:    pushl {{[0-9]+}}(%esp)
-; X86-NEXT:    calll __udivdi3
-; X86-NEXT:    addl $28, %esp
+; X86-NEXT:    pushl %ebp
+; X86-NEXT:    pushl %ebx
+; X86-NEXT:    pushl %edi
+; X86-NEXT:    pushl %esi
+; X86-NEXT:    movl {{[0-9]+}}(%esp), %edi
+; X86-NEXT:    movl {{[0-9]+}}(%esp), %esi
+; X86-NEXT:    shrdl $1, %esi, %edi
+; X86-NEXT:    movl $-1840700270, %ecx # imm = 0x92492492
+; X86-NEXT:    movl %edi, %eax
+; X86-NEXT:    mull %ecx
+; X86-NEXT:    movl %eax, %ebp
+; X86-NEXT:    movl %edx, %ecx
+; X86-NEXT:    movl $1577743089, %edx # imm = 0x5E0A72F1
+; X86-NEXT:    movl %edi, %eax
+; X86-NEXT:    mull %edx
+; X86-NEXT:    movl %edx, %ebx
+; X86-NEXT:    addl %ebp, %ebx
+; X86-NEXT:    adcl $0, %ecx
+; X86-NEXT:    shrl %esi
+; X86-NEXT:    movl %esi, %eax
+; X86-NEXT:    movl $-1840700270, %edx # imm = 0x92492492
+; X86-NEXT:    mull %edx
+; X86-NEXT:    movl %edx, %edi
+; X86-NEXT:    movl %eax, %ebp
+; X86-NEXT:    movl %esi, %eax
+; X86-NEXT:    movl $1577743089, %edx # imm = 0x5E0A72F1
+; X86-NEXT:    mull %edx
+; X86-NEXT:    addl %ebx, %eax
+; X86-NEXT:    adcl %ecx, %edx
+; X86-NEXT:    adcl $0, %edi
+; X86-NEXT:    addl %ebp, %edx
+; X86-NEXT:    adcl $0, %edi
+; X86-NEXT:    shrl $2, %edi
+; X86-NEXT:    movl %edi, %eax
+; X86-NEXT:    xorl %edx, %edx
+; X86-NEXT:    popl %esi
+; X86-NEXT:    popl %edi
+; X86-NEXT:    popl %ebx
+; X86-NEXT:    popl %ebp
 ; X86-NEXT:    retl
 ;
 ; X64-LABEL: udiv_i64_magic_large_preshift:
@@ -1273,13 +1421,57 @@ define i64 @udiv_i64_magic_large_preshift(i64 %x) nounwind {
 define i64 @urem_i64_magic_large_preshift(i64 %x) nounwind {
 ; X86-LABEL: urem_i64_magic_large_preshift:
 ; X86:       # %bb.0:
-; X86-NEXT:    subl $12, %esp
-; X86-NEXT:    pushl $13
-; X86-NEXT:    pushl $-2
-; X86-NEXT:    pushl {{[0-9]+}}(%esp)
-; X86-NEXT:    pushl {{[0-9]+}}(%esp)
-; X86-NEXT:    calll __umoddi3
-; X86-NEXT:    addl $28, %esp
+; X86-NEXT:    pushl %ebp
+; 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), %ecx
+; X86-NEXT:    shrdl $1, %ecx, %ebx
+; X86-NEXT:    movl $-1840700270, %edx # imm = 0x92492492
+; X86-NEXT:    movl %ebx, %eax
+; X86-NEXT:    mull %edx
+; X86-NEXT:    movl %eax, %esi
+; X86-NEXT:    movl %edx, %edi
+; X86-NEXT:    movl $1577743089, %edx # imm = 0x5E0A72F1
+; X86-NEXT:    movl %ebx, %eax
+; X86-NEXT:    mull %edx
+; X86-NEXT:    movl %edx, %ebp
+; X86-NEXT:    addl %esi, %ebp
+; X86-NEXT:    adcl $0, %edi
+; X86-NEXT:    movl %ecx, %esi
+; X86-NEXT:    shrl %esi
+; X86-NEXT:    movl %esi, %eax
+; X86-NEXT:    movl $-1840700270, %edx # imm = 0x92492492
+; X86-NEXT:    mull %edx
+; X86-NEXT:    movl %edx, %ebx
+; X86-NEXT:    movl %eax, (%esp) # 4-byte Spill
+; X86-NEXT:    movl %esi, %eax
+; X86-NEXT:    movl $1577743089, %edx # imm = 0x5E0A72F1
+; X86-NEXT:    mull %edx
+; X86-NEXT:    addl %ebp, %eax
+; X86-NEXT:    adcl %edi, %edx
+; X86-NEXT:    adcl $0, %ebx
+; X86-NEXT:    addl (%esp), %edx # 4-byte Folded Reload
+; X86-NEXT:    adcl $0, %ebx
+; X86-NEXT:    shrl $2, %ebx
+; X86-NEXT:    leal (%ebx,%ebx,2), %eax
+; X86-NEXT:    leal (%ebx,%eax,4), %esi
+; X86-NEXT:    movl $-2, %edx
+; X86-NEXT:    movl %ebx, %eax
+; X86-NEXT:    mull %edx
+; X86-NEXT:    addl %esi, %edx
+; X86-NEXT:    movl {{[0-9]+}}(%esp), %esi
+; X86-NEXT:    subl %eax, %esi
+; X86-NEXT:    sbbl %edx, %ecx
+; X86-NEXT:    movl %esi, %eax
+; X86-NEXT:    movl %ecx, %edx
+; X86-NEXT:    addl $4, %esp
+; X86-NEXT:    popl %esi
+; X86-NEXT:    popl %edi
+; X86-NEXT:    popl %ebx
+; X86-NEXT:    popl %ebp
 ; X86-NEXT:    retl
 ;
 ; X64-LABEL: urem_i64_magic_large_preshift:
@@ -1302,13 +1494,51 @@ define i64 @urem_i64_magic_large_preshift(i64 %x) nounwind {
 define i64 @udiv_i64_magic_is_add(i64 %x) nounwind {
 ; X86-LABEL: udiv_i64_magic_is_add:
 ; X86:       # %bb.0:
-; X86-NEXT:    subl $12, %esp
-; X86-NEXT:    pushl $196608 # imm = 0x30000
-; X86-NEXT:    pushl $-1
-; X86-NEXT:    pushl {{[0-9]+}}(%esp)
-; X86-NEXT:    pushl {{[0-9]+}}(%esp)
-; X86-NEXT:    calll __udivdi3
-; X86-NEXT:    addl $28, %esp
+; X86-NEXT:    pushl %ebp
+; X86-NEXT:    pushl %ebx
+; X86-NEXT:    pushl %edi
+; X86-NEXT:    pushl %esi
+; X86-NEXT:    pushl %eax
+; X86-NEXT:    movl {{[0-9]+}}(%esp), %esi
+; X86-NEXT:    movl {{[0-9]+}}(%esp), %ecx
+; X86-NEXT:    movl $1431626638, %edx # imm = 0x5554E38E
+; X86-NEXT:    movl %esi, %eax
+; X86-NEXT:    mull %edx
+; X86-NEXT:    movl %eax, %edi
+; X86-NEXT:    movl %edx, %ebx
+; X86-NEXT:    movl $1590754519, %edx # imm = 0x5ED0FCD7
+; X86-NEXT:    movl %esi, %eax
+; X86-NEXT:    mull %edx
+; X86-NEXT:    movl %edx, %ebp
+; X86-NEXT:    addl %edi, %ebp
+; X86-NEXT:    adcl $0, %ebx
+; X86-NEXT:    movl %ecx, %eax
+; X86-NEXT:    movl $1431626638, %edx # imm = 0x5554E38E
+; X86-NEXT:    mull %edx
+; X86-NEXT:    movl %edx, %edi
+; X86-NEXT:    movl %eax, (%esp) # 4-byte Spill
+; X86-NEXT:    movl %ecx, %eax
+; X86-NEXT:    movl $1590754519, %edx # imm = 0x5ED0FCD7
+; X86-NEXT:    mull %edx
+; X86-NEXT:    addl %ebp, %eax
+; X86-NEXT:    adcl %ebx, %edx
+; X86-NEXT:    adcl $0, %edi
+; X86-NEXT:    addl (%esp), %edx # 4-byte Folded Reload
+; X86-NEXT:    adcl $0, %edi
+; X86-NEXT:    subl %edx, %esi
+; X86-NEXT:    sbbl %edi, %ecx
+; X86-NEXT:    shrdl $1, %ecx, %esi
+; X86-NEXT:    shrl %ecx
+; X86-NEXT:    addl %edx, %esi
+; X86-NEXT:    adcl %edi, %ecx
+; X86-NEXT:    shrl $17, %ecx
+; X86-NEXT:    movl %ecx, %eax
+; X86-NEXT:    xorl %edx, %edx
+; X86-NEXT:    addl $4, %esp
+; X86-NEXT:    popl %esi
+; X86-NEXT:    popl %edi
+; X86-NEXT:    popl %ebx
+; X86-NEXT:    popl %ebp
 ; X86-NEXT:    retl
 ;
 ; X64-LABEL: udiv_i64_magic_is_add:
@@ -1329,13 +1559,61 @@ define i64 @udiv_i64_magic_is_add(i64 %x) nounwind {
 define i64 @urem_i64_magic_is_add(i64 %x) nounwind {
 ; X86-LABEL: urem_i64_magic_is_add:
 ; X86:       # %bb.0:
-; X86-NEXT:    subl $12, %esp
-; X86-NEXT:    pushl $196608 # imm = 0x30000
-; X86-NEXT:    pushl $-1
-; X86-NEXT:    pushl {{[0-9]+}}(%esp)
-; X86-NEXT:    pushl {{[0-9]+}}(%esp)
-; X86-NEXT:    calll __umoddi3
-; X86-NEXT:    addl $28, %esp
+; X86-NEXT:    pushl %ebp
+; X86-NEXT:    pushl %ebx
+; X86-NEXT:    pushl %edi
+; X86-NEXT:    pushl %esi
+; X86-NEXT:    pushl %eax
+; X86-NEXT:    movl {{[0-9]+}}(%esp), %ecx
+; X86-NEXT:    movl {{[0-9]+}}(%esp), %esi
+; X86-NEXT:    movl $1431626638, %edx # imm = 0x5554E38E
+; X86-NEXT:    movl %ecx, %eax
+; X86-NEXT:    mull %edx
+; X86-NEXT:    movl %eax, %edi
+; X86-NEXT:    movl %edx, %ebx
+; X86-NEXT:    movl $1590754519, %edx # imm = 0x5ED0FCD7
+; X86-NEXT:    movl %ecx, %eax
+; X86-NEXT:    mull %edx
+; X86-NEXT:    movl %edx, %ebp
+; X86-NEXT:    addl %edi, %ebp
+; X86-NEXT:    adcl $0, %ebx
+; X86-NEXT:    movl %esi, %eax
+; X86-NEXT:    movl $1431626638, %edx # imm = 0x5554E38E
+; X86-NEXT:    mull %edx
+; X86-NEXT:    movl %edx, %edi
+; X86-NEXT:    movl %eax, (%esp) # 4-byte Spill
+; X86-NEXT:    movl %esi, %eax
+; X86-NEXT:    movl $1590754519, %edx # imm = 0x5ED0FCD7
+; X86-NEXT:    mull %edx
+; X86-NEXT:    addl %ebp, %eax
+; X86-NEXT:    adcl %ebx, %edx
+; X86-NEXT:    adcl $0, %edi
+; X86-NEXT:    addl (%esp), %edx # 4-byte Folded Reload
+; X86-NEXT:    adcl $0, %edi
+; X86-NEXT:    movl %ecx, %eax
+; X86-NEXT:    subl %edx, %eax
+; X86-NEXT:    movl %esi, %ebx
+; X86-NEXT:    sbbl %edi, %ebx
+; X86-NEXT:    shrdl $1, %ebx, %eax
+; X86-NEXT:    shrl %ebx
+; X86-NEXT:    addl %edx, %eax
+; X86-NEXT:    adcl %edi, %ebx
+; X86-NEXT:    shrl $17, %ebx
+; X86-NEXT:    movl $-1, %edx
+; X86-NEXT:    movl %ebx, %eax
+; X86-NEXT:    mull %edx
+; X86-NEXT:    shll $16, %ebx
+; X86-NEXT:    leal (%ebx,%ebx,2), %edi
+; X86-NEXT:    orl %edx, %edi
+; X86-NEXT:    subl %eax, %ecx
+; X86-NEXT:    sbbl %edi, %esi
+; X86-NEXT:    movl %ecx, %eax
+; X86-NEXT:    movl %esi, %edx
+; X86-NEXT:    addl $4, %esp
+; X86-NEXT:    popl %esi
+; X86-NEXT:    popl %edi
+; X86-NEXT:    popl %ebx
+; X86-NEXT:    popl %ebp
 ; X86-NEXT:    retl
 ;
 ; X64-LABEL: urem_i64_magic_is_add:
diff --git a/llvm/test/CodeGen/X86/divmod128.ll b/llvm/test/CodeGen/X86/divmod128.ll
index ee9bca86d6ea8..b6d7c6724f394 100644
--- a/llvm/test/CodeGen/X86/divmod128.ll
+++ b/llvm/test/CodeGen/X86/divmod128.ll
@@ -1173,27 +1173,70 @@ entry:
 define i128 @udiv_magic_preshift_and_postshift(i128 %x) nounwind {
 ; X86-64-LABEL: udiv_magic_preshift_and_postshift:
 ; X86-64:       # %bb.0:
-; X86-64-NEXT:    pushq %rax
-; X86-64-NEXT:    movl $358, %edx # imm = 0x166
-; X86-64-NEXT:    xorl %ecx, %ecx
-; X86-64-NEXT:    callq __udivti3 at PLT
-; X86-64-NEXT:    popq %rcx
+; X86-64-NEXT:    shrdq $1, %rsi, %rdi
+; X86-64-NEXT:    movabsq $3297741957311204758, %r9 # imm = 0x2DC3EED6866F8D96
+; X86-64-NEXT:    movq %rdi, %rax
+; X86-64-NEXT:    mulq %r9
+; X86-64-NEXT:    movq %rax, %r8
+; X86-64-NEXT:    movq %rdx, %rcx
+; X86-64-NEXT:    movabsq $3091633084979254461, %r10 # imm = 0x2AE7AFE91E0894BD
+; X86-64-NEXT:    movq %rdi, %rax
+; X86-64-NEXT:    mulq %r10
+; X86-64-NEXT:    movq %rdx, %rdi
+; X86-64-NEXT:    addq %r8, %rdi
+; X86-64-NEXT:    adcq $0, %rcx
+; X86-64-NEXT:    shrq %rsi
+; X86-64-NEXT:    movq %rsi, %rax
+; X86-64-NEXT:    mulq %r9
+; X86-64-NEXT:    movq %rdx, %r8
+; X86-64-NEXT:    movq %rax, %r9
+; X86-64-NEXT:    movq %rsi, %rax
+; X86-64-NEXT:    mulq %r10
+; X86-64-NEXT:    addq %rdi, %rax
+; X86-64-NEXT:    adcq %rdx, %rcx
+; X86-64-NEXT:    adcq $0, %r8
+; X86-64-NEXT:    addq %r9, %rcx
+; X86-64-NEXT:    adcq $0, %r8
+; X86-64-NEXT:    shrdq $5, %r8, %rcx
+; X86-64-NEXT:    shrq $5, %r8
+; X86-64-NEXT:    movq %rcx, %rax
+; X86-64-NEXT:    movq %r8, %rdx
 ; X86-64-NEXT:    retq
 ;
 ; WIN64-LABEL: udiv_magic_preshift_and_postshift:
 ; WIN64:       # %bb.0:
-; WIN64-NEXT:    subq $72, %rsp
-; WIN64-NEXT:    movq %rdx, {{[0-9]+}}(%rsp)
-; WIN64-NEXT:    movq %rcx, {{[0-9]+}}(%rsp)
-; WIN64-NEXT:    movq $358, {{[0-9]+}}(%rsp) # imm = 0x166
-; WIN64-NEXT:    movq $0, {{[0-9]+}}(%rsp)
-; WIN64-NEXT:    leaq {{[0-9]+}}(%rsp), %rcx
-; WIN64-NEXT:    leaq {{[0-9]+}}(%rsp), %rdx
-; WIN64-NEXT:    callq __udivti3
-; WIN64-NEXT:    movq %xmm0, %rax
-; WIN64-NEXT:    pshufd {{.*#+}} xmm0 = xmm0[2,3,2,3]
-; WIN64-NEXT:    movq %xmm0, %rdx
-; WIN64-NEXT:    addq $72, %rsp
+; WIN64-NEXT:    pushq %rsi
+; WIN64-NEXT:    movq %rdx, %r8
+; WIN64-NEXT:    movq %rcx, %r9
+; WIN64-NEXT:    shrdq $1, %rdx, %r9
+; WIN64-NEXT:    movabsq $3297741957311204758, %r11 # imm = 0x2DC3EED6866F8D96
+; WIN64-NEXT:    movq %r9, %rax
+; WIN64-NEXT:    mulq %r11
+; WIN64-NEXT:    movq %rax, %r10
+; WIN64-NEXT:    movq %rdx, %rcx
+; WIN64-NEXT:    movabsq $3091633084979254461, %rsi # imm = 0x2AE7AFE91E0894BD
+; WIN64-NEXT:    movq %r9, %rax
+; WIN64-NEXT:    mulq %rsi
+; WIN64-NEXT:    movq %rdx, %r9
+; WIN64-NEXT:    addq %r10, %r9
+; WIN64-NEXT:    adcq $0, %rcx
+; WIN64-NEXT:    shrq %r8
+; WIN64-NEXT:    movq %r8, %rax
+; WIN64-NEXT:    mulq %r11
+; WIN64-NEXT:    movq %rdx, %r10
+; WIN64-NEXT:    movq %rax, %r11
+; WIN64-NEXT:    movq %r8, %rax
+; WIN64-NEXT:    mulq %rsi
+; WIN64-NEXT:    addq %r9, %rax
+; WIN64-NEXT:    adcq %rdx, %rcx
+; WIN64-NEXT:    adcq $0, %r10
+; WIN64-NEXT:    addq %r11, %rcx
+; WIN64-NEXT:    adcq $0, %r10
+; WIN64-NEXT:    shrdq $5, %r10, %rcx
+; WIN64-NEXT:    shrq $5, %r10
+; WIN64-NEXT:    movq %rcx, %rax
+; WIN64-NEXT:    movq %r10, %rdx
+; WIN64-NEXT:    popq %rsi
 ; WIN64-NEXT:    retq
   %ret = udiv i128 %x, 358
   ret i128 %ret
@@ -1203,27 +1246,93 @@ define i128 @udiv_magic_preshift_and_postshift(i128 %x) nounwind {
 define i128 @urem_magic_preshift_and_postshift(i128 %x) nounwind {
 ; X86-64-LABEL: urem_magic_preshift_and_postshift:
 ; X86-64:       # %bb.0:
-; X86-64-NEXT:    pushq %rax
+; X86-64-NEXT:    pushq %rbx
+; X86-64-NEXT:    movq %rdi, %r8
+; X86-64-NEXT:    shrdq $1, %rsi, %r8
+; X86-64-NEXT:    movabsq $3297741957311204758, %r11 # imm = 0x2DC3EED6866F8D96
+; X86-64-NEXT:    movq %r8, %rax
+; X86-64-NEXT:    mulq %r11
+; X86-64-NEXT:    movq %rax, %r9
+; X86-64-NEXT:    movq %rdx, %rcx
+; X86-64-NEXT:    movabsq $3091633084979254461, %rbx # imm = 0x2AE7AFE91E0894BD
+; X86-64-NEXT:    movq %r8, %rax
+; X86-64-NEXT:    mulq %rbx
+; X86-64-NEXT:    movq %rdx, %r10
+; X86-64-NEXT:    addq %r9, %r10
+; X86-64-NEXT:    adcq $0, %rcx
+; X86-64-NEXT:    movq %rsi, %r9
+; X86-64-NEXT:    shrq %r9
+; X86-64-NEXT:    movq %r9, %rax
+; X86-64-NEXT:    mulq %r11
+; X86-64-NEXT:    movq %rdx, %r8
+; X86-64-NEXT:    movq %rax, %r11
+; X86-64-NEXT:    movq %r9, %rax
+; X86-64-NEXT:    mulq %rbx
+; X86-64-NEXT:    addq %r10, %rax
+; X86-64-NEXT:    adcq %rdx, %rcx
+; X86-64-NEXT:    adcq $0, %r8
+; X86-64-NEXT:    addq %r11, %rcx
+; X86-64-NEXT:    adcq $0, %r8
+; X86-64-NEXT:    shrdq $5, %r8, %rcx
 ; X86-64-NEXT:    movl $358, %edx # imm = 0x166
-; X86-64-NEXT:    xorl %ecx, %ecx
-; X86-64-NEXT:    callq __umodti3 at PLT
-; X86-64-NEXT:    popq %rcx
+; X86-64-NEXT:    movq %rcx, %rax
+; X86-64-NEXT:    mulq %rdx
+; X86-64-NEXT:    shrq $5, %r8
+; X86-64-NEXT:    imulq $358, %r8, %rcx # imm = 0x166
+; X86-64-NEXT:    addq %rdx, %rcx
+; X86-64-NEXT:    subq %rax, %rdi
+; X86-64-NEXT:    sbbq %rcx, %rsi
+; X86-64-NEXT:    movq %rdi, %rax
+; X86-64-NEXT:    movq %rsi, %rdx
+; X86-64-NEXT:    popq %rbx
 ; X86-64-NEXT:    retq
 ;
 ; WIN64-LABEL: urem_magic_preshift_and_postshift:
 ; WIN64:       # %bb.0:
-; WIN64-NEXT:    subq $72, %rsp
-; WIN64-NEXT:    movq %rdx, {{[0-9]+}}(%rsp)
-; WIN64-NEXT:    movq %rcx, {{[0-9]+}}(%rsp)
-; WIN64-NEXT:    movq $358, {{[0-9]+}}(%rsp) # imm = 0x166
-; WIN64-NEXT:    movq $0, {{[0-9]+}}(%rsp)
-; WIN64-NEXT:    leaq {{[0-9]+}}(%rsp), %rcx
-; WIN64-NEXT:    leaq {{[0-9]+}}(%rsp), %rdx
-; WIN64-NEXT:    callq __umodti3
-; WIN64-NEXT:    movq %xmm0, %rax
-; WIN64-NEXT:    pshufd {{.*#+}} xmm0 = xmm0[2,3,2,3]
-; WIN64-NEXT:    movq %xmm0, %rdx
-; WIN64-NEXT:    addq $72, %rsp
+; WIN64-NEXT:    pushq %rsi
+; WIN64-NEXT:    pushq %rdi
+; WIN64-NEXT:    pushq %rbx
+; WIN64-NEXT:    movq %rdx, %r8
+; WIN64-NEXT:    movq %rcx, %r10
+; WIN64-NEXT:    shrdq $1, %rdx, %r10
+; WIN64-NEXT:    movabsq $3297741957311204758, %rdi # imm = 0x2DC3EED6866F8D96
+; WIN64-NEXT:    movq %r10, %rax
+; WIN64-NEXT:    mulq %rdi
+; WIN64-NEXT:    movq %rax, %r11
+; WIN64-NEXT:    movq %rdx, %r9
+; WIN64-NEXT:    movabsq $3091633084979254461, %rbx # imm = 0x2AE7AFE91E0894BD
+; WIN64-NEXT:    movq %r10, %rax
+; WIN64-NEXT:    mulq %rbx
+; WIN64-NEXT:    movq %rdx, %rsi
+; WIN64-NEXT:    addq %r11, %rsi
+; WIN64-NEXT:    adcq $0, %r9
+; WIN64-NEXT:    movq %r8, %r11
+; WIN64-NEXT:    shrq %r11
+; WIN64-NEXT:    movq %r11, %rax
+; WIN64-NEXT:    mulq %rdi
+; WIN64-NEXT:    movq %rdx, %r10
+; WIN64-NEXT:    movq %rax, %rdi
+; WIN64-NEXT:    movq %r11, %rax
+; WIN64-NEXT:    mulq %rbx
+; WIN64-NEXT:    addq %rsi, %rax
+; WIN64-NEXT:    adcq %rdx, %r9
+; WIN64-NEXT:    adcq $0, %r10
+; WIN64-NEXT:    addq %rdi, %r9
+; WIN64-NEXT:    adcq $0, %r10
+; WIN64-NEXT:    shrdq $5, %r10, %r9
+; WIN64-NEXT:    movl $358, %edx # imm = 0x166
+; WIN64-NEXT:    movq %r9, %rax
+; WIN64-NEXT:    mulq %rdx
+; WIN64-NEXT:    shrq $5, %r10
+; WIN64-NEXT:    imulq $358, %r10, %r9 # imm = 0x166
+; WIN64-NEXT:    addq %rdx, %r9
+; WIN64-NEXT:    subq %rax, %rcx
+; WIN64-NEXT:    sbbq %r9, %r8
+; WIN64-NEXT:    movq %rcx, %rax
+; WIN64-NEXT:    movq %r8, %rdx
+; WIN64-NEXT:    popq %rbx
+; WIN64-NEXT:    popq %rdi
+; WIN64-NEXT:    popq %rsi
 ; WIN64-NEXT:    retq
   %ret = urem i128 %x, 358
   ret i128 %ret
@@ -1233,28 +1342,37 @@ define i128 @urem_magic_preshift_and_postshift(i128 %x) nounwind {
 define i128 @udiv_magic_large_preshift(i128 %x) nounwind {
 ; X86-64-LABEL: udiv_magic_large_preshift:
 ; X86-64:       # %bb.0:
-; X86-64-NEXT:    pushq %rax
-; X86-64-NEXT:    movabsq $12300786335744, %rcx # imm = 0xB3000000000
+; X86-64-NEXT:    shrq $36, %rsi
+; X86-64-NEXT:    movabsq $103054436165975148, %rcx # imm = 0x16E1F76B4337C6C
+; X86-64-NEXT:    movq %rsi, %rax
+; X86-64-NEXT:    mulq %rcx
+; X86-64-NEXT:    movq %rax, %rcx
+; X86-64-NEXT:    movq %rdx, %rdi
+; X86-64-NEXT:    movabsq $-5667993989128633178, %rdx # imm = 0xB1573D7F48F044A6
+; X86-64-NEXT:    movq %rsi, %rax
+; X86-64-NEXT:    mulq %rdx
+; X86-64-NEXT:    addq %rcx, %rdx
+; X86-64-NEXT:    adcq $0, %rdi
+; X86-64-NEXT:    movq %rdi, %rax
 ; X86-64-NEXT:    xorl %edx, %edx
-; X86-64-NEXT:    callq __udivti3 at PLT
-; X86-64-NEXT:    popq %rcx
 ; X86-64-NEXT:    retq
 ;
 ; WIN64-LABEL: udiv_magic_large_preshift:
 ; WIN64:       # %bb.0:
-; WIN64-NEXT:    subq $72, %rsp
-; WIN64-NEXT:    movq %rdx, {{[0-9]+}}(%rsp)
-; WIN64-NEXT:    movq %rcx, {{[0-9]+}}(%rsp)
-; WIN64-NEXT:    movabsq $12300786335744, %rax # imm = 0xB3000000000
-; WIN64-NEXT:    movq %rax, {{[0-9]+}}(%rsp)
-; WIN64-NEXT:    movq $0, {{[0-9]+}}(%rsp)
-; WIN64-NEXT:    leaq {{[0-9]+}}(%rsp), %rcx
-; WIN64-NEXT:    leaq {{[0-9]+}}(%rsp), %rdx
-; WIN64-NEXT:    callq __udivti3
-; WIN64-NEXT:    movq %xmm0, %rax
-; WIN64-NEXT:    pshufd {{.*#+}} xmm0 = xmm0[2,3,2,3]
-; WIN64-NEXT:    movq %xmm0, %rdx
-; WIN64-NEXT:    addq $72, %rsp
+; WIN64-NEXT:    movq %rdx, %rcx
+; WIN64-NEXT:    shrq $36, %rcx
+; WIN64-NEXT:    movabsq $103054436165975148, %rdx # imm = 0x16E1F76B4337C6C
+; WIN64-NEXT:    movq %rcx, %rax
+; WIN64-NEXT:    mulq %rdx
+; WIN64-NEXT:    movq %rax, %r8
+; WIN64-NEXT:    movq %rdx, %r9
+; WIN64-NEXT:    movabsq $-5667993989128633178, %rdx # imm = 0xB1573D7F48F044A6
+; WIN64-NEXT:    movq %rcx, %rax
+; WIN64-NEXT:    mulq %rdx
+; WIN64-NEXT:    addq %r8, %rdx
+; WIN64-NEXT:    adcq $0, %r9
+; WIN64-NEXT:    movq %r9, %rax
+; WIN64-NEXT:    xorl %edx, %edx
 ; WIN64-NEXT:    retq
   %ret = udiv i128 %x, 226909457440853062867909873762304 ; = 179 * 2^100
   ret i128 %ret
@@ -1264,28 +1382,45 @@ define i128 @udiv_magic_large_preshift(i128 %x) nounwind {
 define i128 @urem_magic_large_preshift(i128 %x) nounwind {
 ; X86-64-LABEL: urem_magic_large_preshift:
 ; X86-64:       # %bb.0:
-; X86-64-NEXT:    pushq %rax
-; X86-64-NEXT:    movabsq $12300786335744, %rcx # imm = 0xB3000000000
-; X86-64-NEXT:    xorl %edx, %edx
-; X86-64-NEXT:    callq __umodti3 at PLT
-; X86-64-NEXT:    popq %rcx
+; X86-64-NEXT:    movq %rsi, %rcx
+; X86-64-NEXT:    shrq $36, %rcx
+; X86-64-NEXT:    movabsq $103054436165975148, %rdx # imm = 0x16E1F76B4337C6C
+; X86-64-NEXT:    movq %rcx, %rax
+; X86-64-NEXT:    mulq %rdx
+; X86-64-NEXT:    movq %rax, %r8
+; X86-64-NEXT:    movq %rdx, %r9
+; X86-64-NEXT:    movabsq $-5667993989128633178, %rdx # imm = 0xB1573D7F48F044A6
+; X86-64-NEXT:    movq %rcx, %rax
+; X86-64-NEXT:    mulq %rdx
+; X86-64-NEXT:    addq %r8, %rdx
+; X86-64-NEXT:    adcq $0, %r9
+; X86-64-NEXT:    movabsq $12300786335744, %rax # imm = 0xB3000000000
+; X86-64-NEXT:    imulq %r9, %rax
+; X86-64-NEXT:    subq %rax, %rsi
+; X86-64-NEXT:    movq %rdi, %rax
+; X86-64-NEXT:    movq %rsi, %rdx
 ; X86-64-NEXT:    retq
 ;
 ; WIN64-LABEL: urem_magic_large_preshift:
 ; WIN64:       # %bb.0:
-; WIN64-NEXT:    subq $72, %rsp
-; WIN64-NEXT:    movq %rdx, {{[0-9]+}}(%rsp)
-; WIN64-NEXT:    movq %rcx, {{[0-9]+}}(%rsp)
+; WIN64-NEXT:    movq %rdx, %r8
+; WIN64-NEXT:    movq %rdx, %r9
+; WIN64-NEXT:    shrq $36, %r9
+; WIN64-NEXT:    movabsq $103054436165975148, %rdx # imm = 0x16E1F76B4337C6C
+; WIN64-NEXT:    movq %r9, %rax
+; WIN64-NEXT:    mulq %rdx
+; WIN64-NEXT:    movq %rax, %r10
+; WIN64-NEXT:    movq %rdx, %r11
+; WIN64-NEXT:    movabsq $-5667993989128633178, %rdx # imm = 0xB1573D7F48F044A6
+; WIN64-NEXT:    movq %r9, %rax
+; WIN64-NEXT:    mulq %rdx
+; WIN64-NEXT:    addq %r10, %rdx
+; WIN64-NEXT:    adcq $0, %r11
 ; WIN64-NEXT:    movabsq $12300786335744, %rax # imm = 0xB3000000000
-; WIN64-NEXT:    movq %rax, {{[0-9]+}}(%rsp)
-; WIN64-NEXT:    movq $0, {{[0-9]+}}(%rsp)
-; WIN64-NEXT:    leaq {{[0-9]+}}(%rsp), %rcx
-; WIN64-NEXT:    leaq {{[0-9]+}}(%rsp), %rdx
-; WIN64-NEXT:    callq __umodti3
-; WIN64-NEXT:    movq %xmm0, %rax
-; WIN64-NEXT:    pshufd {{.*#+}} xmm0 = xmm0[2,3,2,3]
-; WIN64-NEXT:    movq %xmm0, %rdx
-; WIN64-NEXT:    addq $72, %rsp
+; WIN64-NEXT:    imulq %r11, %rax
+; WIN64-NEXT:    subq %rax, %r8
+; WIN64-NEXT:    movq %rcx, %rax
+; WIN64-NEXT:    movq %r8, %rdx
 ; WIN64-NEXT:    retq
   %ret = urem i128 %x, 226909457440853062867909873762304 ; = 179 * 2^100
   ret i128 %ret
@@ -1295,27 +1430,39 @@ define i128 @urem_magic_large_preshift(i128 %x) nounwind {
 define i128 @udiv_magic_large_postshift(i128 %x) nounwind {
 ; X86-64-LABEL: udiv_magic_large_postshift:
 ; X86-64:       # %bb.0:
-; X86-64-NEXT:    pushq %rax
-; X86-64-NEXT:    movl $1, %edx
-; X86-64-NEXT:    movl $1, %ecx
-; X86-64-NEXT:    callq __udivti3 at PLT
-; X86-64-NEXT:    popq %rcx
+; X86-64-NEXT:    movq $-1, %r9
+; X86-64-NEXT:    movq %rsi, %rax
+; X86-64-NEXT:    mulq %r9
+; X86-64-NEXT:    movq %rdx, %rcx
+; X86-64-NEXT:    movq %rax, %r8
+; X86-64-NEXT:    movq %rdi, %rax
+; X86-64-NEXT:    mulq %r9
+; X86-64-NEXT:    addq %rsi, %rax
+; X86-64-NEXT:    adcq $0, %rdx
+; X86-64-NEXT:    adcq $0, %rcx
+; X86-64-NEXT:    addq %r8, %rdx
+; X86-64-NEXT:    adcq $0, %rcx
+; X86-64-NEXT:    movq %rcx, %rax
+; X86-64-NEXT:    xorl %edx, %edx
 ; X86-64-NEXT:    retq
 ;
 ; WIN64-LABEL: udiv_magic_large_postshift:
 ; WIN64:       # %bb.0:
-; WIN64-NEXT:    subq $72, %rsp
-; WIN64-NEXT:    movq %rdx, {{[0-9]+}}(%rsp)
-; WIN64-NEXT:    movq %rcx, {{[0-9]+}}(%rsp)
-; WIN64-NEXT:    movq $1, {{[0-9]+}}(%rsp)
-; WIN64-NEXT:    movq $1, {{[0-9]+}}(%rsp)
-; WIN64-NEXT:    leaq {{[0-9]+}}(%rsp), %rcx
-; WIN64-NEXT:    leaq {{[0-9]+}}(%rsp), %rdx
-; WIN64-NEXT:    callq __udivti3
-; WIN64-NEXT:    movq %xmm0, %rax
-; WIN64-NEXT:    pshufd {{.*#+}} xmm0 = xmm0[2,3,2,3]
-; WIN64-NEXT:    movq %xmm0, %rdx
-; WIN64-NEXT:    addq $72, %rsp
+; WIN64-NEXT:    movq %rdx, %r8
+; WIN64-NEXT:    movq $-1, %r11
+; WIN64-NEXT:    movq %rdx, %rax
+; WIN64-NEXT:    mulq %r11
+; WIN64-NEXT:    movq %rdx, %r9
+; WIN64-NEXT:    movq %rax, %r10
+; WIN64-NEXT:    movq %rcx, %rax
+; WIN64-NEXT:    mulq %r11
+; WIN64-NEXT:    addq %r8, %rax
+; WIN64-NEXT:    adcq $0, %rdx
+; WIN64-NEXT:    adcq $0, %r9
+; WIN64-NEXT:    addq %r10, %rdx
+; WIN64-NEXT:    adcq $0, %r9
+; WIN64-NEXT:    movq %r9, %rax
+; WIN64-NEXT:    xorl %edx, %edx
 ; WIN64-NEXT:    retq
   %ret = udiv i128 %x, 18446744073709551617 ; = 2^64 + 1
   ret i128 %ret
@@ -1325,27 +1472,43 @@ define i128 @udiv_magic_large_postshift(i128 %x) nounwind {
 define i128 @urem_magic_large_postshift(i128 %x) nounwind {
 ; X86-64-LABEL: urem_magic_large_postshift:
 ; X86-64:       # %bb.0:
-; X86-64-NEXT:    pushq %rax
-; X86-64-NEXT:    movl $1, %edx
-; X86-64-NEXT:    movl $1, %ecx
-; X86-64-NEXT:    callq __umodti3 at PLT
-; X86-64-NEXT:    popq %rcx
+; X86-64-NEXT:    movq $-1, %r9
+; X86-64-NEXT:    movq %rsi, %rax
+; X86-64-NEXT:    mulq %r9
+; X86-64-NEXT:    movq %rdx, %rcx
+; X86-64-NEXT:    movq %rax, %r8
+; X86-64-NEXT:    movq %rdi, %rax
+; X86-64-NEXT:    mulq %r9
+; X86-64-NEXT:    addq %rsi, %rax
+; X86-64-NEXT:    adcq $0, %rdx
+; X86-64-NEXT:    adcq $0, %rcx
+; X86-64-NEXT:    addq %r8, %rdx
+; X86-64-NEXT:    adcq $0, %rcx
+; X86-64-NEXT:    subq %rcx, %rdi
+; X86-64-NEXT:    sbbq %rcx, %rsi
+; X86-64-NEXT:    movq %rdi, %rax
+; X86-64-NEXT:    movq %rsi, %rdx
 ; X86-64-NEXT:    retq
 ;
 ; WIN64-LABEL: urem_magic_large_postshift:
 ; WIN64:       # %bb.0:
-; WIN64-NEXT:    subq $72, %rsp
-; WIN64-NEXT:    movq %rdx, {{[0-9]+}}(%rsp)
-; WIN64-NEXT:    movq %rcx, {{[0-9]+}}(%rsp)
-; WIN64-NEXT:    movq $1, {{[0-9]+}}(%rsp)
-; WIN64-NEXT:    movq $1, {{[0-9]+}}(%rsp)
-; WIN64-NEXT:    leaq {{[0-9]+}}(%rsp), %rcx
-; WIN64-NEXT:    leaq {{[0-9]+}}(%rsp), %rdx
-; WIN64-NEXT:    callq __umodti3
-; WIN64-NEXT:    movq %xmm0, %rax
-; WIN64-NEXT:    pshufd {{.*#+}} xmm0 = xmm0[2,3,2,3]
-; WIN64-NEXT:    movq %xmm0, %rdx
-; WIN64-NEXT:    addq $72, %rsp
+; WIN64-NEXT:    movq %rdx, %r8
+; WIN64-NEXT:    movq $-1, %r11
+; WIN64-NEXT:    movq %rdx, %rax
+; WIN64-NEXT:    mulq %r11
+; WIN64-NEXT:    movq %rdx, %r9
+; WIN64-NEXT:    movq %rax, %r10
+; WIN64-NEXT:    movq %rcx, %rax
+; WIN64-NEXT:    mulq %r11
+; WIN64-NEXT:    addq %r8, %rax
+; WIN64-NEXT:    adcq $0, %rdx
+; WIN64-NEXT:    adcq $0, %r9
+; WIN64-NEXT:    addq %r10, %rdx
+; WIN64-NEXT:    adcq $0, %r9
+; WIN64-NEXT:    subq %r9, %rcx
+; WIN64-NEXT:    sbbq %r9, %r8
+; WIN64-NEXT:    movq %rcx, %rax
+; WIN64-NEXT:    movq %r8, %rdx
 ; WIN64-NEXT:    retq
   %ret = urem i128 %x, 18446744073709551617 ; = 2^64 + 1
   ret i128 %ret
@@ -1355,28 +1518,77 @@ define i128 @urem_magic_large_postshift(i128 %x) nounwind {
 define i128 @udiv_magic_is_add(i128 %x) nounwind {
 ; X86-64-LABEL: udiv_magic_is_add:
 ; X86-64:       # %bb.0:
-; X86-64-NEXT:    pushq %rax
-; X86-64-NEXT:    movabsq $-9223372036854775808, %rcx # imm = 0x8000000000000000
-; X86-64-NEXT:    movl $1, %edx
-; X86-64-NEXT:    callq __udivti3 at PLT
-; X86-64-NEXT:    popq %rcx
+; X86-64-NEXT:    movq $-1, %r10
+; X86-64-NEXT:    movq %rdi, %rax
+; X86-64-NEXT:    mulq %r10
+; X86-64-NEXT:    movq %rax, %rcx
+; X86-64-NEXT:    movq %rdx, %r8
+; X86-64-NEXT:    movq $-3, %r11
+; X86-64-NEXT:    movq %rdi, %rax
+; X86-64-NEXT:    mulq %r11
+; X86-64-NEXT:    movq %rdx, %r9
+; X86-64-NEXT:    addq %rcx, %r9
+; X86-64-NEXT:    adcq $0, %r8
+; X86-64-NEXT:    movq %rsi, %rax
+; X86-64-NEXT:    mulq %r10
+; X86-64-NEXT:    movq %rdx, %rcx
+; X86-64-NEXT:    movq %rax, %r10
+; X86-64-NEXT:    movq %rsi, %rax
+; X86-64-NEXT:    mulq %r11
+; X86-64-NEXT:    addq %r9, %rax
+; X86-64-NEXT:    adcq %r8, %rdx
+; X86-64-NEXT:    adcq $0, %rcx
+; X86-64-NEXT:    addq %r10, %rdx
+; X86-64-NEXT:    adcq $0, %rcx
+; X86-64-NEXT:    subq %rdx, %rdi
+; X86-64-NEXT:    sbbq %rcx, %rsi
+; X86-64-NEXT:    shrdq $1, %rsi, %rdi
+; X86-64-NEXT:    shrq %rsi
+; X86-64-NEXT:    addq %rdx, %rdi
+; X86-64-NEXT:    adcq %rsi, %rcx
+; X86-64-NEXT:    shrq $63, %rcx
+; X86-64-NEXT:    movq %rcx, %rax
+; X86-64-NEXT:    xorl %edx, %edx
 ; X86-64-NEXT:    retq
 ;
 ; WIN64-LABEL: udiv_magic_is_add:
 ; WIN64:       # %bb.0:
-; WIN64-NEXT:    subq $72, %rsp
-; WIN64-NEXT:    movq %rdx, {{[0-9]+}}(%rsp)
-; WIN64-NEXT:    movq %rcx, {{[0-9]+}}(%rsp)
-; WIN64-NEXT:    movabsq $-9223372036854775808, %rax # imm = 0x8000000000000000
-; WIN64-NEXT:    movq %rax, {{[0-9]+}}(%rsp)
-; WIN64-NEXT:    movq $1, {{[0-9]+}}(%rsp)
-; WIN64-NEXT:    leaq {{[0-9]+}}(%rsp), %rcx
-; WIN64-NEXT:    leaq {{[0-9]+}}(%rsp), %rdx
-; WIN64-NEXT:    callq __udivti3
-; WIN64-NEXT:    movq %xmm0, %rax
-; WIN64-NEXT:    pshufd {{.*#+}} xmm0 = xmm0[2,3,2,3]
-; WIN64-NEXT:    movq %xmm0, %rdx
-; WIN64-NEXT:    addq $72, %rsp
+; WIN64-NEXT:    pushq %rsi
+; WIN64-NEXT:    pushq %rdi
+; WIN64-NEXT:    movq %rdx, %r8
+; WIN64-NEXT:    movq $-1, %rsi
+; WIN64-NEXT:    movq %rcx, %rax
+; WIN64-NEXT:    mulq %rsi
+; WIN64-NEXT:    movq %rax, %r9
+; WIN64-NEXT:    movq %rdx, %r10
+; WIN64-NEXT:    movq $-3, %rdi
+; WIN64-NEXT:    movq %rcx, %rax
+; WIN64-NEXT:    mulq %rdi
+; WIN64-NEXT:    movq %rdx, %r11
+; WIN64-NEXT:    addq %r9, %r11
+; WIN64-NEXT:    adcq $0, %r10
+; WIN64-NEXT:    movq %r8, %rax
+; WIN64-NEXT:    mulq %rsi
+; WIN64-NEXT:    movq %rdx, %r9
+; WIN64-NEXT:    movq %rax, %rsi
+; WIN64-NEXT:    movq %r8, %rax
+; WIN64-NEXT:    mulq %rdi
+; WIN64-NEXT:    addq %r11, %rax
+; WIN64-NEXT:    adcq %r10, %rdx
+; WIN64-NEXT:    adcq $0, %r9
+; WIN64-NEXT:    addq %rsi, %rdx
+; WIN64-NEXT:    adcq $0, %r9
+; WIN64-NEXT:    subq %rdx, %rcx
+; WIN64-NEXT:    sbbq %r9, %r8
+; WIN64-NEXT:    shrdq $1, %r8, %rcx
+; WIN64-NEXT:    shrq %r8
+; WIN64-NEXT:    addq %rdx, %rcx
+; WIN64-NEXT:    adcq %r9, %r8
+; WIN64-NEXT:    shrq $63, %r8
+; WIN64-NEXT:    movq %r8, %rax
+; WIN64-NEXT:    xorl %edx, %edx
+; WIN64-NEXT:    popq %rdi
+; WIN64-NEXT:    popq %rsi
 ; WIN64-NEXT:    retq
   %ret = udiv i128 %x, 170141183460469231731687303715884105729 ; = 2^127 + 1
   ret i128 %ret
@@ -1386,28 +1598,89 @@ define i128 @udiv_magic_is_add(i128 %x) nounwind {
 define i128 @urem_magic_is_add(i128 %x) nounwind {
 ; X86-64-LABEL: urem_magic_is_add:
 ; X86-64:       # %bb.0:
-; X86-64-NEXT:    pushq %rax
-; X86-64-NEXT:    movabsq $-9223372036854775808, %rcx # imm = 0x8000000000000000
-; X86-64-NEXT:    movl $1, %edx
-; X86-64-NEXT:    callq __umodti3 at PLT
-; X86-64-NEXT:    popq %rcx
+; X86-64-NEXT:    movq $-1, %r10
+; X86-64-NEXT:    movq %rdi, %rax
+; X86-64-NEXT:    mulq %r10
+; X86-64-NEXT:    movq %rax, %rcx
+; X86-64-NEXT:    movq %rdx, %r8
+; X86-64-NEXT:    movq $-3, %r11
+; X86-64-NEXT:    movq %rdi, %rax
+; X86-64-NEXT:    mulq %r11
+; X86-64-NEXT:    movq %rdx, %r9
+; X86-64-NEXT:    addq %rcx, %r9
+; X86-64-NEXT:    adcq $0, %r8
+; X86-64-NEXT:    movq %rsi, %rax
+; X86-64-NEXT:    mulq %r10
+; X86-64-NEXT:    movq %rdx, %rcx
+; X86-64-NEXT:    movq %rax, %r10
+; X86-64-NEXT:    movq %rsi, %rax
+; X86-64-NEXT:    mulq %r11
+; X86-64-NEXT:    addq %r9, %rax
+; X86-64-NEXT:    adcq %r8, %rdx
+; X86-64-NEXT:    adcq $0, %rcx
+; X86-64-NEXT:    addq %r10, %rdx
+; X86-64-NEXT:    adcq $0, %rcx
+; X86-64-NEXT:    movq %rdi, %rax
+; X86-64-NEXT:    subq %rdx, %rax
+; X86-64-NEXT:    movq %rsi, %r8
+; X86-64-NEXT:    sbbq %rcx, %r8
+; X86-64-NEXT:    shrdq $1, %r8, %rax
+; X86-64-NEXT:    shrq %r8
+; X86-64-NEXT:    addq %rdx, %rax
+; X86-64-NEXT:    adcq %rcx, %r8
+; X86-64-NEXT:    movabsq $-9223372036854775808, %rax # imm = 0x8000000000000000
+; X86-64-NEXT:    andq %r8, %rax
+; X86-64-NEXT:    shrq $63, %r8
+; X86-64-NEXT:    subq %r8, %rdi
+; X86-64-NEXT:    sbbq %rax, %rsi
+; X86-64-NEXT:    movq %rdi, %rax
+; X86-64-NEXT:    movq %rsi, %rdx
 ; X86-64-NEXT:    retq
 ;
 ; WIN64-LABEL: urem_magic_is_add:
 ; WIN64:       # %bb.0:
-; WIN64-NEXT:    subq $72, %rsp
-; WIN64-NEXT:    movq %rdx, {{[0-9]+}}(%rsp)
-; WIN64-NEXT:    movq %rcx, {{[0-9]+}}(%rsp)
+; WIN64-NEXT:    pushq %rsi
+; WIN64-NEXT:    pushq %rdi
+; WIN64-NEXT:    movq %rdx, %r8
+; WIN64-NEXT:    movq $-1, %rsi
+; WIN64-NEXT:    movq %rcx, %rax
+; WIN64-NEXT:    mulq %rsi
+; WIN64-NEXT:    movq %rax, %r9
+; WIN64-NEXT:    movq %rdx, %r10
+; WIN64-NEXT:    movq $-3, %rdi
+; WIN64-NEXT:    movq %rcx, %rax
+; WIN64-NEXT:    mulq %rdi
+; WIN64-NEXT:    movq %rdx, %r11
+; WIN64-NEXT:    addq %r9, %r11
+; WIN64-NEXT:    adcq $0, %r10
+; WIN64-NEXT:    movq %r8, %rax
+; WIN64-NEXT:    mulq %rsi
+; WIN64-NEXT:    movq %rdx, %r9
+; WIN64-NEXT:    movq %rax, %rsi
+; WIN64-NEXT:    movq %r8, %rax
+; WIN64-NEXT:    mulq %rdi
+; WIN64-NEXT:    addq %r11, %rax
+; WIN64-NEXT:    adcq %r10, %rdx
+; WIN64-NEXT:    adcq $0, %r9
+; WIN64-NEXT:    addq %rsi, %rdx
+; WIN64-NEXT:    adcq $0, %r9
+; WIN64-NEXT:    movq %rcx, %rax
+; WIN64-NEXT:    subq %rdx, %rax
+; WIN64-NEXT:    movq %r8, %r10
+; WIN64-NEXT:    sbbq %r9, %r10
+; WIN64-NEXT:    shrdq $1, %r10, %rax
+; WIN64-NEXT:    shrq %r10
+; WIN64-NEXT:    addq %rdx, %rax
+; WIN64-NEXT:    adcq %r9, %r10
 ; WIN64-NEXT:    movabsq $-9223372036854775808, %rax # imm = 0x8000000000000000
-; WIN64-NEXT:    movq %rax, {{[0-9]+}}(%rsp)
-; WIN64-NEXT:    movq $1, {{[0-9]+}}(%rsp)
-; WIN64-NEXT:    leaq {{[0-9]+}}(%rsp), %rcx
-; WIN64-NEXT:    leaq {{[0-9]+}}(%rsp), %rdx
-; WIN64-NEXT:    callq __umodti3
-; WIN64-NEXT:    movq %xmm0, %rax
-; WIN64-NEXT:    pshufd {{.*#+}} xmm0 = xmm0[2,3,2,3]
-; WIN64-NEXT:    movq %xmm0, %rdx
-; WIN64-NEXT:    addq $72, %rsp
+; WIN64-NEXT:    andq %r10, %rax
+; WIN64-NEXT:    shrq $63, %r10
+; WIN64-NEXT:    subq %r10, %rcx
+; WIN64-NEXT:    sbbq %rax, %r8
+; WIN64-NEXT:    movq %rcx, %rax
+; WIN64-NEXT:    movq %r8, %rdx
+; WIN64-NEXT:    popq %rdi
+; WIN64-NEXT:    popq %rsi
 ; WIN64-NEXT:    retq
   %ret = urem i128 %x, 170141183460469231731687303715884105729 ; = 2^127 + 1
   ret i128 %ret
diff --git a/llvm/test/CodeGen/X86/i128-udiv.ll b/llvm/test/CodeGen/X86/i128-udiv.ll
index e25584c64496a..e11725e426602 100644
--- a/llvm/test/CodeGen/X86/i128-udiv.ll
+++ b/llvm/test/CodeGen/X86/i128-udiv.ll
@@ -649,11 +649,31 @@ define i128 @test3(i128 %x) nounwind {
 ;
 ; X64-LABEL: test3:
 ; X64:       # %bb.0:
-; X64-NEXT:    pushq %rax
-; X64-NEXT:    movq $-3, %rdx
-; X64-NEXT:    movq $-5, %rcx
-; X64-NEXT:    callq __udivti3 at PLT
-; X64-NEXT:    popq %rcx
+; X64-NEXT:    movabsq $4611686018427387905, %r9 # imm = 0x4000000000000001
+; X64-NEXT:    movq %rdi, %rax
+; X64-NEXT:    mulq %r9
+; X64-NEXT:    movq %rax, %rcx
+; X64-NEXT:    movq %rdx, %r8
+; X64-NEXT:    movl $5, %r10d
+; X64-NEXT:    movq %rdi, %rax
+; X64-NEXT:    mulq %r10
+; X64-NEXT:    movq %rdx, %rdi
+; X64-NEXT:    addq %rcx, %rdi
+; X64-NEXT:    adcq $0, %r8
+; X64-NEXT:    movq %rsi, %rax
+; X64-NEXT:    mulq %r9
+; X64-NEXT:    movq %rdx, %rcx
+; X64-NEXT:    movq %rax, %r9
+; X64-NEXT:    movq %rsi, %rax
+; X64-NEXT:    mulq %r10
+; X64-NEXT:    addq %rdi, %rax
+; X64-NEXT:    adcq %r8, %rdx
+; X64-NEXT:    adcq $0, %rcx
+; X64-NEXT:    addq %r9, %rdx
+; X64-NEXT:    adcq $0, %rcx
+; X64-NEXT:    shrq $62, %rcx
+; X64-NEXT:    movq %rcx, %rax
+; X64-NEXT:    xorl %edx, %edx
 ; X64-NEXT:    retq
   %tmp = udiv i128 %x, -73786976294838206467
   ret i128 %tmp

>From 0f3b0826025f8be3e39910b4a231c15054c6c79f Mon Sep 17 00:00:00 2001
From: Marius Kamp <msk at posteo.org>
Date: Fri, 1 May 2026 11:25:54 +0200
Subject: [PATCH 5/5] [SelectionDAG] Update Method Comment; NFC

---
 llvm/include/llvm/CodeGen/TargetLowering.h | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/llvm/include/llvm/CodeGen/TargetLowering.h b/llvm/include/llvm/CodeGen/TargetLowering.h
index 429cf94f18469..668a88361cf3e 100644
--- a/llvm/include/llvm/CodeGen/TargetLowering.h
+++ b/llvm/include/llvm/CodeGen/TargetLowering.h
@@ -5529,10 +5529,12 @@ class LLVM_ABI TargetLowering : public TargetLoweringBase {
                  SDValue LL = SDValue(), SDValue LH = SDValue(),
                  SDValue RL = SDValue(), SDValue RH = SDValue()) const;
 
-  /// Attempt to expand an n-bit div/rem/divrem by constant using a n/2-bit
-  /// urem by constant and other arithmetic ops. The n/2-bit urem by constant
-  /// will be expanded by DAGCombiner. This is not possible for all constant
-  /// divisors.
+  /// Attempt to expand an n-bit div/rem/divrem by constant using an n/2-bit
+  /// algorithm. First, attempt to expand the division using a n/2-bit urem by
+  /// constant and other arithmetic ops. The n/2-bit urem by constant will be
+  /// expanded by DAGCombiner. As this is not possible for all constant
+  /// divisors, this method falls back to an implementation of the magic
+  /// algorithm using n/2-bit operations.
   /// \param N Node to expand
   /// \param Result A vector that will be filled with the lo and high parts of
   ///        the results. For *DIVREM, this will be the quotient parts followed



More information about the llvm-commits mailing list